diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Wed Aug 20 04:41:21 2003
+++ b/CREDITS	Sun Aug 31 08:22:06 2003
@@ -1238,14 +1238,13 @@
 
 N: Christoph Hellwig
 E: hch@infradead.org
-E: hch@sgi.com
 D: all kinds of driver, filesystem & core kernel hacking
 D: freevxfs driver
 D: sysvfs maintainer
 D: chief codingstyle nitpicker
-S: Auweg 38
-S: 85748 Garching
-S: Germany
+S: Ampferstr. 50 / 4
+S: 6020 Innsbruck
+S: Austria
 
 N: Richard Henderson
 E: rth@twiddle.net
@@ -2208,6 +2207,15 @@
 E: wolfgang@iksw-muees.de
 D: Auerswald USB driver
 
+N: Paul Mundt
+E: lethal@linux-sh.org
+P: 1024D/917167DC 563C FC60 83BB A3EE D816  E60D D4AF AD78 9171 67DC
+D: Linux/SH and Linux/sh64
+D: Occasional MIPS hacker
+D: fbdev hacker
+S: Hamilton, Ontario
+S: Canada
+
 N: Ian A. Murdock
 E: imurdock@gnu.ai.mit.edu
 D: Creator of Debian distribution
@@ -2967,12 +2975,12 @@
 S: USA
 
 N: Marcelo W. Tosatti
-E: marcelo@conectiva.com.br
-W: http://bazar.conectiva.com.br/~marcelo/
+E: marcelo@parcelfarce.linux.theplanet.co.uk
+E: marcelo.tosatti@cyclades.com.br
 D: Miscellaneous kernel hacker (mostly VM/MM work)
-S: Conectiva S.A.
-S: R. Tocantins, 89 - Cristo Rei
-S: 80050-430 - Curitiba - Paraná
+D: 2.4 maintainer
+S: Av Cristovao Colombo, 462. Floresta.
+S: Porto Alegre
 S: Brazil
 
 N: Stefan Traby
diff -Nru a/Documentation/Configure.help b/Documentation/Configure.help
--- a/Documentation/Configure.help	Sat Aug 23 06:49:21 2003
+++ b/Documentation/Configure.help	Sat Aug 30 07:24:48 2003
@@ -2,8 +2,6 @@
 #	Eric S. Raymond <mailto:esr@thyrsus.com>
 #	Steven Cole <mailto:elenstev@mesatop.com>
 #
-# Version 3.01: current with 2.4.19+
-#
 # Translations of this file available on the WWW:
 #
 #   - Japanese, maintained by the JF Project <mailto:JF@linux.or.jp>, at
@@ -19,13 +17,6 @@
 #   - Catalan, by Antoni Bella <mailto:bella5@teleline.es>, at
 #     <http://www.terra.es/personal7/bella5/traduccions.htm>
 #
-# To access a document on the WWW, you need to have a direct Internet
-# connection and a browser program such as netscape or lynx. If you
-# only have email access, you can still use FTP and WWW servers: send
-# an email to <mailto:mail-server@rtfm.mit.edu> with the text
-#   send usenet/news.answers/internet-services/access-via-email
-# in the body of the message.
-#
 # Information about what a kernel is, what it does, how to patch and
 # compile it and much more is contained in the Kernel-HOWTO, available
 # at <http://www.tldp.org/docs.html#howto>. Before you start
@@ -137,6 +128,15 @@
 
   If you don't know what to do here, say N.
 
+Maximum number of CPUs
+CONFIG_NR_CPUS
+  This allows you to specify the maximum number of CPUs which this
+  kernel will support.  The maximum supported value is 32 and the
+  mimimum value which makes sense is 2.
+
+  This is purely to save memory - each supported CPU adds
+  approximately eight kilobytes to the kernel image.
+
 Intel or compatible 80x86 processor
 CONFIG_X86
   This is Linux's home port.  Linux was originally native to the Intel
@@ -1141,6 +1141,15 @@
   Say Y here if you have an IDE controller which uses any of these
   chipsets: CMD643, CMD646 and CMD648.
 
+Compaq Triflex IDE support
+CONFIG_BLK_DEV_TRIFLEX
+  Say Y here if you have a Compaq Triflex IDE controller, such
+  as those commonly found on Compaq Pentium-Pro systems
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  triflex.o.
+
 CY82C693 chipset support
 CONFIG_BLK_DEV_CY82C693
   This driver adds detection and support for the CY82C693 chipset
@@ -1210,11 +1219,26 @@
   This is a driver for the OPTi 82C621 EIDE controller.
   Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
 
+National SCx200 chipset support
+CONFIG_BLK_DEV_SC1200
+  This driver adds support for the built in IDE on the National
+  SCx200 series of embedded x86 "Geode" systems
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  sc1200.o.
+
 ServerWorks OSB4/CSB5 chipset support
 CONFIG_BLK_DEV_SVWKS
   This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
   chipsets.
 
+SGI IOC4 chipset support
+CONFIG_BLK_DEV_SGIIOC4
+  This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
+  chipset.  Please say Y here, if you have an Altix System from
+  Silicon Graphics Inc.
+
 Intel PIIXn chipsets support
 CONFIG_BLK_DEV_PIIX
   This driver adds PIO mode setting and tuning for all PIIX IDE
@@ -1264,6 +1288,29 @@
 
   If unsure, say N.
 
+PROMISE PDC202{68|69|70|71|75|76|77} support
+CONFIG_BLK_DEV_PDC202XX_NEW
+  Promise Ultra 100 TX2 [PDC20268]
+  Promise Ultra 133 PTX2 [PDC20269]
+  Promise FastTrak LP/TX2/TX4 [PDC20270]
+  Promise FastTrak TX2000 [PDC20271]
+  Promise MB Ultra 133 [PDC20275]
+  Promise MB FastTrak 133 [PDC20276]
+  Promise FastTrak 133 [PDC20277]
+
+  This driver adds up to 4 more EIDE devices sharing a single
+  interrupt. This device is a bootable PCI UDMA controller. Since
+  multiple cards can be installed and there are BIOS ROM problems that
+  happen if the BIOS revisions of all installed cards (max of five) do
+  not match, the driver attempts to do dynamic tuning of the chipset
+  at boot-time for max speed.  Ultra33 BIOS 1.25 or newer is required
+  for more than one card.
+
+  If you say Y here, you need to say Y to "Use DMA by default when
+  available" as well.
+
+  If unsure, say N.
+
 Special UDMA Feature
 CONFIG_PDC202XX_BURST
   This option causes the pdc202xx driver to enable UDMA modes on the
@@ -2031,6 +2078,17 @@
   The board uses the R4300 and a R5230 CPUs.  For more information
   about this board see <http://www.algor.co.uk/>.
 
+SGI SN2 L1 serial port support
+CONFIG_SGI_L1_SERIAL
+  If you have an SGI SN2 and you want to use the serial port connected
+  to the system controller (you want this!), say Y.  Otherwise, say N.
+
+SGI SN2 L1 serial console support
+CONFIG_SGI_L1_SERIAL_CONSOLE
+  If you have an SGI SN2 and you would like to use the system
+  controller serial port as your console (you want this!), say Y.
+  Otherwise, say N.
+
 Support for BAGET MIPS series
 CONFIG_BAGET_MIPS
   This enables support for the Baget, a Russian embedded system.  For
@@ -3217,6 +3275,255 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+IP: virtual server support
+CONFIG_IP_VS
+  IP Virtual Server support will let you build a high-performance
+  virtual server based on cluster of two or more real servers. This
+  option must be enabled for at least one of the clustered computers
+  that will take care of intercepting incomming connections to a
+  single IP address and scheduling them to real servers.
+
+  Three request dispatching techniques are implemented, they are
+  virtual server via NAT, virtual server via tunneling and virtual
+  server via direct routing. The several scheduling algorithms can
+  be used to choose which server the connection is directed to,
+  thus load balancing can be achieved among the servers.  For more
+  information and its administration program, please visit the
+  following URL:
+	http://www.linuxvirtualserver.org/
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IP virtual server debugging
+CONFIG_IP_VS_DEBUG
+  Say Y here if you want to get additional messages useful in
+  debugging the IP virtual server code. You can change the debug
+  level in /proc/sys/net/ipv4/vs/debug_level
+
+IPVS connection hash table size (the Nth power of 2)
+CONFIG_IP_VS_TAB_BITS
+  The IPVS connection hash table uses the chaining scheme to handle
+  hash collisions. Using a big IPVS connection hash table will greatly
+  reduce conflicts when there are hundreds of thousands of connections
+  in the hash table.
+
+  Note the table size must be power of 2. The table size will be the
+  value of 2 to the your input number power. The number to choose is
+  from 8 to 20, the default number is 12, which means the table size
+  is 4096. Don't input the number too small, otherwise you will lose
+  performance on it. You can adapt the table size yourself, according
+  to your virtual server application. It is good to set the table size
+  not far less than the number of connections per second multiplying
+  average lasting time of connection in the table.  For example, your
+  virtual server gets 200 connections per second, the connection lasts
+  for 200 seconds in average in the connection table, the table size
+  should be not far less than 200x200, it is good to set the table
+  size 32768 (2**15).
+
+  Another note that each connection occupies 128 bytes effectively and
+  each hash entry uses 8 bytes, so you can estimate how much memory is
+  needed for your box.
+
+IPVS: round-robin scheduling
+CONFIG_IP_VS_RR
+  The robin-robin scheduling algorithm simply directs network
+  connections to different real servers in a round-robin manner.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: weighted round-robin scheduling
+CONFIG_IP_VS_WRR
+  The weighted robin-robin scheduling algorithm directs network
+  connections to different real servers based on server weights
+  in a round-robin manner. Servers with higher weights receive
+  new connections first than those with less weights, and servers
+  with higher weights get more connections than those with less
+  weights and servers with equal weights get equal connections.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: least-connection scheduling
+CONFIG_IP_VS_LC
+  The least-connection scheduling algorithm directs network
+  connections to the server with the least number of active 
+  connections.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: weighted least-connection scheduling
+CONFIG_IP_VS_WLC
+  The weighted least-connection scheduling algorithm directs network
+  connections to the server with the least active connections
+  normalized by the server weight.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: locality-based least-connection scheduling
+CONFIG_IP_VS_LBLC
+  The locality-based least-connection scheduling algorithm is for
+  destination IP load balancing. It is usually used in cache cluster.
+  This algorithm usually directs packet destined for an IP address to
+  its server if the server is alive and under load. If the server is
+  overloaded (its active connection numbers is larger than its weight)
+  and there is a server in its half load, then allocate the weighted
+  least-connection server to this IP address.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: locality-based least-connection with replication scheduling
+CONFIG_IP_VS_LBLCR
+  The locality-based least-connection with replication scheduling
+  algorithm is also for destination IP load balancing. It is 
+  usually used in cache cluster. It differs from the LBLC scheduling
+  as follows: the load balancer maintains mappings from a target
+  to a set of server nodes that can serve the target. Requests for
+  a target are assigned to the least-connection node in the target's
+  server set. If all the node in the server set are over loaded,
+  it picks up a least-connection node in the cluster and adds it
+  in the sever set for the target. If the server set has not been
+  modified for the specified time, the most loaded node is removed
+  from the server set, in order to avoid high degree of replication.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: destination hashing scheduling
+CONFIG_IP_VS_DH
+  The destination hashing scheduling algorithm assigns network
+  connections to the servers through looking up a statically assigned
+  hash table by their destination IP addresses.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: source hashing scheduling
+CONFIG_IP_VS_SH
+  The source hashing scheduling algorithm assigns network
+  connections to the servers through looking up a statically assigned
+  hash table by their source IP addresses.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: shortest expected delay scheduling
+CONFIG_IP_VS_SED
+  The shortest expected delay scheduling algorithm assigns network
+  connections to the server with the shortest expected delay. The 
+  expected delay that the job will experience is (Ci + 1) / Ui if 
+  sent to the ith server, in which Ci is the number of connections
+  on the the ith server and Ui is the fixed service rate (weight)
+  of the ith server.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: never queue scheduling
+CONFIG_IP_VS_NQ
+  The never queue scheduling algorithm adopts a two-speed model.
+  When there is an idle server available, the job will be sent to
+  the idle server, instead of waiting for a fast one. When there
+  is no idle server available, the job will be sent to the server
+  that minimize its expected delay (The Shortest Expected Delay
+  scheduling algorithm).
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+IPVS: FTP protocol helper
+CONFIG_IP_VS_FTP
+  FTP is a protocol that transfers IP address and/or port number in
+  the payload. In the virtual server via Network Address Translation,
+  the IP address and port number of real servers cannot be sent to
+  clients in ftp connections directly, so FTP protocol helper is
+  required for tracking the connection and mangling it back to that of
+  virtual service.
+
+  If you want to compile it in kernel, say Y. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt. If
+  unsure, say N.
+
+AH/ESP match support (EXPERIMENTAL)
+CONFIG_IP6_NF_MATCH_AHESP
+  This module allows one to match AH and ESP packets.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The modules will be called
+  ip6t_ah.o and ip6t_esp.o.
+
+  If unsure, say 'N'.
+
+Routing header match support
+CONFIG_IP6_NF_MATCH_RT
+  rt matching allows you to match packets based on the routing
+  header of the packet.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  ip6t_rt.o.
+
+  If unsure, say 'N'.
+
+Hop-by-hop and Dst opts header match support
+CONFIG_IP6_NF_MATCH_OPTS
+  This allows one to match packets based on the hop-by-hop
+  and destination options headers of a packet.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The modules will be called
+  ip6t_hbh.o and ip6t_dst.o.
+
+  If unsure, say 'N'.
+
+Fragmentation header match support
+CONFIG_IP6_NF_MATCH_FRAG
+  frag matching allows you to match packets based on the fragmentation
+  header of the packet.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  ip6t_frag.o.
+
+  If unsure, say 'N'.
+
+HL match support
+CONFIG_IP6_NF_MATCH_HL
+  HL matching allows you to match packets based on the hop
+  limit of the packet.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  ip6t_hl.o.
+
+  If unsure, say 'N'.
+
+IPv6 Extension Headers Match (EXPERIMENTAL)
+CONFIG_IP6_NF_MATCH_IPV6HEADER
+  This module allows one to match packets based upon
+  the ipv6 extension headers.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The module will be called
+  ip6t_ipv6header.o.
+
+  If unsure, say 'N'.
+
 SYN flood protection
 CONFIG_SYN_COOKIES
   Normal TCP/IP networking is open to an attack known as "SYN
@@ -3706,18 +4013,18 @@
 
 Generic SiS support
 CONFIG_AGP_SIS
-  This option gives you AGP support for the GLX component of the "soon
-  to be released" XFree86 4.x on Silicon Integrated Systems [SiS]
-  chipsets.
+  This option gives you AGP support for the GLX component of
+  XFree86 4.x on Silicon Integrated Systems [SiS] chipsets.
 
-  Note that 5591/5592 AGP chipsets are NOT supported.
+  Note that 5591/5592 AGP chipsets are NOT specifically supported;
+  However, the driver works well on these, too.
 
   You should say Y here if you use XFree86 3.3.6 or 4.x and want to
   use GLX or DRI.  If unsure, say N.
 
 Serverworks LE/HE support
 CONFIG_AGP_SWORKS
-  Say Y here to support the Serverworks AGP card.  See 
+  Say Y here to support the Serverworks AGP card.  See
   <http://www.serverworks.com/> for product descriptions and images.
 
 NVIDIA chipset support
@@ -5107,21 +5414,23 @@
   This is the frame buffer device driver for the Hitachi HD64461 LCD
   frame buffer card.
 
-SIS acceleration
+SIS display support
 CONFIG_FB_SIS
-  This is the frame buffer device driver for the SiS 630 and 640 Super
-  Socket 7 UMA cards.  Specs available at <http://www.sis.com.tw/>.
+  This is the frame buffer device driver for the SiS 300, 315 and 330
+  series chipsets.  Documentation available at the maintainer's site
+  at <http://www.winischhofer.net/linuxsisvga.shtml>.
 
-SIS 630/540/730 support
+SIS 300 series support
 CONFIG_FB_SIS_300
-  This is the frame buffer device driver for the SiS 630 and related
-  Super Socket 7 UMA cards.  Specs available at
-  <http://www.sis.com.tw/>.
+  This enables support for SiS 300 series chipsets (300/305, 540, 630,
+  730).  Documentation available at the maintainer's website at
+   <http://www.winischhofer.net/linuxsisvga.shtml>.
 
-SIS 315H/315 support
+SIS 315/330 series support
 CONFIG_FB_SIS_315
-  This is the frame buffer device driver for the SiS 315 graphics
-  card.  Specs available at <http://www.sis.com.tw/>.
+  This enables support for SiS 315/330 series chipsets (315, 550, 650,
+  M650, 651, 661FX, M661FX, 740, 741, 330). Documentation available at
+  the maintainer's site <http://www.winischhofer.net/linuxsisvga.shtml>.
 
 IMS Twin Turbo display support
 CONFIG_FB_IMSTT
@@ -6915,7 +7224,7 @@
 CONFIG_CISS_SCSI_TAPE
   When enabled (Y), this option allows SCSI tape drives and SCSI medium
   changers (tape robots) to be accessed via a Compaq 5xxx array
-  controller.  (See Documentation/cciss.txt for more details.)
+  controller.  (See <file:Documentation/cciss.txt> for more details.)
 
   "SCSI support" and "SCSI tape support" must also be enabled for this
   option to work.
@@ -6923,6 +7232,15 @@
   When this option is disabled (N), the SCSI portion of the driver
   is not compiled.
 
+Enable monitor thread
+CONFIG_CISS_MONITOR_THREAD
+  Intended for use with multipath configurations (see the md driver).
+  This option allows a per-adapter monitoring thread to periodically
+  poll the adapter to detect failure modes in which the processor
+  is unable to receive interrupts from the adapter, thus enabling 
+  fail-over to an alternate adapter in such situations.  See 
+  <file:Documentation/cciss.txt> for more details.
+
 QuickNet Internet LineJack/PhoneJack support
 CONFIG_PHONE_IXJ
   Say M if you have a telephony card manufactured by Quicknet
@@ -7087,6 +7405,16 @@
   architecture is based on LSI Logic's Message Passing Interface (MPI)
   specification.
 
+Maximum number of scatter gather entries
+CONFIG_FUSION_MAX_SGE
+  This option allows you to specify the maximum number of scatter-
+  gather entries per I/O. The driver defaults to 40, a reasonable number
+  for most systems. However, the user may increase this up to 128.
+  Increasing this parameter will require significantly more memory
+  on a per controller instance. Increasing the parameter is not
+  necessary (or recommended) unless the user will be running
+  large I/O's via the raw interface.
+
 Fusion MPT enhanced SCSI error reporting [optional] module
 CONFIG_FUSION_ISENSE
   The isense module (roughly stands for Interpret SENSE data) is
@@ -7354,6 +7682,27 @@
   there should be no noticeable performance impact as long as you have
   logging turned off.
 
+QDIO base support for IBM S/390 and zSeries
+CONFIG_QDIO
+  This driver provides the Queued Direct I/O base support for the
+  IBM S/390 (G5 and G6) and eServer zSeries (z800 and z900).
+
+  For details please refer to the documentation provided by IBM at
+  <http://www10.software.ibm.com/developerworks/opensource/linux390>
+
+  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 be called qdio.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say Y.
+
+Performance statistics for QDIO base support
+CONFIG_QDIO_PERF_STATS
+  Say Y here to get performance statistics in /proc/qdio_perf
+
+  If unsure, say N.
+
 SGI WD93C93 SCSI Driver
 CONFIG_SCSI_SGIWD93
   Say Y here to support the on-board WD93C93 SCSI controller found (a)
@@ -8979,6 +9328,17 @@
   Say Y if you really want or need the debugging output, everyone else
   says N.
 
+CONFIG_IEEE1394_OUI_DB
+  If you say Y here, then an OUI list (vendor unique ID's) will be
+  compiled into the ieee1394 module. This doesn't really do much
+  except being able to display the vendor of a hardware node. The
+  downside is that it adds about 300k to the size of the module,
+  or kernel (depending on whether you compile ieee1394 as a
+  module, or static in the kernel).
+
+  This option is not needed for userspace programs like gscanbus
+  to show this information.
+
 Network device support
 CONFIG_NETDEVICES
   You can say N here if you don't intend to connect your Linux box to
@@ -13126,6 +13486,15 @@
 
   If unsure, say 'N'.
 
+MTD concatenating support
+CONFIG_MTD_CONCAT
+  Support for concatenating several MTD devices into a single
+  (virtual) one. This allows you to have -for example- a JFFS(2)
+  file system spanning multiple physical flash chips. If unsure,
+  say 'Y'.
+
+  If compiled as a module, it will be called mtdconcat.o.
+
 ARM Firmware Suite flash layout / partition parsing
 CONFIG_MTD_AFS_PARTS
   The ARM Firmware Suite allows the user to divide flash devices into
@@ -13532,6 +13901,14 @@
   D-Box 2 board. If you have one of these boards and would like to use
   the flash chips on it, say 'Y'.
 
+CFI Flash devices mapped on IBM Redwood
+CONFIG_MTD_REDWOOD
+  This enables access routines for the flash chips on the IBM
+  Redwood board. If you have one of these boards and would like to
+  use the flash chips on it, say 'Y'.
+
+  If compiled as a module, it will be called redwood.o.
+
 CFI Flash device mapped on the XScale IQ80310 board
 CONFIG_MTD_IQ80310
   This enables access routines for the flash chips on the Intel XScale
@@ -13664,6 +14041,20 @@
 CONFIG_MTD_NAND_SPIA
   If you had to ask, you don't have one. Say 'N'.
 
+SmartMediaCard on autronix autcpu12 board
+CONFIG_MTD_NAND_AUTCPU12
+  This enables the driver for the autronix autcpu12 board to
+  access the SmartMediaCard.
+
+  If compiled as a module, it will be called autcpu12.o.
+
+Support for Cirrus Logic EBD7312 evaluation board
+CONFIG_MTD_NAND_EDB7312
+  This enables the driver for the Cirrus Logic EBD7312 evaluation
+  board to access the onboard NAND Flash.
+
+  If compiled as a module, it will be called edb7312.o.
+
 M-Systems Disk-On-Chip 1000 support
 CONFIG_MTD_DOC1000
   This provides an MTD device driver for the M-Systems DiskOnChip
@@ -17494,6 +17885,24 @@
 
   Enable this option if you intend to use a HIL keyboard.
 
+HP System Device Controller support
+CONFIG_HP_SDC
+  This option enables supports for the the "System Device Controller",
+  an i8042 carrying microcode to manage a few miscellanous devices
+  on some Hewlett Packard systems.  The SDC itself contains a 10ms
+  resolution timer/clock capable of delivering interrupts on periodic
+  and one-shot basis.  The SDC may also be connected to a battery-backed
+  real-time clock, a basic audio waveform generator, and an HP-HIL
+  Master Link Controller serving up to seven input devices.
+
+  By itself this option is rather useless, but enabling it will
+  enable selection of drivers for the abovementioned devices.
+  It is, however, incompatible with the old, reliable HIL keyboard
+  driver, and the new HIL driver is experimental, so if you plan to
+  use a HIL keyboard as your primary keyboard, you may wish to
+  keep using that driver until the new HIL drivers have had more
+  testing.
+
 Include IOP (IIfx/Quadra 9x0) ADB driver
 CONFIG_ADB_IOP
   The I/O Processor (IOP) is an Apple custom IC designed to provide
@@ -17809,6 +18218,19 @@
   read <file:Documentation/modules.txt>. The module will be called
   istallion.o.
 
+PDC software console support
+CONFIG_PDC_CONSOLE
+  Saying Y here will enable the software based PDC console to be
+  used as the system console.  This is useful for machines in
+  which the hardware based console has not been written yet.  The
+  following steps must be competed to use the PDC console:
+
+    1. create the device entry (mknod /dev/ttyB0 c 60 0)
+    2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
+    3. Add device ttyB0 to /etc/securetty (if you want to log on as
+         root on this console.)
+    4. Change the kernel command console parameter to: console=ttyB0
+
 Microgate SyncLink adapter support
 CONFIG_SYNCLINK
   Provides support for the SyncLink ISA and PCI multiprotocol serial
@@ -18259,6 +18681,15 @@
   it as a module, say M here and read <file:Documentation/modules.txt>.
   The module will be called i2c-proc.o.
 
+Powermac Keywest I2C interface
+CONFIG_I2C_KEYWEST
+  This supports the use of the I2C interface in the combo-I/O
+  chip on recent Apple machines.  Say Y if you have such a machine.
+
+  This driver is also available as a module.  If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+  The module will be called i2c-keywest.o.
+
 Bus Mouse Support
 CONFIG_BUSMOUSE
   Say Y here if your machine has a bus mouse as opposed to a serial
@@ -18768,6 +19199,13 @@
   selected, the module will be called i810.o.  AGP support is required
   for this driver to work.
 
+Intel 830M, 845G, 852GM, 855GM, 865G
+CONFIG_DRM_I830
+  Choose this option if you have a system that has Intel 830M, 845G,
+  852GM, 855GM or 865G integrated graphics.  If M is selected, the
+  module will be called i830.o.  AGP support is required for this driver
+  to work.
+
 Matrox G200/G400/G450
 CONFIG_DRM_MGA
   Choose this option if you have a Matrox G200, G400 or G450 graphics
@@ -18921,6 +19359,21 @@
 
   If unsure, say N.
 
+Intel/AMD/VIA HW Random Number Generator support
+CONFIG_HW_RANDOM
+  This driver provides kernel-side support for the
+  Random Number Generator hardware found on Intel i8xx-based motherboards,
+  AMD 76x-based motherboards, and Via Nehemiah CPUs.
+
+  Provides a character driver, used to read() entropy data.
+
+  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 <file:Documentation/modules.txt>. The module will be called
+  hw_random.
+
+  If unsure, say N.
+
 Power Management support
 CONFIG_PM
   "Power Management" means that parts of your computer are shut
@@ -21540,6 +21993,11 @@
   This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
   cards. This code is not finished yet.
 
+Formula-n enter:now PCI card (EXPERIMENTAL)
+CONFIG_HISAX_ENTERNOW_PCI
+  This enables HiSax support for the Formula-n enter:now PCI
+  ISDN card.
+
 Am7930
 CONFIG_HISAX_AMD7930
   This enables HiSax support for the AMD7930 chips on some SPARCs.
@@ -22687,15 +23145,16 @@
   want). The module is called ariadne.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
-Ariadne II and X-Surf support
-CONFIG_ARIADNE2
-  This driver is for the Village Tronic Ariadne II and the Individual
+Zorro NS8390-based Ethernet support
+CONFIG_ZORRO8390
+  This driver is for Zorro Ethernet cards using an NS8390-compatible
+  chipset, like the Village Tronic Ariadne II and the Individual
   Computers X-Surf Ethernet cards. If you have such a card, say Y.
   Otherwise, say N.
 
   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 be called ariadne2.o. If you want to compile it as
+  The module is called zorro8390.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
 A2065 support
@@ -24735,6 +25194,46 @@
   Say Y if you want support for the ARM1020 processor.
   Otherwise, say N.
 
+Disable I-Cache
+CONFIG_CPU_ICACHE_DISABLE
+  Say Y here to disable the processor instruction cache. Unless
+  you have a reason not to or are unsure, say N.
+
+Disable D-Cache
+CONFIG_CPU_DCACHE_DISABLE
+  Say Y here to disable the processor data cache. Unless
+  you have a reason not to or are unsure, say N.
+
+Force write through D-cache
+CONFIG_CPU_DCACHE_WRITETHROUGH
+  Say Y here to use the data cache in write-through mode. Unless you
+  specifically require this or are unsure, say N.
+
+Round robin I and D cache replacement algorithm
+CONFIG_CPU_CACHE_ROUND_ROBIN
+  Say Y here to use the predictable round-robin cache replacement
+  policy.  Unless you specifically require this or are unsure, say N.
+
+Disable branch prediction
+CONFIG_CPU_BPREDICT_DISABLE
+  Say Y here to disable branch prediction.  If unsure, say N.
+
+Compressed boot loader in ROM/flash
+CONFIG_ZBOOT_ROM
+  Say Y here if you intend to execute your compressed kernel image (zImage)
+  directly from ROM or flash.  If unsure, say N.
+
+Compressed ROM boot loader base address
+CONFIG_ZBOOT_ROM_TEXT
+  The base address for zImage.  Unless you have special requirements, you
+  should not change this value.
+
+Compressed ROM boot loader BSS address
+CONFIG_ZBOOT_ROM_BSS
+  The base address of 64KiB of read/write memory, which must be available
+  while the decompressor is running.  Unless you have special requirements,
+  you should not change this value.
+
 Support StrongARM SA-110 processor
 CONFIG_CPU_SA110
   The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and
@@ -24894,6 +25393,19 @@
   output to the second serial port on these devices.  Saying N will
   cause the debug messages to appear on the first serial port.
 
+Kernel log buffer length shift
+CONFIG_LOG_BUF_SHIFT
+  The kernel log buffer has a fixed size of :
+      64 kB (2^16) on MULTIQUAD and IA64,
+     128 kB (2^17) on S390
+      32 kB (2^15) on SMP systems
+      16 kB (2^14) on UP systems
+
+  You have the ability to change this size with this paramter which
+  fixes the bit shift of to get the buffer length (which must be a
+  power of 2). Eg: a value of 16 sets the buffer to 64 kB (2^16).
+  The default value of 0 uses standard values above.
+
 Disable pgtable cache
 CONFIG_NO_PGT_CACHE
   Normally the kernel maintains a `quicklist' of preallocated
@@ -25250,6 +25762,44 @@
   brave people.  System crashes and other bad things are likely to occur if
   you use this driver.  If in doubt, select N.
 
+Tieman Voyager USB Braille display support (EXPERIMENTAL)
+CONFIG_USB_BRLVGER
+  Say Y here if you want to use the Voyager USB Braille display from
+  Tieman. See <file:Documentation/usb/brlvger.txt> for more
+  information.
+
+  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 brlvger.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+KB Gear JamStudio tablet support
+CONFIG_USB_KBTAB
+  Say Y here if you want to use the USB version of the KB Gear
+  JamStudio tablet.  Make sure to say Y to "Mouse support"
+  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+  (CONFIG_INPUT_EVDEV) as well.
+
+  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 be called kbtab.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+USB Inside Out Edgeport Serial Driver (TI devices)
+CONFIG_USB_SERIAL_EDGEPORT_TI
+  Say Y here if you want to use any of the devices from Inside Out
+  Networks (Digi) that are not supported by the io_edgeport driver.
+  This includes the Edgeport/1 device.
+
+  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_ti.o.  If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+USB Keyspan MPR Firmware
+CONFIG_USB_SERIAL_KEYSPAN_MPR
+  Say Y here to include firmware for the Keyspan MPR converter.
+
 Winbond W83977AF IrDA Device Driver
 CONFIG_WINBOND_FIR
   Say Y here if you want to build IrDA support for the Winbond
@@ -26497,6 +27047,11 @@
   best used in conjunction with the NMI watchdog so that spinlock
   deadlocks are also debuggable.
 
+Additional run-time checks
+CONFIG_CHECKING
+  Enables some internal consistency checks for kernel debugging.
+  You should normally say N.
+
 Read-write spinlock debugging
 CONFIG_DEBUG_RWLOCK
   If you say Y here then read-write lock processing will count how many
@@ -27395,6 +27950,82 @@
   kernel tree does. Such modules that use library CRC32 functions
   require that you say M or Y here.
 
+Chassis LCD and LED support
+CONFIG_CHASSIS_LCD_LED
+  Say Y here if you want to enable support for the Heartbeat,
+  Disk/Network activities LEDs on some PA-RISC machines,
+  or support for the LCD that can be found on recent material.
+
+  This has nothing to do with LED State support for A, J and E class.
+
+  If unsure, say Y.
+
+VSC/GSC/HSC bus support
+CONFIG_GSC
+  The VSC, GSC and HSC busses were used from the earliest 700-series
+  workstations up to and including the C360/J2240 workstations.  They
+  were also used in servers from the E-class to the K-class.  They
+  are not found in B1000, C3000, J5000, A500, L1000, N4000 and upwards.
+  If in doubt, say "Y".
+
+Wax I/O support
+CONFIG_GSC_WAX
+  Say Y here to support the Wax multifunction chip found in some
+  older systems, including B/C/D/R class and 715/64, 715/80 and
+  715/100.  Wax includes an EISA adapter, a serial port (not always
+  used), a HIL interface chip and is also known to be used as the
+  GSC bridge for an X.25 GSC card.
+
+GSCtoPCI/Dino PCI support
+CONFIG_GSC_DINO
+  Say Y here to support the Dino & Cujo GSC to PCI bridges found in
+  machines from the B132 to the C360, the J2240 and the A180.  Some
+  GSC/HSC cards (eg gigabit & dual 100 Mbit Ethernet) have a Dino on
+  the card, and you also need to say Y here if you have such a card.
+  Note that Dino also supplies one of the serial ports on certain
+  machines.  If in doubt, say Y.
+
+HPET timers
+CONFIG_HPET_TIMER
+  Use the IA-PC HPET (High Precision Event Timer) to manage
+  time in preference to the PIT and RTC, if a HPET is
+  present.  The HPET provides a stable time base on SMP
+  systems, unlike the RTC, but it is more expensive to access,
+  as it is off-chip.  You can find the HPET spec at
+  <http://www.intel.com/labs/platcomp/hpet/hpetspec.htm>.
+
+  If unsure, say Y.
+
+IOMMU support
+CONFIG_GART_IOMMU
+  Support the K8 IOMMU. Needed to run systems with more than 4GB of memory
+  properly with 32-bit PCI devices that do not support DAC (Double Address
+  Cycle). The IOMMU can be turned off at runtime with the iommu=off parameter.
+  Normally the kernel will take the right choice by itself.
+  If unsure say Y
+
+Debug __init statements
+CONFIG_INIT_DEBUG
+  Fill __init and __initdata at the end of boot. This helps debugging
+  invalid uses of __init and __initdata after initialization.	
+
+Force IOMMU to on
+CONFIG_IOMMU_DEBUG
+  Force the IOMMU to on even when you have less than 4GB of memory and add
+  debugging code.
+  Can be disabled at boot time with iommu=noforce.
+
+IOMMU leak tracing
+CONFIG_IOMMU_LEAK
+  Add a simple leak tracer to the IOMMU code. This is useful when you
+  are debugging a buggy device driver that leaks IOMMU mappings.
+
+pSeries Hypervisor Virtual Console support
+CONFIG_HVC_CONSOLE
+  pSeries machines when partitioned support a hypervisor virtual
+  console. This driver allows each pSeries partition to have a console
+  which is accessed via the HMC.
+
 CONFIG_CRYPTO
   This option provides the core Cryptographic API.
 
@@ -27477,6 +28108,12 @@
   The AES specifies three key sizes: 128, 192 and 256 bits	  
 
   See http://csrc.nist.gov/encryption/aes/ for more information.
+
+CONFIG_CRYPTO_CAST5
+  CAST5 (CAST-128) cipher algorithm.
+
+  The CAST5 encryption algorithm (synonymous with CAST-128) is
+  described in RFC2144.
 
 CONFIG_CRYPTO_DEFLATE
   This is the Deflate algorithm (RFC1951), specified for use in
diff -Nru a/Documentation/cciss.txt b/Documentation/cciss.txt
--- a/Documentation/cciss.txt	Mon Jul  7 11:50:28 2003
+++ b/Documentation/cciss.txt	Fri Aug 29 08:21:37 2003
@@ -127,3 +127,55 @@
 access these devices too, as if the array controller were merely a SCSI 
 controller in the same way that we are allowing it to access SCSI tape drives.
 
+Monitor Threads
+---------------
+
+For multipath configurations (acheived via a higher level driver, such
+as the "md" driver) it is important that failure of a controller is detected.
+Ordinarily, the driver is entirely interrupt driven.  If a failure occurs
+in such a way that the processor cannot receive interrupts from an adapter,
+the driver will wait forever for i/o's to complete.  In a multipath
+configuration this is undesirable, as the md driver relies on i/o's being
+reported as failed by the low level driver to trigger failing over to an 
+alternate controller.  The monitor threads allow the driver to detect such 
+situations and report outstanding i/o's as having failed so that recovery 
+actions such switching to an alternate controller can occur.  The monitor 
+threads periodically sends a trivial "no-operation" command down to 
+the controllers and expect them to complete within a a reasonable (short)
+time period.  The firmware on the adapter is designed such that no matter
+how busy the adapter is serving i/o, it can respond quickly to a
+"no-operation" command.  In the event that a deadline elapses before a no 
+operation command completes, all outstanding commands on that controller 
+are reported back to the upper layers as having failed, and any new commands 
+sent to the controller are immediately reported back as failed. 
+
+To enable the monitor threads, the compile time option must be enabled
+(via the usual linux kernel configuration) and the monitor thread must
+be enabled at runtime as well.  A system may have many adapters, but 
+perhaps only a single pair operating in a multipath configuration.  
+In this way, it is possible to run monitoring threads only for those 
+adapters which require it.
+
+To start a monitoring thread on the first cciss adapter, "cciss0" with
+a polling interval of 30 seconds, execute the following command:
+
+	echo "monitor 30" > /proc/driver/cciss/cciss0
+
+To change the polling interval, to say, 60 seconds:
+
+	echo "monitor 60" > /proc/driver/cciss/cciss0
+
+(Note, the change will not take effect until the previous polling 
+interval elapses.)
+
+To disable the monitoring thread, set the polling interval to 0 seconds:
+
+	echo "monitor 0" > /proc/driver/cciss/cciss0
+
+(Again, the monitoring thread will not exit until the previous polling
+interval elapses.)
+
+The minimum monitoring period is 10 seconds, and the maximum monitoring
+period is 3600 seconds (1 hour).  The no-operation command must complete
+with 5 seconds of submission in all cases or the controller will be presumed
+failed.
diff -Nru a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
--- a/Documentation/crypto/api-intro.txt	Mon Jun 23 13:58:51 2003
+++ b/Documentation/crypto/api-intro.txt	Mon Aug 11 22:20:11 2003
@@ -186,7 +186,6 @@
   Dag Arne Osvik (Serpent)
   Brian Gladman (AES)
 
-
 SHA1 algorithm contributors:
   Jean-Francois Dive
   
@@ -213,6 +212,9 @@
   Herbert Valerio Riedel
   Kyle McMartin
   Adam J. Richter
+
+CAST5 algorithm contributors:
+  Kartikey Mahendra Bhatt (original developers unknown, FSF copyright).
 
 Generic scatterwalk code by Adam J. Richter <adam@yggdrasil.com>
 
diff -Nru a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt
--- a/Documentation/filesystems/jfs.txt	Thu May  1 10:49:53 2003
+++ b/Documentation/filesystems/jfs.txt	Mon Aug 25 11:19:31 2003
@@ -23,6 +23,15 @@
 		read-write.  The resize keyword with no value will grow
 		the volume to the full size of the partition.
 
+nointegrity	Do not write to the journal.  The primary use of this option
+		is to allow for higher performance when restoring a volume
+		from backup media.  The integrity of the volume is not
+		guaranteed if the system abnormally abends.
+
+integrity	Default.  Commit metadata changes to the journal.  Use this
+		option to remount a volume where the nointegrity option was
+		previously specified in order to restore normal behavior.
+
 JFS TODO list:
 
 Plans for our near term development items
diff -Nru a/Documentation/hw_random.txt b/Documentation/hw_random.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/hw_random.txt	Thu Aug  7 19:50:06 2003
@@ -0,0 +1,138 @@
+	Hardware driver for Intel/AMD/VIA Random Number Generators (RNG)
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+
+Introduction:
+
+	The hw_random device driver is software that makes use of a
+	special hardware feature on your CPU or motherboard,
+	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 "rng-tools" package from the
+	hw_random 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 hardware 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/hwrandom 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 <msottek@quiknet.com>
+
+	Special thanks to Matt Sottek.  I did the "guts", he
+	did the "brains" and all the testing.
+
+Change history:
+
+	Version 1.0.0:
+	* Merge Intel, AMD, VIA RNG drivers into one.
+	  Further changelog in BitKeeper.
+
+	Version 0.9.8:
+	* Support other i8xx chipsets by adding 82801E detection
+	* 82801DB detection is the same as for 82801CA.
+
+	Version 0.9.7:
+	* Support other i8xx chipsets too (by adding 82801BA(M) and
+	  82801CA(M) detection)
+
+	Version 0.9.6:
+	* Internal driver cleanups, prep for 1.0.0 release.
+
+	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 -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt	Thu Aug 21 07:39:06 2003
+++ b/Documentation/kernel-parameters.txt	Mon Aug 25 11:15:50 2003
@@ -278,6 +278,8 @@
 
 	keepinitrd	[HW, ARM]
 
+	lapic		[IA-32,APIC] Enable the local APIC even if BIOS disabled it.
+
 	load_ramdisk=	[RAM] List of ramdisks to load from floppy.
 
 	lockd.udpport=	[NFS]
@@ -414,6 +416,8 @@
 
 	nointroute	[IA-64]
  
+	nolapic		[IA-32,APIC] Do not enable or use the local APIC.
+
 	no-scroll	[VGA]
 
 	nosmp		[SMP] Tells an SMP kernel to act as a UP kernel.
diff -Nru a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
--- a/Documentation/networking/00-INDEX	Mon Jan  6 07:38:40 2003
+++ b/Documentation/networking/00-INDEX	Wed Aug 13 06:10:39 2003
@@ -97,8 +97,8 @@
 sis900.txt
 	- SiS 900/7016 Fast Ethernet device driver info.
 sk98lin.txt
-	- SysKonnect SK-98xx and SK-98xx Gigabit Ethernet Adapter family 
-	  driver info.
+	- Marvell Yukon Chipset / SysKonnect SK-98xx compliant Gigabit
+	  Ethernet Adapter family driver info
 skfp.txt
 	- SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
 smc9.txt
diff -Nru a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c
--- a/Documentation/networking/ifenslave.c	Thu Jul 31 12:09:37 2003
+++ b/Documentation/networking/ifenslave.c	Wed Aug 27 14:31:33 2003
@@ -140,6 +140,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
+#include <linux/if.h>
 #include <net/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/if_bonding.h>
diff -Nru a/Documentation/sonypi.txt b/Documentation/sonypi.txt
--- a/Documentation/sonypi.txt	Sun Jun 29 08:10:46 2003
+++ b/Documentation/sonypi.txt	Tue Aug 26 09:01:45 2003
@@ -8,7 +8,9 @@
 	Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enables access to the Sony Programmable I/O Control Device which
-can be found in many (all ?) Sony Vaio laptops.
+can be found in many Sony Vaio laptops. Some newer Sony laptops (seems to be
+limited to new FX series laptops, at least the FX501 and the FX702) lack a
+sonypi device and are not supported at all by this driver.
 
 It will give access (through a user space utility) to some events those laptops
 generate, like:
@@ -96,6 +98,7 @@
 				SONYPI_THUMBPHRASE_MASK 	0x0200
 				SONYPI_MEYE_MASK		0x0400
 				SONYPI_MEMORYSTICK_MASK		0x0800
+				SONYPI_BATTERY_MASK		0x1000
 
 	useinput:	if set (which is the default) jogdial events are
 			forwarded to the input subsystem as mouse wheel
diff -Nru a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
--- a/Documentation/usb/usb-serial.txt	Tue Dec 24 02:22:08 2002
+++ b/Documentation/usb/usb-serial.txt	Tue Jul 29 23:03:49 2003
@@ -88,6 +88,9 @@
   necessary.  Some devices need this before they can talk to the USB port
   properly.
   
+  Devices that are not compiled into the kernel can be specified with module
+  parameters.  e.g. modprobe visor vendor=0x54c product=0x66
+  
   There is a webpage and mailing lists for this portion of the driver at:
   http://usbvisor.sourceforge.net/
 
diff -Nru a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
--- a/Documentation/video4linux/meye.txt	Tue Feb 18 03:32:22 2003
+++ b/Documentation/video4linux/meye.txt	Fri Aug  1 05:47:23 2003
@@ -16,6 +16,23 @@
 
 MJPEG hardware grabbing is supported via a private API (see below).
 
+Hardware supported:
+-------------------
+
+This driver supports the 'second' version of the MotionEye camera :)
+
+The first version was connected directly on the video bus of the Neomagic
+video card and is unsupported.
+
+The second one, made by Kawasaki Steel is fully supported by this 
+driver (PCI vendor/device is 0x136b/0xff01)
+
+The third one, present in recent (more or less last year) Picturebooks
+(C1M* models), is not supported. The manufacturer has given the specs
+to the developers under a NDA (which allows the develoment of a GPL
+driver however), but things are not moving very fast (see
+http://r-engine.sourceforge.net/) (PCI vendor/device is 0x10cf/0x2011).
+
 Driver options:
 ---------------
 
diff -Nru a/Documentation/wolfson-touchscreen.txt b/Documentation/wolfson-touchscreen.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/wolfson-touchscreen.txt	Thu Jul 31 06:00:07 2003
@@ -0,0 +1,178 @@
+
+Wolfson Microelectronics WM9705 and WM9712 Touchscreen Controllers
+===================================================================
+
+The WM9705 and WM9712 are high performance AC97 audio codecs with built
+in touchscreen controllers that are mainly found in portable devices.
+i.e. Dell Axim and Toshiba e740. 
+
+This driver uses the AC97 link controller for all communication with the 
+codec and can be either built into the kernel or built as a module. 
+
+Build Instructions
+==================
+
+The driver will be built into the kernel if "sound card support" = y and
+"wolfson AC97 touchscreen support" = y in the kernel sound configuration.
+
+To build as a module, "wolfson AC97 touchscreen support" = m
+in the kernel sound configuration.
+
+
+Driver Features
+===============
+
+ * supports WM9705, WM9712
+ * polling mode
+ * coordinate polling
+ * adjustable rpu/dpp settings
+ * adjustable pressure current
+ * adjustable sample settle delay
+ * 4 and 5 wire touchscreens (5 wire is WM9712 only)
+ * pen down detection
+ * power management
+ * AUX ADC sampling
+
+
+Driver Usage
+============
+
+In order to use this driver, a char device called wm97xx with a major
+number of 10 and minor number 16 will have to be created under 
+/dev/touchscreen.
+  
+e.g.
+mknod /dev/touchscreen/wm97xx c 10 16
+
+
+Driver Parameters
+=================
+The driver can accept several parameters for fine tuning the touchscreen. 
+However, the syntax is different between module options and passing the 
+options in the kernel command line.
+
+e.g.
+
+rpu=1   (module)
+rpu:1   (kernel command line)
+
+
+1. Codec sample mode. (mode)
+ 
+   The WM9712 can sample touchscreen data in 3 different operating
+   modes. i.e. polling, coordinate and continous.
+  
+   Polling:-     The driver polls the codec and issues 3 seperate commands
+                 over the AC97 link to read X,Y and pressure.
+   
+   Coordinate: - The driver polls the codec and only issues 1 command over
+                 the AC97 link to read X,Y and pressure. This mode has
+                 strict timing requirements and may drop samples if 
+                 interrupted. However, it is less demanding on the AC97
+                 link. Note: this mode requires a larger delay than polling
+                 mode.
+  
+   Continuous:-  The codec automatically samples X,Y and pressure and then
+                 sends the data over the AC97 link in slots. This is then
+                 same method used by the codec when recording audio.
+ 
+   Set mode = 0 for polling, 1 for coordinate and 2 for continuous.
+             
+   Default mode = 0
+   
+   
+
+2. WM9712 Internal pull up for pen detect. (rpu) 
+  
+   Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
+   i.e. pull up resistance = 64k Ohms / rpu.
+   
+   Adjust this value if you are having problems with pen detect not 
+   detecting any down events.
+   
+   Set rpu = value
+
+   Default rpu = 1
+   
+   
+
+3. WM9705 Pen detect comparator threshold. (pdd) 
+   
+   0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
+   i.e. 1 =  Vmid/15 threshold
+        15 =  Vmid/1 threshold
+   
+   Adjust this value if you are having problems with pen detect not 
+   detecting any down events.
+   
+   Set pdd = value
+
+   Default pdd = 0
+
+
+ 
+4. Set current used for pressure measurement. (pil)
+ 
+   Set pil = 2 to use 400uA 
+       pil = 1 to use 200uA and
+       pil = 0 to disable pressure measurement.
+  
+   This is used to increase the range of values returned by the adc
+   when measureing touchpanel pressure. 
+   
+   Default pil = 0
+  
+
+
+5. WM9712 Set 5 wire touchscreen mode. (five_wire)
+
+   Set five_wire = 1 to enable 5 wire mode on the WM9712.
+   
+   Default five_wire = 0
+   
+   NOTE: Five wire mode does not allow for readback of pressure.
+
+
+
+6. ADC sample delay. (delay)
+  
+   For accurate touchpanel measurements, some settling time may be
+   required between the switch matrix applying a voltage across the
+   touchpanel plate and the ADC sampling the signal.
+  
+   This delay can be set by setting delay = n, where n is the array
+   position of the delay in the array delay_table below.
+   Long delays > 1ms are supported for completeness, but are not
+   recommended.
+   
+   Default delay = 4
+ 
+    wm_delay     uS     AC97 link frames
+    ====================================
+       0	      21          1
+       1	      42          2
+       2          84          4
+       3         167          8
+       4         333         16
+       5         667         32
+       6        1000         48
+       7        1333         64
+       8        2000         96
+       9        2667        128
+      10        3333        160
+      11        4000        192
+      12        4667        224
+      13        5333        256
+      14        6000        288
+      15           0          0 (No delay, switch matrix always on)
+
+
+
+Contact
+=======
+
+Further information about the WM9705 and WM9712 can be found on the 
+Wolfson Website. http://www.wolfsonmicro.com
+
+Please report bugs to liam.girdwood@wolfsonmicro.com or 
+                      linux@wolfsonmicro.com
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Wed Aug 20 04:40:46 2003
+++ b/MAINTAINERS	Wed Aug 27 13:07:27 2003
@@ -670,7 +670,7 @@
 ETHERNET BRIDGE
 P:	Stephen Hemminger
 M:	shemminger@osdl.org
-L:	bridge@math.leidenuniv.nl
+L:	bridge@osdl.org
 W:	http://bridge.sourceforge.net/
 S:	Maintained
 
@@ -942,6 +942,11 @@
 P:	Ralf Baechle
 M:	ralf@oss.sgi.com
 L:	linux-mips@linux-mips.org
+S:	Maintained
+
+IOC4 IDE DRIVER
+P:	Jeremy Higdon
+M:	jeremy@sgi.com
 S:	Maintained
 
 IP MASQUERADING:
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Mon Aug 25 09:56:36 2003
+++ b/Makefile	Mon Sep  1 02:49:43 2003
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 22
-EXTRAVERSION =
+EXTRAVERSION = -bk7
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in
--- a/arch/alpha/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/alpha/config.in	Fri Aug 29 16:09:49 2003
@@ -269,6 +269,7 @@
 
 if [ "$CONFIG_SMP" = "y" ]; then
    define_bool CONFIG_HAVE_DEC_LOCK y
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
 fi
 
 if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_SRM" = "y" ]; then
@@ -452,6 +453,8 @@
 else
    define_tristate CONFIG_MATHEMU y
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
 
 endmenu
 
diff -Nru a/arch/arm/config.in b/arch/arm/config.in
--- a/arch/arm/config.in	Wed Jul  2 14:58:37 2003
+++ b/arch/arm/config.in	Fri Aug 29 16:10:15 2003
@@ -730,6 +730,9 @@
 dep_bool '  Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_DEBUG_KERNEL
 dep_bool '    Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
 dep_bool '    Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
 
 source crypto/Config.in
diff -Nru a/arch/arm/mm/mm-armo.c b/arch/arm/mm/mm-armo.c
--- a/arch/arm/mm/mm-armo.c	Mon Feb  4 23:39:16 2002
+++ b/arch/arm/mm/mm-armo.c	Fri Apr  5 10:06:57 2002
@@ -104,6 +104,7 @@
 no_pte:
 	spin_unlock(&mm->page_table_lock);
 	pmd_free(new_pmd);
+	check_pgt_cache();
 	free_pgd_slow(new_pgd);
 	return NULL;
 
diff -Nru a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
--- a/arch/arm/mm/mm-armv.c	Wed Jul  2 14:55:38 2003
+++ b/arch/arm/mm/mm-armv.c	Fri Apr  5 10:06:57 2002
@@ -123,6 +123,7 @@
 no_pte:
 	spin_unlock(&mm->page_table_lock);
 	pmd_free(new_pmd);
+	check_pgt_cache();
 	free_pages((unsigned long)new_pgd, 2);
 	return NULL;
 
@@ -157,6 +158,7 @@
 	pmd_clear(pmd);
 	pte_free(pte);
 	pmd_free(pmd);
+	check_pgt_cache();
 free:
 	free_pages((unsigned long) pgd, 2);
 }
diff -Nru a/arch/cris/config.in b/arch/cris/config.in
--- a/arch/cris/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/cris/config.in	Fri Aug 29 16:10:22 2003
@@ -272,6 +272,8 @@
   int '  Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
 
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 source crypto/Config.in
 source lib/Config.in
 endmenu
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/i386/config.in	Tue Mar 25 00:25:12 2003
@@ -231,6 +231,7 @@
       define_bool CONFIG_X86_IO_APIC y
    fi
 else
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
    bool 'Multi-node NUMA system support' CONFIG_X86_NUMA
    if [ "$CONFIG_X86_NUMA" = "y" ]; then
       #Platform Choices
@@ -475,6 +476,8 @@
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
    bool '  Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
 
 endmenu
 
diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig	Tue Oct  1 18:48:05 2002
+++ b/arch/i386/defconfig	Wed Jun 19 10:26:35 2002
@@ -64,6 +64,7 @@
 CONFIG_SMP=y
 # CONFIG_MULTIQUAD is not set
 CONFIG_HAVE_DEC_LOCK=y
+CONFIG_NR_CPUS=32
 
 #
 # General setup
diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
--- a/arch/i386/kernel/apic.c	Sat Apr  5 03:10:51 2003
+++ b/arch/i386/kernel/apic.c	Mon Aug 25 11:18:43 2003
@@ -38,6 +38,8 @@
 int prof_old_multiplier[NR_CPUS] = { 1, };
 int prof_counter[NR_CPUS] = { 1, };
 
+static int enabled_via_apicbase;
+
 int get_maxlvt(void)
 {
 	unsigned int v, ver, maxlvt;
@@ -142,6 +144,13 @@
 	value = apic_read(APIC_SPIV);
 	value &= ~APIC_SPIV_APIC_ENABLED;
 	apic_write_around(APIC_SPIV, value);
+
+	if (enabled_via_apicbase) {
+		unsigned int l, h;
+		rdmsr(MSR_IA32_APICBASE, l, h);
+		l &= ~MSR_IA32_APICBASE_ENABLE;
+		wrmsr(MSR_IA32_APICBASE, l, h);
+	}
 }
 
 /*
@@ -464,7 +473,6 @@
 
 static void apic_pm_suspend(void *data)
 {
-	unsigned int l, h;
 	unsigned long flags;
 
 	if (apic_pm_state.perfctr_pmdev)
@@ -484,9 +492,6 @@
 	__save_flags(flags);
 	__cli();
 	disable_local_APIC();
-	rdmsr(MSR_IA32_APICBASE, l, h);
-	l &= ~MSR_IA32_APICBASE_ENABLE;
-	wrmsr(MSR_IA32_APICBASE, l, h);
 	__restore_flags(flags);
 }
 
@@ -593,7 +598,26 @@
  * Detect and enable local APICs on non-SMP boards.
  * Original code written by Keir Fraser.
  */
-int dont_enable_local_apic __initdata = 0;
+
+/*
+ * Knob to control our willingness to enable the local APIC.
+ */
+int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
+
+static int __init lapic_disable(char *str)
+{
+	enable_local_apic = -1;
+	clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
+	return 0;
+}
+__setup("nolapic", lapic_disable);
+
+static int __init lapic_enable(char *str)
+{
+	enable_local_apic = 1;
+	return 0;
+}
+__setup("lapic", lapic_enable);
 
 static int __init detect_init_APIC (void)
 {
@@ -601,7 +625,7 @@
 	extern void get_cpu_vendor(struct cpuinfo_x86*);
 
 	/* Disabled by DMI scan or kernel option? */
-	if (dont_enable_local_apic)
+	if (enable_local_apic < 0)
 		return -1;
 
 	/* Workaround for us being called before identify_cpu(). */
@@ -616,7 +640,7 @@
 		goto no_apic;
 	case X86_VENDOR_INTEL:
 		if (boot_cpu_data.x86 == 6 ||
-		    (boot_cpu_data.x86 == 15 && cpu_has_apic) ||
+		    (boot_cpu_data.x86 == 15 && (cpu_has_apic || enable_local_apic > 0)) ||
 		    (boot_cpu_data.x86 == 5 && cpu_has_apic))
 			break;
 		goto no_apic;
@@ -636,6 +660,7 @@
 			l &= ~MSR_IA32_APICBASE_BASE;
 			l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
 			wrmsr(MSR_IA32_APICBASE, l, h);
+			enabled_via_apicbase = 1;
 		}
 	}
 	/*
@@ -928,14 +953,8 @@
 
 static unsigned int calibration_result;
 
-int dont_use_local_apic_timer __initdata = 0;
-
 void __init setup_APIC_clocks (void)
 {
-	/* Disabled by DMI scan or kernel option? */
-	if (dont_use_local_apic_timer)
-		return;
-
 	printk("Using local APIC timer interrupts.\n");
 	using_apic_timer = 1;
 
@@ -1152,6 +1171,9 @@
  */
 int __init APIC_init_uniprocessor (void)
 {
+	if (enable_local_apic < 0)
+		clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
+
 	if (!smp_found_config && !cpu_has_apic)
 		return -1;
 
diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c	Thu Aug 21 07:39:06 2003
+++ b/arch/i386/kernel/dmi_scan.c	Thu Aug 28 10:31:51 2003
@@ -335,9 +335,9 @@
 static int __init local_apic_kills_bios(struct dmi_blacklist *d)
 {
 #ifdef CONFIG_X86_LOCAL_APIC
-	extern int dont_enable_local_apic;
-	if (!dont_enable_local_apic) {
-		dont_enable_local_apic = 1;
+	extern int enable_local_apic;
+	if (enable_local_apic == 0) {
+		enable_local_apic = -1;
 		printk(KERN_WARNING "%s with broken BIOS detected. "
 		       "Refusing to enable the local APIC.\n",
 		       d->ident);
@@ -347,43 +347,6 @@
 }
 
 /*
- * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after
- * resumes, and also at what appears to be asynchronous APM events,
- * if the local APIC is enabled.
- */
-static int __init apm_kills_local_apic(struct dmi_blacklist *d)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-	extern int dont_enable_local_apic;
-	if (apm_info.bios.version && !dont_enable_local_apic) {
-		dont_enable_local_apic = 1;
-		printk(KERN_WARNING "%s with broken BIOS detected. "
-		       "Refusing to enable the local APIC.\n",
-		       d->ident);
-	}
-#endif
-	return 0;
-}
-
-/*
- * The Intel AL440LX mainboard will hang randomly if the local APIC
- * timer is running and the APM BIOS hasn't been disabled.
- */
-static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-	extern int dont_use_local_apic_timer;
-	if (apm_info.bios.version && !dont_use_local_apic_timer) {
-		dont_use_local_apic_timer = 1;
-		printk(KERN_WARNING "%s with broken BIOS detected. "
-		       "The local APIC timer will not be used.\n",
-		       d->ident);
-	}
-#endif
-	return 0;
-}
-
-/*
  *  Check for clue free BIOS implementations who use
  *  the following QA technique
  *
@@ -437,37 +400,6 @@
 }
 
 /*
- * The Intel 440GX hall of shame. 
- *
- * On many (all we have checked) of these boxes the $PIRQ table is wrong.
- * The MP1.4 table is right however and so SMP kernels tend to work. 
- */
- 
-#ifdef CONFIG_PCI
-extern int broken_440gx_bios;
-extern unsigned int pci_probe;
-#endif
-static __init int broken_pirq(struct dmi_blacklist *d)
-{
-	printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n");
-	printk(KERN_INFO " *** Many BIOSes matching this signature have incorrect IRQ routing tables.\n");
-	printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n");
-	printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n");
-	printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n");
-#ifdef CONFIG_X86_IO_APIC
-	{
-		extern int skip_ioapic_setup; 
-		skip_ioapic_setup = 0;
-	}
-#endif
-#ifdef CONFIG_PCI
-	broken_440gx_bios = 1;
-	pci_probe |= PCI_BIOS_IRQ_SCAN;
-#endif
-	return 0;
-}
-
-/*
  * ASUS K7V-RM has broken ACPI table defining sleep modes
  */
 
@@ -861,87 +793,17 @@
 			NO_MATCH, NO_MATCH
 			} },
 
-	{ apm_kills_local_apic, "Microstar 6163", {
-			MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
-			MATCH(DMI_BOARD_NAME, "MS-6163"),
-			NO_MATCH, NO_MATCH } },
-
-	{ apm_kills_local_apic_timer, "Intel AL440LX", {
-			MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BOARD_NAME, "AL440LX"),
-			NO_MATCH, NO_MATCH } },
-
-	/* Problem Intel 440GX bioses */
-
-	{ broken_pirq, "SABR1 Bios", {			/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"SABR1"),
-			NO_MATCH, NO_MATCH
-			} },
-	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0066.P07"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "IBM xseries 370", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "IBM"),
-			MATCH(DMI_BIOS_VERSION,"MMKT33AUS"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0094.P10"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0115.P12"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0120.P12"),
-			NO_MATCH, NO_MATCH
-                        } },
-	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"),
-			NO_MATCH, NO_MATCH
-			} },
-	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"C440GX0.86B"),
-			NO_MATCH, NO_MATCH
-			} },
-	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0133.P14"),
-			NO_MATCH, NO_MATCH
-			} },
-	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
-			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
-			MATCH(DMI_BIOS_VERSION,"L440GX0"),
-			NO_MATCH, NO_MATCH
-			} },
-                        
-	/* Intel in disgiuse - In this case they can't hide and they don't run
-	   too well either... */
-	{ broken_pirq, "Dell PowerEdge 8450", {		/* Bad $PIR */
-			MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"),
+	{ init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */
+			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
 			NO_MATCH, NO_MATCH, NO_MATCH
 			} },
-			
+
 	{ broken_acpi_Sx, "ASUS K7V-RM", {		/* Bad ACPI Sx table */
 			MATCH(DMI_BIOS_VERSION,"ASUS K7V-RM ACPI BIOS Revision 1003A"),
 			MATCH(DMI_BOARD_NAME, "<K7V-RM>"),
 			NO_MATCH, NO_MATCH
 			} },
 			
-	{ init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */
-			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
-			NO_MATCH, NO_MATCH, NO_MATCH
-			} },
-
 	{ print_if_true, KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.", {
 			MATCH(DMI_SYS_VENDOR, "IBM"),
 			MATCH(DMI_BIOS_VERSION, "1AET38WW (1.01b)"),
diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
--- a/arch/i386/kernel/head.S	Sun Dec 15 22:22:30 2002
+++ b/arch/i386/kernel/head.S	Mon Aug 25 14:37:33 2003
@@ -34,7 +34,7 @@
 #define X86_HARD_MATH	CPU_PARAMS+6
 #define X86_CPUID	CPU_PARAMS+8
 #define X86_CAPABILITY	CPU_PARAMS+12
-#define X86_VENDOR_ID	CPU_PARAMS+28
+#define X86_VENDOR_ID	CPU_PARAMS+36	/* tied to NCAPINTS in cpufeature.h */
 
 /*
  * swapper_pg_dir is the main page directory, address 0x00101000
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c	Thu Aug 21 07:39:06 2003
+++ b/arch/i386/kernel/io_apic.c	Fri Aug 22 12:05:33 2003
@@ -169,6 +169,14 @@
 {
 	struct IO_APIC_route_entry entry;
 	unsigned long flags;
+	
+	/* Check delivery_mode to be sure we're not clearing an SMI pin */
+	spin_lock_irqsave(&ioapic_lock, flags);
+	*(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
+	*(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+	if (entry.delivery_mode == dest_SMI)
+		return;
 
 	/*
 	 * Disable it in the IO-APIC irq-routing table:
@@ -1365,6 +1373,13 @@
 static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
 {
 	unsigned long flags;
+
+	/* pick a single cpu for clustered xapics */
+	if(clustered_apic_mode == CLUSTERED_APIC_XAPIC){
+		int cpu = ffs(mask)-1;
+		mask = cpu_to_physical_apicid(cpu);
+	}
+
 	/*
 	 * Only the first 8 bits are valid.
 	 */
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
--- a/arch/i386/kernel/irq.c	Tue Aug  6 14:35:28 2002
+++ b/arch/i386/kernel/irq.c	Sat Aug 30 05:02:26 2003
@@ -32,6 +32,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 #include <asm/atomic.h>
 #include <asm/io.h>
@@ -131,55 +132,55 @@
  * Generic, controller-independent functions:
  */
 
-int get_irq_list(char *buf)
+int show_interrupts(struct seq_file *p, void *v)
 {
 	int i, j;
 	struct irqaction * action;
-	char *p = buf;
 
-	p += sprintf(p, "           ");
+	seq_printf(p, "           ");
 	for (j=0; j<smp_num_cpus; j++)
-		p += sprintf(p, "CPU%d       ",j);
-	*p++ = '\n';
+		seq_printf(p, "CPU%d       ",j);
+	seq_putc(p,'\n');
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
 		action = irq_desc[i].action;
 		if (!action) 
 			continue;
-		p += sprintf(p, "%3d: ",i);
+		seq_printf(p, "%3d: ",i);
 #ifndef CONFIG_SMP
-		p += sprintf(p, "%10u ", kstat_irqs(i));
+		seq_printf(p, "%10u ", kstat_irqs(i));
 #else
 		for (j = 0; j < smp_num_cpus; j++)
-			p += sprintf(p, "%10u ",
+			seq_printf(p, "%10u ",
 				kstat.irqs[cpu_logical_map(j)][i]);
 #endif
-		p += sprintf(p, " %14s", irq_desc[i].handler->typename);
-		p += sprintf(p, "  %s", action->name);
+		seq_printf(p, " %14s", irq_desc[i].handler->typename);
+		seq_printf(p, "  %s", action->name);
 
 		for (action=action->next; action; action = action->next)
-			p += sprintf(p, ", %s", action->name);
-		*p++ = '\n';
+			seq_printf(p, ", %s", action->name);
+		seq_putc(p,'\n');
 	}
-	p += sprintf(p, "NMI: ");
+	seq_printf(p, "NMI: ");
 	for (j = 0; j < smp_num_cpus; j++)
-		p += sprintf(p, "%10u ",
+		seq_printf(p, "%10u ",
 			nmi_count(cpu_logical_map(j)));
-	p += sprintf(p, "\n");
+	seq_printf(p, "\n");
 #if CONFIG_X86_LOCAL_APIC
-	p += sprintf(p, "LOC: ");
+	seq_printf(p, "LOC: ");
 	for (j = 0; j < smp_num_cpus; j++)
-		p += sprintf(p, "%10u ",
+		seq_printf(p, "%10u ",
 			apic_timer_irqs[cpu_logical_map(j)]);
-	p += sprintf(p, "\n");
+	seq_printf(p, "\n");
 #endif
-	p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+	seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
 #ifdef CONFIG_X86_IO_APIC
 #ifdef APIC_MISMATCH_DEBUG
-	p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+	seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
 #endif
 #endif
-	return p - buf;
+
+	return 0;
 }
 
 
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Thu Aug 21 07:39:06 2003
+++ b/arch/i386/kernel/mpparse.c	Tue Jul  1 16:07:40 2003
@@ -977,7 +977,14 @@
 
 	processor.mpc_type = MP_PROCESSOR;
 	processor.mpc_apicid = id;
-	processor.mpc_apicver = 0x10; /* TBD: lapic version */
+
+	/*
+	 * mp_register_lapic_address() which is called before the
+	 * current function does the fixmap of FIX_APIC_BASE.
+	 * Read in the correct APIC version from there
+	 */
+	processor.mpc_apicver = apic_read(APIC_LVR);
+
 	processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0);
 	processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0);
 	processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | 
diff -Nru a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c
--- a/arch/i386/kernel/pci-i386.c	Tue Sep 17 07:08:45 2002
+++ b/arch/i386/kernel/pci-i386.c	Sat Aug 30 19:53:19 2003
@@ -295,6 +295,17 @@
 	}
 }
 
+void __init pcibios_set_cacheline_size(void)
+{
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+
+	pci_cache_line_size = 32 >> 2;
+	if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
+		pci_cache_line_size = 64 >> 2;	/* K7 & K8 */
+	else if (c->x86 > 6)
+		pci_cache_line_size = 128 >> 2;	/* P4 */
+}
+
 void __init pcibios_resource_survey(void)
 {
 	DBG("PCI: Allocating resources\n");
diff -Nru a/arch/i386/kernel/pci-i386.h b/arch/i386/kernel/pci-i386.h
--- a/arch/i386/kernel/pci-i386.h	Tue Aug  6 07:42:19 2002
+++ b/arch/i386/kernel/pci-i386.h	Sat Aug 30 19:53:19 2003
@@ -27,8 +27,10 @@
 /* pci-i386.c */
 
 extern unsigned int pcibios_max_latency;
+extern u8 pci_cache_line_size;
 
 void pcibios_resource_survey(void);
+void pcibios_set_cacheline_size(void);
 int pcibios_enable_resources(struct pci_dev *, int);
 
 /* pci-pc.c */
diff -Nru a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c
--- a/arch/i386/kernel/pci-irq.c	Tue Aug  5 08:35:31 2003
+++ b/arch/i386/kernel/pci-irq.c	Sun Aug 31 06:51:03 2003
@@ -23,7 +23,6 @@
 #define PIRQ_VERSION 0x0100
 
 int broken_hp_bios_irq9;
-int broken_440gx_bios;
 
 static struct irq_routing_table *pirq_table;
 
@@ -46,6 +45,11 @@
 	int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
 };
 
+struct irq_router_handler {
+	u16 vendor;
+	int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device);
+};
+
 /*
  *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
  */
@@ -257,111 +261,221 @@
 }
 
 /*
- *	PIRQ routing for SiS 85C503 router used in several SiS chipsets
- *	According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997)
- *	the related registers work as follows:
- *	
- *	general: one byte per re-routable IRQ,
+ *	PIRQ routing for SiS 85C503 router used in several SiS chipsets.
+ *	We have to deal with the following issues here:
+ *	- vendors have different ideas about the meaning of link values
+ *	- some onboard devices (integrated in the chipset) have special
+ *	  links and are thus routed differently (i.e. not via PCI INTA-INTD)
+ *	- different revision of the router have a different layout for
+ *	  the routing registers, particularly for the onchip devices
+ *
+ *	For all routing registers the common thing is we have one byte
+ *	per routeable link which is defined as:
  *		 bit 7      IRQ mapping enabled (0) or disabled (1)
- *		 bits [6:4] reserved
+ *		 bits [6:4] reserved (sometimes used for onchip devices)
  *		 bits [3:0] IRQ to map to
  *		     allowed: 3-7, 9-12, 14-15
  *		     reserved: 0, 1, 2, 8, 13
  *
- *	individual registers in device config space:
+ *	The config-space registers located at 0x41/0x42/0x43/0x44 are
+ *	always used to route the normal PCI INT A/B/C/D respectively.
+ *	Apparently there are systems implementing PCI routing table using
+ *	link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D.
+ *	We try our best to handle both link mappings.
+ *	
+ *	Currently (2003-05-21) it appears most SiS chipsets follow the
+ *	definition of routing registers from the SiS-5595 southbridge.
+ *	According to the SiS 5595 datasheets the revision id's of the
+ *	router (ISA-bridge) should be 0x01 or 0xb0.
  *
- *	0x41/0x42/0x43/0x44:	PCI INT A/B/C/D - bits as in general case
+ *	Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1.
+ *	Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets.
+ *	They seem to work with the current routing code. However there is
+ *	some concern because of the two USB-OHCI HCs (original SiS 5595
+ *	had only one). YMMV.
  *
- *	0x61:			IDEIRQ: bits as in general case - but:
- *				bits [6:5] must be written 01
- *				bit 4 channel-select primary (0), secondary (1)
+ *	Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1:
  *
- *	0x62:			USBIRQ: bits as in general case - but:
- *				bit 4 OHCI function disabled (0), enabled (1)
+ *	0x61:	IDEIRQ:
+ *		bits [6:5] must be written 01
+ *		bit 4 channel-select primary (0), secondary (1)
+ *
+ *	0x62:	USBIRQ:
+ *		bit 6 OHCI function disabled (0), enabled (1)
  *	
- *	0x6a:			ACPI/SCI IRQ - bits as in general case
+ *	0x6a:	ACPI/SCI IRQ: bits 4-6 reserved
+ *
+ *	0x7e:	Data Acq. Module IRQ - bits 4-6 reserved
+ *
+ *	We support USBIRQ (in addition to INTA-INTD) and keep the
+ *	IDE, ACPI and DAQ routing untouched as set by the BIOS.
+ *
+ *	Currently the only reported exception is the new SiS 65x chipset
+ *	which includes the SiS 69x southbridge. Here we have the 85C503
+ *	router revision 0x04 and there are changes in the register layout
+ *	mostly related to the different USB HCs with USB 2.0 support.
  *
- *	0x7e:			Data Acq. Module IRQ - bits as in general case
+ *	Onchip routing for router rev-id 0x04 (try-and-error observation)
  *
- *	Apparently there are systems implementing PCI routing table using both
- *	link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets
- *	like 0x62 as link values for USBIRQ e.g. So there is no simple
- *	"register = offset + pirq" relation.
- *	Currently we support PCI INTA..D and USBIRQ and try our best to handle
- *	both link mappings.
- *	IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS).
+ *	0x60/0x61/0x62/0x63:	1xEHCI and 3xOHCI (companion) USB-HCs
+ *				bit 6-4 are probably unused, not like 5595
  */
 
-static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+#define PIRQ_SIS_IRQ_MASK	0x0f
+#define PIRQ_SIS_IRQ_DISABLE	0x80
+#define PIRQ_SIS_USB_ENABLE	0x40
+#define PIRQ_SIS_DETECT_REGISTER 0x40
+
+/* return value:
+ * -1 on error
+ * 0 for PCI INTA-INTD
+ * 0 or enable bit mask to check or set for onchip functions
+ */
+static inline int pirq_sis5595_onchip(int pirq, int *reg)
 {
-	u8 x;
-	int reg = pirq;
+	int ret = -1;
 
+	*reg = pirq;
 	switch(pirq) {
-		case 0x01:
-		case 0x02:
-		case 0x03:
-		case 0x04:
-			reg += 0x40;
-		case 0x41:
-		case 0x42:
-		case 0x43:
-		case 0x44:
-		case 0x62:
-			pci_read_config_byte(router, reg, &x);
-			if (reg != 0x62)
-				break;
-			if (!(x & 0x40))
-				return 0;
-			break;
-		case 0x61:
-		case 0x6a:
-		case 0x7e:
-			printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
-			return 0;
-		default:			
-			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
-			return 0;
+	case 0x01:
+	case 0x02:
+	case 0x03:
+	case 0x04:
+		*reg += 0x40;
+	case 0x41:
+	case 0x42:
+	case 0x43:
+	case 0x44:
+		ret = 0;
+		break;
+
+	case 0x62:
+		ret = PIRQ_SIS_USB_ENABLE;	/* documented for 5595 */
+		break;
+
+	case 0x61:
+	case 0x6a:
+	case 0x7e:
+		printk(KERN_INFO "SiS pirq: IDE/ACPI/DAQ mapping not implemented: (%u)\n",
+		       (unsigned) pirq);
+		/* fall thru */
+	default:
+		printk(KERN_INFO "SiS router unknown request: (%u)\n",
+		       (unsigned) pirq);
+		break;
+	}
+	return ret;
+}		
+
+/* return value:
+ * -1 on error
+ * 0 for PCI INTA-INTD
+ * 0 or enable bit mask to check or set for onchip functions
+ */
+static inline int pirq_sis96x_onchip(int pirq, int *reg)
+{
+	int ret = -1;
+
+	*reg = pirq;
+	switch(pirq) {
+	case 0x01:
+	case 0x02:
+	case 0x03:
+	case 0x04:
+		*reg += 0x40;
+	case 0x41:
+	case 0x42:
+	case 0x43:
+	case 0x44:
+	case 0x60:
+	case 0x61:
+	case 0x62:
+	case 0x63:
+		ret = 0;
+		break;
+
+	default:
+		printk(KERN_INFO "SiS router unknown request: (%u)\n",
+		       (unsigned) pirq);
+		break;
 	}
-	return (x & 0x80) ? 0 : (x & 0x0f);
+	return ret;
+}		
+
+
+static int pirq_sis5595_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	u8 x;
+	int reg, check;
+
+	check = pirq_sis5595_onchip(pirq, &reg);
+	if (check < 0)
+		return 0;
+
+	pci_read_config_byte(router, reg, &x);
+	if (check != 0  &&  !(x & check))
+		return 0;
+
+	return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK);
 }
 
-static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+static int pirq_sis96x_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
 {
 	u8 x;
-	int reg = pirq;
+	int reg, check;
+
+	check = pirq_sis96x_onchip(pirq, &reg);
+	if (check < 0)
+		return 0;
+
+	pci_read_config_byte(router, reg, &x);
+	if (check != 0  &&  !(x & check))
+		return 0;
+
+	return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK);
+}
+
+static int pirq_sis5595_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	u8 x;
+	int reg, set;
+
+	set = pirq_sis5595_onchip(pirq, &reg);
+	if (set < 0)
+		return 0;
+
+	x = (irq & PIRQ_SIS_IRQ_MASK);
+	if (x == 0)
+		x = PIRQ_SIS_IRQ_DISABLE;
+	else
+		x |= set;
 
-	switch(pirq) {
-		case 0x01:
-		case 0x02:
-		case 0x03:
-		case 0x04:
-			reg += 0x40;
-		case 0x41:
-		case 0x42:
-		case 0x43:
-		case 0x44:
-		case 0x62:
-			x = (irq&0x0f) ? (irq&0x0f) : 0x80;
-			if (reg != 0x62)
-				break;
-			/* always mark OHCI enabled, as nothing else knows about this */
-			x |= 0x40;
-			break;
-		case 0x61:
-		case 0x6a:
-		case 0x7e:
-			printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n");
-			return 0;
-		default:			
-			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
-			return 0;
-	}
 	pci_write_config_byte(router, reg, x);
 
 	return 1;
 }
 
+static int pirq_sis96x_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	u8 x;
+	int reg, set;
+
+	set = pirq_sis96x_onchip(pirq, &reg);
+	if (set < 0)
+		return 0;
+
+	x = (irq & PIRQ_SIS_IRQ_MASK);
+	if (x == 0)
+		x = PIRQ_SIS_IRQ_DISABLE;
+	else
+		x |= set;
+
+	pci_write_config_byte(router, reg, x);
+
+	return 1;
+}
+
+
 /*
  * VLSI: nibble offset 0x74 - educated guess due to routing table and
  *       config space of VLSI 82C534 PCI-bridge/router (1004:0102)
@@ -454,96 +568,263 @@
 	return pcibios_set_irq_routing(bridge, pin, irq);
 }
 
-static struct irq_router pirq_bios_router =
-	{ "BIOS", 0, 0, NULL, pirq_bios_set };
-
 #endif
 
-static struct irq_router pirq_routers[] = {
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, pirq_piix_get, pirq_piix_set },
-	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_0, pirq_piix_get, pirq_piix_set },
-
-	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
-
-	{ "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set },
-
-	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
-	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
-	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
-
-	{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
-
-	{ "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
-	{ "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
-	{ "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
-	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
-	  pirq_serverworks_get, pirq_serverworks_set },
-	{ "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5,
-	  pirq_serverworks_get, pirq_serverworks_set },
-	{ "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
-		pirq_amd756_get, pirq_amd756_set },
-	{ "AMD766", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413,
-		pirq_amd756_get, pirq_amd756_set },
-	{ "AMD768", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443,
-		pirq_amd756_get, pirq_amd756_set },
 
-	{ "default", 0, 0, NULL, NULL }
-};
+static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	/* We must not touch 440GX even if we have tables. 440GX has
+	   different IRQ routing weirdness */
+	if(pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82450GX, NULL))
+		return 0;
+	switch(device)
+	{
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371SB_0:
+		case PCI_DEVICE_ID_INTEL_82371AB_0:
+		case PCI_DEVICE_ID_INTEL_82371MX:
+		case PCI_DEVICE_ID_INTEL_82443MX_0:
+		case PCI_DEVICE_ID_INTEL_82801AA_0:
+		case PCI_DEVICE_ID_INTEL_82801AB_0:
+		case PCI_DEVICE_ID_INTEL_82801BA_0:
+		case PCI_DEVICE_ID_INTEL_82801BA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_0:
+		case PCI_DEVICE_ID_INTEL_82801CA_12:
+		case PCI_DEVICE_ID_INTEL_82801DB_0:
+		case PCI_DEVICE_ID_INTEL_82801E_0:
+		case PCI_DEVICE_ID_INTEL_82801EB_0:
+		case PCI_DEVICE_ID_INTEL_ESB_0:
+			r->name = "PIIX/ICH";
+			r->get = pirq_piix_get;
+			r->set = pirq_piix_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int via_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	/* FIXME: We should move some of the quirk fixup stuff here */
+	switch(device)
+	{
+		case PCI_DEVICE_ID_VIA_82C586_0:
+		case PCI_DEVICE_ID_VIA_82C596:
+		case PCI_DEVICE_ID_VIA_82C686:
+		case PCI_DEVICE_ID_VIA_8231:
+		/* FIXME: add new ones for 8233/5 */
+			r->name = "VIA";
+			r->get = pirq_via_get;
+			r->set = pirq_via_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_VLSI_82C534:
+			r->name = "VLSI 82C534";
+			r->get = pirq_vlsi_get;
+			r->set = pirq_vlsi_set;
+			return 1;
+	}
+	return 0;
+}
+
+
+static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_SERVERWORKS_OSB4:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB5:
+			r->name = "ServerWorks";
+			r->get = pirq_serverworks_get;
+			r->set = pirq_serverworks_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	u8 reg;
+	u16 devid;
+
+	if (device != PCI_DEVICE_ID_SI_503)
+		return 0;
+		
+	/*
+	 * In case of SiS south bridge, we need to detect the two
+	 * kinds of routing tables we have seen so far (5595 and 96x). 
+	 * Since the maintain the same device ID, we need to do poke 
+	 * the PCI configuration space to find the router type we are
+	 * dealing with.
+	 */
+
+	/*
+	 * Factoid: writing bit6 of register 0x40 of the router config space
+	 * will make the SB to show up 0x096x inside the device id. Note,
+	 * we need to restore register 0x40 after the device id poke.
+	 */
+
+	pci_read_config_byte(router, PIRQ_SIS_DETECT_REGISTER, &reg);
+	pci_write_config_byte(router, PIRQ_SIS_DETECT_REGISTER, reg | (1 << 6));
+	pci_read_config_word(router, PCI_DEVICE_ID, &devid);
+	pci_write_config_byte(router, PIRQ_SIS_DETECT_REGISTER, reg);
+
+	if ((devid & 0xfff0) == 0x0960) {
+		r->name = "SIS96x";
+		r->get = pirq_sis96x_get;
+		r->set = pirq_sis96x_set;
+		DBG("PCI: Detecting SiS router at %02x:%02x : SiS096x detected\n",
+		    rt->rtr_bus, rt->rtr_devfn);
+	} else {
+		r->name = "SIS5595";
+		r->get = pirq_sis5595_get;
+		r->set = pirq_sis5595_set;
+		DBG("PCI: Detecting SiS router at %02x:%02x : SiS5595 detected\n",
+		    rt->rtr_bus, rt->rtr_devfn);
+	}
+	return 1;
+}
 
-static struct irq_router *pirq_router;
+static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_CYRIX_5520:
+			r->name = "NatSemi";
+			r->get = pirq_cyrix_get;
+			r->set = pirq_cyrix_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_OPTI_82C700:
+			r->name = "OPTI";
+			r->get = pirq_opti_get;
+			r->set = pirq_opti_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_ITE_IT8330G_0:
+			r->name = "ITE";
+			r->get = pirq_ite_get;
+			r->set = pirq_ite_set;
+			return 1;
+	}
+	return 0;
+}
+
+static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_AL_M1533:
+			r->name = "ALI";
+			r->get = pirq_ali_get;
+			r->set = pirq_ali_set;
+			return 1;
+		/* Should add 156x some day */
+	}
+	return 0;
+}
+
+static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
+{
+	switch(device)
+	{
+		case PCI_DEVICE_ID_AMD_VIPER_740B:
+			r->name = "AMD756";
+			break;
+		case PCI_DEVICE_ID_AMD_VIPER_7413:
+			r->name = "AMD766";
+			break;
+		case PCI_DEVICE_ID_AMD_VIPER_7443:
+			r->name = "AMD768";
+			break;
+		default:
+			return 0;
+	}
+	r->get = pirq_amd756_get;
+	r->set = pirq_amd756_set;
+	return 1;
+}
+		
+static __initdata struct irq_router_handler pirq_routers[] = {
+	{ PCI_VENDOR_ID_INTEL, intel_router_probe },
+	{ PCI_VENDOR_ID_AL, ali_router_probe },
+	{ PCI_VENDOR_ID_ITE, ite_router_probe },
+	{ PCI_VENDOR_ID_VIA, via_router_probe },
+	{ PCI_VENDOR_ID_OPTI, opti_router_probe },
+	{ PCI_VENDOR_ID_SI, sis_router_probe },
+	{ PCI_VENDOR_ID_CYRIX, cyrix_router_probe },
+	{ PCI_VENDOR_ID_VLSI, vlsi_router_probe },
+	{ PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe },
+	{ PCI_VENDOR_ID_AMD, amd_router_probe },
+	/* Someone with docs needs to add the ATI Radeon IGP */
+	{ 0, NULL }
+};
+static struct irq_router pirq_router;
 static struct pci_dev *pirq_router_dev;
 
-static void __init pirq_find_router(void)
+/*
+ *	FIXME: should we have an option to say "generic for
+ *	chipset" ?
+ */
+ 
+static void __init pirq_find_router(struct irq_router *r)
 {
 	struct irq_routing_table *rt = pirq_table;
-	struct irq_router *r;
+	struct irq_router_handler *h;
 
 #ifdef CONFIG_PCI_BIOS
 	if (!rt->signature) {
 		printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
-		pirq_router = &pirq_bios_router;
+		r->set = pirq_bios_set;
+		r->name = "BIOS";
 		return;
 	}
 #endif
 
+	/* Default unless a driver reloads it */
+	r->name = "default";
+	r->get = NULL;
+	r->set = NULL;
+	
 	DBG("PCI: Attempting to find IRQ router for %04x:%04x\n",
 	    rt->rtr_vendor, rt->rtr_device);
 
-	/* fall back to default router if nothing else found */
-	pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1];
-
 	pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
 	if (!pirq_router_dev) {
 		DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
 		return;
 	}
 
-	for(r=pirq_routers; r->vendor; r++) {
-		/* Exact match against router table entry? Use it! */
-		if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {
-			pirq_router = r;
+	for( h = pirq_routers; h->vendor; h++) {
+		/* First look for a router match */
+		if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device))
+			break;
+		/* Fall back to a device match */
+		if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device))
 			break;
-		}
-		/* Match against router device entry? Use it as a fallback */
-		if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
-			pirq_router = r;
-		}
 	}
 	printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
-		pirq_router->name,
+		pirq_router.name,
 		pirq_router_dev->vendor,
 		pirq_router_dev->device,
 		pirq_router_dev->slot_name);
@@ -572,7 +853,7 @@
 	int i, pirq, newirq;
 	int irq = 0;
 	u32 mask;
-	struct irq_router *r = pirq_router;
+	struct irq_router *r = &pirq_router;
 	struct pci_dev *dev2;
 	char *msg = NULL;
 
@@ -685,17 +966,14 @@
 void __init pcibios_irq_init(void)
 {
 	DBG("PCI: IRQ init\n");
-	if (broken_440gx_bios)
- 		pirq_table = NULL;	
- 	else
-		pirq_table = pirq_find_routing_table();
+	pirq_table = pirq_find_routing_table();
 #ifdef CONFIG_PCI_BIOS
 	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
 		pirq_table = pcibios_get_irq_routing_table();
 #endif
 	if (pirq_table) {
 		pirq_peer_trick();
-		pirq_find_router();
+		pirq_find_router(&pirq_router);
 		if (pirq_table->exclusive_irqs) {
 			int i;
 			for (i=0; i<16; i++)
diff -Nru a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
--- a/arch/i386/kernel/pci-pc.c	Tue Oct 15 16:56:59 2002
+++ b/arch/i386/kernel/pci-pc.c	Sat Aug 30 19:53:19 2003
@@ -1016,7 +1016,8 @@
 		"xor %%ah, %%ah\n"
 		"1:"
 		: "=a" (ret),
-		  "=b" (map)
+		  "=b" (map),
+		  "+m" (opt)
 		: "0" (PCIBIOS_GET_ROUTING_OPTIONS),
 		  "1" (0),
 		  "D" ((long) &opt),
@@ -1426,6 +1427,8 @@
 		printk(KERN_WARNING "PCI: System does not support PCI\n");
 		return;
 	}
+
+	pcibios_set_cacheline_size();
 
 	printk(KERN_INFO "PCI: Probing PCI hardware\n");
 #ifdef CONFIG_ACPI_PCI
diff -Nru a/arch/i386/kernel/pci-visws.c b/arch/i386/kernel/pci-visws.c
--- a/arch/i386/kernel/pci-visws.c	Tue Aug  6 07:42:19 2002
+++ b/arch/i386/kernel/pci-visws.c	Sat Aug 30 19:53:19 2003
@@ -119,6 +119,7 @@
 {
 	unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
 
+	pcibios_set_cacheline_size();
 	printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus);
 	pci_scan_bus(0, &visws_pci_ops, NULL);
 	pci_scan_bus(sec_bus, &visws_pci_ops, NULL);
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Sun Jun 29 08:10:34 2003
+++ b/arch/i386/kernel/process.c	Mon Aug 25 11:18:43 2003
@@ -47,6 +47,7 @@
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
+#include <asm/apic.h>
 
 #include <linux/irq.h>
 
@@ -399,6 +400,14 @@
 	 * other OSs see a clean IRQ state.
 	 */
 	smp_send_stop();
+#elif CONFIG_X86_LOCAL_APIC
+	if (cpu_has_apic) {
+		__cli();
+		disable_local_APIC();
+		__sti();
+	}
+#endif
+#ifdef CONFIG_X86_IO_APIC
 	disable_IO_APIC();
 #endif
 
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Thu Aug 21 07:39:06 2003
+++ b/arch/i386/kernel/setup.c	Mon Aug 25 14:38:49 2003
@@ -1976,6 +1976,37 @@
 	
 #endif
 
+static void __init init_c3(struct cpuinfo_x86 *c)
+{
+	u32  lo, hi;
+
+	/* Test for Centaur Extended Feature Flags presence */
+	if (cpuid_eax(0xC0000000) >= 0xC0000001) {
+		/* store Centaur Extended Feature Flags as
+		 * word 5 of the CPU capability bit array
+		 */
+		c->x86_capability[5] = cpuid_edx(0xC0000001);
+	}
+
+	switch (c->x86_model) {
+		case 6 ... 8:		/* Cyrix III family */
+			rdmsr (MSR_VIA_FCR, lo, hi);
+			lo |= (1<<1 | 1<<7);	/* Report CX8 & enable PGE */
+			wrmsr (MSR_VIA_FCR, lo, hi);
+
+			set_bit(X86_FEATURE_CX8, c->x86_capability);
+			set_bit(X86_FEATURE_3DNOW, c->x86_capability);
+
+			/* fall through */
+
+		case 9:	/* Nehemiah */
+		default:
+			get_model_name(c);
+			display_cacheinfo(c);
+			break;
+	}
+}
+
 static void __init init_centaur(struct cpuinfo_x86 *c)
 {
 	enum {
@@ -2114,23 +2145,7 @@
 			break;
 
 		case 6:
-			switch (c->x86_model) {
-				case 6 ... 8:		/* Cyrix III family */
-					rdmsr (MSR_VIA_FCR, lo, hi);
-					lo |= (1<<1 | 1<<7);	/* Report CX8 & enable PGE */
-					wrmsr (MSR_VIA_FCR, lo, hi);
-
-					set_bit(X86_FEATURE_CX8, &c->x86_capability);
-					set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
-
-					/* fall through */
-
-				case 9: /* Nehemiah */
-				default:
-					get_model_name(c);
-					display_cacheinfo(c);
-					break;
-			}
+			init_c3(c);
 			break;
 	}
 }
@@ -2765,10 +2780,16 @@
 
 		/* Intel-defined flags: level 0x00000001 */
 		if ( c->cpuid_level >= 0x00000001 ) {
-			cpuid(0x00000001, &tfms, &junk, &junk,
-			      &c->x86_capability[0]);
+			u32 capability, excap;
+			cpuid(0x00000001, &tfms, &junk, &excap, &capability);
+			c->x86_capability[0] = capability;
+			c->x86_capability[4] = excap;
 			c->x86 = (tfms >> 8) & 15;
 			c->x86_model = (tfms >> 4) & 15;
+			if (c->x86 == 0xf) {
+				c->x86 += (tfms >> 20) & 0xff;
+				c->x86_model += ((tfms >> 16) & 0xF) << 4;
+			} 
 			c->x86_mask = tfms & 15;
 		} else {
 			/* Have CPUID level 0 only - unheard of */
@@ -2972,12 +2993,12 @@
 	        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
 	        "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
 	        "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
-	        "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
+	        "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
 
 		/* AMD-defined */
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, NULL, NULL, "mmxext", NULL,
+		NULL, NULL, NULL, "mp", NULL, NULL, "mmxext", NULL,
 		NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
 
 		/* Transmeta-defined */
@@ -2987,7 +3008,20 @@
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
 		/* Other (Linux-defined) */
-		"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
+		"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
+		NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+		/* Intel-defined (#2) */
+		"pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "tm2",
+		"est", NULL, "cid", NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+		/* VIA/Cyrix/Centaur-defined */
+		NULL, NULL, "xstore", NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
--- a/arch/i386/kernel/smpboot.c	Thu Aug 21 07:39:06 2003
+++ b/arch/i386/kernel/smpboot.c	Thu Jun  6 06:49:14 2002
@@ -51,7 +51,7 @@
 static int smp_b_stepping;
 
 /* Setup configured maximum number of CPUs to activate */
-static int max_cpus = -1;
+static int max_cpus = NR_CPUS;
 
 /* Total count of live CPUs */
 int smp_num_cpus = 1;
@@ -1116,7 +1116,7 @@
 
 		if (!(phys_cpu_present_map & (1ul << bit)))
 			continue;
-		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
+		if (max_cpus <= cpucount+1)
 			continue;
 
 		do_boot_cpu(apicid);
diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in
--- a/arch/ia64/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/ia64/config.in	Fri Aug 29 16:11:01 2003
@@ -87,6 +87,10 @@
 define_bool CONFIG_KCORE_ELF y	# On IA-64, we always want an ELF /proc/kcore.
 
 bool 'SMP support' CONFIG_SMP
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
+
 tristate 'Support running of Linux/x86 binaries' CONFIG_IA32_SUPPORT
 bool 'Performance monitor support' CONFIG_PERFMON
 tristate '/proc/pal support' CONFIG_IA64_PALINFO
@@ -289,5 +293,7 @@
    bool '  Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
    bool '  Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
 
 endmenu
diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig
--- a/arch/ia64/defconfig	Mon May 19 09:43:17 2003
+++ b/arch/ia64/defconfig	Wed Jun 19 10:26:35 2002
@@ -50,6 +50,7 @@
 # CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
 # CONFIG_HUGETLB_PAGE_SIZE_256KB is not set
 CONFIG_SMP=y
+CONFIG_NR_CPUS=32
 CONFIG_IA32_SUPPORT=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
diff -Nru a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
--- a/arch/m68k/apollo/dn_ints.c	Mon Sep  9 04:36:58 2002
+++ b/arch/m68k/apollo/dn_ints.c	Mon Jul 21 13:39:55 2003
@@ -43,7 +43,7 @@
 int dn_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) {
 
   if((irq<0) || (irq>15)) {
-    printk("Trying to request illegal IRQ\n");
+    printk("Trying to request invalid IRQ\n");
     return -ENXIO;
   }
 
@@ -69,7 +69,7 @@
 void dn_free_irq(unsigned int irq, void *dev_id) {
 
   if((irq<0) || (irq>15)) {
-    printk("Trying to free illegal IRQ\n");
+    printk("Trying to free invalid IRQ\n");
     return ;
   }
 
diff -Nru a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
--- a/arch/m68k/atari/time.c	Tue Apr 23 07:20:57 2002
+++ b/arch/m68k/atari/time.c	Mon Jun 30 08:15:40 2003
@@ -16,7 +16,7 @@
 #include <linux/init.h>
 #include <linux/rtc.h>
 
-#include <asm/rtc.h>
+#include <asm/atariints.h>
 
 void __init
 atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
diff -Nru a/arch/m68k/config.in b/arch/m68k/config.in
--- a/arch/m68k/config.in	Mon Jun 23 13:50:43 2003
+++ b/arch/m68k/config.in	Fri Aug 29 16:11:08 2003
@@ -320,9 +320,9 @@
       tristate '  EQL (serial line load balancing) support' CONFIG_EQUALIZER
       if [ "$CONFIG_ZORRO" = "y" ]; then
 	 tristate '  Ariadne support' CONFIG_ARIADNE
-	 tristate '  Ariadne II support' CONFIG_ARIADNE2
 	 tristate '  A2065 support' CONFIG_A2065
 	 tristate '  Hydra support' CONFIG_HYDRA
+	 tristate '  Zorro NS8390-based Ethernet support' CONFIG_ZORRO8390
       fi
       if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
 	 tristate '  PCMCIA NE2000 support' CONFIG_APNE
@@ -513,14 +513,10 @@
    bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
    bool '  Software Watchdog' CONFIG_SOFT_WATCHDOG
 fi
-if [ "$CONFIG_ATARI" = "y" ]; then
-   bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+if [ "$CONFIG_SUN3" = "y" ]; then
+   define_bool CONFIG_GEN_RTC y
 else
-   if [ "$CONFIG_SUN3" = "y" ]; then
-      define_bool CONFIG_GEN_RTC y
-   else
-      tristate 'Generic /dev/rtc emulation' CONFIG_GEN_RTC      
-   fi
+   tristate 'Generic /dev/rtc emulation' CONFIG_GEN_RTC      
 fi
 if [ "$CONFIG_GEN_RTC" != "n" ]; then
    bool '   Extended RTC operation' CONFIG_GEN_RTC_X
@@ -559,6 +555,8 @@
    bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
    bool '  Verbose BUG() reporting' CONFIG_DEBUG_BUGVERBOSE
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
 
 endmenu
 
diff -Nru a/arch/m68k/defconfig b/arch/m68k/defconfig
--- a/arch/m68k/defconfig	Tue Feb  5 09:40:26 2002
+++ b/arch/m68k/defconfig	Sat Jun 28 12:40:55 2003
@@ -177,7 +177,7 @@
 # CONFIG_PPP is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ARIADNE is not set
-# CONFIG_ARIADNE2 is not set
+# CONFIG_ZORRO8390 is not set
 # CONFIG_A2065 is not set
 # CONFIG_HYDRA is not set
 
diff -Nru a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
--- a/arch/m68k/kernel/ptrace.c	Sun Nov 25 03:19:19 2001
+++ b/arch/m68k/kernel/ptrace.c	Sat Mar 22 10:38:07 2003
@@ -133,14 +133,9 @@
 		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
-	ret = -ESRCH;
-	if (!(child->ptrace & PT_PTRACED))
-		goto out_tsk;
-	if (child->state != TASK_STOPPED) {
-		if (request != PTRACE_KILL)
-			goto out_tsk;
-	}
-	if (child->p_pptr != current)
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
 		goto out_tsk;
 
 	switch (request) {
diff -Nru a/arch/m68k/math-emu/fp_emu.h b/arch/m68k/math-emu/fp_emu.h
--- a/arch/m68k/math-emu/fp_emu.h	Sat Sep 29 09:02:11 2001
+++ b/arch/m68k/math-emu/fp_emu.h	Wed Jul 23 15:06:23 2003
@@ -115,6 +115,15 @@
 	__res;							\
 })
 
+#define fp_conv_long2ext(dest, src) ({				\
+	register struct fp_ext *__dest asm ("a0") = dest;	\
+	register int __src asm ("d0") = src;			\
+								\
+	asm volatile ("jsr fp_conv_ext2long"			\
+			: : "d" (__src), "a" (__dest)		\
+			: "a1", "d1", "d2", "memory");		\
+})
+
 #else /* __ASSEMBLY__ */
 
 /*
diff -Nru a/arch/m68k/math-emu/fp_log.c b/arch/m68k/math-emu/fp_log.c
--- a/arch/m68k/math-emu/fp_log.c	Tue Feb  5 09:40:28 2002
+++ b/arch/m68k/math-emu/fp_log.c	Wed Jul 23 15:06:23 2003
@@ -17,10 +17,22 @@
 
 #include "fp_emu.h"
 
+static const struct fp_ext fp_one =
+{
+	0, 0, 0x3fff, { 0 }
+};
+
+extern struct fp_ext *fp_fadd(struct fp_ext *dest, const struct fp_ext *src);
+extern struct fp_ext *fp_fdiv(struct fp_ext *dest, const struct fp_ext *src);
+extern struct fp_ext *fp_fmul(struct fp_ext *dest, const struct fp_ext *src);
+
 struct fp_ext *
 fp_fsqrt(struct fp_ext *dest, struct fp_ext *src)
 {
-	uprint("fsqrt\n");
+	struct fp_ext tmp, src2;
+	int i, exp;
+
+	dprint(PINSTR, "fsqrt\n");
 
 	fp_monadic_check(dest, src);
 
@@ -34,6 +46,56 @@
 	if (IS_INF(dest))
 		return dest;
 
+	/*
+	 *		 sqrt(m) * 2^(p)	, if e = 2*p
+	 * sqrt(m*2^e) = 
+	 *		 sqrt(2*m) * 2^(p)	, if e = 2*p + 1
+	 *
+	 * So we use the last bit of the exponent to decide wether to
+	 * use the m or 2*m.
+	 *
+	 * Since only the fractional part of the mantissa is stored and
+	 * the integer part is assumed to be one, we place a 1 or 2 into
+	 * the fixed point representation.
+	 */
+	exp = dest->exp;
+	dest->exp = 0x3FFF;
+	if (!(exp & 1))		/* lowest bit of exponent is set */
+		dest->exp++;
+	fp_copy_ext(&src2, dest);
+
+	/*
+	 * The taylor row arround a for sqrt(x) is:
+	 *	sqrt(x) = sqrt(a) + 1/(2*sqrt(a))*(x-a) + R
+	 * With a=1 this gives:
+	 *	sqrt(x) = 1 + 1/2*(x-1)
+	 *		= 1/2*(1+x)
+	 */
+	fp_fadd(dest, &fp_one);
+	dest->exp--;		/* * 1/2 */
+
+	/*
+	 * We now apply the newton rule to the function
+	 *	f(x) := x^2 - r
+	 * which has a null point on x = sqrt(r).
+	 *
+	 * It gives:
+	 * 	x' := x - f(x)/f'(x)
+	 *	    = x - (x^2 -r)/(2*x)
+	 *	    = x - (x - r/x)/2
+	 *          = (2*x - x + r/x)/2
+	 *	    = (x + r/x)/2
+	 */
+	for (i = 0; i < 9; i++) {
+		fp_copy_ext(&tmp, &src2);
+
+		fp_fdiv(&tmp, dest);
+		fp_fadd(dest, &tmp);
+		dest->exp--;
+	}
+
+	dest->exp += (exp - 0x3FFF) / 2;
+
 	return dest;
 }
 
@@ -123,19 +185,38 @@
 struct fp_ext *
 fp_fgetexp(struct fp_ext *dest, struct fp_ext *src)
 {
-	uprint("fgetexp\n");
+	dprint(PINSTR, "fgetexp\n");
 
 	fp_monadic_check(dest, src);
 
+	if (IS_INF(dest)) {
+		fp_set_nan(dest);
+		return dest;
+	}
+	if (IS_ZERO(dest))
+		return dest;
+
+	fp_conv_long2ext(dest, (int)dest->exp - 0x3FFF);
+
+	fp_normalize_ext(dest);
+
 	return dest;
 }
 
 struct fp_ext *
 fp_fgetman(struct fp_ext *dest, struct fp_ext *src)
 {
-	uprint("fgetman\n");
+	dprint(PINSTR, "fgetman\n");
 
 	fp_monadic_check(dest, src);
+
+	if (IS_ZERO(dest))
+		return dest;
+
+	if (IS_INF(dest))
+		return dest;
+
+	dest->exp = 0x3FFF;
 
 	return dest;
 }
diff -Nru a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
--- a/arch/m68k/mm/kmap.c	Mon Feb  4 23:37:24 2002
+++ b/arch/m68k/mm/kmap.c	Tue Jul  1 15:06:18 2003
@@ -71,7 +71,7 @@
 		addr = tmp->size + (unsigned long)tmp->addr;
 	}
 	area->addr = (void *)addr;
-	area->size = size + IO_SIZE;
+	area->size = size + IO_SIZE;	/* leave a gap between */
 	area->next = *p;
 	*p = area;
 	return area;
@@ -87,7 +87,10 @@
 	for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
-			__iounmap(tmp->addr, tmp->size);
+			if ( tmp->size > IO_SIZE )
+				__iounmap(tmp->addr, tmp->size - IO_SIZE);
+			else
+				printk("free_io_area: Invalid I/O area size %lu\n", tmp->size);
 			kfree(tmp);
 			return;
 		}
diff -Nru a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
--- a/arch/m68k/mm/memory.c	Sun Jun 29 08:10:38 2003
+++ b/arch/m68k/mm/memory.c	Tue Jul  1 14:29:03 2003
@@ -19,75 +19,9 @@
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/traps.h>
-#include <asm/io.h>
 #include <asm/machdep.h>
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#endif
 
 struct pgtable_cache_struct quicklists;
-
-void __bad_pte(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	pmd_set(pmd, BAD_PAGETABLE);
-}
-
-void __bad_pmd(pgd_t *pgd)
-{
-	printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-	pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
-}
-
-#if 0
-pte_t *get_pte_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);
-			__flush_page_to_ram((unsigned long)pte);
-			flush_tlb_kernel_page((unsigned long)pte);
-			nocache_page((unsigned long)pte);
-			pmd_set(pmd, pte);
-			return pte + offset;
-		}
-		pmd_set(pmd, BAD_PAGETABLE);
-		return NULL;
-	}
-	free_page((unsigned long)pte);
-	if (pmd_bad(*pmd)) {
-		__bad_pte(pmd);
-		return NULL;
-	}
-	return (pte_t *)__pmd_page(*pmd) + offset;
-}
-#endif
-
-#if 0
-pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
-{
-	pmd_t *pmd;
-
-	pmd = get_pointer_table();
-	if (pgd_none(*pgd)) {
-		if (pmd) {
-			pgd_set(pgd, pmd);
-			return pmd + offset;
-		}
-		pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
-		return NULL;
-	}
-	free_pointer_table(pmd);
-	if (pgd_bad(*pgd)) {
-		__bad_pmd(pgd);
-		return NULL;
-	}
-	return (pmd_t *)__pgd_page(*pgd) + offset;
-}
-#endif
 
 /* ++andreas: {get,free}_pointer_table rewritten to use unused fields from
    struct page instead of separately kmalloced struct.  Stolen from
diff -Nru a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
--- a/arch/m68k/q40/q40ints.c	Wed Mar 12 07:16:10 2003
+++ b/arch/m68k/q40/q40ints.c	Mon Jul 21 13:39:55 2003
@@ -168,7 +168,7 @@
 	  {
 	  case 1: case 2: case 8: case 9:
 	  case 12: case 13:
-	    printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
+	    printk("%s: ISA IRQ %d from %x invalid\n", __FUNCTION__, irq, (unsigned)dev_id);
 	    return;
 	  case 11: irq=10;
 	  default:
diff -Nru a/arch/mips/config-shared.in b/arch/mips/config-shared.in
--- a/arch/mips/config-shared.in	Wed Aug 13 08:41:01 2003
+++ b/arch/mips/config-shared.in	Fri Aug 29 16:14:12 2003
@@ -1039,7 +1039,12 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 if [ "$CONFIG_SMP" != "y" ]; then
    bool 'Run uncached' CONFIG_MIPS_UNCACHED
+else
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
 
 source crypto/Config.in
diff -Nru a/arch/mips64/defconfig b/arch/mips64/defconfig
--- a/arch/mips64/defconfig	Fri Jul  4 20:50:14 2003
+++ b/arch/mips64/defconfig	Wed Jun 19 10:26:35 2002
@@ -102,6 +102,7 @@
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_SB1 is not set
 CONFIG_SMP=y
+CONFIG_NR_CPUS=32
 # CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
diff -Nru a/arch/parisc/config.in b/arch/parisc/config.in
--- a/arch/parisc/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/parisc/config.in	Fri Aug 29 16:11:39 2003
@@ -45,6 +45,10 @@
 comment 'General options'
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
+
 bool 'Chassis LCD and LED support' CONFIG_CHASSIS_LCD_LED
 
 bool 'Kernel Debugger support' CONFIG_KWDB
@@ -194,6 +198,9 @@
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
 
 source crypto/Config.in
diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile	Thu Jun 19 04:56:31 2003
+++ b/arch/ppc/Makefile	Thu Aug 28 05:40:29 2003
@@ -42,18 +42,13 @@
   CFLAGS += $(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
 endif
 
-ifdef CONFIG_40x
-  HEAD := arch/ppc/kernel/head_4xx.o
-else
-  ifdef CONFIG_8xx
-    HEAD := arch/ppc/kernel/head_8xx.o
-  else
-    HEAD := arch/ppc/kernel/head.o
-    ifdef CONFIG_6xx
-	HEAD += arch/ppc/kernel/idle_6xx.o
-    endif
-  endif
-endif
+HEAD-y			:= arch/ppc/kernel/head.o
+HEAD-$(CONFIG_40x)	:= arch/ppc/kernel/head_4xx.o
+HEAD-$(CONFIG_44x)	:= arch/ppc/kernel/head_44x.o
+HEAD-$(CONFIG_8xx)	:= arch/ppc/kernel/head_8xx.o
+HEAD-$(CONFIG_6xx)	+= arch/ppc/kernel/idle_6xx.o
+
+HEAD := $(HEAD-y)
 
 ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/platforms arch/ppc/mm arch/ppc/lib
 SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
diff -Nru a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
--- a/arch/ppc/boot/simple/Makefile	Thu Jul  3 09:15:26 2003
+++ b/arch/ppc/boot/simple/Makefile	Thu Aug 28 05:31:04 2003
@@ -28,6 +28,22 @@
 TFTPIMAGE			:= /tftpboot/zImage.embedded
 MISC				:= misc-embedded.o
 endif
+ifeq ($(CONFIG_EBONY),y)
+ZIMAGE				:= zImage-TREE
+ZIMAGEINITRD			:= zImage.initrd-TREE
+END				:= ebony
+ENTRYPOINT			:= 0x00800000
+TFTPIMAGE			:= /tftpboot/zImage.$(END)
+EXTRA				:= misc-44x.o
+endif
+ifeq ($(CONFIG_OCOTEA),y)
+ZIMAGE				:= zImage-TREE
+ZIMAGEINITRD			:= zImage.initrd-TREE
+END				:= ocotea
+ENTRYPOINT			:= 0x00800000
+TFTPIMAGE			:= /tftpboot/zImage.$(END)
+EXTRA				:= misc-44x.o
+endif
 ifeq ($(CONFIG_GEMINI),y)
 ZIMAGE				:= zImage-SMON
 ZIMAGEINITRD			:= zImage.initrd-SMON
@@ -68,7 +84,7 @@
 ifdef CONFIG_8xx
 LD_ARGS				:= -T ../ld.script -Ttext 0x00180000 -Bstatic
 endif
-ifeq ($(CONFIG_8260)$(CONFIG_4xx),y)
+ifeq ($(CONFIG_8260)$(CONFIG_40x),y)
 LD_ARGS				:= -T ../ld.script -Ttext 0x00400000 -Bstatic
 endif
 OBJCOPY_ARGS			:= -O elf32-powerpc
diff -Nru a/arch/ppc/boot/simple/embed_config.c b/arch/ppc/boot/simple/embed_config.c
--- a/arch/ppc/boot/simple/embed_config.c	Tue Jul 29 10:27:43 2003
+++ b/arch/ppc/boot/simple/embed_config.c	Fri Aug 29 00:22:02 2003
@@ -640,7 +640,7 @@
 }
 #endif /* WILLOW */
 
-#ifdef CONFIG_TREEBOOT
+#ifdef CONFIG_IBM_OPENBIOS
 /* This could possibly work for all treeboot roms.
 */
 #define	BOARD_INFO_VECTOR	0xFFFE0B50
diff -Nru a/arch/ppc/boot/simple/head.S b/arch/ppc/boot/simple/head.S
--- a/arch/ppc/boot/simple/head.S	Tue Feb 25 10:58:28 2003
+++ b/arch/ppc/boot/simple/head.S	Fri Aug 29 00:22:02 2003
@@ -35,8 +35,8 @@
 	.globl	start
 start:
 	bl	start_
-#ifdef CONFIG_TREEBOOT
-	/* The IBM "Tree" bootrom knows that the address of the bootrom
+#ifdef CONFIG_IBM_OPENBIOS
+	/* The IBM OpenBIOS bootroms know that the address of the bootrom
 	 * read only structure is 4 bytes after _start.
 	 */
 	.long	0x62726f6d		# structure ID - "brom"
diff -Nru a/arch/ppc/boot/simple/misc-44x.c b/arch/ppc/boot/simple/misc-44x.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/simple/misc-44x.c	Thu Aug 28 05:25:04 2003
@@ -0,0 +1,32 @@
+/*
+ * arch/ppc/simple/misc-44x.c
+ *
+ * Misc. bootloader code for IBM PPC 44x reference boards (Ebony, Ocotea)
+ *
+ * Matt Porter <mporter@mvista.com>
+ * Eugene Surovegin <ebs@ebshome.net>
+ * 
+ * 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.
+ */
+#include <linux/config.h> 
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/ibm4xx.h>
+
+extern struct bi_record *decompress_kernel(unsigned long load_addr,
+	int num_words, unsigned long cksum);
+
+struct bi_record *
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
+{
+	mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR);		  /* reset MAL */
+	while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {}; /* wait for reset */
+	*(volatile unsigned long *)PPC44x_EMAC0_MR0 = 0x20000000; /* reset EMAC */
+	eieio();
+
+	return decompress_kernel(load_addr, num_words, cksum);
+}
diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in
--- a/arch/ppc/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/ppc/config.in	Fri Aug 29 16:12:10 2003
@@ -30,11 +30,12 @@
 choice 'Processor Type'	\
 	"6xx/7xx/74xx/8260	CONFIG_6xx	\
 	 40x			CONFIG_40x	\
+	 44x			CONFIG_44x	\
 	 POWER3			CONFIG_POWER3	\
 	 POWER4			CONFIG_POWER4	\
 	 8xx			CONFIG_8xx"	6xx
 
-if [ "$CONFIG_40x" = "y" ]; then
+if [ "$CONFIG_40x" = "y" -o "$CONFIG_44x" = "y" ]; then
   define_bool CONFIG_4xx y
 fi
 
@@ -64,6 +65,12 @@
 	 Walnut		CONFIG_WALNUT"		Walnut
 fi
 
+if [ "$CONFIG_44x" = "y" ]; then
+    choice 'Machine Type'			\
+	 "Ebony		CONFIG_EBONY		\
+	 Ocotea		CONFIG_OCOTEA"		Ebony
+fi
+
 if [ "$CONFIG_8xx" = "y" ]; then
   define_bool CONFIG_SERIAL_CONSOLE y
   define_bool CONFIG_NOT_COHERENT_CACHE y
@@ -123,6 +130,7 @@
 bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_SMP" = "y" ]; then
   bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
+  int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
 fi
 
 if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then
@@ -134,35 +142,103 @@
   fi
   define_bool CONFIG_PPC_ISATIMER y
 fi
+if [ "$CONFIG_POWER4" = "y" ]; then
+  bool 'VMX (same as AltiVec) support' CONFIG_ALTIVEC
+fi
 
 if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then
   bool 'Math emulation' CONFIG_MATH_EMULATION
 fi
 
-if [ "$CONFIG_40x" = "y" ]; then
-# It's often necessary to know the specific 4xx processor type.
-# Fortunately, it is impled (so far) from the board type, so we
-# don't need to ask more redundant questions.
+if [ "$CONFIG_4xx" = "y" ]; then
+
+  bool 'PPC4xx DMA controller support' CONFIG_PPC4xx_DMA
+  if [ "$CONFIG_PPC4xx_DMA" = "y" ]; then
+    define_bool CONFIG_PPC4xx_EDMA y
+  fi
+
+#
+# Set generic PPC4xx options
+#
+  define_bool CONFIG_NOT_COHERENT_CACHE y
+
+  if [ "$CONFIG_40x" = "y" ]; then
+    choice 'TTYS0 device and default console'	\
+	"UART0  CONFIG_UART0_TTYS0		\
+	 UART1	CONFIG_UART0_TTYS1"		UART0
+  fi
+
+#
+# Set processor implementation based on board
+#
   if [ "$CONFIG_OAK" = "y" -o "$CONFIG_TIVO" = "y" ]; then
     define_bool CONFIG_403GCX y
-    define_bool CONFIG_IBM_OPENBIOS y
   fi
+
   if [ "$CONFIG_WALNUT" = "y" ]; then
     define_bool CONFIG_405GP y
-    define_bool CONFIG_BIOS_FIXUP y
-    define_bool CONFIG_IBM_OPENBIOS y
-    define_bool CONFIG_IBM405_ERR77 y
+  fi
+
+  if [ "$CONFIG_EBONY" = "y" ]; then
+    define_bool CONFIG_440GP y
+  fi
+
+  if [ "$CONFIG_OCOTEA" = "y" ]; then
+    define_bool CONFIG_440GX y
+  fi
+
+#
+# Set options based on processor implementation
+#
+  if [ "$CONFIG_405GP" = "y" ]; then
+    define_bool CONFIG_IBM_OCP y
+    define_bool CONFIG_405 y
+  fi
+
+  if [ "$CONFIG_440GP" = "y" ]; then
+    define_bool CONFIG_IBM_OCP y
+    define_bool CONFIG_GEN550 y
+    define_bool CONFIG_440 y
+  fi
+
+  if [ "$CONFIG_440GX" = "y" ]; then
     define_bool CONFIG_IBM_OCP y
+    define_bool CONFIG_GEN550 y
+    define_bool CONFIG_IBM_EMAC4 y
+    define_bool CONFIG_440A y
   fi
+
+#
+# Set options based on processor core
+#
   if [ "$CONFIG_40x" = "y" ]; then
-    choice 'TTYS0 device and default console'	\
-	"UART0  CONFIG_UART0_TTYS0		\
-	 UART1	CONFIG_UART0_TTYS1"		UART0
+    define_bool CONFIG_IBM405_ERR51 y
+  fi
+
+  if [ "$CONFIG_405" = "y" ]; then
+    define_bool CONFIG_IBM405_ERR77 y
+  fi
+
+  if [ "$CONFIG_44x" = "y" ]; then
+    define_bool CONFIG_PTE_64BIT y
+    define_bool CONFIG_PIN_TLB y
+    define_bool CONFIG_BOOKE y
+  fi
+
+#
+# Set other board specific options
+#
+  if [ "$CONFIG_OAK" = "y" -o "$CONFIG_TIVO" = "y" -o \
+  "$CONFIG_WALNUT" = "y" ]; then
+    define_bool CONFIG_IBM_OPENBIOS y
+  fi
+
+  if [ "$CONFIG_WALNUT" = "y" ]; then
+    define_bool CONFIG_BIOS_FIXUP y
   fi
 
-  define_bool CONFIG_IBM405_ERR51 y
-  define_bool CONFIG_NOT_COHERENT_CACHE y
 fi
+
 if [ "$CONFIG_8xx" = "y" -o "$CONFIG_8260" = "y" ]; then
     define_bool CONFIG_EMBEDDEDBOOT y
 fi
@@ -487,4 +563,7 @@
 if [ "$CONFIG_GEN550" = "y" ]; then
   bool 'Support for early boot texts over serial port' CONFIG_SERIAL_TEXT_DEBUG
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
diff -Nru a/arch/ppc/configs/apus_defconfig b/arch/ppc/configs/apus_defconfig
--- a/arch/ppc/configs/apus_defconfig	Tue Apr 29 17:19:36 2003
+++ b/arch/ppc/configs/apus_defconfig	Sat Jun 28 12:42:45 2003
@@ -415,7 +415,7 @@
 # CONFIG_BMAC is not set
 # CONFIG_GMAC is not set
 CONFIG_ARIADNE=y
-CONFIG_NE2K_ZORRO=y
+CONFIG_ZORRO8390=y
 CONFIG_A2065=y
 CONFIG_HYDRA=y
 # CONFIG_SUNLANCE is not set
diff -Nru a/arch/ppc/configs/ebony_defconfig b/arch/ppc/configs/ebony_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/configs/ebony_defconfig	Thu Aug 28 05:09:28 2003
@@ -0,0 +1,491 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# 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_PPC32=y
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+CONFIG_44x=y
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+CONFIG_EBONY=y
+# CONFIG_OCOTEA is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_PPC4xx_DMA is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_440GP=y
+CONFIG_IBM_OCP=y
+CONFIG_GEN550=y
+CONFIG_440=y
+CONFIG_PTE_64BIT=y
+CONFIG_PIN_TLB=y
+CONFIG_BOOKE=y
+
+#
+# General setup
+#
+CONFIG_HIGHMEM=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_PC_KEYBOARD 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_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+CONFIG_GEN_RTC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="ip=on"
+
+#
+# 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_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_STATS=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD 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_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+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_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK 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_NET_DIVERT 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN 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
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 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_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=8
+CONFIG_IBM_OCP_ENET_SKB_RES=0
+CONFIG_OCP_NET=y
+CONFIG_IBM_OCP_MAL_CNT=1
+CONFIG_IBM_OCP_ZMII=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP 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
+#
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_GPIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO 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_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG 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_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_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_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_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP 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_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
diff -Nru a/arch/ppc/configs/ocotea_defconfig b/arch/ppc/configs/ocotea_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/configs/ocotea_defconfig	Thu Aug 28 05:09:37 2003
@@ -0,0 +1,490 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# 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_PPC32=y
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+CONFIG_44x=y
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_EBONY is not set
+CONFIG_OCOTEA=y
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_PPC4xx_DMA is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_440GX=y
+CONFIG_IBM_OCP=y
+CONFIG_GEN550=y
+CONFIG_IBM_EMAC4=y
+CONFIG_440A=y
+CONFIG_PTE_64BIT=y
+CONFIG_PIN_TLB=y
+CONFIG_BOOKE=y
+
+#
+# General setup
+#
+CONFIG_HIGHMEM=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_PC_KEYBOARD 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_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+CONFIG_GEN_RTC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="ip=on console=ttyS0,115200"
+
+#
+# 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_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_STATS=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD 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_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+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_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK 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_NET_DIVERT 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
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN 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
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 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_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=8
+CONFIG_IBM_OCP_ENET_SKB_RES=0
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP 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
+#
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_GPIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO 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_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG 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_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_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_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_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP 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_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
diff -Nru a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
--- a/arch/ppc/kernel/Makefile	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/kernel/Makefile	Thu Aug 28 21:31:27 2003
@@ -24,13 +24,15 @@
 HEAD-y				:= head.o
 HEAD-$(CONFIG_6xx)		+= idle_6xx.o
 HEAD-$(CONFIG_40x)		:= head_4xx.o
+HEAD-$(CONFIG_44x)		:= head_44x.o
 HEAD-$(CONFIG_8xx)		:= head_8xx.o
 
 all: $(HEAD-y) kernel.o
 
 O_TARGET := kernel.o
 
-export-objs			:= ppc_ksyms.o time.o ocp.o ppc4xx_setup.o
+export-objs			:= ppc_ksyms.o time.o ocp.o ppc4xx_setup.o \
+					ppc4xx_dma.o ppc4xx_sgdma.o
 
 obj-y				:= entry.o traps.o irq.o idle.o time.o misc.o \
 					process.o signal.o ptrace.o align.o \
@@ -51,12 +53,16 @@
 obj-$(CONFIG_KGDB)		+= gen550_kgdb.o gen550_dbg.o
 obj-$(CONFIG_SERIAL_TEXT_DEBUG)	+= gen550_dbg.o
 endif
-obj-$(CONFIG_4xx)		+= todc_time.o
-obj-$(CONFIG_40x)		+= ppc4xx_setup.o ocp.o
-obj-$(CONFIG_40x)		+= ppc4xx_pic.o
+obj-$(CONFIG_40x)		+= ppc4xx_setup.o
+obj-$(CONFIG_4xx)		+= ocp.o ppc4xx_pic.o todc_time.o
 ifeq ($(CONFIG_PCI),y)
-obj-$(CONFIG_40x)		+= ppc405_pci.o indirect_pci.o pci_auto.o
+obj-$(CONFIG_40x)		+= ppc405_pci.o
+obj-$(CONFIG_4xx)		+= indirect_pci.o pci_auto.o
 endif
+obj-$(CONFIG_44x)		+= ibm44x_common.o
+obj-$(CONFIG_440GP)		+= ibm440gp_common.o
+obj-$(CONFIG_PPC4xx_DMA)	+= ppc4xx_dma.o
+obj-$(CONFIG_PPC4xx_EDMA)	+= ppc4xx_sgdma.o
 obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o
 ifeq ($(CONFIG_8xx),y)
 obj-$(CONFIG_PCI)		+= qspan_pci.o
@@ -84,6 +90,7 @@
 l2cr.o: l2cr.S ppc_defs.h
 head.o: head.S ppc_defs.h
 head_4xx.o: head_4xx.S ppc_defs.h
+head_44x.o: head_44x.S ppc_defs.h
 head_8xx.o: head_8xx.S ppc_defs.h
 idle_6xx.o: idle_6xx.S ppc_defs.h
 
diff -Nru a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
--- a/arch/ppc/kernel/cputable.c	Thu Jul 17 10:28:11 2003
+++ b/arch/ppc/kernel/cputable.c	Fri Aug 29 02:07:59 2003
@@ -29,12 +29,12 @@
 extern void __setup_cpu_745x(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_power3(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_power4(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_ppc970(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_8xx(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 
-#define CLASSIC_PPC (!defined(CONFIG_8xx) && 	 \
-		     !defined(CONFIG_4xx) && !defined(CONFIG_POWER3) &&  \
-		     !defined(CONFIG_POWER4))
+#define CLASSIC_PPC (!defined(CONFIG_8xx) && !defined(CONFIG_4xx) && \
+		     !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4))
 
 /* This table only contains "desktop" CPUs, it need to be filled with embedded
  * ones as well...
@@ -322,6 +322,14 @@
 	128, 128,
 	__setup_cpu_power4
     },
+    {	/* PPC970 */
+	0xffff0000, 0x00390000, "PPC970",
+	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+	CPU_FTR_ALTIVEC_COMP,
+	COMMON_PPC | PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC,
+	128, 128,
+	__setup_cpu_ppc970
+    },
 #endif /* CONFIG_POWER4 */
 #ifdef CONFIG_8xx
     {	/* 8xx */
@@ -370,6 +378,29 @@
 	0, /*__setup_cpu_405 */
     },
 #endif /* CONFIG_4xx */
+#ifdef CONFIG_44x
+    { /* 440GP Rev. B */
+        0xf0000fff, 0x40000440, "440GP Rev. B",
+        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+        PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+        32, 32,
+        0, /*__setup_cpu_440 */
+    },
+    { /* 440GP Rev. C */
+        0xf0000fff, 0x40000481, "440GP Rev. C",
+        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+        PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+        32, 32,
+        0, /*__setup_cpu_440 */
+    },
+    { /* 440GX Rev. A */
+        0xf0000fff, 0x50000850, "440GX Rev. A",
+        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+        PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+        32, 32,
+        0, /*__setup_cpu_440 */
+    },
+#endif /* CONFIG_44x */
 #if !CLASSIC_PPC
     {	/* default match */
     	0x00000000, 0x00000000, "(generic PPC)",
diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
--- a/arch/ppc/kernel/entry.S	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/kernel/entry.S	Fri Aug 29 03:56:51 2003
@@ -258,6 +258,15 @@
 	addi	r1,r1,INT_FRAME_SIZE
 	blr
 
+	.globl	syscall_direct_return
+syscall_direct_return:
+	addi	r1,r3,-STACK_FRAME_OVERHEAD
+	lwz	r10,TASK_PTRACE(r2)
+	andi.	r10,r10,PT_TRACESYS
+	beq+	ret_from_except
+	bl	syscall_trace
+	b	ret_from_except
+
 	.globl	ret_from_fork
 ret_from_fork:
 	bl	schedule_tail
diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/kernel/head.S	Fri Aug 29 03:56:51 2003
@@ -137,6 +137,18 @@
 	mr	r28,r6
 	mr	r27,r7
 	li	r24,0			/* cpu # */
+
+#ifdef CONFIG_POWER4
+/*
+ * On the PPC970, we have to turn off real-mode cache inhibit
+ * early, before we first turn the MMU off.
+ */
+	mfspr	r0,SPRN_PVR
+	srwi	r0,r0,16
+	cmpwi	r0,0x39
+	beql	ppc970_setup_hid
+#endif
+
 /*
  * early_init() does the early machine identification and does
  * the necessary low-level setup and clears the BSS
@@ -157,11 +169,10 @@
  */
  	bl	mmu_off
 __after_mmu_off:
-	bl	clear_bats
-	bl	flush_tlbs
 
 #ifndef CONFIG_POWER4
-	/* POWER4 doesn't have BATs */
+	bl	clear_bats
+	bl	flush_tlbs
 	bl	initial_bats
 #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
 	bl	setup_disp_bat
@@ -170,15 +181,23 @@
 /*
  * Load up the SDR1 and segment register values now
  * since we don't have the BATs.
+ * Also make sure we are running in 32-bit mode.
  */
 	bl	reloc_offset
-	addis	r4,r3,_SDR1@ha		/* get the value from _SDR1 */
-	lwz	r4,_SDR1@l(r4)		/* assume hash table below 4GB */
-	mtspr	SDR1,r4
+	addis	r14,r3,_SDR1@ha		/* get the value from _SDR1 */
+	lwz	r14,_SDR1@l(r14)	/* assume hash table below 4GB */
+	mtspr	SDR1,r14
 	slbia
-	lis	r5,0x2000		/* set pseudo-segment reg 12 */
-	ori	r5,r5,0x0ccc
+	lis	r4,0x2000		/* set pseudo-segment reg 12 */
+	ori	r5,r4,0x0ccc
 	mtsr	12,r5
+	ori	r4,r4,0x0888		/* set pseudo-segment reg 8 */
+	mtsr	8,r4			/* (for access to serial port) */
+	mfmsr	r0
+	clrldi	r0,r0,1
+	sync
+	mtmsr	r0
+	isync
 #endif /* CONFIG_POWER4 */
 
 	/*
@@ -707,12 +726,22 @@
 	mtcrf	0x80,r3
 	rfi
 
+#ifndef CONFIG_ALTIVEC
+#define AltivecAssistException	UnknownException
+#endif
+
 	STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
 	STD_EXCEPTION(0x1400, SMI, SMIException)
 	STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+#ifdef CONFIG_POWER4
 	STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+	STD_EXCEPTION(0x1700, Trap_17, AltivecAssistException)
+	STD_EXCEPTION(0x1800, Trap_18, TAUException)
+#else /* !CONFIG_POWER4 */
+	STD_EXCEPTION(0x1600, Trap_16, AltivecAssistException)
 	STD_EXCEPTION(0x1700, Trap_17, TAUException)
 	STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+#endif
 	STD_EXCEPTION(0x1900, Trap_19, UnknownException)
 	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
 	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
@@ -828,6 +857,7 @@
 	bt-	9,power_save_6xx_restore	/* Check NAP */
 END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
 	b	transfer_to_handler_cont
+
 #endif /* CONFIG_6xx */
 
 /*
@@ -983,7 +1013,9 @@
 	/* enable use of AltiVec after return */
 	oris	r23,r23,MSR_VEC@h
 	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
+	li	r4,1
 	li	r20,THREAD_VSCR
+	stw	r4,THREAD_USED_VR(r5)
 	LVX(vr0,r20,r5)
 	MTVSCR(vr0)
 	REST_32VR(0,r20,r5)
@@ -1233,7 +1265,6 @@
         andc    r4,r4,r3
         mtspr   HID0,r4
         sync
-        bl      prom_init
         b       __secondary_start
 #endif /* CONFIG_GEMINI */
 	.globl	__secondary_start_psurge
@@ -1305,6 +1336,7 @@
 
 	/* enable MMU and jump to start_secondary */
 	li	r4,MSR_KERNEL
+	FIX_SRR1(r4,r5)
 	lis	r3,start_secondary@h
 	ori	r3,r3,start_secondary@l
 	mtspr	SRR0,r3
@@ -1319,6 +1351,10 @@
  */
 _GLOBAL(__setup_cpu_power3)
 	blr
+_GLOBAL(__setup_cpu_power4)
+	blr
+_GLOBAL(__setup_cpu_ppc970)
+	blr
 _GLOBAL(__setup_cpu_generic)
 	blr
 
@@ -1326,7 +1362,14 @@
 _GLOBAL(__save_cpu_setup)
 	blr
 _GLOBAL(__restore_cpu_setup)
+#ifdef CONFIG_POWER4
+	/* turn off real-mode cache inhibit on the PPC970 */
+	mfspr	r0,SPRN_PVR
+	srwi	r0,r0,16
+	cmpwi	r0,0x39
+	beq	ppc970_setup_hid
 	blr
+#endif
 #endif /* CONFIG_6xx */
 
 /*
@@ -1334,6 +1377,11 @@
  * IR=0 and DR=0.
  */
 load_up_mmu:
+	sync			/* Force all PTE updates to finish */
+	isync
+	tlbia			/* Clear all TLB entries */
+	sync			/* wait for tlbia/tlbie to finish */
+	TLBSYNC			/* ... on all CPUs */
 	/* Load the SDR1 register (hash table base & size) */
 	lis	r6,_SDR1@ha
 	tophys(r6,r6)
@@ -1428,14 +1476,7 @@
 	SYNC
 	RFI
 /* Load up the kernel context */
-2:
-	sync			/* Force all PTE updates to finish */
-	isync
-	tlbia			/* Clear all TLB entries */
-	sync			/* wait for tlbia/tlbie to finish */
-	TLBSYNC			/* ... on all CPUs */
-
-	bl	load_up_mmu
+2:	bl	load_up_mmu
 
 #ifdef CONFIG_BDI_SWITCH
 	/* Add helper information for the Abatron bdiGDB debugger.
@@ -1648,6 +1689,41 @@
 	blr
 
 #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
+
+#else /* CONFIG_POWER4 */
+ppc970_setup_hid:
+	li	r0,0
+	sync
+	mtspr	0x3f4,r0
+	isync
+	sync
+	mtspr	0x3f6,r0
+	isync
+	mfspr	r0,SPRN_HID0
+	li	r11,0x40		/* clear NAP bit */
+	sldi	r11,r11,48
+	andc	r0,r0,r11
+	mtspr	SPRN_HID0,r0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	sync
+	isync
+	mfspr	r0,SPRN_HID1
+	li	r11,0x1200		/* enable i-fetch cacheability */
+	sldi	r11,r11,44		/* and prefetch */
+	or	r0,r0,r11
+	mtspr	SPRN_HID1,r0
+	mtspr	SPRN_HID1,r0
+	isync
+	li	r0,0
+	sync
+	mtspr	0x137,0
+	isync
+	blr
 #endif /* CONFIG_POWER4 */
 
 #ifdef CONFIG_8260
diff -Nru a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/head_44x.S	Thu Aug 28 04:53:46 2003
@@ -0,0 +1,1070 @@
+/*
+ * arch/ppc/kernel/head_44x.S
+ *
+ * Kernel execution entry point code.
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002-2003 MontaVista Software, 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.
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/ibm44x.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include "ppc_defs.h"
+
+/*
+ * Preprocessor Defines
+ */
+
+#define STND_EXC        0
+#define CRIT_EXC        1
+
+/*
+ * Macros
+ */
+
+#define SET_IVOR(vector_number, vector_label)		\
+		li	r26,vector_label@l; 		\
+		mtspr	SPRN_IVOR##vector_number,r26;	\
+		sync
+					
+/* As with the other PowerPC ports, it is expected that when code
+ * execution begins here, the following registers contain valid, yet
+ * optional, information:
+ *
+ *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
+ *   r4 - Starting address of the init RAM disk
+ *   r5 - Ending address of the init RAM disk
+ *   r6 - Start of kernel command line string (e.g. "mem=128")
+ *   r7 - End of kernel command line string
+ *
+ */ 
+	.text
+_GLOBAL(_stext)
+_GLOBAL(_start)
+	/*
+	 * Reserve a word at a fixed location to store the address
+	 * of abatron_pteptrs
+	 */
+	nop
+
+/*
+ * Save parameters we are passed
+ */
+	mr	r31,r3
+	mr	r30,r4
+	mr	r29,r5
+	mr	r28,r6
+	mr	r27,r7
+	li	r24,0		/* CPU number */
+
+/*
+ * Set up the initial MMU state
+ *
+ * We are still executing code at the virtual address
+ * mappings set by the firmware for the base of RAM.
+ *
+ * We first invalidate all TLB entries but the one
+ * we are running from.  We then load the KERNELBASE
+ * mappings so we can begin to use kernel addresses
+ * natively and so the interrupt vector locations are
+ * permanently pinned (necessary since Book E
+ * implementations always have translation enabled).
+ *
+ * TODO: Use the known TLB entry we are running from to
+ *	 determine which physical region we are located
+ *	 in.  This can be used to determine where in RAM
+ *	 (on a shared CPU system) or PCI memory space
+ *	 (on a DRAMless system) we are located.
+ *       For now, we assume a perfect world which means
+ *	 we are located at the base of DRAM (physical 0).
+ */
+
+/*
+ * Search TLB for entry that we are currently using.
+ * Invalidate all entries but the one we are using.
+ */
+	/* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */
+ 	mfspr	r3,SPRN_MMUCR			/* Get MMUCR */
+	lis	r4,PPC44x_MMUCR_STS@h
+	ori	r4,r4,PPC44x_MMUCR_TID@l	/* Create mask */
+	andc	r3,r3,r4			/* Clear out TID/STS bits */
+	mfspr	r4,SPRN_PID			/* Get PID */
+	or	r3,r3,r4			/* Set TID bits */
+	mfmsr	r5				/* Get MSR */
+	andi.	r5,r5,MSR_IS@l			/* TS=1? */
+	beq	wmmucr				/* If not, leave STS=0 */
+	oris	r3,r3,PPC44x_MMUCR_STS@h	/* Set STS=1 */
+wmmucr:	mtspr	SPRN_MMUCR,r3			/* Put MMUCR */
+	sync
+	
+	bl	invstr				/* Find our address */
+invstr:	mflr	r5				/* Make it accessible */
+	tlbsx	r23,0,r5			/* Find entry we are in */
+	li	r4,0				/* Start at TLB entry 0 */
+	li	r3,0				/* Set PAGEID inval value */
+1:	cmpw	r23,r4				/* Is this our entry? */
+	beq	skpinv				/* If so, skip the inval */
+	tlbwe	r3,r4,PPC44x_TLB_PAGEID		/* If not, inval the entry */
+skpinv:	addi	r4,r4,1				/* Increment */
+	cmpwi	r4,64				/* Are we done? */
+	bne	1b				/* If not, repeat */
+	isync					/* If so, context change */
+
+/*
+ * Configure and load pinned entries into TLB slots 62 and 63.
+ */
+
+	lis	r3,KERNELBASE@h		/* Load the kernel virtual address */
+	ori	r3,r3,KERNELBASE@l
+
+	/* Kernel is at the base of RAM */
+	li r4, 0			/* Load the kernel physical address */
+
+	/* Load the kernel PID = 0 */
+	li	r0,0
+	mtspr	SPRN_PID,r0
+	sync
+
+	/* Load the kernel TID  = 0 */
+	mfspr	r5,SPRN_MMUCR
+	lis	r6, PPC44x_MMUCR_TID@h
+	ori	r6,r6,PPC44x_MMUCR_TID@l
+	andc	r5,r5,r6
+	mtspr	SPRN_MMUCR,r5
+	sync
+
+ 	/* pageid fields */
+	clrrwi	r3,r3,10		/* Mask off the effective page number */
+	ori	r3,r3,(PPC44x_TLB_VALID | PPC44x_TLB_PAGESZ(PPC44x_PAGESZ_256M))
+
+	/* xlat fields */
+	clrrwi	r4,r4,10		/* Mask off the real page number */
+					/* ERPN is 0 for first 4GB page */
+
+	/* attrib fields */
+	/* Added guarded bit to protect against speculative loads/stores */
+	li	r5,0
+	ori	r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G)
+
+        li      r0,62                    /* TLB slot 62 */
+
+	tlbwe	r3,r0,PPC44x_TLB_PAGEID	/* Load the pageid fields */
+	tlbwe	r4,r0,PPC44x_TLB_XLAT	/* Load the translation fields */
+	tlbwe	r5,r0,PPC44x_TLB_ATTRIB	/* Load the attrib/access fields */
+
+	/* Force context change */
+	mfmsr	r0
+	mtspr	SRR1, r0
+	lis	r0,3f@h
+	ori	r0,r0,3f@l
+	mtspr	SRR0,r0
+	sync
+	rfi
+
+	/* If necessary, invalidate original entry we used */
+3:	cmpwi	r23,62
+	beq	4f
+	li	r6,0
+	tlbwe   r6,r23,PPC44x_TLB_PAGEID
+	sync
+
+4:	ori	r3,r3,PPC44x_TLB_TS	/* TS = 1 */
+
+        li      r0,63                   /* TLB slot 63 */
+
+	tlbwe	r3,r0,PPC44x_TLB_PAGEID	/* Load the pageid fields */
+	tlbwe	r4,r0,PPC44x_TLB_XLAT	/* Load the translation fields */
+	tlbwe	r5,r0,PPC44x_TLB_ATTRIB	/* Load the attrib/access fields */
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	/*
+	 * Add temporary UART mapping for early debug.  This
+	 * mapping must be identical to that used by the early
+	 * bootloader code since the same asm/serial.h parameters
+	 * are used for polled operation.
+	 */
+ 	/* pageid fields */
+	lis	r3,0xe000		
+	ori	r3,r3,(PPC44x_TLB_VALID | PPC44x_TLB_PAGESZ(PPC44x_PAGESZ_256M))
+
+	/* xlat fields */
+	lis	r4,0x4000		/* RPN is 0x40000000 */
+	ori	r4,r4,0x0001		/* ERPN is 1 for second 4GB page */
+
+	/* attrib fields */
+	li	r5,0
+	ori	r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G)
+
+        li      r0,60                    /* TLB slot 60 */
+
+	tlbwe	r3,r0,PPC44x_TLB_PAGEID	/* Load the pageid fields */
+	tlbwe	r4,r0,PPC44x_TLB_XLAT	/* Load the translation fields */
+	tlbwe	r5,r0,PPC44x_TLB_ATTRIB	/* Load the attrib/access fields */
+
+	ori	r3,r3,PPC44x_TLB_TS	/* Translation state 1 */
+
+        li      r0,61			/* TLB slot 61 */
+
+	tlbwe	r3,r0,PPC44x_TLB_PAGEID	/* Load the pageid fields */
+	tlbwe	r4,r0,PPC44x_TLB_XLAT	/* Load the translation fields */
+	tlbwe	r5,r0,PPC44x_TLB_ATTRIB	/* Load the attrib/access fields */
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+
+	/* Force context change */
+	isync
+
+	/* Establish the interrupt vector offsets */
+	SET_IVOR(0,  CriticalInput);
+	SET_IVOR(1,  MachineCheck);
+	SET_IVOR(2,  DataStorage);
+	SET_IVOR(3,  InstructionStorage);
+	SET_IVOR(4,  ExternalInput);
+	SET_IVOR(5,  Alignment);
+	SET_IVOR(6,  Program);
+	SET_IVOR(7,  FloatingPointUnavailable);
+	SET_IVOR(8,  SystemCall);
+	SET_IVOR(9,  AuxillaryProcessorUnavailable);
+	SET_IVOR(10, Decrementer);
+	SET_IVOR(11, FixedIntervalTimer);
+	SET_IVOR(12, WatchdogTimer);
+	SET_IVOR(13, DataTLBError);
+	SET_IVOR(14, InstructionTLBError);
+	SET_IVOR(15, Debug);
+
+	/* Establish the interrupt vector base */
+	lis	r4,interrupt_base@h	/* IVPR only uses the high 16-bits */
+	mtspr	SPRN_IVPR,r4
+
+	/*
+	 * This is where the main kernel code starts.
+	 */ 
+
+	/* ptr to current */
+	lis	r2,init_task_union@h
+	ori	r2,r2,init_task_union@l
+
+	/* ptr to current thread */
+	addi	r4,r2,THREAD	/* init task's THREAD */
+	mtspr	SPRG3,r4
+	li	r3,0
+	mtspr	SPRG2,r3	/* 0 => r1 has kernel sp */
+
+	/* stack */
+	addi	r1,r2,TASK_UNION_SIZE
+	li	r0,0
+	stwu	r0,-STACK_FRAME_OVERHEAD(r1)
+
+	bl	early_init
+
+/*
+ * Decide what sort of machine this is and initialize the MMU.
+ */
+	mr	r3,r31
+	mr	r4,r30
+	mr	r5,r29
+	mr	r6,r28
+	mr	r7,r27
+	bl	machine_init
+	bl	MMU_init
+
+	/* Setup PTE pointers for the Abatron bdiGDB */
+	lis	r6, swapper_pg_dir@h
+	ori	r6, r6, swapper_pg_dir@l
+	lis	r5, abatron_pteptrs@h
+	ori	r5, r5, abatron_pteptrs@l
+	lis	r4, KERNELBASE@h
+	ori	r4, r4, KERNELBASE@l
+	stw	r5, 0(r4)	/* Save abatron_pteptrs at a fixed location */
+	stw	r6, 0(r5)
+
+	/* Let's move on */
+	lis	r4,start_kernel@h
+	ori	r4,r4,start_kernel@l
+	lis	r3,MSR_KERNEL@h
+	ori	r3,r3,MSR_KERNEL@l
+	mtspr	SRR0,r4
+	mtspr	SRR1,r3
+	rfi			/* change context and jump to start_kernel */
+
+/*
+ * Interrupt vector entry code
+ *
+ * The Book E MMUs are always on so we don't need to handle
+ * interrupts in real mode as with previous PPC processors. In
+ * this case we handle interrupts in the kernel virtual address
+ * space.
+ *
+ * Interrupt vectors are dynamically placed relative to the 
+ * interrupt prefix as determined by the address of interrupt_base.
+ * The interrupt vectors offsets are programmed using the labels
+ * for each interrupt vector entry.
+ *
+ * Interrupt vectors must be aligned on a 16 byte boundary.
+ * We align on a 32 byte cache line boundary for good measure.
+ */
+
+#define COMMON_PROLOG                                                        \
+0:	mtspr	SPRN_SPRG0,r20;         /* We need r20, move it to SPRG0   */\
+	mtspr	SPRN_SPRG1,r21;         /* We need r21, move it to SPRG1   */\
+	mfcr	r20;                    /* We need the CR, move it to r20  */\
+	mfspr	r21,SPRN_SPRG2;         /* Exception stack to use          */\
+	cmpwi	cr0,r21,0;              /* From user mode or RTAS?         */\
+	bne	1f;                     /* Not RTAS, branch                */\
+	mr	r21, r1;                /* Move vka in r1 to r21           */\
+	subi	r21,r21,INT_FRAME_SIZE; /* Allocate an exception frame     */\
+1:	stw	r20,_CCR(r21);          /* Save CR on the stack            */\
+	stw	r22,GPR22(r21);         /* Save r22 on the stack           */\
+	stw	r23,GPR23(r21);         /* r23 Save on the stack           */\
+	mfspr	r20,SPRN_SPRG0;         /* Get r20 back out of SPRG0       */\
+	stw	r20,GPR20(r21);         /* Save r20 on the stack           */\
+	mfspr	r22,SPRN_SPRG1;         /* Get r21 back out of SPRG0       */\
+	stw	r22,GPR21(r21);         /* Save r21 on the stack           */\
+	mflr	r20;                                                         \
+	stw	r20,_LINK(r21);         /* Save LR on the stack            */\
+	mfctr	r22;                                                         \
+	stw	r22,_CTR(r21);          /* Save CTR on the stack           */\
+	mfspr	r20,XER;                                                     \
+	stw	r20,_XER(r21);          /* Save XER on the stack           */
+
+#define	COMMON_EPILOG							     \
+	stw	r0,GPR0(r21);		/* Save r0 on the stack		   */\
+	stw	r1,GPR1(r21);		/* Save r1 on the stack		   */\
+	stw	r2,GPR2(r21);		/* Save r2 on the stack		   */\
+	stw	r1,0(r21);						     \
+	mr	r1,r21;			/* Set-up new kernel stack pointer */\
+	SAVE_4GPRS(3, r21);		/* Save r3 through r6 on the stack */\
+	SAVE_GPR(7, r21);		/* Save r7 on the stack		   */
+
+#define	STND_EXCEPTION_PROLOG						     \
+	COMMON_PROLOG;							     \
+	mfspr	r22,SPRN_SRR0;		/* Faulting instruction address	   */\
+	lis	r20,MSR_WE@h;						     \
+	mfspr	r23,SPRN_SRR1;		/* MSR at the time of fault	   */\
+	andc	r23,r23,r20;		/* disable processor wait state    */\
+	COMMON_EPILOG;
+
+#define CRIT_EXCEPTION_PROLOG	                                             \
+	COMMON_PROLOG;	                                                     \
+	mfspr   r22,SPRN_CSRR0;         /* Faulting instruction address    */\
+	lis     r20,MSR_WE@h;                                                \
+	mfspr   r23,SPRN_CSRR1;         /* MSR at the time of fault        */\
+	andc    r23,r23,r20;            /* disable processor wait state    */\
+	COMMON_EPILOG;
+
+#define START_EXCEPTION(label) \
+        .align 5;              \
+label:
+
+#define FINISH_EXCEPTION(n, func)					     \
+	bl	transfer_to_handler;					     \
+	.long	func;							     \
+	.long	ret_from_except;					     \
+	.long	n
+
+#define STND_EXCEPTION(n, label, func)					     \
+	START_EXCEPTION(label)						     \
+	STND_EXCEPTION_PROLOG;						     \
+	addi	r3,r1,STACK_FRAME_OVERHEAD;				     \
+	li	r7,STND_EXC;						     \
+	li	r20,MSR_KERNEL;						     \
+	FINISH_EXCEPTION(n, func)
+
+#define	CRIT_EXCEPTION(n, label, func)					     \
+	START_EXCEPTION(label)						     \
+	CRIT_EXCEPTION_PROLOG;						     \
+	addi	r3,r1,STACK_FRAME_OVERHEAD;				     \
+	li	r7,CRIT_EXC;						     \
+	li	r20,MSR_KERNEL;						     \
+	FINISH_EXCEPTION(n, func)
+
+interrupt_base:
+
+	/* Critical Input Interrupt */
+	CRIT_EXCEPTION(0x100, CriticalInput,UnknownException);
+
+	/* Machine Check Interrupt */
+	/* TODO: provide bus error register status */
+	CRIT_EXCEPTION(0x200, MachineCheck,MachineCheckException);
+
+	/* Data Storage Interrupt */
+	START_EXCEPTION(DataStorage)
+	mtspr	SPRG0, r20		/* Save some working registers */
+	mtspr	SPRG1, r21
+	mtspr	SPRG4W, r22
+	mtspr	SPRG5W, r23
+	mtspr	SPRG6W, r24
+	mfcr	r21
+	mtspr	SPRG7W, r21
+
+	/*
+	 * Check if it was a store fault, if not then bail
+	 * because a user tried to access a kernel or
+	 * read-protected page.  Otherwise, get the
+	 * offending address and handle it.
+	 */
+	mfspr	r20, SPRN_ESR
+	andis.	r20, r20, ESR_ST@h
+	beq	2f
+
+	mfspr	r20, SPRN_DEAR		/* Get faulting address */
+
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	andis.	r21, r20, 0x8000
+	beq	3f
+	lis	r21, swapper_pg_dir@h
+	ori	r21, r21, swapper_pg_dir@l
+
+	mfspr   r22,SPRN_MMUCR          /* Set TID to 0 */
+	li      r23,PPC44x_MMUCR_TID@l
+	andc    r22,r22,r23
+	mtspr   SPRN_MMUCR,r22
+
+	b	4f
+
+	/* Get the PGD for the current thread */
+3:
+	mfspr	r21,SPRG3
+	lwz	r21,PGDIR(r21)
+
+	/* Load MMUCR with our PID and STS=<current TS> */
+	mfspr	r22,SPRN_MMUCR			/* Get MMUCR */
+	lis     r23,PPC44x_MMUCR_STS@h
+	ori     r23,r23,PPC44x_MMUCR_TID@l      /* Create mask */
+	andc    r22,r22,r23                     /* Clear out TID/STS bits */
+	mfspr   r23,SPRN_PID                    /* Get PID */
+	or      r22,r22,r23			/* Set TID bits */
+	mfspr	r24,SPRN_SRR1			/* Get SRR1 */
+	andi.	r24,r24,MSR_IS@l		/* TS=1? */
+	beq	4f				/* If not, leave STS=0 */
+	oris	r22,r22,PPC44x_MMUCR_STS@h	/* Set STS=1 */
+	mtspr   SPRN_MMUCR,r22
+4:
+	rlwinm  r22, r20, 13, 19, 29    /* Compute pgdir/pmd offset */
+	lwzx    r21, r22, r21           /* Get pgd/pmd entry */
+	rlwinm. r22, r21, 0, 0, 20      /* Extract pt base address */
+	beq     2f                      /* Bail if no table */
+
+	rlwimi  r22, r20, 23, 20, 28    /* Compute pte address */
+	lwz     r21, 4(r22)             /* Get pte entry */
+	
+	andi.	r23, r21, _PAGE_RW	/* Is it writeable? */
+	beq	2f			/* Bail if not */
+
+	/* Update 'changed'.
+	*/
+	ori	r21, r21, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
+	stw	r21, 4(r22)		/* Update Linux page table */
+
+	/* FIXME: Staticly setting some permissions */
+	li	r23, 0x003f		/* Set UX,UW,UR,SX,SW,SR */
+	andi.	r21,r21,0xffff		/* Clear MS 16 bits */
+	/* FIXME: Force attributes */
+	ori	r21,r21, 0x0100		/* Set G */
+	/* FIXME: Already set in PTE */
+	rlwimi	r21,r23,0,26,31		/* Insert static perms */
+
+	lis	r23,0xffff
+	ori	r23,r23,0x0fff			/* Set U0-U3 mask */
+	and	r21,r21,r23			/* Clear U0-U3 */
+
+	/* find the TLB index that caused the fault.  It has to be here. */
+	tlbsx	r24, 0, r20
+
+	tlbwe	r21, r24, PPC44x_TLB_ATTRIB		/* Write ATTRIB */
+
+	/* Done...restore registers and get out of here.
+	*/
+	mfspr	r21, SPRG7R
+	mtcr	r21
+	mfspr	r24, SPRG6R
+	mfspr	r23, SPRG5R
+	mfspr	r22, SPRG4R
+
+	mfspr	r21, SPRG1
+	mfspr	r20, SPRG0
+	rfi			/* Force context change */
+
+2:
+	/*
+	 * The bailout.  Restore registers to pre-exception conditions
+	 * and call the heavyweights to help us out.
+	 */
+	mfspr	r21, SPRG7R
+	mtcr	r21
+	mfspr	r24, SPRG6R
+	mfspr	r23, SPRG5R
+	mfspr	r22, SPRG4R
+
+	mfspr	r21, SPRG1
+	mfspr	r20, SPRG0
+	b	data_access
+
+	/* Instruction Storage Interrupt */
+	START_EXCEPTION(InstructionStorage)
+	STND_EXCEPTION_PROLOG
+	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it */
+	stw	r5,_ESR(r21)
+	mr      r4,r22                  /* Pass SRR0 as arg2 */
+	li      r5,0                    /* Pass zero as arg3 */
+	addi    r3,r1,STACK_FRAME_OVERHEAD
+	li      r7,STND_EXC
+	li      r20,MSR_KERNEL
+	rlwimi  r20,r23,0,16,16         /* Copy EE bit from the saved MSR */
+	FINISH_EXCEPTION(0x400, do_page_fault)/* do_page_fault(regs, SRR0, SRR1) */
+
+	/* External Input Interrupt */
+	START_EXCEPTION(ExternalInput)
+	STND_EXCEPTION_PROLOG
+	addi    r3,r1,STACK_FRAME_OVERHEAD
+	li      r7,STND_EXC
+	li      r20,MSR_KERNEL
+	li      r4,0
+	bl      transfer_to_handler
+_GLOBAL(do_IRQ_intercept)
+	.long   do_IRQ
+	.long   ret_from_intercept
+	.long	0x500
+
+	/* Alignment Interrupt */
+	START_EXCEPTION(Alignment)
+	STND_EXCEPTION_PROLOG
+	mfspr   r4,SPRN_DEAR            /* Grab the DEAR and save it */
+	stw     r4,_DEAR(r21)
+	addi    r3,r1,STACK_FRAME_OVERHEAD
+	li      r7,STND_EXC
+	li      r20,MSR_KERNEL
+	rlwimi  r20,r23,0,16,16         /* Copy EE bit from the saved MSR */
+	FINISH_EXCEPTION(0x600, AlignmentException)
+
+	/* Program Interrupt */
+	START_EXCEPTION(Program)
+	STND_EXCEPTION_PROLOG
+	mfspr	r4,SPRN_ESR		/* Grab the ESR, save it */
+	stw	r4,_ESR(r21)
+	addi    r3,r1,STACK_FRAME_OVERHEAD
+	li      r7,STND_EXC
+	li      r20,MSR_KERNEL
+	rlwimi  r20,r23,0,16,16         /* Copy EE bit from the saved MSR */
+	FINISH_EXCEPTION(0x700, ProgramCheckException)
+
+	/* Floating Point Unavailable Interrupt */
+	STND_EXCEPTION(0x2010, FloatingPointUnavailable,UnknownException);
+
+	/* System Call Interrupt */
+	START_EXCEPTION(SystemCall)
+	STND_EXCEPTION_PROLOG
+	stw	r3,ORIG_GPR3(r21)
+	li	r7,STND_EXC
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16		/* Copy EE bit from the saved MSR */
+	FINISH_EXCEPTION(0xc00, DoSyscall)
+
+	/* Auxillary Processor Unavailable */
+	STND_EXCEPTION(0x2020, AuxillaryProcessorUnavailable,UnknownException);
+
+	/* Decrementer Interrupt */
+	START_EXCEPTION(Decrementer)
+	STND_EXCEPTION_PROLOG
+	lis     r0,TSR_DIS@h            /* Setup the DEC interrupt mask */
+	mtspr   SPRN_TSR,r0            /* Clear the DEC interrupt */
+	addi    r3,r1,STACK_FRAME_OVERHEAD
+	li      r7,STND_EXC
+	li      r20,MSR_KERNEL
+	bl      transfer_to_handler
+_GLOBAL(timer_interrupt_intercept)
+	.long   timer_interrupt
+	.long   ret_from_intercept
+	.long	0x1000
+
+	/* Fixed Internal Timer Interrupt */
+	/* TODO: Add FIT support */
+	STND_EXCEPTION(0x1010, FixedIntervalTimer,UnknownException);
+
+	/* Watchdog Timer Interrupt */
+	/* TODO: Add watchdog support */
+	CRIT_EXCEPTION(0x1020, WatchdogTimer,UnknownException);
+
+	/* Data TLB Error Interrupt */
+	START_EXCEPTION(DataTLBError)
+	mtspr	SPRG0, r20		/* Save some working registers */
+	mtspr	SPRG1, r21
+	mtspr	SPRG4W, r22
+	mtspr	SPRG5W, r23
+	mtspr	SPRG6W, r24
+	mfcr	r21
+	mtspr	SPRG7W, r21
+	mfspr	r20, SPRN_DEAR		/* Get faulting address */
+
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	andis.	r21, r20, 0x8000
+	beq	3f
+	lis	r21, swapper_pg_dir@h
+	ori	r21, r21, swapper_pg_dir@l
+
+	mfspr	r22,SPRN_MMUCR		/* Set TID to 0 */
+	li	r23,PPC44x_MMUCR_TID@l
+	andc	r22,r22,r23
+	mtspr	SPRN_MMUCR,r22
+
+	b	4f
+
+	/* Get the PGD for the current thread */
+3:
+	mfspr	r21,SPRG3
+	lwz	r21,PGDIR(r21)
+
+	/* Load PID into MMUCR TID */
+	li      r23,PPC44x_MMUCR_TID@l       	 /* Create mask */
+	andc    r22,r22,r23                      /* Clear out TID/STS bits */
+	mfspr   r23,SPRN_PID                     /* Get PID */
+	or      r22,r22,r23
+	mtspr	SPRN_MMUCR,r22
+4:
+	rlwinm 	r22, r20, 13, 19, 29	/* Compute pgdir/pmd offset */
+	lwzx	r21, r22, r21		/* Get pgd/pmd entry */
+	rlwinm.	r22, r21, 0, 0, 20	/* Extract pt base address */
+	beq	2f			/* Bail if no table */
+
+	rlwimi	r22, r20, 23, 20, 28	/* Compute pte address */
+	lwz	r21, 4(r22)		/* Get pte entry */
+	andi.	r23, r21, _PAGE_PRESENT	/* Is the page present? */
+	beq	2f			/* Bail if not present */
+
+	ori	r21, r21, _PAGE_ACCESSED
+	stw	r21, 4(r22)
+
+	 /* Jump to common tlb load */
+	b	finish_tlb_load
+
+2:
+	/* The bailout.  Restore registers to pre-exception conditions
+	 * and call the heavyweights to help us out.
+	 */
+	mfspr	r21, SPRG7R
+	mtcr	r21
+	mfspr	r24, SPRG6R
+	mfspr	r23, SPRG5R
+	mfspr	r22, SPRG4R
+	mfspr	r21, SPRG1
+	mfspr	r20, SPRG0
+	b	data_access
+
+	/* Instruction TLB Error Interrupt */
+	/*
+	 * Nearly the same as above, except we get our
+	 * information from different registers and bailout
+	 * to a different point.
+	 */
+	START_EXCEPTION(InstructionTLBError)
+	mtspr	SPRG0, r20		/* Save some working registers */
+	mtspr	SPRG1, r21
+	mtspr	SPRG4W, r22
+	mtspr	SPRG5W, r23
+	mtspr	SPRG6W, r24
+	mfcr	r21
+	mtspr	SPRG7W, r21
+	mfspr	r20, SRR0		/* Get faulting address */
+
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	andis.	r21, r20, 0x8000
+	beq	3f
+	lis	r21, swapper_pg_dir@h
+	ori	r21, r21, swapper_pg_dir@l
+
+	mfspr	r22,SPRN_MMUCR		/* Set TID to 0 */
+	li	r23,PPC44x_MMUCR_TID@l
+	andc	r22,r22,r23
+	mtspr	SPRN_MMUCR,r22
+
+	b	4f
+
+	/* Get the PGD for the current thread */
+3:
+	mfspr	r21,SPRG3
+	lwz	r21,PGDIR(r21)
+
+	/* Load PID into MMUCR TID */
+	li      r23,PPC44x_MMUCR_TID@l       	 /* Create mask */
+	andc    r22,r23,r23                      /* Clear out TID/STS bits */
+	mfspr   r23,SPRN_PID                     /* Get PID */
+	or      r22,r22,r23
+	mtspr	SPRN_MMUCR,r22
+
+4:
+	rlwinm	r22, r20, 13, 19, 29	/* Compute pgdir/pmd offset */
+	lwzx	r21, r22, r21		/* Get pgd/pmd entry */
+	rlwinm.	r22, r21, 0, 0, 20	/* Extract pt base address */
+	beq	2f			/* Bail if no table */
+
+	rlwimi	r22, r20, 23, 20, 28	/* Compute pte address */
+	lwz	r21, 4(r22)		/* Get pte entry */
+	andi.	r23, r21, _PAGE_PRESENT	/* Is the page present? */
+	beq	2f			/* Bail if not present */
+
+	ori	r21, r21, _PAGE_ACCESSED
+	stw	r21, 4(r22)
+
+	/* Jump to common TLB load point */
+	b	finish_tlb_load
+
+2:
+	/* The bailout.  Restore registers to pre-exception conditions
+	 * and call the heavyweights to help us out.
+	 */
+	mfspr	r21, SPRG7R
+	mtcr	r21
+	mfspr	r24, SPRG6R
+	mfspr	r23, SPRG5R
+	mfspr	r22, SPRG4R
+	mfspr	r21, SPRG1
+	mfspr	r20, SPRG0
+	b	InstructionStorage
+
+/* Check for a single step debug exception while in an exception
+ * handler before state has been saved.  This is to catch the case
+ * where an instruction that we are trying to single step causes
+ * an exception (eg ITLB/DTLB miss) and thus the first instruction of
+ * the exception handler generates a single step debug exception.
+ *
+ * If we get a debug trap on the first instruction of an exception handler,
+ * we reset the MSR_DE in the _exception handlers_ MSR (the debug trap is
+ * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
+ * The exception handler was handling a non-critical interrupt, so it will
+ * save (and later restore) the MSR via SPRN_SRR1, which will still have
+ * the MSR_DE bit set.
+ */
+	/* Debug Interrupt */
+	START_EXCEPTION(Debug)
+	/* This first instruction was already executed by the exception
+	 * handler and must be the first instruction of every exception
+	 * handler.
+	 */
+	mtspr	SPRN_SPRG0,r20		/* Save some working registers... */
+	mtspr	SPRN_SPRG1,r21
+	mtspr	SPRN_SPRG4W,r22
+	mfcr	r20			/* ..and the cr because we change it */
+
+	mfspr   r21,SPRN_CSRR1		/* MSR at the time of fault */
+	andi.   r21,r21,MSR_PR
+	bne+    2f			/* trapped from problem state */
+
+	mfspr   r21,SPRN_CSRR0		/* Faulting instruction address */
+	lis	r22, KERNELBASE@h
+	ori	r22, r22, KERNELBASE@l
+	cmplw   r21,r22
+	blt+    2f			/* addr below exception vectors */
+
+	lis	r22, Debug@h
+	ori	r22, r22, Debug@l
+	cmplw   r21,r22
+	bgt+    2f			/* addr above TLB exception vectors */
+
+	lis     r21,DBSR_IC@h           /* Remove the trap status */
+	mtspr   SPRN_DBSR,r21
+
+	mfspr	r21,SPRN_CSRR1
+	rlwinm	r21,r21,0,23,21		/* clear MSR_DE */
+	mtspr	SPRN_CSRR1, r21		/* restore MSR at rcfi without DE */
+
+	mtcrf   0xff,r20                /* restore registers */
+	mfspr	r22,SPRN_SPRG4R
+	mfspr   r21,SPRN_SPRG1
+	mfspr   r20,SPRN_SPRG0
+
+	sync
+	rfci                            /* return to the exception handler  */
+	b	.			/* prevent prefetch past rfci */
+
+2:
+	mtcrf   0xff,r20                /* restore registers */
+	mfspr	r22,SPRN_SPRG4R
+	mfspr   r21,SPRN_SPRG1
+	mfspr   r20,SPRN_SPRG0
+
+	CRIT_EXCEPTION_PROLOG
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r7,CRIT_EXC;
+        li      r20,MSR_KERNEL
+	FINISH_EXCEPTION(0x2000, DebugException)
+
+/*
+ * Local functions
+ */
+
+	/*
+	 * Data TLB exceptions will bail out to this point
+	 * if they can't resolve the lightweight TLB fault.
+	 */
+data_access:
+	STND_EXCEPTION_PROLOG
+	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it, pass arg3 */
+	stw	r5,_ESR(r21)
+	mfspr	r4,SPRN_DEAR		/* Grab the DEAR, save it, pass arg2 */
+	stw	r4,_DEAR(r21)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r7,STND_EXC
+	li	r20,MSR_KERNEL
+	rlwimi	r20,r23,0,16,16		/* Copy EE bit from the saved MSR */
+	FINISH_EXCEPTION(0x800, do_page_fault) /* do_page_fault(regs, ESR, DEAR) */
+
+/*
+ * Both the instruction and data TLB miss get to this
+ * point to load the TLB.
+ * 	r20 - EA of fault
+ * 	r21 - available to use
+ *	r22 - Pointer to the 64-bit PTE
+ *	r23 - available to use
+ *	r24 - available to use
+ *	MMUCR - loaded with proper value when we get here
+ *	Upon exit, we reload everything and RFI.
+ */
+finish_tlb_load:
+	/*
+	 * We set execute, because we don't have the granularity to
+	 * properly set this at the page level (Linux problem).
+	 * If shared is set, we cause a zero PID->TID load.
+	 * Many of these bits are software only.  Bits we don't set
+	 * here we (properly should) assume have the appropriate value.
+	 */
+
+	/* Load the next available TLB index */
+	lis	r23, tlb_44x_index@h
+	ori	r23, r23, tlb_44x_index@l
+	lwz	r24, 0(r23)
+	/* Load the TLB high watermark */
+	lis	r23, tlb_44x_hwater@h
+	ori	r23, r23, tlb_44x_hwater@l
+	lwz	r21, 0(r23)
+
+	
+	/* Increment, rollover, and store TLB index */
+	addi	r24, r24, 1
+	cmpw	0, r24, r21		/* reserve entries 62-63 for kernel */
+	ble	7f
+	li	r24, 0
+7:
+	/* Load the next available TLB index */
+	lis     r23, tlb_44x_index@h
+	ori     r23, r23, tlb_44x_index@l
+	stw	r24, 0(r23)
+
+6:
+	lwz	r23, 0(r22)			/* Get MS word of PTE */
+	lwz	r21, 4(r22)			/* Get LS word of PTE */
+	rlwimi	r23, r21, 0, 0 , 19		/* Insert RPN */
+	tlbwe	r23, r24, PPC44x_TLB_XLAT	/* Write XLAT */
+
+	/*
+	 * Create PAGEID. This is the faulting address plus
+	 * a set of static bits. The static bits are page
+	 * size and valid. Bits 20  and 21 should be zero
+	 * for a page size of 4KB.
+	 */
+	li	r22, 0x0210			/* Set size and valid */
+	mfspr	r23, SPRN_SRR1			/* Get SRR1 */
+	andi.	r23, r23, MSR_IS@l
+	beq	7f
+	ori	r22, r22, PPC44x_TLB_TS@l	/* Set TS=1 */
+7:	rlwimi	r20, r22, 0, 20, 31		/* Insert statics */
+	tlbwe	r20, r24, PPC44x_TLB_PAGEID	/* Write PAGEID */
+
+	/* FIXME: Staticly setting some permissions */
+	li	r23, 0x002d			/* Set UX,UR,SX,SR */
+	andi.	r21, r21, 0xffff		/* Clear MS 16 bits */
+	andi.	r22, r21, 0x0002		/* _PAGE_HWWRITE? */
+	beq	8f
+	ori	r23, r23, 0x0002		/* Set SW */
+	/* FIXME: Force attributes */
+8:	ori	r21, r21, 0x0100		/* Set G */
+	/* FIXME: Already set in PTE */
+	rlwimi	r21, r23, 0, 26, 31		/* Insert static perms */
+
+	lis	r23,0xffff
+	ori	r23,r23,0x0fff			/* Set U0-U3 mask */
+	and	r21,r21,r23			/* Clear U0-U3 */
+	tlbwe	r21, r24, PPC44x_TLB_ATTRIB	/* Write ATTRIB */
+
+	/* Done...restore registers and get out of here.
+	*/
+	mfspr	r21, SPRG7R
+	mtcr	r21
+	mfspr	r24, SPRG6R
+	mfspr	r23, SPRG5R
+	mfspr	r22, SPRG4R
+	mfspr	r21, SPRG1
+	mfspr	r20, SPRG0
+	rfi					/* Force context change */
+
+/*
+ * Global functions
+ */
+
+/*
+ * extern void giveup_altivec(struct task_struct *prev)
+ *
+ * The 44x core does not have an AltiVec unit.
+ */
+_GLOBAL(giveup_altivec)
+	blr
+
+/*
+ * extern void giveup_fpu(struct task_struct *prev)
+ *
+ * The 44x core does not have an FPU.
+ */
+_GLOBAL(giveup_fpu)
+	blr
+
+/*
+ * extern void abort(void)
+ *
+ * At present, this routine just applies a system reset.
+ */ 
+_GLOBAL(abort)
+        mfspr   r13,SPRN_DBCR0
+        oris    r13,r13,DBCR_RST(DBCR_RST_SYSTEM)@h
+        mtspr   SPRN_DBCR0,r13
+
+_GLOBAL(set_context)
+
+#ifdef CONFIG_BDI_SWITCH
+	/* Context switch the PTE pointer for the Abatron BDI2000.
+	 * The PGDIR is the second parameter.
+	 */
+	lis	r5, abatron_pteptrs@h
+	ori	r5, r5, abatron_pteptrs@l
+	stw	r4, 0x4(r5)
+#endif
+	mtspr	SPRN_PID,r3
+	isync			/* Force context change */
+	blr
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception, turning
+ * on address translation.
+ */
+_GLOBAL(transfer_to_handler)
+	stw	r22,_NIP(r21)		/* Save the faulting IP on the stack */
+	stw	r23,_MSR(r21)		/* Save the exception MSR on stack */
+	SAVE_4GPRS(8, r21)		/* Save r8 through r11 on the stack */
+	SAVE_8GPRS(12, r21)		/* Save r12 through r19 on the stack */
+	SAVE_8GPRS(24, r21)		/* Save r24 through r31 on the stack */
+	andi.	r23,r23,MSR_PR		/* Is this from user space? */
+	mfspr	r23,SPRN_SPRG3		/* If from user, fix up THREAD.regs */
+	beq	2f			/* No, it is from the kernel; branch. */
+	mfspr   r24,SPRN_DBCR0
+	stw     r24,THREAD_DBCR0(r23)	/* Save Debug Control in thread_struct */
+	addi	r24,r1,STACK_FRAME_OVERHEAD
+	stw	r24,PT_REGS(r23)
+2:	addi	r2,r23,-THREAD		/* Set r2 to current thread */
+	mflr	r23
+	lwz	r24,8(r23)		/* Emulate classic PPC vectors */
+	stw	r24,TRAP(r21)
+	li	r22,RESULT
+	/* No need to put an erratum #77 workaround here
+		because interrupts are currently disabled */
+	stwcx.	r22,r22,r21		/* Clear the reservation */
+	li	r22,0
+	stw	r22,RESULT(r21)
+	mtspr	SPRN_SPRG2,r22		/* r1 is now the kernel stack pointer */
+	addi	r24,r2,TASK_STRUCT_SIZE	/* Check for kernel stack overflow */
+	cmplw	cr0,r1,r2
+	cmplw	cr1,r1,r24
+	crand	cr1,cr1,cr4
+	bgt-	stack_ovf		/* If r2 < r1 < r2 + TASK_STRUCT_SIZE */
+	lwz	r24,0(r23)		/* Virtual address of the handler */
+	lwz	r23,4(r23)		/* Handler return pointer */
+	cmpwi	cr0,r7,STND_EXC		/* What type of exception is this? */
+	bne	3f			/* It is a critical exception... */
+
+	/* Standard exception jump path
+	*/
+
+	/* We have to recover r7 from the register save stack.
+	 * It was used to indicate standard/critical exception.  In
+	 * the case of a standard exception that is the system call
+	 * trap, it may have originally contained one of the syscall
+	 * parameters and we have to get it back now.
+	 */
+	lwz	r7,GPR7(r21)
+	mtspr	SPRN_SRR0,r24		/* Set up the instruction pointer */
+	mtspr	SPRN_SRR1,r20		/* Set up the machine state register */
+	mtlr	r23			/* Set up the return pointer */
+	SYNC
+	/* We shouldn't need a 405 erratum #77 workaround here, because we're not
+	 * actually returning to the interrupted instruction yet. */
+	rfi
+
+	/* Critical exception jump path
+	*/
+
+3:	mtspr	SPRN_CSRR0,r24		/* Set up the instruction pointer */
+	mtspr	SPRN_CSRR1,r20		/* Set up the machine state register */
+	mtlr	r23			/* Set up the return pointer */
+	SYNC
+	rfci
+
+/* On kernel stack overlow, load up an initial stack pointer and call
+ * StackOverflow(regs), which should NOT return.
+ */ 
+
+stack_ovf:
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	lis	r1,init_task_union@ha
+	addi	r1,r1,init_task_union@l
+	addi	r1,r1,TASK_UNION_SIZE - STACK_FRAME_OVERHEAD
+	lis	r24,StackOverflow@ha
+	addi	r24,r24,StackOverflow@l
+	li	r20,MSR_KERNEL
+	mtspr	SPRN_SRR0,r24
+	mtspr	SPRN_SRR1,r20
+	SYNC
+	rfi
+
+/*
+ * We put a few things here that have to be page-aligned. This stuff
+ * goes at the beginning of the data segment, which is page-aligned.
+ */
+	.data
+_GLOBAL(sdata)
+_GLOBAL(empty_zero_page)
+	.space	4096
+
+/*
+ * To support >32-bit physical addresses, we use an 8KB pgdir.
+ */
+_GLOBAL(swapper_pg_dir)
+	.space	8192
+
+/*
+ * This space gets a copy of optional info passed to us by the bootstrap
+ * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
+ */
+_GLOBAL(cmd_line)
+	.space	512
+
+/*
+ * Room for two PTE pointers, usually the kernel and current user pointers
+ * to their respective root page table.
+ */
+abatron_pteptrs:
+	.space	8
diff -Nru a/arch/ppc/kernel/ibm440gp_common.c b/arch/ppc/kernel/ibm440gp_common.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/ibm440gp_common.c	Thu Aug 28 05:12:00 2003
@@ -0,0 +1,78 @@
+/*
+ * arch/ppc/syslib/ibm440gp_common.c
+ *
+ * PPC440GP system library
+ *
+ * Matt Porter <mporter@mvista.com>
+ * Copyright 2002-2003 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003 Zultys Technologies
+ *
+ * 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.
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/ibm44x.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <kernel/ibm440gp_common.h>
+
+/*
+ * Calculate 440GP clocks
+ */
+void __init ibm440gp_get_clocks(struct ibm440gp_clocks* p, unsigned int sys_clk, 
+	unsigned int ser_clk)
+{
+	u32 cpc0_sys0 = mfdcr(DCRN_CPC0_SYS0);
+	u32 cpc0_cr0 = mfdcr(DCRN_CPC0_CR0);
+	u32 opdv, epdv;
+	
+	if (cpc0_sys0 & 0x2){
+		/* Bypass system PLL */
+		p->cpu = p->plb = sys_clk;
+	}
+	else {
+		u32 fbdv, fwdva, fwdvb, m, vco;
+		
+		fbdv = (cpc0_sys0 >> 18) & 0x0f;
+		if (!fbdv)
+			fbdv = 16;
+    
+		fwdva = 8 - ((cpc0_sys0 >> 15) & 0x7);
+		fwdvb = 8 - ((cpc0_sys0 >> 12) & 0x7);
+    
+    		/* Feedback path */	    
+		if (cpc0_sys0 & 0x00000080){
+			/* PerClk */
+			m = fwdvb * opdv * epdv;
+		}
+		else {
+			/* CPU clock */
+			m = fbdv * fwdva;
+    		}
+		vco = sys_clk * m;
+		p->cpu = vco / fwdva;
+		p->plb = vco / fwdvb;
+	}
+    
+	opdv = ((cpc0_sys0 >> 10) & 0x3) + 1;
+	epdv = ((cpc0_sys0 >> 8) & 0x3) + 1;
+	
+	p->opb = p->plb / opdv;
+	p->ebc = p->opb / epdv;
+    
+	if (cpc0_cr0 & 0x00400000){
+		/* External UART clock */
+		p->uart = ser_clk;
+	}
+	else {
+		/* Internal UART clock */    
+    		u32 uart_div = ((cpc0_cr0 >> 16) & 0x1f) + 1;
+		p->uart = p->plb / uart_div;
+	}
+}
diff -Nru a/arch/ppc/kernel/ibm440gp_common.h b/arch/ppc/kernel/ibm440gp_common.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/ibm440gp_common.h	Thu Aug 28 05:12:11 2003
@@ -0,0 +1,45 @@
+/*
+ * arch/ppc/kernel/ibm440gp_common.h
+ *
+ * PPC440GP system library
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003 Zultys Technologies
+ *
+ * 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.
+ *
+ */
+#ifdef __KERNEL__
+#ifndef __PPC_SYSLIB_IBM440GP_COMMON_H
+#define __PPC_SYSLIB_IBM440GP_COMMON_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+/*
+ * All clocks are in Hz
+ */
+struct ibm440gp_clocks {
+	unsigned int cpu;	/* CPUCoreClk */
+	unsigned int plb;	/* PLBClk */
+	unsigned int opb;	/* OPBClk */
+	unsigned int ebc;	/* PerClk */
+	unsigned int uart;	
+};
+
+/*
+ * Please, refer to the Figure 13.1 in 440GP user manual
+ * 
+ * if internal UART clock is used, ser_clk is ignored
+ */
+void ibm440gp_get_clocks(struct ibm440gp_clocks*, unsigned int sys_clk, 
+	unsigned int ser_clk) __init;
+ 
+#endif /* __ASSEMBLY__ */
+#endif /* __PPC_SYSLIB_IBM440GP_COMMON_H */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/kernel/ibm44x_common.c b/arch/ppc/kernel/ibm44x_common.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/ibm44x_common.c	Thu Aug 28 05:12:21 2003
@@ -0,0 +1,37 @@
+/*
+ * arch/ppc/kernel/ibm44x_common.c
+ *
+ * PPC44x system library
+ *
+ * Matt Porter <mporter@mvista.com>
+ * Copyright 2002-2003 MontaVista Software 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.
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/ibm44x.h>
+#include <asm/mmu.h>
+
+phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size)
+{
+	phys_addr_t page_4gb = 0;
+
+        /*
+	 * Trap the least significant 32-bit portions of an
+	 * address in the 440's 36-bit address space.  Fix
+	 * them up with the appropriate ERPN
+	 */
+	if ((addr >= PPC44x_IO_LO) && (addr < PPC44x_IO_HI))
+		page_4gb = PPC44x_IO_PAGE;
+	else if ((addr >= PPC44x_PCICFG_LO) && (addr < PPC44x_PCICFG_HI))
+		page_4gb = PPC44x_PCICFG_PAGE;
+	else if ((addr >= PPC44x_PCIMEM_LO) && (addr < PPC44x_PCIMEM_HI))
+		page_4gb = PPC44x_PCIMEM_PAGE;
+
+	return (page_4gb | addr);
+};
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/kernel/misc.S	Fri Aug 29 03:56:51 2003
@@ -361,7 +361,20 @@
 	cmpwi	0, r3, 61		/* reserve last two entries */
 	ble	1b
 	isync
-#else
+#elif defined(CONFIG_44x)
+	lis	r3,0
+	sync
+1:
+	tlbwe	r3,r3,PPC44x_TLB_PAGEID
+	addi	r3,r3,1
+	/* Load high watermark */
+	lis	r4,tlb_44x_hwater@h
+	ori	r4,r4,tlb_44x_hwater@l
+	lwz	r5,0(r4)
+	cmpw	0,r3,r5
+	ble	1b
+	isync
+#else /* !(CONFIG_40x || CONFIG_44x) */
 #if defined(CONFIG_SMP)
 	mfmsr	r10
 	SYNC
@@ -406,7 +419,31 @@
 	tlbwe	r3, r3, TLB_TAG
 	isync
 10:
-#else
+#elif defined(CONFIG_44x)
+	mfspr	r4,SPRN_MMUCR			/* Get MMUCR */
+	lis	r5,PPC44x_MMUCR_STS@h
+	ori	r5,r5,PPC44x_MMUCR_TID@l	/* Create mask */
+	andc	r4,r4,r5			/* Clear out TID/STS bits */
+	mfspr	r5,SPRN_PID			/* Get PID */
+	or	r4,r4,r5			/* Set TID bits */
+	mfmsr	r6				/* Get MSR */
+	andi.	r6,r6,MSR_IS@l			/* TS=1? */
+	beq	11f				/* If not, leave STS=0 */
+	oris	r4,r4,PPC44x_MMUCR_STS@h	/* Set STS=1 */
+11:	mtspr	SPRN_MMUCR, r4			/* Put MMUCR */
+
+	tlbsx.	r3, 0, r3
+	bne	10f
+	sync
+	/* There are only 64 TLB entries, so r3 < 64,
+	 * which means bit 22, is clear.  Since 22 is
+	 * the V bit in the TLB_PAGEID, loading this
+	 * value will invalidate the TLB entry.
+	 */
+	tlbwe	r3, r3, PPC44x_TLB_PAGEID
+	isync
+10:
+#else /* !(CONFIG_40x || CONFIG_44x) */
 #if defined(CONFIG_SMP)
 	mfmsr	r10
 	SYNC
@@ -570,7 +607,7 @@
 #ifdef CONFIG_NOT_COHERENT_CACHE
 /*
  * 40x cores have 8K or 16K dcache and 32 byte line size.
- * 440 has a 32K dcache and 32 byte line size.
+ * 44x has a 32K dcache and 32 byte line size.
  * 8xx has 1, 2, 4, 8K variants.
  * For now, cover the worst case of the 440.
  * Must be called with external interrupts disabled.
@@ -1243,6 +1280,24 @@
 	.long sys_ni_syscall 	/*	reserved for sys_io_getevents */
 	.long sys_ni_syscall 	/* 230	reserved for sys_io_submit */
 	.long sys_ni_syscall 	/*	reserved for sys_io_cancel */
+	.long sys_ni_syscall	/*	reserved for sys_set_tid_address */
+	.long sys_ni_syscall	/*	reserved for sys_fadvise64 */
+	.long sys_ni_syscall	/*	reserved for sys_exit_group */
+	.long sys_ni_syscall	/* 235	reserved for sys_lookup_dcookie */
+	.long sys_ni_syscall	/*	reserved for sys_epoll_create */
+	.long sys_ni_syscall	/*	reserved for sys_epoll_ctl */
+	.long sys_ni_syscall	/*	reserved for sys_epoll_wait */
+	.long sys_ni_syscall	/*	reserved for sys_remap_file_pages */
+	.long sys_ni_syscall	/* 240	reserved for sys_timer_create */
+	.long sys_ni_syscall	/*	reserved for sys_timer_settime */
+	.long sys_ni_syscall	/*	reserved for sys_timer_gettime */
+	.long sys_ni_syscall	/*	reserved for sys_timer_getoverrun */
+	.long sys_ni_syscall	/*	reserved for sys_timer_delete */
+	.long sys_ni_syscall	/* 245	reserved for sys_clock_settime */
+	.long sys_ni_syscall	/*	reserved for sys_clock_gettime */
+	.long sys_ni_syscall	/*	reserved for sys_clock_getres */
+	.long sys_ni_syscall	/*	reserved for sys_clock_nanosleep */
+	.long sys_swapcontext
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
diff -Nru a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
--- a/arch/ppc/kernel/mk_defs.c	Thu Jun 19 04:21:16 2003
+++ b/arch/ppc/kernel/mk_defs.c	Fri Aug 29 03:56:51 2003
@@ -56,6 +56,7 @@
 	DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0]));
 	DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave));
 	DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
+	DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr));
 #endif /* CONFIG_ALTIVEC */
 #ifdef CONFIG_4xx
 	DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
diff -Nru a/arch/ppc/kernel/pci-dma.c b/arch/ppc/kernel/pci-dma.c
--- a/arch/ppc/kernel/pci-dma.c	Tue Feb 11 12:37:28 2003
+++ b/arch/ppc/kernel/pci-dma.c	Thu Aug 28 03:51:50 2003
@@ -20,13 +20,20 @@
 	void *ret;
 	int gfp = GFP_ATOMIC;
 
-	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff)
 		gfp |= GFP_DMA;
+
+#ifdef CONFIG_NOT_COHERENT_CACHE
+	ret = consistent_alloc(gfp, size, dma_handle);
+#else
 	ret = (void *)__get_free_pages(gfp, get_order(size));
+#endif
 
 	if (ret != NULL) {
 		memset(ret, 0, size);
+#ifndef CONFIG_NOT_COHERENT_CACHE
 		*dma_handle = virt_to_bus(ret);
+#endif
 	}
 	return ret;
 }
@@ -34,5 +41,9 @@
 void pci_free_consistent(struct pci_dev *hwdev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
+#ifdef CONFIG_NOT_COHERENT_CACHE
+	consistent_free(vaddr);
+#else
 	free_pages((unsigned long)vaddr, get_order(size));
+#endif
 }
diff -Nru a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c
--- a/arch/ppc/kernel/ppc-stub.c	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/kernel/ppc-stub.c	Mon Aug 25 13:29:19 2003
@@ -135,7 +135,7 @@
 /* typedef void (*trapfunc_t)(void); */
 
 static void kgdb_fault_handler(struct pt_regs *regs);
-static void handle_exception (struct pt_regs *regs);
+static int handle_exception (struct pt_regs *regs);
 
 #if 0
 /* Install an exception handler for kgdb */
@@ -387,14 +387,12 @@
 
 int kgdb_bpt(struct pt_regs *regs)
 {
-	handle_exception(regs);
-	return 1;
+	return handle_exception(regs);
 }
 
 int kgdb_sstep(struct pt_regs *regs)
 {
-	handle_exception(regs);
-	return 1;
+	return handle_exception(regs);
 }
 
 void kgdb(struct pt_regs *regs)
@@ -404,16 +402,14 @@
 
 int kgdb_iabr_match(struct pt_regs *regs)
 {
-	printk("kgdb doesn't support iabr, what?!?\n");
-	handle_exception(regs);
-	return 1;
+	printk(KERN_ERR "kgdb doesn't support iabr, what?!?\n");
+	return handle_exception(regs);
 }
 
 int kgdb_dabr_match(struct pt_regs *regs)
 {
-	printk("kgdb doesn't support dabr, what?!?\n");
-	handle_exception(regs);
-	return 1;
+	printk(KERN_ERR "kgdb doesn't support dabr, what?!?\n");
+	return handle_exception(regs);
 }
 
 /* Convert the SPARC hardware trap type code to a unix signal number. */
@@ -459,7 +455,7 @@
 /*
  * This function does all command processing for interfacing to gdb.
  */
-static void
+static int
 handle_exception (struct pt_regs *regs)
 {
 	int sigval;
@@ -468,14 +464,19 @@
 	char *ptr;
 	unsigned int msr;
 
+	/* We don't handle user-mode breakpoints. */
+	if (user_mode(regs))
+		return 0;
+
 	if (debugger_fault_handler) {
 		debugger_fault_handler(regs);
 		panic("kgdb longjump failed!\n");
 	}
 	if (kgdb_active) {
-		printk("interrupt while in kgdb, returning\n");
-		return;
+		printk(KERN_ERR "interrupt while in kgdb, returning\n");
+		return 0;
 	}
+
 	kgdb_active = 1;
 	kgdb_started = 1;
 
@@ -677,14 +678,14 @@
 			kgdb_interruptible(1);
 			unlock_kernel();
 			kgdb_active = 0;
-			return;
+			return 1;
 
 		case 's':
 			kgdb_flush_cache_all();
 			regs->msr |= MSR_SE;
 			unlock_kernel();
 			kgdb_active = 0;
-			return;
+			return 1;
 
 		case 'r':		/* Reset (if user process..exit ???)*/
 			panic("kgdb reset.");
diff -Nru a/arch/ppc/kernel/ppc4xx_dma.c b/arch/ppc/kernel/ppc4xx_dma.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/ppc4xx_dma.c	Thu Aug 28 21:19:08 2003
@@ -0,0 +1,852 @@
+/*
+ * arch/ppc/kernel/ppc4xx_dma.c
+ *
+ * IBM PPC4xx DMA engine core library
+ *
+ * Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * Cleaned by Matt Porter <mporter@mvista.com>
+ *
+ * Original code by Armin Kuster <akuster@mvista.com>
+ * and Pete Popov <ppopov@mvista.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.
+ *
+ * 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 <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/ppc4xx_dma.h>
+
+ppc_dma_ch_t dma_channels[MAX_PPC4xx_DMA_CHANNELS];
+
+int
+ppc4xx_get_dma_status(void)
+{
+	return (mfdcr(DCRN_DMASR));
+}
+
+void
+ppc4xx_set_src_addr(int dmanr, phys_addr_t src_addr)
+{
+	switch (dmanr) {
+		case 0:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_DMASAH0, (u32)(src_addr >> 32));
+#endif		
+			mtdcr(DCRN_DMASA0, (u32)src_addr);
+			break;
+		case 1:
+#ifdef PPC4xx_DMA_64BIT 
+			mtdcr(DCRN_DMASAH1, (u32)(src_addr >> 32));
+#endif		
+			mtdcr(DCRN_DMASA1, (u32)src_addr);
+			break;
+		case 2:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_DMASAH2, (u32)(src_addr >> 32));
+#endif			
+			mtdcr(DCRN_DMASA2, (u32)src_addr);
+			break;
+		case 3:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_DMASAH3, (u32)(src_addr >> 32));
+#endif			
+			mtdcr(DCRN_DMASA3, (u32)src_addr);
+			break;
+		default:
+			if (dmanr >= MAX_PPC4xx_DMA_CHANNELS)
+				printk("set_src_addr: bad channel: %d\n", dmanr);
+	}
+}
+
+void
+ppc4xx_set_dst_addr(int dmanr, phys_addr_t dst_addr)
+{
+	switch (dmanr) {
+		case 0:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_DMADAH0, (u32)(dst_addr >> 32));
+#endif
+			mtdcr(DCRN_DMADA0, (u32)dst_addr);
+			break;
+		case 1:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_DMADAH1, (u32)(dst_addr >> 32));
+#endif			
+			mtdcr(DCRN_DMADA1, (u32)dst_addr);
+			break;
+		case 2:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_DMADAH2, (u32)(dst_addr >> 32));
+#endif
+			mtdcr(DCRN_DMADA2, (u32)dst_addr);
+			break;
+		case 3:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_DMADAH3, (u32)(dst_addr >> 32));
+#endif
+			mtdcr(DCRN_DMADA3, (u32)dst_addr);
+			break;
+		default:
+			if (dmanr >= MAX_PPC4xx_DMA_CHANNELS)
+				printk("set_dst_addr: bad channel: %d\n", dmanr);
+	}
+}
+
+
+void
+ppc4xx_enable_dma(unsigned int dmanr)
+{
+	unsigned int control;
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+	unsigned int status_bits[] = { DMA_CS0 | DMA_TS0 | DMA_CH0_ERR,
+				       DMA_CS1 | DMA_TS1 | DMA_CH1_ERR,
+				       DMA_CS2 | DMA_TS2 | DMA_CH2_ERR,
+				       DMA_CS3 | DMA_TS3 | DMA_CH3_ERR};
+	
+	if (p_dma_ch->in_use) {
+		printk("enable_dma: channel %d in use\n", dmanr);
+		return;
+	}
+
+	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+		printk("enable_dma: bad channel: %d\n", dmanr);
+		return;
+	}
+
+	if (p_dma_ch->mode == DMA_MODE_READ) {
+		/* peripheral to memory */
+		ppc4xx_set_src_addr(dmanr, 0);
+		ppc4xx_set_dst_addr(dmanr, p_dma_ch->addr);
+	} else if (p_dma_ch->mode == DMA_MODE_WRITE) {
+		/* memory to peripheral */
+		ppc4xx_set_src_addr(dmanr, p_dma_ch->addr);
+		ppc4xx_set_dst_addr(dmanr, 0);
+	}
+
+	/* for other xfer modes, the addresses are already set */
+	switch (dmanr) {
+		case 0:
+			control = mfdcr(DCRN_DMACR0);
+			break;
+		case 1:
+			control = mfdcr(DCRN_DMACR1);
+			break;
+		case 2:
+			control = mfdcr(DCRN_DMACR2);
+			break;
+		case 3:
+			control = mfdcr(DCRN_DMACR3);
+			break;
+		default:
+			printk("enable_dma: bad channel: %d\n", dmanr);
+	}
+
+	control &= ~(DMA_TM_MASK | DMA_TD);	/* clear all mode bits */
+	if (p_dma_ch->mode == DMA_MODE_MM) {
+		/* software initiated memory to memory */
+		control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;
+	}
+
+	switch (dmanr) {
+		case 0:
+			mtdcr(DCRN_DMACR0, control);
+			break;
+		case 1:
+			mtdcr(DCRN_DMACR1, control);
+			break;
+		case 2:
+			mtdcr(DCRN_DMACR2, control);
+			break;
+		case 3:
+			mtdcr(DCRN_DMACR3, control);
+			break;
+		default:
+			printk("enable_dma: bad channel: %d\n", dmanr);
+	}
+
+	/*
+	 * Clear the CS, TS, RI bits for the channel from DMASR.  This
+	 * has been observed to happen correctly only after the mode and
+	 * ETD/DCE bits in DMACRx are set above.  Must do this before
+	 * enabling the channel.
+	 */
+
+	mtdcr(DCRN_DMASR, status_bits[dmanr]);
+
+	/*
+	 * For device-paced transfers, Terminal Count Enable apparently
+	 * must be on, and this must be turned on after the mode, etc.
+	 * bits are cleared above (at least on Redwood-6).
+	 */
+
+	if ((p_dma_ch->mode == DMA_MODE_MM_DEVATDST) ||
+	    (p_dma_ch->mode == DMA_MODE_MM_DEVATSRC))
+		control |= DMA_TCE_ENABLE;
+
+	/*
+	 * Now enable the channel.
+	 */
+
+	control |= (p_dma_ch->mode | DMA_CE_ENABLE);
+
+	switch (dmanr) {
+		case 0:
+			mtdcr(DCRN_DMACR0, control);
+			break;
+		case 1:
+			mtdcr(DCRN_DMACR1, control);
+			break;
+		case 2:
+			mtdcr(DCRN_DMACR2, control);
+			break;
+		case 3:
+			mtdcr(DCRN_DMACR3, control);
+			break;
+		default:
+			printk("enable_dma: bad channel: %d\n", dmanr);
+	}
+
+	p_dma_ch->in_use = 1;
+}
+
+void
+ppc4xx_disable_dma(unsigned int dmanr)
+{
+	unsigned int control;
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+
+	if (!p_dma_ch->in_use) {
+		printk("disable_dma: channel %d not in use\n", dmanr);
+		return;
+	}
+
+	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+		printk("disable_dma: bad channel: %d\n", dmanr);
+		return;
+	}
+
+	switch (dmanr) {
+	case 0:
+		control = mfdcr(DCRN_DMACR0);
+		control &= ~DMA_CE_ENABLE;
+		mtdcr(DCRN_DMACR0, control);
+		break;
+	case 1:
+		control = mfdcr(DCRN_DMACR1);
+		control &= ~DMA_CE_ENABLE;
+		mtdcr(DCRN_DMACR1, control);
+		break;
+	case 2:
+		control = mfdcr(DCRN_DMACR2);
+		control &= ~DMA_CE_ENABLE;
+		mtdcr(DCRN_DMACR2, control);
+		break;
+	case 3:
+		control = mfdcr(DCRN_DMACR3);
+		control &= ~DMA_CE_ENABLE;
+		mtdcr(DCRN_DMACR3, control);
+		break;
+	default:
+		printk("disable_dma: bad channel: %d\n", dmanr);
+	}
+
+	p_dma_ch->in_use = 0;
+}
+
+/*
+ * Sets the dma mode for single DMA transfers only.
+ * For scatter/gather transfers, the mode is passed to the
+ * alloc_dma_handle() function as one of the parameters.
+ *
+ * The mode is simply saved and used later.  This allows
+ * the driver to call set_dma_mode() and set_dma_addr() in
+ * any order.
+ *
+ * Valid mode values are:
+ *
+ * DMA_MODE_READ          peripheral to memory 
+ * DMA_MODE_WRITE         memory to peripheral
+ * DMA_MODE_MM            memory to memory
+ * DMA_MODE_MM_DEVATSRC   device-paced memory to memory, device at src
+ * DMA_MODE_MM_DEVATDST   device-paced memory to memory, device at dst
+ */
+int
+ppc4xx_set_dma_mode(unsigned int dmanr, unsigned int mode)
+{
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+
+	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+		printk("set_dma_mode: bad channel 0x%x\n", dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+	p_dma_ch->mode = mode;
+
+	return DMA_STATUS_GOOD;
+}
+
+/*
+ * Sets the DMA Count register. Note that 'count' is in bytes.
+ * However, the DMA Count register counts the number of "transfers",
+ * where each transfer is equal to the bus width.  Thus, count
+ * MUST be a multiple of the bus width.
+ */
+void
+ppc4xx_set_dma_count(unsigned int dmanr, unsigned int count)
+{
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+
+#ifdef DEBUG_4xxDMA
+	{
+		int error = 0;
+		switch (p_dma_ch->pwidth) {
+		case PW_8:
+			break;
+		case PW_16:
+			if (count & 0x1)
+				error = 1;
+			break;
+		case PW_32:
+			if (count & 0x3)
+				error = 1;
+			break;
+		case PW_64:
+			if (count & 0x7)
+				error = 1;
+			break;
+		default:
+			printk("set_dma_count: invalid bus width: 0x%x\n",
+			       p_dma_ch->pwidth);
+			return;
+		}
+		if (error)
+			printk
+			    ("Warning: set_dma_count count 0x%x bus width %d\n",
+			     count, p_dma_ch->pwidth);
+	}
+#endif
+
+	count = count >> p_dma_ch->shift;
+	switch (dmanr) {
+	case 0:
+		mtdcr(DCRN_DMACT0, count);
+		break;
+	case 1:
+		mtdcr(DCRN_DMACT1, count);
+		break;
+	case 2:
+		mtdcr(DCRN_DMACT2, count);
+		break;
+	case 3:
+		mtdcr(DCRN_DMACT3, count);
+		break;
+	default:
+		printk("ppc4xx_set_dma_count: bad channel: %d\n", dmanr);
+	}
+}
+
+/*
+ *   Returns the number of bytes left to be transfered.
+ *   After a DMA transfer, this should return zero.
+ *   Reading this while a DMA transfer is still in progress will return
+ *   unpredictable results.
+ */ 
+int
+ppc4xx_get_dma_residue(unsigned int dmanr)
+{
+	unsigned int count;
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+
+	switch (dmanr) {
+	case 0:
+		count = mfdcr(DCRN_DMACT0);
+		break;
+	case 1:
+		count = mfdcr(DCRN_DMACT1);
+		break;
+	case 2:
+		count = mfdcr(DCRN_DMACT2);
+		break;
+	case 3:
+		count = mfdcr(DCRN_DMACT3);
+		break;
+	default:
+		printk("ppc4xx_get_dma_residue: bad channel: %d\n", dmanr);
+		return 0;
+	}
+
+	return (count << p_dma_ch->shift);
+}
+
+/*
+ * Sets the DMA address for a memory to peripheral or peripheral
+ * to memory transfer.  The address is just saved in the channel
+ * structure for now and used later in enable_dma().
+ */
+void
+ppc4xx_set_dma_addr(unsigned int dmanr, phys_addr_t addr)
+{
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+
+	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+		printk("ppc4xx_set_dma_addr: bad channel: %d\n", dmanr);
+		return;
+	}
+
+#ifdef DEBUG_4xxDMA
+	{
+		int error = 0;
+		switch (p_dma_ch->pwidth) {
+		case PW_8:
+			break;
+		case PW_16:
+			if ((unsigned) addr & 0x1)
+				error = 1;
+			break;
+		case PW_32:
+			if ((unsigned) addr & 0x3)
+				error = 1;
+			break;
+		case PW_64:
+			if ((unsigned) addr & 0x7)
+				error = 1;
+			break;
+		default:
+			printk("ppc4xx_set_dma_addr: invalid bus width: 0x%x\n",
+			       p_dma_ch->pwidth);
+			return;
+		}
+		if (error)
+			printk("Warning: ppc4xx_set_dma_addr addr 0x%x bus width %d\n",
+			       addr, p_dma_ch->pwidth);
+	}
+#endif
+
+	/* save dma address and program it later after we know the xfer mode */
+	p_dma_ch->addr = addr;
+}
+
+/*
+ * Sets both DMA addresses for a memory to memory transfer. 
+ * For memory to peripheral or peripheral to memory transfers
+ * the function set_dma_addr() should be used instead.
+ */
+void
+ppc4xx_set_dma_addr2(unsigned int dmanr, phys_addr_t src_dma_addr,
+		     phys_addr_t dst_dma_addr)
+{
+#ifdef DEBUG_4xxDMA
+	{
+		ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+		int error = 0;
+		switch (p_dma_ch->pwidth) {
+			case PW_8:
+				break;
+			case PW_16:
+				if (((unsigned) src_dma_addr & 0x1) ||
+						((unsigned) dst_dma_addr & 0x1)
+				   )
+					error = 1;
+				break;
+			case PW_32:
+				if (((unsigned) src_dma_addr & 0x3) ||
+						((unsigned) dst_dma_addr & 0x3)
+				   )
+					error = 1;
+				break;
+			case PW_64:
+				if (((unsigned) src_dma_addr & 0x7) ||
+						((unsigned) dst_dma_addr & 0x7)
+				   )
+					error = 1;
+				break;
+			default:
+				printk("ppc4xx_set_dma_addr2: invalid bus width: 0x%x\n",
+						p_dma_ch->pwidth);
+				return;
+		}
+		if (error)
+			printk
+				("Warning: ppc4xx_set_dma_addr2 src 0x%x dst 0x%x bus width %d\n",
+				 src_dma_addr, dst_dma_addr, p_dma_ch->pwidth);
+	}
+#endif
+
+	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+		printk("ppc4xx_set_dma_addr2: bad channel: %d\n", dmanr);
+	}
+	else {
+		ppc4xx_set_src_addr(dmanr, src_dma_addr);
+		ppc4xx_set_dst_addr(dmanr, dst_dma_addr);
+	}
+}
+
+/*
+ * Enables the channel interrupt.
+ *
+ * If performing a scatter/gatter transfer, this function 
+ * MUST be called before calling alloc_dma_handle() and building
+ * the sgl list.  Otherwise, interrupts will not be enabled, if 
+ * they were previously disabled.
+ */
+int
+ppc4xx_enable_dma_interrupt(unsigned int dmanr)
+{
+	unsigned int control;
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+
+	p_dma_ch->int_enable = 1;
+	switch (dmanr) {
+	case 0:
+		control = mfdcr(DCRN_DMACR0);
+		control |= DMA_CIE_ENABLE;	/* Channel Interrupt Enable */
+		mtdcr(DCRN_DMACR0, control);
+		break;
+	case 1:
+		control = mfdcr(DCRN_DMACR1);
+		control |= DMA_CIE_ENABLE;
+		mtdcr(DCRN_DMACR1, control);
+		break;
+	case 2:
+		control = mfdcr(DCRN_DMACR2);
+		control |= DMA_CIE_ENABLE;
+		mtdcr(DCRN_DMACR2, control);
+		break;
+	case 3:
+		control = mfdcr(DCRN_DMACR3);
+		control |= DMA_CIE_ENABLE;
+		mtdcr(DCRN_DMACR3, control);
+		break;
+	default:
+		printk("ppc4xx_enable_dma_interrupt: bad channel: %d\n", dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+	return DMA_STATUS_GOOD;
+}
+
+/*
+ * Disables the channel interrupt.
+ *
+ * If performing a scatter/gatter transfer, this function 
+ * MUST be called before calling alloc_dma_handle() and building
+ * the sgl list.  Otherwise, interrupts will not be disabled, if 
+ * they were previously enabled.
+ */
+int
+ppc4xx_disable_dma_interrupt(unsigned int dmanr)
+{
+	unsigned int control;
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+
+	p_dma_ch->int_enable = 0;
+	switch (dmanr) {
+	case 0:
+		control = mfdcr(DCRN_DMACR0);
+		control &= ~DMA_CIE_ENABLE;	/* Channel Interrupt Enable */
+		mtdcr(DCRN_DMACR0, control);
+		break;
+	case 1:
+		control = mfdcr(DCRN_DMACR1);
+		control &= ~DMA_CIE_ENABLE;
+		mtdcr(DCRN_DMACR1, control);
+		break;
+	case 2:
+		control = mfdcr(DCRN_DMACR2);
+		control &= ~DMA_CIE_ENABLE;
+		mtdcr(DCRN_DMACR2, control);
+		break;
+	case 3:
+		control = mfdcr(DCRN_DMACR3);
+		control &= ~DMA_CIE_ENABLE;
+		mtdcr(DCRN_DMACR3, control);
+		break;
+	default:
+		printk("ppc4xx_disable_dma_interrupt: bad channel: %d\n", dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+	return DMA_STATUS_GOOD;
+}
+
+/*
+ * Configures a DMA channel, including the peripheral bus width, if a
+ * peripheral is attached to the channel, the polarity of the DMAReq and
+ * DMAAck signals, etc.  This information should really be setup by the boot 
+ * code, since most likely the configuration won't change dynamically.
+ * If the kernel has to call this function, it's recommended that it's
+ * called from platform specific init code.  The driver should not need to 
+ * call this function.
+ */
+int
+ppc4xx_init_dma_channel(unsigned int dmanr, ppc_dma_ch_t * p_init)
+{
+	unsigned int polarity;
+	uint32_t control = 0;
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+
+	DMA_MODE_READ = (unsigned long) DMA_TD;	/* Peripheral to Memory */
+	DMA_MODE_WRITE = 0;	/* Memory to Peripheral */
+
+	if (!p_init) {
+		printk("ppc4xx_init_dma_channel: NULL p_init\n");
+		return DMA_STATUS_NULL_POINTER;
+	}
+
+	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+		printk("ppc4xx_init_dma_channel: bad channel %d\n", dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+#if DCRN_POL > 0
+	polarity = mfdcr(DCRN_POL);
+#else
+	polarity = 0;
+#endif
+
+	/* Setup the control register based on the values passed to
+	 * us in p_init.  Then, over-write the control register with this
+	 * new value.
+	 */
+	control |= SET_DMA_CONTROL;
+
+	switch (dmanr) {
+	case 0:
+		/* clear all polarity signals and then "or" in new signal levels */
+		polarity &= ~GET_DMA_POLARITY(0);
+		polarity |= p_dma_ch->polarity;
+#if DCRN_POL > 0
+		mtdcr(DCRN_POL, polarity);
+#endif
+		mtdcr(DCRN_DMACR0, control);
+		break;
+	case 1:
+		polarity &= ~GET_DMA_POLARITY(1);
+		polarity |= p_dma_ch->polarity;
+#if DCRN_POL > 0
+		mtdcr(DCRN_POL, polarity);
+#endif
+		mtdcr(DCRN_DMACR1, control);
+		break;
+	case 2:
+		polarity &= ~GET_DMA_POLARITY(2);
+		polarity |= p_dma_ch->polarity;
+#if DCRN_POL > 0
+		mtdcr(DCRN_POL, polarity);
+#endif
+		mtdcr(DCRN_DMACR2, control);
+		break;
+	case 3:
+		polarity &= ~GET_DMA_POLARITY(3);
+		polarity |= p_dma_ch->polarity;
+#if DCRN_POL > 0
+		mtdcr(DCRN_POL, polarity);
+#endif
+		mtdcr(DCRN_DMACR3, control);
+		break;
+	default:
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+	/* save these values in our dma channel structure */
+	memcpy(p_dma_ch, p_init, sizeof (ppc_dma_ch_t));
+
+	/*
+	 * The peripheral width values written in the control register are:
+	 *   PW_8                 0
+	 *   PW_16                1
+	 *   PW_32                2
+	 *   PW_64                3
+	 *
+	 *   Since the DMA count register takes the number of "transfers",
+	 *   we need to divide the count sent to us in certain
+	 *   functions by the appropriate number.  It so happens that our
+	 *   right shift value is equal to the peripheral width value.
+	 */
+	p_dma_ch->shift = p_init->pwidth;
+
+	/*
+	 * Save the control word for easy access.
+	 */
+	p_dma_ch->control = control;
+
+	mtdcr(DCRN_DMASR, 0xffffffff);	/* clear status register */
+	return DMA_STATUS_GOOD;
+}
+
+/*
+ * This function returns the channel configuration.
+ */
+int
+ppc4xx_get_channel_config(unsigned int dmanr, ppc_dma_ch_t * p_dma_ch)
+{
+	unsigned int polarity;
+	unsigned int control;
+
+#if DCRN_POL > 0
+	polarity = mfdcr(DCRN_POL);
+#else
+	polarity = 0;
+#endif
+
+	switch (dmanr) {
+	case 0:
+		p_dma_ch->polarity = polarity & GET_DMA_POLARITY(0);
+		control = mfdcr(DCRN_DMACR0);
+		break;
+	case 1:
+		p_dma_ch->polarity = polarity & GET_DMA_POLARITY(1);
+		control = mfdcr(DCRN_DMACR1);
+		break;
+	case 2:
+		p_dma_ch->polarity = polarity & GET_DMA_POLARITY(2);
+		control = mfdcr(DCRN_DMACR2);
+		break;
+	case 3:
+		p_dma_ch->polarity = polarity & GET_DMA_POLARITY(3);
+		control = mfdcr(DCRN_DMACR3);
+		break;
+	default:
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+	p_dma_ch->cp = GET_DMA_PRIORITY(control);
+	p_dma_ch->pwidth = GET_DMA_PW(control);
+	p_dma_ch->psc = GET_DMA_PSC(control);
+	p_dma_ch->pwc = GET_DMA_PWC(control);
+	p_dma_ch->phc = GET_DMA_PHC(control);
+	p_dma_ch->ce = GET_DMA_CE_ENABLE(control);
+	p_dma_ch->int_enable = GET_DMA_CIE_ENABLE(control);
+	p_dma_ch->shift = GET_DMA_PW(control);
+
+#ifdef CONFIG_PPC4xx_EDMA
+	p_dma_ch->pf = GET_DMA_PREFETCH(control);
+#else
+	p_dma_ch->ch_enable = GET_DMA_CH(control);
+	p_dma_ch->ece_enable = GET_DMA_ECE(control);
+	p_dma_ch->tcd_disable = GET_DMA_TCD(control);
+#endif
+	return DMA_STATUS_GOOD;
+}
+
+/*
+ * Sets the priority for the DMA channel dmanr.
+ * Since this is setup by the hardware init function, this function 
+ * can be used to dynamically change the priority of a channel.
+ *
+ * Acceptable priorities:
+ *
+ * PRIORITY_LOW
+ * PRIORITY_MID_LOW
+ * PRIORITY_MID_HIGH
+ * PRIORITY_HIGH
+ *
+ */
+int
+ppc4xx_set_channel_priority(unsigned int dmanr, unsigned int priority)
+{
+	unsigned int control;
+
+	if ((priority != PRIORITY_LOW) &&
+	    (priority != PRIORITY_MID_LOW) &&
+	    (priority != PRIORITY_MID_HIGH) && (priority != PRIORITY_HIGH)) {
+		printk("ppc4xx_set_channel_priority: bad priority: 0x%x\n", priority);
+	}
+
+	switch (dmanr) {
+	case 0:
+		control = mfdcr(DCRN_DMACR0);
+		control |= SET_DMA_PRIORITY(priority);
+		mtdcr(DCRN_DMACR0, control);
+		break;
+	case 1:
+		control = mfdcr(DCRN_DMACR1);
+		control |= SET_DMA_PRIORITY(priority);
+		mtdcr(DCRN_DMACR1, control);
+		break;
+	case 2:
+		control = mfdcr(DCRN_DMACR2);
+		control |= SET_DMA_PRIORITY(priority);
+		mtdcr(DCRN_DMACR2, control);
+		break;
+	case 3:
+		control = mfdcr(DCRN_DMACR3);
+		control |= SET_DMA_PRIORITY(priority);
+		mtdcr(DCRN_DMACR3, control);
+		break;
+	default:
+		printk("ppc4xx_set_channel_priority: bad channel: %d\n", dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+	return DMA_STATUS_GOOD;
+}
+
+/*
+ * Returns the width of the peripheral attached to this channel. This assumes
+ * that someone who knows the hardware configuration, boot code or some other 
+ * init code, already set the width.
+ *
+ * The return value is one of:
+ *   PW_8
+ *   PW_16
+ *   PW_32
+ *   PW_64
+ *
+ *   The function returns 0 on error.
+ */
+unsigned int
+ppc4xx_get_peripheral_width(unsigned int dmanr)
+{
+	unsigned int control;
+
+	switch (dmanr) {
+	case 0:
+		control = mfdcr(DCRN_DMACR0);
+		break;
+	case 1:
+		control = mfdcr(DCRN_DMACR1);
+		break;
+	case 2:
+		control = mfdcr(DCRN_DMACR2);
+		break;
+	case 3:
+		control = mfdcr(DCRN_DMACR3);
+		break;
+	default:
+		printk("ppc4xx_get_peripheral_width: bad channel: %d\n", dmanr);
+		return 0;
+	}
+	return (GET_DMA_PW(control));
+}
+
+
+EXPORT_SYMBOL(ppc4xx_init_dma_channel);
+EXPORT_SYMBOL(ppc4xx_get_channel_config);
+EXPORT_SYMBOL(ppc4xx_set_channel_priority);
+EXPORT_SYMBOL(ppc4xx_get_peripheral_width);
+EXPORT_SYMBOL(dma_channels);
+EXPORT_SYMBOL(ppc4xx_set_src_addr);
+EXPORT_SYMBOL(ppc4xx_set_dst_addr);
+EXPORT_SYMBOL(ppc4xx_set_dma_addr);
+EXPORT_SYMBOL(ppc4xx_set_dma_addr2);
+EXPORT_SYMBOL(ppc4xx_enable_dma);
+EXPORT_SYMBOL(ppc4xx_disable_dma);
+EXPORT_SYMBOL(ppc4xx_set_dma_mode);
+EXPORT_SYMBOL(ppc4xx_set_dma_count);
+EXPORT_SYMBOL(ppc4xx_get_dma_residue);
+EXPORT_SYMBOL(ppc4xx_enable_dma_interrupt);
+EXPORT_SYMBOL(ppc4xx_disable_dma_interrupt);
+EXPORT_SYMBOL(ppc4xx_get_dma_status);
diff -Nru a/arch/ppc/kernel/ppc4xx_sgdma.c b/arch/ppc/kernel/ppc4xx_sgdma.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/ppc4xx_sgdma.c	Thu Aug 28 21:19:09 2003
@@ -0,0 +1,536 @@
+/*
+ * arch/ppc/kernel/ppc4xx_sgdma.c
+ *
+ * IBM PPC4xx DMA engine scatter/gather library 
+ *
+ * Copyright 2002-2003 MontaVista Software Inc.
+ *
+ * Cleaned by Matt Porter <mporter@mvista.com>
+ *
+ * Original code by Armin Kuster <akuster@mvista.com>
+ * and Pete Popov <ppopov@mvista.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.
+ *
+ * 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 <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/ppc4xx_dma.h>
+
+static __inline__ void
+ppc4xx_set_sg_addr(int dmanr, phys_addr_t sg_addr)
+{
+	switch (dmanr) {
+		case 0:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_ASGH0, (u32)(sg_addr >> 32));
+#endif			
+			mtdcr(DCRN_ASG0, (u32)sg_addr);
+			break;
+		case 1:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_ASGH1, (u32)(sg_addr >> 32));
+#endif			
+			mtdcr(DCRN_ASG1, (u32)sg_addr);
+			break;
+		case 2:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_ASGH2, (u32)(sg_addr >> 32));
+#endif			
+			mtdcr(DCRN_ASG2, sg_addr);
+			break;
+		case 3:
+#ifdef PPC4xx_DMA_64BIT
+			mtdcr(DCRN_ASGH3, (u32)(sg_addr >> 32));
+#endif			
+			mtdcr(DCRN_ASG3, (u32)sg_addr);
+			break;
+	}
+}
+
+
+/*
+ *   Add a new sgl descriptor to the end of a scatter/gather list 
+ *   which was created by alloc_dma_handle(). 
+ *
+ *   For a memory to memory transfer, both dma addresses must be
+ *   valid. For a peripheral to memory transfer, one of the addresses
+ *   must be set to NULL, depending on the direction of the transfer:
+ *   memory to peripheral: set dst_addr to NULL,
+ *   peripheral to memory: set src_addr to NULL.
+ */
+static __inline__ int
+ppc4xx_add_dma_sgl(sgl_handle_t handle, phys_addr_t src_addr, phys_addr_t dst_addr,
+		   unsigned int count)
+{
+	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+	ppc_dma_ch_t *p_dma_ch;
+
+	if (!handle) {
+		printk("ppc4xx_add_dma_sgl: null handle\n");
+		return DMA_STATUS_BAD_HANDLE;
+	}
+
+	if (psgl->dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+		printk("ppc4xx_add_dma_sgl: bad channel: %d\n", psgl->dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+	p_dma_ch = &dma_channels[psgl->dmanr];
+
+#ifdef DEBUG_4xxDMA
+	{
+		int error = 0;
+		unsigned int aligned =
+		    (unsigned) src_addr | (unsigned) dst_addr | count;
+		switch (p_dma_ch->pwidth) {
+		case PW_8:
+			break;
+		case PW_16:
+			if (aligned & 0x1)
+				error = 1;
+			break;
+		case PW_32:
+			if (aligned & 0x3)
+				error = 1;
+			break;
+		case PW_64:
+			if (aligned & 0x7)
+				error = 1;
+			break;
+		default:
+			printk("ppc4xx_add_dma_sgl: invalid bus width: 0x%x\n",
+			       p_dma_ch->pwidth);
+			return DMA_STATUS_GENERAL_ERROR;
+		}
+		if (error)
+			printk
+			    ("Alignment warning: ppc4xx_add_dma_sgl src 0x%x dst 0x%x count 0x%x bus width var %d\n",
+			     src_addr, dst_addr, count, p_dma_ch->pwidth);
+
+	}
+#endif
+
+	if ((unsigned) (psgl->ptail + 1) >= ((unsigned) psgl + SGL_LIST_SIZE)) {
+		printk("sgl handle out of memory \n");
+		return DMA_STATUS_OUT_OF_MEMORY;
+	}
+
+	if (!psgl->ptail) {
+		psgl->phead = (ppc_sgl_t *)
+		    ((unsigned) psgl + sizeof (sgl_list_info_t));
+		psgl->ptail = psgl->phead;
+	} else {
+		psgl->ptail->next = iopa((unsigned long)(psgl->ptail + 1));
+		psgl->ptail++;
+	}
+
+	psgl->ptail->control = psgl->control;
+	psgl->ptail->src_addr = src_addr;
+	psgl->ptail->dst_addr = dst_addr;
+	psgl->ptail->control_count = (count >> p_dma_ch->shift) |
+	    psgl->sgl_control;
+	psgl->ptail->next = (uint32_t) NULL;
+
+	return DMA_STATUS_GOOD;
+}
+
+/*
+ * Enable (start) the DMA described by the sgl handle.
+ */
+static __inline__ void
+ppc4xx_enable_dma_sgl(sgl_handle_t handle)
+{
+	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+	ppc_dma_ch_t *p_dma_ch;
+	uint32_t sg_command;
+
+	if (!handle) {
+		printk("ppc4xx_enable_dma_sgl: null handle\n");
+		return;
+	} else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
+		printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
+		       psgl->dmanr);
+		return;
+	} else if (!psgl->phead) {
+		printk("ppc4xx_enable_dma_sgl: sg list empty\n");
+		return;
+	}
+
+	p_dma_ch = &dma_channels[psgl->dmanr];
+	psgl->ptail->control_count &= ~SG_LINK;	/* make this the last dscrptr */
+	sg_command = mfdcr(DCRN_ASGC);
+
+	ppc4xx_set_sg_addr(psgl->dmanr, iopa((unsigned long)psgl->phead));
+
+	switch (psgl->dmanr) {
+	case 0:
+		sg_command |= SSG0_ENABLE;
+		break;
+	case 1:
+		sg_command |= SSG1_ENABLE;
+		break;
+	case 2:
+		sg_command |= SSG2_ENABLE;
+		break;
+	case 3:
+		sg_command |= SSG3_ENABLE;
+		break;
+	default:
+		printk("ppc4xx_enable_dma_sgl: bad channel: %d\n", psgl->dmanr);
+	}
+
+	mtdcr(DCRN_ASGC, sg_command);	/* start transfer */
+}
+
+/*
+ * Halt an active scatter/gather DMA operation.
+ */
+static __inline__ void
+ppc4xx_disable_dma_sgl(sgl_handle_t handle)
+{
+	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+	uint32_t sg_command;
+
+	if (!handle) {
+		printk("ppc4xx_enable_dma_sgl: null handle\n");
+		return;
+	} else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
+		printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
+		       psgl->dmanr);
+		return;
+	}
+
+	sg_command = mfdcr(DCRN_ASGC);
+	switch (psgl->dmanr) {
+	case 0:
+		sg_command &= ~SSG0_ENABLE;
+		break;
+	case 1:
+		sg_command &= ~SSG1_ENABLE;
+		break;
+	case 2:
+		sg_command &= ~SSG2_ENABLE;
+		break;
+	case 3:
+		sg_command &= ~SSG3_ENABLE;
+		break;
+	default:
+		printk("ppc4xx_enable_dma_sgl: bad channel: %d\n", psgl->dmanr);
+	}
+
+	mtdcr(DCRN_ASGC, sg_command);	/* stop transfer */
+}
+
+/*
+ *  Returns number of bytes left to be transferred from the entire sgl list.
+ *  *src_addr and *dst_addr get set to the source/destination address of
+ *  the sgl descriptor where the DMA stopped.
+ *
+ *  An sgl transfer must NOT be active when this function is called.
+ */
+static __inline__ int
+ppc4xx_get_dma_sgl_residue(sgl_handle_t handle, phys_addr_t * src_addr,
+			   phys_addr_t * dst_addr)
+{
+	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+	ppc_dma_ch_t *p_dma_ch;
+	ppc_sgl_t *pnext, *sgl_addr;
+	uint32_t count_left;
+
+	if (!handle) {
+		printk("ppc4xx_get_dma_sgl_residue: null handle\n");
+		return DMA_STATUS_BAD_HANDLE;
+	} else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
+		printk("ppc4xx_get_dma_sgl_residue: bad channel in handle %d\n",
+		       psgl->dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+	switch (psgl->dmanr) {
+	case 0:
+		sgl_addr = (ppc_sgl_t *) bus_to_virt(mfdcr(DCRN_ASG0));
+		count_left = mfdcr(DCRN_DMACT0);
+		break;
+	case 1:
+		sgl_addr = (ppc_sgl_t *) bus_to_virt(mfdcr(DCRN_ASG1));
+		count_left = mfdcr(DCRN_DMACT1);
+		break;
+	case 2:
+		sgl_addr = (ppc_sgl_t *) bus_to_virt(mfdcr(DCRN_ASG2));
+		count_left = mfdcr(DCRN_DMACT2);
+		break;
+	case 3:
+		sgl_addr = (ppc_sgl_t *) bus_to_virt(mfdcr(DCRN_ASG3));
+		count_left = mfdcr(DCRN_DMACT3);
+		break;
+	default:
+		printk("ppc4xx_get_dma_sgl_residue: bad channel %d\n", psgl->dmanr);
+		goto error;
+	}
+
+	if (!sgl_addr) {
+		printk("ppc4xx_get_dma_sgl_residue: sgl addr register is null\n");
+		goto error;
+	}
+
+	pnext = psgl->phead;
+	while (pnext &&
+	       ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE) &&
+		(pnext != sgl_addr))
+	    ) {
+		pnext++;
+	}
+
+	if (pnext == sgl_addr) {	/* found the sgl descriptor */
+
+		*src_addr = pnext->src_addr;
+		*dst_addr = pnext->dst_addr;
+
+		/*
+		 * Now search the remaining descriptors and add their count.
+		 * We already have the remaining count from this descriptor in
+		 * count_left.
+		 */
+		pnext++;
+
+		while ((pnext != psgl->ptail) &&
+		       ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE))
+		    ) {
+			count_left += pnext->control_count & SG_COUNT_MASK;
+		}
+
+		if (pnext != psgl->ptail) {	/* should never happen */
+			printk
+			    ("ppc4xx_get_dma_sgl_residue error (1) psgl->ptail 0x%x handle 0x%x\n",
+			     (unsigned int) psgl->ptail, (unsigned int) handle);
+			goto error;
+		}
+
+		/* success */
+		p_dma_ch = &dma_channels[psgl->dmanr];
+		return (count_left << p_dma_ch->shift);	/* count in bytes */
+
+	} else {
+		/* this shouldn't happen */
+		printk
+		    ("get_dma_sgl_residue, unable to match current address 0x%x, handle 0x%x\n",
+		     (unsigned int) sgl_addr, (unsigned int) handle);
+
+	}
+
+      error:
+	*src_addr = (phys_addr_t) NULL;
+	*dst_addr = (phys_addr_t) NULL;
+	return 0;
+}
+
+/*
+ * Returns the address(es) of the buffer(s) contained in the head element of
+ * the scatter/gather list.  The element is removed from the scatter/gather
+ * list and the next element becomes the head.
+ *
+ * This function should only be called when the DMA is not active.
+ */
+static __inline__ int
+ppc4xx_delete_dma_sgl_element(sgl_handle_t handle, phys_addr_t * src_dma_addr,
+			      phys_addr_t * dst_dma_addr)
+{
+	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+
+	if (!handle) {
+		printk("ppc4xx_delete_sgl_element: null handle\n");
+		return DMA_STATUS_BAD_HANDLE;
+	} else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
+		printk("ppc4xx_delete_sgl_element: bad channel in handle %d\n",
+		       psgl->dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+	if (!psgl->phead) {
+		printk("ppc4xx_delete_sgl_element: sgl list empty\n");
+		*src_dma_addr = (phys_addr_t) NULL;
+		*dst_dma_addr = (phys_addr_t) NULL;
+		return DMA_STATUS_SGL_LIST_EMPTY;
+	}
+
+	*src_dma_addr = (phys_addr_t) psgl->phead->src_addr;
+	*dst_dma_addr = (phys_addr_t) psgl->phead->dst_addr;
+
+	if (psgl->phead == psgl->ptail) {
+		/* last descriptor on the list */
+		psgl->phead = NULL;
+		psgl->ptail = NULL;
+	} else {
+		psgl->phead++;
+	}
+
+	return DMA_STATUS_GOOD;
+}
+
+
+/*
+ *   Create a scatter/gather list handle.  This is simply a structure which
+ *   describes a scatter/gather list.
+ *
+ *   A handle is returned in "handle" which the driver should save in order to 
+ *   be able to access this list later.  A chunk of memory will be allocated 
+ *   to be used by the API for internal management purposes, including managing 
+ *   the sg list and allocating memory for the sgl descriptors.  One page should 
+ *   be more than enough for that purpose.  Perhaps it's a bit wasteful to use 
+ *   a whole page for a single sg list, but most likely there will be only one 
+ *   sg list per channel.
+ *
+ *   Interrupt notes:
+ *   Each sgl descriptor has a copy of the DMA control word which the DMA engine
+ *   loads in the control register.  The control word has a "global" interrupt 
+ *   enable bit for that channel. Interrupts are further qualified by a few bits
+ *   in the sgl descriptor count register.  In order to setup an sgl, we have to
+ *   know ahead of time whether or not interrupts will be enabled at the completion
+ *   of the transfers.  Thus, enable_dma_interrupt()/disable_dma_interrupt() MUST
+ *   be called before calling alloc_dma_handle().  If the interrupt mode will never
+ *   change after powerup, then enable_dma_interrupt()/disable_dma_interrupt() 
+ *   do not have to be called -- interrupts will be enabled or disabled based
+ *   on how the channel was configured after powerup by the hw_init_dma_channel()
+ *   function.  Each sgl descriptor will be setup to interrupt if an error occurs;
+ *   however, only the last descriptor will be setup to interrupt. Thus, an 
+ *   interrupt will occur (if interrupts are enabled) only after the complete
+ *   sgl transfer is done.
+ */
+int
+ppc4xx_alloc_dma_handle(sgl_handle_t * phandle, unsigned int mode, unsigned int dmanr)
+{
+	sgl_list_info_t *psgl;
+	dma_addr_t dma_addr;
+	ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+	uint32_t sg_command;
+	void *ret;
+
+	if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
+		printk("ppc4xx_alloc_dma_handle: invalid channel 0x%x\n", dmanr);
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+	if (!phandle) {
+		printk("ppc4xx_alloc_dma_handle: null handle pointer\n");
+		return DMA_STATUS_NULL_POINTER;
+	}
+
+	/* Get a page of memory, which is zeroed out by consistent_alloc() */
+	ret = consistent_alloc(GFP_KERNEL, DMA_PPC4xx_SIZE, &dma_addr);
+	if (ret != NULL) {
+		memset(ret, 0, DMA_PPC4xx_SIZE);
+		psgl = (sgl_list_info_t *) ret;
+	}
+
+	if (psgl == NULL) {
+		*phandle = (sgl_handle_t) NULL;
+		return DMA_STATUS_OUT_OF_MEMORY;
+	}
+
+	psgl->dma_addr = dma_addr;
+	psgl->dmanr = dmanr;
+
+	/*
+	 * Modify and save the control word. These words will be
+	 * written to each sgl descriptor.  The DMA engine then
+	 * loads this control word into the control register
+	 * every time it reads a new descriptor.
+	 */
+	psgl->control = p_dma_ch->control;
+	/* Clear all mode bits */
+	psgl->control &= ~(DMA_TM_MASK | DMA_TD);
+	/* Save control word and mode */
+	psgl->control |= (mode | DMA_CE_ENABLE);
+
+	/* In MM mode, we must set ETD/TCE */
+	if (mode == DMA_MODE_MM)
+		psgl->control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;
+
+	if (p_dma_ch->int_enable) {
+		/* Enable channel interrupt */
+		psgl->control |= DMA_CIE_ENABLE;
+	} else {
+		psgl->control &= ~DMA_CIE_ENABLE;
+	}
+
+	sg_command = mfdcr(DCRN_ASGC);
+	switch (dmanr) {
+	case 0:
+		sg_command |= SSG0_MASK_ENABLE;
+		break;
+	case 1:
+		sg_command |= SSG1_MASK_ENABLE;
+		break;
+	case 2:
+		sg_command |= SSG2_MASK_ENABLE;
+		break;
+	case 3:
+		sg_command |= SSG3_MASK_ENABLE;
+		break;
+	default:
+		printk("ppc4xx_alloc_dma_handle: bad channel: %d\n", dmanr);
+		ppc4xx_free_dma_handle((sgl_handle_t) psgl);
+		*phandle = (sgl_handle_t) NULL;
+		return DMA_STATUS_BAD_CHANNEL;
+	}
+
+	/* Enable SGL control access */
+	mtdcr(DCRN_ASGC, sg_command);
+	psgl->sgl_control = SG_ERI_ENABLE | SG_LINK;
+
+	if (p_dma_ch->int_enable) {
+		if (p_dma_ch->tce_enable)
+			psgl->sgl_control |= SG_TCI_ENABLE;
+		else
+			psgl->sgl_control |= SG_ETI_ENABLE;
+	}
+
+	*phandle = (sgl_handle_t) psgl;
+	return DMA_STATUS_GOOD;
+}
+
+/*
+ * Destroy a scatter/gather list handle that was created by alloc_dma_handle().
+ * The list must be empty (contain no elements).
+ */
+void
+ppc4xx_free_dma_handle(sgl_handle_t handle)
+{
+	sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
+
+	if (!handle) {
+		printk("ppc4xx_free_dma_handle: got NULL\n");
+		return;
+	} else if (psgl->phead) {
+		printk("ppc4xx_free_dma_handle: list not empty\n");
+		return;
+	} else if (!psgl->dma_addr) {	/* should never happen */
+		printk("ppc4xx_free_dma_handle: no dma address\n");
+		return;
+	}
+
+	consistent_free((void *) psgl);
+}
+
+EXPORT_SYMBOL(ppc4xx_alloc_dma_handle);
+EXPORT_SYMBOL(ppc4xx_free_dma_handle);
+EXPORT_SYMBOL(ppc4xx_add_dma_sgl);
+EXPORT_SYMBOL(ppc4xx_delete_dma_sgl_element);
+EXPORT_SYMBOL(ppc4xx_enable_dma_sgl);
+EXPORT_SYMBOL(ppc4xx_disable_dma_sgl);
+EXPORT_SYMBOL(ppc4xx_get_dma_sgl_residue);
diff -Nru a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
--- a/arch/ppc/kernel/ppc_htab.c	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/kernel/ppc_htab.c	Fri Aug 29 02:07:59 2003
@@ -113,7 +113,7 @@
 {
 	unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
 	int n = 0;
-#ifdef CONFIG_PPC_STD_MMU
+#if defined(CONFIG_PPC_STD_MMU) && !defined(CONFIG_PPC64BRIDGE)
 	int valid;
 	unsigned int kptes = 0, uptes = 0, zombie_ptes = 0;
 	PTE *ptr;
@@ -150,6 +150,7 @@
 		goto return_string;
 	}
 
+#ifndef CONFIG_PPC64BRIDGE
 	for ( ptr = Hash ; ptr < Hash_end ; ptr++)
 	{
 		unsigned int ctx, mctx, vsid;
@@ -177,6 +178,7 @@
 		if (!valid)
 			zombie_ptes++;
 	}
+#endif
 
 	n += sprintf( buffer + n,
 		      "PTE Hash Table Information\n"
@@ -184,18 +186,22 @@
 		      "Buckets\t\t: %lu\n"
  		      "Address\t\t: %08lx\n"
 		      "Entries\t\t: %lu\n"
+#ifndef CONFIG_PPC64BRIDGE
 		      "User ptes\t: %u\n"
 		      "Kernel ptes\t: %u\n"
 		      "Zombies\t\t: %u\n"
-		      "Percent full\t: %lu%%\n",
-                      (unsigned long)(Hash_size>>10),
+		      "Percent full\t: %lu%%\n"
+#endif
+                      , (unsigned long)(Hash_size>>10),
 		      (Hash_size/(sizeof(PTE)*8)),
 		      (unsigned long)Hash,
-		      Hash_size/sizeof(PTE),
-                      uptes,
+		      Hash_size/sizeof(PTE)
+#ifndef CONFIG_PPC64BRIDGE
+                      , uptes,
 		      kptes,
 		      zombie_ptes,
 		      ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
+#endif
 		);
 
 	n += sprintf( buffer + n,
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Wed Jul 30 05:51:44 2003
+++ b/arch/ppc/kernel/ppc_ksyms.c	Thu Aug 28 05:31:04 2003
@@ -159,11 +159,14 @@
 EXPORT_SYMBOL(_outsw_ns);
 EXPORT_SYMBOL(_insl_ns);
 EXPORT_SYMBOL(_outsl_ns);
+EXPORT_SYMBOL(iopa);
+EXPORT_SYMBOL(mm_ptov);
 EXPORT_SYMBOL(ioremap);
+#ifdef CONFIG_44x
+EXPORT_SYMBOL(ioremap64);
+#endif
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(iopa);
-EXPORT_SYMBOL(mm_ptov);
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
 	|| defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
@@ -176,8 +179,23 @@
 EXPORT_SYMBOL_NOVERS(pci_dram_offset);
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pci_bus_io_base);
+EXPORT_SYMBOL(pci_bus_io_base_phys);
+EXPORT_SYMBOL(pci_bus_mem_base_phys);
+EXPORT_SYMBOL(pci_bus_to_hose);
+EXPORT_SYMBOL(pci_resource_to_bus);
+EXPORT_SYMBOL(pci_phys_to_bus);
+EXPORT_SYMBOL(pci_bus_to_phys);
 #endif /* CONFIG_PCI */
 
+#ifdef CONFIG_NOT_COHERENT_CACHE
+EXPORT_SYMBOL(consistent_alloc);
+EXPORT_SYMBOL(consistent_free);
+EXPORT_SYMBOL(consistent_sync);
+EXPORT_SYMBOL(consistent_sync_page);
+EXPORT_SYMBOL(flush_dcache_all);
+#endif
+
 EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(kernel_thread);
 
@@ -253,15 +271,8 @@
 EXPORT_SYMBOL(get_property);
 EXPORT_SYMBOL(request_OF_resource);
 EXPORT_SYMBOL(release_OF_resource);
-EXPORT_SYMBOL(pci_bus_io_base);
-EXPORT_SYMBOL(pci_bus_io_base_phys);
-EXPORT_SYMBOL(pci_bus_mem_base_phys);
 EXPORT_SYMBOL(pci_device_to_OF_node);
 EXPORT_SYMBOL(pci_device_from_OF_node);
-EXPORT_SYMBOL(pci_bus_to_hose);
-EXPORT_SYMBOL(pci_resource_to_bus);
-EXPORT_SYMBOL(pci_phys_to_bus);
-EXPORT_SYMBOL(pci_bus_to_phys);
 EXPORT_SYMBOL(pmac_newworld);
 EXPORT_SYMBOL(nvram_read_byte);
 EXPORT_SYMBOL(nvram_write_byte);
@@ -291,7 +302,7 @@
 
 EXPORT_SYMBOL(abs);
 
-#ifdef CONFIG_VGA_CONSOLE
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_FB)
 EXPORT_SYMBOL(screen_info);
 #endif
 
@@ -338,8 +349,10 @@
 EXPORT_SYMBOL(debugger_fault_handler);
 #endif
 
-#ifdef  CONFIG_8xx
+#if defined(CONFIG_8xx) || defined(CONFIG_4xx)
 EXPORT_SYMBOL(__res);
+#endif
+#ifdef  CONFIG_8xx
 EXPORT_SYMBOL(cpm_install_handler);
 EXPORT_SYMBOL(cpm_free_handler);
 EXPORT_SYMBOL(m8xx_cpm_hostalloc);
@@ -370,4 +383,3 @@
 extern unsigned long agp_special_page;
 EXPORT_SYMBOL_NOVERS(agp_special_page);
 #endif /* defined(CONFIG_ALL_PPC) */
-
diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
--- a/arch/ppc/kernel/process.c	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/kernel/process.c	Fri Aug 29 03:56:51 2003
@@ -417,6 +417,7 @@
 	memset(current->thread.vr, 0, sizeof(current->thread.vr));
 	memset(&current->thread.vscr, 0, sizeof(current->thread.vscr));
 	current->thread.vrsave = 0;
+	current->thread.used_vr = 0;
 #endif /* CONFIG_ALTIVEC */
 }
 
diff -Nru a/arch/ppc/kernel/prom_init.c b/arch/ppc/kernel/prom_init.c
--- a/arch/ppc/kernel/prom_init.c	Sat Feb  1 12:50:03 2003
+++ b/arch/ppc/kernel/prom_init.c	Fri Aug 29 02:07:59 2003
@@ -638,6 +638,72 @@
 	}
 }
 
+#ifdef CONFIG_POWER4
+/*
+ * Set up a hash table with a set of entries in it to map the
+ * first 64MB of RAM.  This is used on 64-bit machines since
+ * some of them don't have BATs.
+ * We assume the PTE will fit in the primary PTEG.
+ */
+
+static inline void make_pte(unsigned long htab, unsigned int hsize,
+			    unsigned int va, unsigned int pa, int mode)
+{
+	unsigned int *pteg;
+	unsigned int hash, i, vsid;
+
+	vsid = ((va >> 28) * 0x111) << 12;
+	hash = ((va ^ vsid) >> 5) & 0x7fff80;
+	pteg = (unsigned int *)(htab + (hash & (hsize - 1)));
+	for (i = 0; i < 8; ++i, pteg += 4) {
+		if ((pteg[1] & 1) == 0) {
+			pteg[1] = vsid | ((va >> 16) & 0xf80) | 1;
+			pteg[3] = pa | mode;
+			break;
+		}
+	}
+}
+
+extern unsigned long _SDR1;
+extern PTE *Hash;
+extern unsigned long Hash_size;
+
+static void __init
+prom_alloc_htab(void)
+{
+	unsigned int hsize;
+	unsigned long htab;
+	unsigned int addr;
+
+	/*
+	 * Because of OF bugs we can't use the "claim" client
+	 * interface to allocate memory for the hash table.
+	 * This code is only used on 64-bit PPCs, and the only
+	 * 64-bit PPCs at the moment are RS/6000s, and their
+	 * OF is based at 0xc00000 (the 12M point), so we just
+	 * arbitrarily use the 0x800000 - 0xc00000 region for the
+	 * hash table.
+	 *  -- paulus.
+	 */
+	hsize = 4 << 20;	/* POWER4 has no BATs */
+	htab = (8 << 20);
+	call_prom("claim", 3, 1, htab, hsize, 0);
+	Hash = (void *)(htab + KERNELBASE);
+	Hash_size = hsize;
+	_SDR1 = htab + __ilog2(hsize) - 18;
+
+	/*
+	 * Put in PTEs for the first 64MB of RAM
+	 */
+	cacheable_memzero((void *)htab, hsize);
+	for (addr = 0; addr < 0x4000000; addr += 0x1000)
+		make_pte(htab, hsize, addr + KERNELBASE, addr,
+			 _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);
+	make_pte(htab, hsize, 0x80013000, 0x80013000,
+		 _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX);
+}
+#endif /* CONFIG_POWER4 */
+
 static void __init
 prom_instantiate_rtas(void)
 {
@@ -705,8 +771,7 @@
 
 	/* First get a handle for the stdout device */
 	prom = pp;
-	prom_chosen = call_prom("finddevice", 1, 1,
-				       "/chosen");
+	prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
 	if (prom_chosen == (void *)-1)
 		prom_exit();
 	if ((int) call_prom("getprop", 4, 1, prom_chosen,
@@ -738,6 +803,14 @@
 	}
 
 	prom_instantiate_rtas();
+
+#ifdef CONFIG_POWER4
+	/*
+	 * Find out how much memory we have and allocate a
+	 * suitably-sized hash table.
+	 */
+	prom_alloc_htab();
+#endif
 
 	mem = check_display(mem);
 
diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c	Thu Jul 17 10:28:11 2003
+++ b/arch/ppc/kernel/setup.c	Mon Aug 25 11:12:14 2003
@@ -566,12 +566,10 @@
 #if defined(CONFIG_KGDB)
 	kgdb_map_scc();
 	set_debug_traps();
-	if (strstr(cmd_line, "nokgdb"))
-		printk("kgdb default breakpoint deactivated on command line\n");
-	else {
+	if (strstr(cmd_line, "gdb")) {
 		if (ppc_md.progress)
 			ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
-		printk("kgdb default breakpoint activated\n");
+		printk("kgdb breakpoint activated\n");
 		breakpoint();
 	}
 #endif
diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
--- a/arch/ppc/kernel/signal.c	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/kernel/signal.c	Fri Aug 29 03:56:51 2003
@@ -40,17 +40,7 @@
 
 #define GP_REGS_SIZE	MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
 
-/*
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack.  SE and BE
- * should not be in this list since gdb may want to change these.  I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
- */
-#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
+extern void syscall_direct_return(struct pt_regs *regs);
 
 int do_signal(sigset_t *oldset, struct pt_regs *regs);
 
@@ -157,9 +147,9 @@
 
 
 int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, int r5, int r6,
+		int r7, int r8, struct pt_regs *regs)
 {
-	struct pt_regs *regs = (struct pt_regs *) &uss;
 	return do_sigaltstack(uss, uoss, regs->gpr[1]);
 }
 
@@ -199,271 +189,301 @@
  * When we have signals to deliver, we set up on the
  * user stack, going down from the original stack pointer:
  *	a sigregs struct
- *	one or more sigcontext structs with
+ *	a sigcontext struct
  *	a gap of __SIGNAL_FRAMESIZE bytes
  *
  * Each of these things must be a multiple of 16 bytes in size.
  *
  */
 struct sigregs {
-	elf_gregset_t	gp_regs;
-	double		fp_regs[ELF_NFPREG];
-	unsigned long	tramp[2];
+	struct mcontext	mctx;		/* all the register values */
 	/* Programs using the rs6000/xcoff abi can save up to 19 gp regs
 	   and 18 fp regs below sp before decrementing it. */
 	int		abigap[56];
 };
 
-struct rt_sigframe
-{
-	unsigned long	_unused[2];
-	struct siginfo *pinfo;
-	void *puc;
-	struct siginfo info;
-	struct ucontext uc;
-};
-
+/* We use the mc_pad field for the signal return trampoline. */
+#define tramp	mc_pad
 
 /*
  *  When we have rt signals to deliver, we set up on the
  *  user stack, going down from the original stack pointer:
- *	   a sigregs struct
- *	   one rt_sigframe struct (siginfo + ucontext)
- *	   a gap of __SIGNAL_FRAMESIZE bytes
+ *	one rt_sigframe struct (siginfo + ucontext + ABI gap)
+ *	a gap of __SIGNAL_FRAMESIZE+16 bytes
+ *  (the +16 is to get the siginfo and ucontext in the same
+ *  positions as in older kernels).
  *
  *  Each of these things must be a multiple of 16 bytes in size.
  *
  */
-int sys_rt_sigreturn(struct pt_regs *regs)
+struct rt_sigframe
 {
-	struct rt_sigframe *rt_sf;
-	struct sigcontext_struct sigctx;
-	struct sigregs *sr;
-	int ret;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
-	sigset_t set;
-	stack_t st;
-	unsigned long prevsp;
+	struct siginfo info;
+	struct ucontext uc;
+	/* Programs using the rs6000/xcoff abi can save up to 19 gp regs
+	   and 18 fp regs below sp before decrementing it. */
+	int		abigap[56];
+};
 
-	rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
-	    || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
-	    || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
-		goto badframe;
-	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
-	current->blocked = set;
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->sigmask_lock);
+/*
+ * Save the current user registers on the user stack.
+ * We only save the altivec registers if the process has used
+ * altivec instructions at some point.
+ */
+static int
+save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret)
+{
+	/* save general and floating-point registers */
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
+	if (__copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE)
+	    || __copy_to_user(&frame->mc_fregs, current->thread.fpr,
+			      ELF_NFPREG * sizeof(double)))
+		return 1;
+
+	current->thread.fpscr = 0;	/* turn off all fp exceptions */
 
-	rt_sf++;			/* Look at next rt_sigframe */
-	if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers -
-		 * sigctx is initialized to point to the
-		 * preamble frame (where registers are stored)
-		 * see handle_signal()
-		 */
-		sr = (struct sigregs *) sigctx.regs;
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-		/* This function sets back the stack flags into
-		   the current task structure.  */
-		sys_sigaltstack(&st, NULL);
-
-		ret = regs->result;
-	} else {
-		/* More signals to go */
-		/* Set up registers for next signal handler */
-		regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		/* Get the siginfo   */
-		get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
-		/* Get the ucontext */
-		get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
-		regs->gpr[6] = (unsigned long) rt_sf;
-
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-		current->thread.fpscr = 0;
+#ifdef CONFIG_ALTIVEC
+	/* save altivec registers */
+	if (current->thread.used_vr) {
+		if (regs->msr & MSR_VEC)
+			giveup_altivec(current);
+		if (__copy_to_user(&frame->mc_vregs, current->thread.vr,
+				   ELF_NVRREG * sizeof(vector128)))
+			return 1;
+		/* set MSR_VEC in the saved MSR value to indicate that
+		   frame->mc_vregs contains valid data */
+		if (__put_user(regs->msr | MSR_VEC, &frame->mc_gregs[PT_MSR]))
+			return 1;
+	}
+	/* else assert((regs->msr & MSR_VEC) == 0) */
+
+	/* We always copy to/from vrsave, it's 0 if we don't have or don't
+	 * use altivec. Since VSCR only contains 32 bits saved in the least
+	 * significant bits of a vector, we "cheat" and stuff VRSAVE in the
+	 * most significant bits of that same vector. --BenH
+	 */
+	if (__put_user(current->thread.vrsave, (u32 *)&frame->mc_vregs[32]))
+		return 1;
+#endif /* CONFIG_ALTIVEC */
+
+	if (sigret) {
+		/* Set up the sigreturn trampoline: li r0,sigret; sc */
+		if (__put_user(0x38000000UL + sigret, &frame->tramp[0])
+		    || __put_user(0x44000002UL, &frame->tramp[1]))
+			return 1;
+		flush_icache_range((unsigned long) &frame->tramp[0],
+				   (unsigned long) &frame->tramp[2]);
 	}
-	return ret;
 
-badframe:
-	do_exit(SIGSEGV);
+	return 0;
 }
 
+/*
+ * Restore the current user register values from the user stack,
+ * (except for MSR).
+ */
+static int
+restore_user_regs(struct pt_regs *regs, struct mcontext *sr)
+{
+#ifdef CONFIG_ALTIVEC
+	unsigned long msr;
+#endif
+
+	/* copy up to but not including MSR */
+	if (__copy_from_user(regs, &sr->mc_gregs, PT_MSR * sizeof(elf_greg_t)))
+		return 1;
+	/* copy from orig_r3 (the word after the MSR) up to the end */
+	if (__copy_from_user(&regs->orig_gpr3, &sr->mc_gregs[PT_ORIG_R3],
+			     GP_REGS_SIZE - PT_ORIG_R3 * sizeof(elf_greg_t)))
+		return 1;
+
+	/* force the process to reload the FP registers from
+	   current->thread when it next does FP instructions */
+	regs->msr &= ~MSR_FP;
+	if (__copy_from_user(current->thread.fpr, &sr->mc_fregs,
+			     sizeof(sr->mc_fregs)))
+		return 1;
+
+#ifdef CONFIG_ALTIVEC
+	/* force the process to reload the altivec registers from
+	   current->thread when it next does altivec instructions */
+	regs->msr &= ~MSR_VEC;
+	if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_VEC) != 0) {
+		/* restore altivec registers from the stack */
+		if (__copy_from_user(current->thread.vr, &sr->mc_vregs,
+				     sizeof(sr->mc_vregs)))
+			return 1;
+	} else if (current->thread.used_vr)
+		memset(&current->thread.vr, 0, sizeof(current->thread.vr));
+
+	/* Always get VRSAVE back */
+	if (__get_user(current->thread.vrsave, (u32 *)&sr->mc_vregs[32]))
+		return 1;
+#endif /* CONFIG_ALTIVEC */
+
+	return 0;
+}
+
+/*
+ * Restore the user process's signal mask
+ */
 static void
-setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
-	       signed long newsp)
+restore_sigmask(sigset_t *set)
 {
-	struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp;
+	sigdelsetmask(set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = *set;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+}
 
-	/* Set up preamble frame */
-	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+/*
+ * Set up a signal frame for a "real-time" signal handler
+ * (one which gets siginfo).
+ */
+static void
+handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
+		 siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
+		 unsigned long newsp)
+{
+	struct rt_sigframe *rt_sf;
+	struct mcontext *frame;
+	unsigned long origsp = newsp;
+
+	/* Set up Signal Frame */
+	/* Put a Real Time Context onto stack */
+	newsp -= sizeof(*rt_sf);
+	rt_sf = (struct rt_sigframe *) newsp;
+
+	/* create a stack frame for the caller of the handler */
+	newsp -= __SIGNAL_FRAMESIZE + 16;
+
+	if (verify_area(VERIFY_WRITE, (void *) newsp, origsp - newsp))
 		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	/* Set up to return from user space.
-	   It calls the sc exception at offset 0x9999
-	   for sys_rt_sigreturn().
-	*/
-	    || __put_user(0x38006666UL, &frame->tramp[0])	/* li r0,0x6666 */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))	/* sc */
+
+	/* Put the siginfo & fill in most of the ucontext */
+	if (__copy_to_user(&rt_sf->info, info, sizeof(*info))
+	    || __put_user(0, &rt_sf->uc.uc_flags)
+	    || __put_user(0, &rt_sf->uc.uc_link)
+	    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
+	    || __put_user(sas_ss_flags(regs->gpr[1]), 
+			  &rt_sf->uc.uc_stack.ss_flags)
+	    || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
+	    || __put_user(&rt_sf->uc.uc_mcontext, &rt_sf->uc.uc_regs)
+	    || __copy_to_user(&rt_sf->uc.uc_oldsigmask, oldset, sizeof(*oldset))
+	    || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset)))
 		goto badframe;
-	flush_icache_range((unsigned long) &frame->tramp[0],
-			   (unsigned long) &frame->tramp[2]);
-	current->thread.fpscr = 0;	/* turn off all fp exceptions */
 
-	/* Retrieve rt_sigframe from stack and
-	   set up registers for signal handler
-	*/
-	newsp -= __SIGNAL_FRAMESIZE;
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler)
-	    || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
-	    || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
-	    || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
+	/* Save user registers on the stack */
+	frame = &rt_sf->uc.uc_mcontext;
+	if (save_user_regs(regs, frame, 0x6666))
 		goto badframe;
 
+	if (put_user(regs->gpr[1], (unsigned long *)newsp))
+		goto badframe;
 	regs->gpr[1] = newsp;
+	regs->gpr[3] = sig;
+	regs->gpr[4] = (unsigned long) &rt_sf->info;
+	regs->gpr[5] = (unsigned long) &rt_sf->uc;
 	regs->gpr[6] = (unsigned long) rt_sf;
+	regs->nip = (unsigned long) ka->sa.sa_handler;
 	regs->link = (unsigned long) frame->tramp;
 
 	return;
 
 badframe:
 #if DEBUG_SIG
-	printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
+	printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
 #endif
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
-/*
- * Do a signal return; undo the signal stack.
- */
-int sys_sigreturn(struct pt_regs *regs)
+static int do_setcontext(struct ucontext *ucp, struct pt_regs *regs)
 {
-	struct sigcontext_struct *sc, sigctx;
-	struct sigregs *sr;
-	int ret;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
 	sigset_t set;
-	unsigned long prevsp;
-
-	sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
-		goto badframe;
 
-	set.sig[0] = sigctx.oldmask;
-#if _NSIG_WORDS > 1
-	set.sig[1] = sigctx._unused[3];
-#endif
-	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
-	current->blocked = set;
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->sigmask_lock);
-	if (regs->msr & MSR_FP )
-		giveup_fpu(current);
+	if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(set)))
+		return -EFAULT;
+	restore_sigmask(&set);
 
-	sc++;			/* Look at next sigcontext */
-	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers */
-		sr = (struct sigregs *) sigctx.regs;
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-
-		ret = regs->result;
-
-	} else {
-		/* More signals to go */
-		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		regs->gpr[4] = (unsigned long) sc;
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
-
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-		current->thread.fpscr = 0;
-	}
-	return ret;
+	if (restore_user_regs(regs, &ucp->uc_mcontext))
+		return -EFAULT;
 
-badframe:
-	do_exit(SIGSEGV);
+	return 0;
 }
 
-/*
- * Set up a signal frame.
- */
-static void
-setup_frame(struct pt_regs *regs, struct sigregs *frame,
-	    unsigned long newsp)
+int sys_swapcontext(struct ucontext *old_ctx, struct ucontext *new_ctx,
+		    int r5, int r6, int r7, int r8, struct pt_regs *regs)
 {
-	struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp;
+	unsigned char tmp;
 
-	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38007777UL, &frame->tramp[0])    /* li r0,0x7777 */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))   /* sc */
-		goto badframe;
-	flush_icache_range((unsigned long) &frame->tramp[0],
-			   (unsigned long) &frame->tramp[2]);
-	current->thread.fpscr = 0;	/* turn off all fp exceptions */
+	if (old_ctx != NULL) {
+		if (verify_area(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
+		    || save_user_regs(regs, &old_ctx->uc_mcontext, 0)
+		    || __copy_to_user(&old_ctx->uc_sigmask,
+				      &current->blocked, sizeof(sigset_t))
+		    /* the next 2 things aren't strictly necessary */
+		    || __copy_to_user(&old_ctx->uc_oldsigmask,
+				      &current->blocked, sizeof(sigset_t))
+		    || __put_user(&old_ctx->uc_mcontext, &old_ctx->uc_regs))
+			return -EFAULT;
+	}
+	if (new_ctx == NULL)
+		return 0;
+	if (verify_area(VERIFY_READ, new_ctx, sizeof(*new_ctx))
+	    || __get_user(tmp, (u8 *) new_ctx)
+	    || __get_user(tmp, (u8 *) (new_ctx + 1) - 1))
+		return -EFAULT;
 
-	newsp -= __SIGNAL_FRAMESIZE;
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, &sc->handler)
-	    || get_user(regs->gpr[3], &sc->signal))
-		goto badframe;
-	regs->gpr[1] = newsp;
-	regs->gpr[4] = (unsigned long) sc;
-	regs->link = (unsigned long) frame->tramp;
+	/*
+	 * If we get a fault copying the context into the kernel's
+	 * image of the user's registers, we can't just return -EFAULT
+	 * because the user's registers will be corrupted.  For instance
+	 * the NIP value may have been updated but not some of the
+	 * other registers.  Given that we have done the verify_area
+	 * and successfully read the first and last bytes of the region
+	 * above, this should only happen in an out-of-memory situation
+	 * or if another thread unmaps the region containing the context.
+	 * We kill the task with a SIGSEGV in this situation.
+	 */
+	if (do_setcontext(new_ctx, regs))
+		do_exit(SIGSEGV);
+	syscall_direct_return(regs);
+	/* doesn't actually return back to here */
+	return 0;
+}
 
-	return;
+int sys_rt_sigreturn(struct pt_regs *regs)
+{
+	struct rt_sigframe *rt_sf;
+	stack_t st;
 
-badframe:
-#if DEBUG_SIG
-	printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n",
-	       regs, frame, newsp);
-#endif
-	do_exit(SIGSEGV);
+	rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16);
+	if (verify_area(VERIFY_READ, rt_sf, sizeof(struct rt_sigframe)))
+		goto bad;
+	if (do_setcontext(&rt_sf->uc, regs))
+		goto bad;
+
+	/*
+	 * It's not clear whether or why it is desirable to save the
+	 * sigaltstack setting on signal delivery and restore it on
+	 * signal return.  But other architectures do this and we have
+	 * always done it up until now so it is probably better not to
+	 * change it.  -- paulus
+	 */
+	if (__copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
+		goto bad;
+	do_sigaltstack(&st, NULL, regs->gpr[1]);
+
+	return regs->result;
+
+ bad:
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 /*
@@ -472,105 +492,103 @@
 static void
 handle_signal(unsigned long sig, struct k_sigaction *ka,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
-	      unsigned long *newspp, unsigned long frame)
+	      unsigned long newsp)
 {
-	struct sigcontext_struct *sc;
-	struct rt_sigframe *rt_sf;
-
-	if (regs->trap == 0x0C00 /* System Call! */
-	    && ((int)regs->result == -ERESTARTNOHAND ||
-		((int)regs->result == -ERESTARTSYS &&
-		 !(ka->sa.sa_flags & SA_RESTART))))
-		regs->result = -EINTR;
+	struct sigcontext *sc;
+	struct sigregs *frame;
+	unsigned long origsp = newsp;
 
 	/* Set up Signal Frame */
-	if (ka->sa.sa_flags & SA_SIGINFO) {
-		/* Put a Real Time Context onto stack */
-		*newspp -= sizeof(*rt_sf);
-		rt_sf = (struct rt_sigframe *) *newspp;
-		if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
-			goto badframe;
-
-		if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler)
-		    || __put_user(&rt_sf->info, &rt_sf->pinfo)
-		    || __put_user(&rt_sf->uc, &rt_sf->puc)
-		    /* Put the siginfo */
-		    || __copy_to_user(&rt_sf->info, info, sizeof(*info))
-		    /* Create the ucontext */
-		    || __put_user(0, &rt_sf->uc.uc_flags)
-		    || __put_user(0, &rt_sf->uc.uc_link)
-		    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
-		    || __put_user(sas_ss_flags(regs->gpr[1]),
-				  &rt_sf->uc.uc_stack.ss_flags)
-		    || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
-		    || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))
-		    /* mcontext.regs points to preamble register frame */
-		    || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
-		    || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
-			goto badframe;
-	} else {
-		/* Put another sigcontext on the stack */
-		*newspp -= sizeof(*sc);
-		sc = (struct sigcontext_struct *) *newspp;
-		if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
-			goto badframe;
-
-		if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
-		    || __put_user(oldset->sig[0], &sc->oldmask)
-#if _NSIG_WORDS > 1
-		    || __put_user(oldset->sig[1], &sc->_unused[3])
+	newsp -= sizeof(struct sigregs);
+	frame = (struct sigregs *) newsp;
+
+	/* Put a sigcontext on the stack */
+	newsp -= sizeof(*sc);
+	sc = (struct sigcontext *) newsp;
+
+	/* create a stack frame for the caller of the handler */
+	newsp -= __SIGNAL_FRAMESIZE;
+
+	if (verify_area(VERIFY_WRITE, (void *) newsp, origsp - newsp))
+		goto badframe;
+
+#if _NSIG != 64
+#error "Please adjust handle_signal()"
 #endif
-		    || __put_user((struct pt_regs *)frame, &sc->regs)
-		    || __put_user(sig, &sc->signal))
-			goto badframe;
-	}
+	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
+	    || __put_user(oldset->sig[0], &sc->oldmask)
+	    || __put_user(oldset->sig[1], &sc->_unused[3])
+	    || __put_user((struct pt_regs *)frame, &sc->regs)
+	    || __put_user(sig, &sc->signal))
+		goto badframe;
 
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
+	if (save_user_regs(regs, &frame->mctx, 0x7777))
+		goto badframe;
+
+	if (put_user(regs->gpr[1], (unsigned long *)newsp))
+		goto badframe;
+	regs->gpr[1] = newsp;
+	regs->gpr[3] = sig;
+	regs->gpr[4] = (unsigned long) sc;
+	regs->nip = (unsigned long) ka->sa.sa_handler;
+	regs->link = (unsigned long) frame->mctx.tramp;
 
-	if (!(ka->sa.sa_flags & SA_NODEFER)) {
-		spin_lock_irq(&current->sigmask_lock);
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-		sigaddset(&current->blocked,sig);
-		recalc_sigpending(current);
-		spin_unlock_irq(&current->sigmask_lock);
-	}
 	return;
 
 badframe:
 #if DEBUG_SIG
 	printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n",
 	       regs, frame, *newspp);
-	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
 #endif
-	do_exit(SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 /*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
+ * Do a signal return; undo the signal stack.
  */
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
+int sys_sigreturn(struct pt_regs *regs)
 {
-	siginfo_t info;
-	struct k_sigaction *ka;
-	unsigned long frame, newsp;
+	struct sigcontext *sc, sigctx;
+	struct mcontext *sr;
+	int ret;
+	sigset_t set;
 
-	if (!oldset)
-		oldset = &current->blocked;
+	sc = (struct sigcontext *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+		goto badframe;
 
-	newsp = frame = 0;
+	set.sig[0] = sigctx.oldmask;
+	set.sig[1] = sigctx._unused[3];
+	restore_sigmask(&set);
 
-	for (;;) {
-		unsigned long signr;
+	sr = (struct mcontext *) sigctx.regs;
+	if (verify_area(VERIFY_READ, sr, sizeof(*sr))
+	    || restore_user_regs(regs, sr))
+		goto badframe;
+
+	ret = regs->result;
 
+	return ret;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}	
+
+static int get_signal_to_deliver(struct siginfo *infop, struct pt_regs *regs)
+{
+	struct k_sigaction *ka;
+	int signr;
+
+	for (;;) {
 		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
+		signr = dequeue_signal(&current->blocked, infop);
 		spin_unlock_irq(&current->sigmask_lock);
 
 		if (!signr)
-			break;
+			return 0;
 
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
 			/* Let the debugger run.  */
@@ -589,17 +607,17 @@
 				continue;
 
 			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+			if (signr != infop->si_signo) {
+				infop->si_signo = signr;
+				infop->si_errno = 0;
+				infop->si_code = SI_USER;
+				infop->si_pid = current->p_pptr->pid;
+				infop->si_uid = current->p_pptr->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
 			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
+				send_sig_info(signr, infop, current);
 				continue;
 			}
 		}
@@ -646,39 +664,85 @@
 				/* FALLTHRU */
 
 			default:
-				sig_exit(signr, exit_code, &info);
+				sig_exit(signr, exit_code, infop);
 				/* NOTREACHED */
 			}
 		}
+		return signr;
+	}
+}
 
-		if ( (ka->sa.sa_flags & SA_ONSTACK)
-		     && (! on_sig_stack(regs->gpr[1])))
-			newsp = (current->sas_ss_sp + current->sas_ss_size);
-		else
-			newsp = regs->gpr[1];
-		newsp = frame = newsp - sizeof(struct sigregs);
-
-		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
-		break;
-	}
-
-	if (regs->trap == 0x0C00 /* System Call! */ &&
-	    ((int)regs->result == -ERESTARTNOHAND ||
-	     (int)regs->result == -ERESTARTSYS ||
-	     (int)regs->result == -ERESTARTNOINTR)) {
-		regs->gpr[3] = regs->orig_gpr3;
-		regs->nip -= 4;		/* Back up & retry system call */
-		regs->result = 0;
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+int do_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+	siginfo_t info;
+	struct k_sigaction *ka;
+	unsigned long frame, newsp;
+	int signr;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	newsp = frame = 0;
+
+	signr = get_signal_to_deliver(&info, regs);
+
+	ka = (signr == 0)? NULL: &current->sig->action[signr-1];
+
+	if (regs->trap == 0xc00) {		/* system call */
+		switch ((int) regs->result) {
+		case -ERESTARTSYS:
+			if (signr == 0 || (ka->sa.sa_flags & SA_RESTART))
+				goto retry;
+			/* fall through */
+		case -ERESTARTNOHAND:
+			if (signr > 0) {
+				/* make the system call return an EINTR */
+				regs->result = -EINTR;
+				break;
+			}
+			/* fall through */
+		case -ERESTARTNOINTR:
+		retry:
+			/* Back up & retry system call */
+			regs->gpr[3] = regs->orig_gpr3;
+			regs->nip -= 4;
+			regs->result = 0;
+			break;
+		}
 	}
 
-	if (newsp == frame)
+	if (signr == 0)
 		return 0;		/* no signals delivered */
 
+	if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
+	    && !on_sig_stack(regs->gpr[1]))
+		newsp = current->sas_ss_sp + current->sas_ss_size;
+	else
+		newsp = regs->gpr[1];
+	newsp &= ~0xfUL;
+
+	/* Whee!  Actually deliver the signal.  */
 	if (ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(regs, (struct sigregs *) frame, newsp);
+		handle_rt_signal(signr, ka, &info, oldset, regs, newsp);
 	else
-		setup_frame(regs, (struct sigregs *) frame, newsp);
+		handle_signal(signr, ka, &info, oldset, regs, newsp);
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sigmask_lock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked, signr);
+		recalc_sigpending(current);
+		spin_unlock_irq(&current->sigmask_lock);
+	}
+
 	return 1;
 }
 
diff -Nru a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
--- a/arch/ppc/kernel/syscalls.c	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/kernel/syscalls.c	Fri Aug 29 04:11:06 2003
@@ -57,7 +57,7 @@
  * This is really horribly ugly.
  */
 int
-sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth)
 {
 	int version, ret;
 
@@ -67,24 +67,28 @@
 	ret = -EINVAL;
 	switch (call) {
 	case SEMOP:
-		ret = sys_semop (first, (struct sembuf *)ptr, second);
+		ret = sys_semtimedop(first, (struct sembuf *)ptr, second, NULL);
+		break;
+	case SEMTIMEDOP:
+		ret = sys_semtimedop(first, (struct sembuf *)ptr, second,
+				     (const struct timespec *)fifth);
 		break;
 	case SEMGET:
-		ret = sys_semget (first, second, third);
+		ret = sys_semget(first, second, third);
 		break;
 	case SEMCTL: {
 		union semun fourth;
 
 		if (!ptr)
 			break;
-		if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
+		if ((ret = verify_area(VERIFY_READ, ptr, sizeof(long)))
 		    || (ret = get_user(fourth.__pad, (void **)ptr)))
 			break;
-		ret = sys_semctl (first, second, third, fourth);
+		ret = sys_semctl(first, second, third, fourth);
 		break;
 		}
 	case MSGSND:
-		ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third);
+		ret = sys_msgsnd(first, (struct msgbuf *) ptr, second, third);
 		break;
 	case MSGRCV:
 		switch (version) {
@@ -93,26 +97,26 @@
 
 			if (!ptr)
 				break;
-			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
+			if ((ret = verify_area(VERIFY_READ, ptr, sizeof(tmp)))
 			    || (ret = copy_from_user(&tmp,
 						(struct ipc_kludge *) ptr,
 						sizeof (tmp))))
 				break;
-			ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
-					  third);
+			ret = sys_msgrcv(first, tmp.msgp, second, tmp.msgtyp,
+					 third);
 			break;
 			}
 		default:
-			ret = sys_msgrcv (first, (struct msgbuf *) ptr,
-					  second, fifth, third);
+			ret = sys_msgrcv(first, (struct msgbuf *) ptr,
+					 second, fifth, third);
 			break;
 		}
 		break;
 	case MSGGET:
-		ret = sys_msgget ((key_t) first, second);
+		ret = sys_msgget((key_t) first, second);
 		break;
 	case MSGCTL:
-		ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+		ret = sys_msgctl(first, second, (struct msqid_ds *) ptr);
 		break;
 	case SHMAT:
 		switch (version) {
@@ -122,29 +126,31 @@
 			if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
 					       sizeof(ulong))))
 				break;
-			ret = sys_shmat (first, (char *) ptr, second, &raddr);
+			ret = sys_shmat(first, (char *) ptr, second, &raddr);
 			if (ret)
 				break;
-			ret = put_user (raddr, (ulong *) third);
+			ret = put_user(raddr, (ulong *) third);
 			break;
 			}
 		case 1:	/* iBCS2 emulator entry point */
 			if (!segment_eq(get_fs(), get_ds()))
 				break;
-			ret = sys_shmat (first, (char *) ptr, second,
-					 (ulong *) third);
+			ret = sys_shmat(first, (char *) ptr, second,
+					(ulong *) third);
 			break;
 		}
 		break;
 	case SHMDT:
-		ret = sys_shmdt ((char *)ptr);
+		ret = sys_shmdt((char *)ptr);
 		break;
 	case SHMGET:
-		ret = sys_shmget (first, second, third);
+		ret = sys_shmget(first, second, third);
 		break;
 	case SHMCTL:
-		ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+		ret = sys_shmctl(first, second, (struct shmid_ds *) ptr);
 		break;
+	default:
+		ret = -ENOSYS;
 	}
 
 	return ret;
@@ -167,6 +173,16 @@
 	return error;
 }
 
+#ifndef CONFIG_40x
+#define allow_mmap_address(addr)	1
+#else
+/* Blech.  On 40x allowing mmap() (MAP_FIXED) at the first few pages
+ * of (any process's) virtual memory is a security hole due to chip
+ * erratum #67 (and possibly also due to the (documented) bizarre
+ * prefetch behaviour around 'sc' see S3.8.2.1 of the user manual). */
+#define allow_mmap_address(addr)	((((addr) & PAGE_MASK) >= 0x2100) || suser())
+#endif
+
 static inline unsigned long
 do_mmap2(unsigned long addr, size_t len,
 	 unsigned long prot, unsigned long flags,
@@ -181,6 +197,10 @@
 			goto out;
 	}
 
+	ret = -EINVAL;
+	if ((! allow_mmap_address(addr)) && (flags & MAP_FIXED))
+		goto out;
+	
 	down_write(&current->mm->mmap_sem);
 	ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	up_write(&current->mm->mmap_sem);
diff -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
--- a/arch/ppc/kernel/traps.c	Thu Jun 19 04:21:16 2003
+++ b/arch/ppc/kernel/traps.c	Fri Aug 29 03:37:49 2003
@@ -457,7 +457,7 @@
 }
 #endif /* CONFIG_8xx */
 
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 
 void DebugException(struct pt_regs *regs)
 {
@@ -484,16 +484,27 @@
 		_exception(SIGTRAP, regs, 0, 0);
 	}
 }
-#endif /* CONFIG_4xx */
+#endif /* CONFIG_4xx || CONFIG_BOOKE */
 
 #if !defined(CONFIG_TAU_INT)
 void
 TAUException(struct pt_regs *regs)
 {
-	printk("TAU trap at PC: %lx, SR: %lx, vector=%lx    %s\n",
+	printk("Thermal trap at PC: %lx, SR: %lx, vector=%lx    %s\n",
 	       regs->nip, regs->msr, regs->trap, print_tainted());
 }
 #endif /* CONFIG_INT_TAU */
+
+#ifdef CONFIG_ALTIVEC
+void
+AltivecAssistException(struct pt_regs *regs)
+{
+	if (regs->msr & MSR_VEC)
+		giveup_altivec(current);
+	/* XXX quick hack for now: set the non-Java bit in the VSCR */
+	current->thread.vscr.u[3] |= 0x10000;
+}
+#endif /* CONFIG_ALTIVEC */
 
 void __init trap_init(void)
 {
diff -Nru a/arch/ppc/mm/44x_mmu.c b/arch/ppc/mm/44x_mmu.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/mm/44x_mmu.c	Thu Aug 28 04:54:23 2003
@@ -0,0 +1,137 @@
+/*
+ * Modifications by Matt Porter (mporter@mvista.com) to support
+ * PPC44x Book E processors.
+ *
+ * This file contains the routines for initializing the MMU
+ * on the 4xx series of chips.
+ *  -- paulus
+ * 
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+
+#include <asm/pgalloc.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/setup.h>
+
+#include "mmu_decl.h"
+#include "mem_pieces.h"
+
+extern char etext[], _stext[];
+extern struct mem_pieces phys_avail;
+
+/* Used by the 44x TLB replacement exception handler.
+ * Just needed it declared someplace.
+ */
+unsigned int tlb_44x_index = 0;
+unsigned int tlb_44x_hwater = 61;
+
+/*
+ * "Pins" a 256MB TLB entry in AS0 for kernel lowmem
+ */
+static void __init
+ppc44x_pin_tlb(int slot, unsigned int virt, unsigned int phys)
+{
+	unsigned long attrib;
+
+	__asm__ __volatile__("\
+	clrrwi	%2,%2,10\n\
+	ori	%2,%2,%4\n\
+	clrrwi	%1,%1,10\n\
+	li	%0,0\n\
+	ori	%0,%0,%5\n\
+	tlbwe	%2,%3,%6\n\
+	tlbwe	%1,%3,%7\n\
+	tlbwe	%0,%3,%8"
+	:
+	: "r" (attrib), "r" (phys), "r" (virt), "r" (slot),
+	  "i" (PPC44x_TLB_VALID | PPC44x_TLB_PAGESZ(PPC44x_PAGESZ_256M)),
+	  "i" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G),
+	  "i" (PPC44x_TLB_PAGEID),
+	  "i" (PPC44x_TLB_XLAT),
+	  "i" (PPC44x_TLB_ATTRIB));
+}
+
+/*
+ * Configure PPC44x TLB for AS0 exception processing.
+ */
+static void __init
+ppc44x_tlb_config(void)
+{
+	unsigned int pinned_tlbs = 1;
+	int i;
+
+	/*
+	 * If lowmem is not on a pin tlb entry size boundary,
+	 * then reserve the last page of system memory. This
+	 * eliminates the possibility of a speculative dcache
+	 * fetch past the end of system memory that would
+	 * result in a machine check exception.
+	 */
+	if (total_lowmem | (PPC44x_PIN_SIZE - 1))
+		mem_pieces_remove(&phys_avail, total_lowmem - PAGE_SIZE, PAGE_SIZE, 1);
+
+	/* Determine number of entries necessary to cover lowmem */
+	pinned_tlbs = (unsigned int)
+		(_ALIGN(total_lowmem, PPC44x_PIN_SIZE) >> PPC44x_PIN_SHIFT);
+
+	/* Write upper watermark to save location */
+	tlb_44x_hwater = PPC44x_LOW_SLOT - pinned_tlbs;
+
+	/* If necessary, set additional pinned TLBs */
+	if (pinned_tlbs > 1)
+		for (i = (PPC44x_LOW_SLOT-(pinned_tlbs-1)); i < PPC44x_LOW_SLOT; i++) {
+			unsigned int phys_addr = (PPC44x_LOW_SLOT-i) * PPC44x_PIN_SIZE;
+			ppc44x_pin_tlb(i, phys_addr+PAGE_OFFSET, phys_addr);
+		}
+}
+
+/*
+ * MMU_init_hw does the chip-specific initialization of the MMU hardware.
+ */
+void __init MMU_init_hw(void)
+{
+	flush_instruction_cache();
+
+	ppc44x_tlb_config();
+}
diff -Nru a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile
--- a/arch/ppc/mm/Makefile	Thu Jun 19 01:27:03 2003
+++ b/arch/ppc/mm/Makefile	Thu Aug 28 05:31:04 2003
@@ -19,6 +19,7 @@
 
 obj-$(CONFIG_PPC_STD_MMU)	+= hashtable.o ppc_mmu.o tlb.o
 obj-$(CONFIG_40x)		+= 4xx_mmu.o
+obj-$(CONFIG_44x)		+= 44x_mmu.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= cachemap.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/mm/cachemap.c b/arch/ppc/mm/cachemap.c
--- a/arch/ppc/mm/cachemap.c	Tue Feb 11 12:37:29 2003
+++ b/arch/ppc/mm/cachemap.c	Thu Aug 28 05:31:04 2003
@@ -11,6 +11,7 @@
  * is the virtual address and 'dma_handle' is the physical address.
  * Mostly stolen from the ARM port, with some changes for PowerPC.
  *						-- Dan
+ * Modified for 36-bit support.  -Matt
  *
  * 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
@@ -48,14 +49,24 @@
 #include <asm/smp.h>
 #include <asm/machdep.h>
 
-extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep);
+#include "mmu_decl.h"
 
+extern int map_page(unsigned long va, phys_addr_t pa, int flags);
+
+/* This function will allocate the requested contiguous pages and
+ * map them into the kernel's vmalloc() space.  This is done so we
+ * get unique mapping for these pages, outside of the kernel's 1:1
+ * virtual:physical mapping.  This is necessary so we can cover large
+ * portions of the kernel with single large page TLB entries, and
+ * still get unique uncached pages for consistent DMA.
+ */
 void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
 {
-	int order, rsize;
-	unsigned long page;
-	void *ret;
-	pte_t	*pte;
+	int order, err, i;
+	unsigned long page, va, flags;
+	phys_addr_t pa;
+	struct vm_struct *area;
+	void	 *ret;
 
 	if (in_interrupt())
 		BUG();
@@ -77,23 +88,41 @@
 	 */
 	invalidate_dcache_range(page, page + size);
 
-	ret = (void *)page;
-	*dma_handle = virt_to_bus(ret);
+	/* Allocate some common virtual space to map the new pages.
+	*/
+	area = get_vm_area(size, VM_ALLOC);
+	if (area == 0) {
+		free_pages(page, order);
+		return NULL;
+	}
+	va = VMALLOC_VMADDR(area->addr);
+	ret = (void *)va;
 
-	/* Chase down all of the PTEs and mark them uncached.
+	/* This gives us the real physical address of the first page.
 	*/
-	rsize = (int)size;
-	while (rsize > 0) {
-		if (get_pteptr(&init_mm, page, &pte)) {
-			pte_val(*pte) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
-			flush_tlb_page(find_vma(&init_mm,page),page);
-		}
-		else {
-			BUG();
-			return NULL;
-		}
-		page += PAGE_SIZE;
-		rsize -= PAGE_SIZE;
+	*dma_handle = pa = virt_to_bus((void *)page);
+
+	flags = _PAGE_KERNEL | _PAGE_NO_CACHE;
+
+	/*
+	 * Set refcount=1 on all pages in an order>0
+	 * allocation so that vfree() will actually
+	 * free all pages that were allocated. 
+	 */
+	if (order > 0)
+	{
+		struct page *rpage = virt_to_page(page);
+		for (i = 1; i < (1 << order); i++)
+			set_page_count(rpage+i, 1);
+	}
+
+	err = 0;
+	for (i = 0; i < size && err == 0; i += PAGE_SIZE)
+		err = map_page(va+i, pa+i, flags);
+	
+	if (err) {
+		vfree((void *)va);
+		return NULL;
 	}
 
 	return ret;
@@ -101,42 +130,12 @@
 
 /*
  * free page(s) as defined by the above mapping.
- * The caller has to tell us the size so we can free the proper number
- * of pages.  We can't vmalloc() a new space for these pages and simply
- * call vfree() like some other architectures because we could end up
- * with aliased cache lines (or at least a cache line with the wrong
- * attributes).  This can happen when the PowerPC speculative loads
- * across page boundaries.
  */
-void consistent_free(void *vaddr, size_t size)
+void consistent_free(void *vaddr)
 {
-	int order, rsize;
-	unsigned long addr;
-	pte_t	*pte;
-
 	if (in_interrupt())
 		BUG();
-
-	size = PAGE_ALIGN(size);
-	order = get_order(size);
-
-	/* Chase down all of the PTEs and mark them cached again.
-	*/
-	addr = (unsigned long)vaddr;
-	rsize = (int)size;
-	while (rsize > 0) {
-		if (get_pteptr(&init_mm, addr, &pte)) {
-			pte_val(*pte) &= ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
-			flush_tlb_page(find_vma(&init_mm,addr),addr);
-		}
-		else {
-			BUG();
-			return;
-		}
-		addr += PAGE_SIZE;
-		rsize -= PAGE_SIZE;
-	}
-	free_pages((unsigned long)vaddr, order);
+	vfree(vaddr);
 }
 
 /*
@@ -160,4 +159,18 @@
 		flush_dcache_range(start, end);
 		break;
 	}
+}
+
+/*
+ * consistent_sync_page make a page are consistent. identical
+ * to consistent_sync, but takes a struct page instead of a virtual address
+ */
+
+void consistent_sync_page(struct page *page, unsigned long offset,
+size_t size, int direction)
+{
+	void *start;
+
+	start = page_address(page) + offset; 
+	consistent_sync(start, size, direction);
 }
diff -Nru a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
--- a/arch/ppc/mm/fault.c	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/mm/fault.c	Fri Aug 29 03:37:49 2003
@@ -100,7 +100,7 @@
 	struct mm_struct *mm = current->mm;
 	siginfo_t info;
 	int code = SEGV_MAPERR;
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
 	int is_write = error_code & ESR_DST;
 #else
 	int is_write = 0;
@@ -115,14 +115,14 @@
 		error_code &= 0x48200000;
 	else
 		is_write = error_code & 0x02000000;
-#endif /* CONFIG_4xx */
+#endif /* CONFIG_4xx || CONFIG_BOOKE */
 
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_fault_handler && regs->trap == 0x300) {
 		debugger_fault_handler(regs);
 		return;
 	}
-#if !defined(CONFIG_4xx)
+#ifndef CONFIG_4xx 
 	if (error_code & 0x00400000) {
 		/* DABR match */
 		if (debugger_dabr_match(regs))
diff -Nru a/arch/ppc/mm/mmu_context.c b/arch/ppc/mm/mmu_context.c
--- a/arch/ppc/mm/mmu_context.c	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/mm/mmu_context.c	Fri Aug 29 02:07:59 2003
@@ -3,9 +3,6 @@
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
  * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
- * Although the iSeries hardware does comply with the architecture
- * specification, the need to work through the hypervisor makes
- * things sufficiently different that it is handled elsewhere.
  *  -- paulus
  *
  *  Derived from arch/ppc/mm/init.c:
diff -Nru a/arch/ppc/mm/mmu_decl.h b/arch/ppc/mm/mmu_decl.h
--- a/arch/ppc/mm/mmu_decl.h	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/mm/mmu_decl.h	Thu Aug 28 04:35:00 2003
@@ -21,11 +21,12 @@
  */
 
 #include <asm/pgtable.h>
+#include <asm/mmu.h>
 
 extern void mapin_ram(void);
 extern void bat_mapin_ram(unsigned long bat2, unsigned long bat3);
 extern void adjust_total_lowmem(void);
-extern int map_page(unsigned long va, unsigned long pa, int flags);
+extern int map_page(unsigned long va, phys_addr_t pa, int flags);
 extern void setbat(int index, unsigned long virt, unsigned long phys,
 		   unsigned int size, int flags);
 extern void reserve_phys_mem(unsigned long start, unsigned long size);
diff -Nru a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
--- a/arch/ppc/mm/pgtable.c	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/mm/pgtable.c	Thu Aug 28 05:31:04 2003
@@ -67,16 +67,35 @@
 #define p_mapped_by_bats(x)	(0UL)
 #endif /* HAVE_BATS */
 
+#ifdef CONFIG_44x
 void *
-ioremap(unsigned long addr, unsigned long size)
+ioremap(phys_addr_t addr, unsigned long size)
+{
+	phys_addr_t addr64 = fixup_bigphys_addr(addr, size);;
+
+	return ioremap64(addr64, size);
+}
+
+void *
+ioremap64(unsigned long long addr, unsigned long size)
+{
+	return __ioremap(addr, size, _PAGE_NO_CACHE);
+}
+
+#else /* CONFIG_44x */
+
+void *
+ioremap(phys_addr_t addr, unsigned long size)
 {
 	return __ioremap(addr, size, _PAGE_NO_CACHE);
 }
+#endif /* CONFIG_44x */
 
 void *
-__ioremap(unsigned long addr, unsigned long size, unsigned long flags)
+__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
 {
-	unsigned long p, v, i;
+	unsigned long v, i;
+	phys_addr_t p;
 	int err;
 
 	/*
@@ -101,7 +120,7 @@
 	 */
 	if ( mem_init_done && (p < virt_to_phys(high_memory)) )
 	{
-		printk("__ioremap(): phys addr %0lx is RAM lr %p\n", p,
+		printk("__ioremap(): phys addr "PTE_FMT" is RAM lr %p\n", p,
 		       __builtin_return_address(0));
 		return NULL;
 	}
@@ -152,7 +171,7 @@
 	}
 
 out:
-	return (void *) (v + (addr & ~PAGE_MASK));
+	return (void *) (v + ((unsigned long)addr & ~PAGE_MASK));
 }
 
 void iounmap(void *addr)
@@ -168,7 +187,7 @@
 }
 
 int
-map_page(unsigned long va, unsigned long pa, int flags)
+map_page(unsigned long va, phys_addr_t pa, int flags)
 {
 	pmd_t *pd;
 	pte_t *pg;
@@ -308,7 +327,7 @@
  * virt, phys, size must all be page-aligned.
  * This should only be called before ioremap is called.
  */
-void __init io_block_mapping(unsigned long virt, unsigned long phys,
+void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
 			     unsigned int size, int flags)
 {
 	int i;
diff -Nru a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c
--- a/arch/ppc/mm/ppc_mmu.c	Thu Jul  3 09:56:34 2003
+++ b/arch/ppc/mm/ppc_mmu.c	Fri Aug 29 02:07:59 2003
@@ -3,9 +3,6 @@
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
  * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
- * Although the iSeries hardware does comply with the architecture
- * specification, the need to work through the hypervisor makes
- * things sufficiently different that it is handled elsewhere.
  *  -- paulus
  *
  *  Derived from arch/ppc/mm/init.c:
@@ -181,6 +178,17 @@
 #define MIN_N_HPTEG	1024		/* min 64kB hash table */
 #endif
 
+#ifdef CONFIG_POWER4
+	/* The hash table has already been allocated and initialized
+	   in prom.c */
+	n_hpteg = Hash_size >> LG_HPTEG_SIZE;
+	lg_n_hpteg = __ilog2(n_hpteg);
+
+	/* Remove the hash table from the available memory */
+	if (Hash)
+		reserve_phys_mem(__pa(Hash), Hash_size);
+
+#else /* CONFIG_POWER4 */
 	/*
 	 * Allow 1 HPTE (1/8 HPTEG) for each page of memory.
 	 * This is less than the recommended amount, but then
@@ -204,6 +212,7 @@
 	cacheable_memzero(Hash, Hash_size);
 	_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
 	Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+#endif /* CONFIG_POWER4 */
 
 	printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
 	       total_memory >> 20, Hash_size >> 10, Hash);
diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
--- a/arch/ppc/platforms/Makefile	Thu Jul  3 09:15:26 2003
+++ b/arch/ppc/platforms/Makefile	Thu Aug 28 05:31:04 2003
@@ -26,9 +26,15 @@
 
 O_TARGET := platform.o
 
-export-objs			:= prep_setup.o
+export-objs			:= prep_setup.o ibm440gp.o ibm440gx.o
 
-obj-$(CONFIG_WALNUT)		+= walnut.o ibm405gp.o
+obj-$(CONFIG_405GP)		+= ibm405gp.o
+obj-$(CONFIG_440GP)		+= ibm440gp.o
+obj-$(CONFIG_440GX)		+= ibm440gx.o
+
+obj-$(CONFIG_EBONY)		+= ebony.o
+obj-$(CONFIG_OCOTEA)		+= ocotea.o
+obj-$(CONFIG_WALNUT)		+= walnut.o
 
 obj-$(CONFIG_APUS)		+= apus_setup.o
 ifeq ($(CONFIG_APUS),y)
diff -Nru a/arch/ppc/platforms/ebony.c b/arch/ppc/platforms/ebony.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/ebony.c	Thu Aug 28 05:13:34 2003
@@ -0,0 +1,534 @@
+/*
+ * arch/ppc/platforms/ebony.c
+ *
+ * Ebony board specific routines
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002-2003 MontaVista Software 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/ppc4xx_pic.h>
+
+#include <kernel/ibm440gp_common.h>
+
+extern void abort(void);
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct serial_struct *);
+
+/*
+ * Ebony IRQ triggering/polarity settings
+ */
+static u_char ebony_IRQ_initsenses[] __initdata = {
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 0: UART 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 1: UART 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 2: IIC 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 3: IIC 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 4: PCI Inb Mess */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 5: PCI Cmd Wrt */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 6: PCI PM */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 7: PCI MSI 0 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 8: PCI MSI 1 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 9: PCI MSI 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 10: MAL TX EOB */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 11: MAL RX EOB */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 12: DMA Chan 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 13: DMA Chan 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 14: DMA Chan 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 15: DMA Chan 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 16: Reserved */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 17: Reserved */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 18: GPT Timer 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 19: GPT Timer 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 20: GPT Timer 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 21: GPT Timer 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 22: GPT Timer 4 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 23: Ext Int 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 24: Ext Int 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 25: Ext Int 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 26: Ext Int 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 27: Ext Int 4 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_NEGATIVE),	/* 28: Ext Int 5 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 29: Ext Int 6 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 30: UIC1 NC Int */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 31: UIC1 Crit Int */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 32: MAL SERR */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 33: MAL TXDE */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 34: MAL RXDE */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 35: ECC Unc Err */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 36: ECC Corr Err */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 37: Ext Bus Ctrl */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 38: Ext Bus Mstr */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 39: OPB->PLB */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 40: PCI MSI 3 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 41: PCI MSI 4 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 42: PCI MSI 5 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 43: PCI MSI 6 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 44: PCI MSI 7 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 45: PCI MSI 8 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 46: PCI MSI 9 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 47: PCI MSI 10 */
+	(IRQ_SENSE_EDGE  | IRQ_POLARITY_POSITIVE),	/* 48: PCI MSI 11 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 49: PLB Perf Mon */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 50: Ext Int 7 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 51: Ext Int 8 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 52: Ext Int 9 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 53: Ext Int 10 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 54: Ext Int 11 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* 55: Ext Int 12 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 56: Ser ROM Err */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 57: Reserved */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 58: Reserved */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 59: PCI Async Err */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 60: EMAC 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 61: EMAC 0 WOL */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 62: EMAC 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* 63: EMAC 1 WOL */
+};
+
+/* Global Variables */
+unsigned char __res[sizeof (bd_t)];
+
+static void __init
+ebony_calibrate_decr(void)
+{
+	unsigned int freq;
+
+	/*
+	 * Determine system clock speed
+	 *
+	 * If we are on Rev. B silicon, then use
+	 * default external system clock.  If we are
+	 * on Rev. C silicon then errata forces us to
+	 * use the internal clock.
+	 */
+	switch (PVR_REV(mfspr(PVR))) {
+		case PVR_REV(PVR_440GP_RB):
+			freq = EBONY_440GP_RB_SYSCLK;
+			break;
+		case PVR_REV(PVR_440GP_RC1):
+		default:
+			freq = EBONY_440GP_RC_SYSCLK;
+			break;
+	}
+	
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+	/* Set the time base to zero */
+	mtspr(SPRN_TBWL, 0);
+	mtspr(SPRN_TBWU, 0);
+
+	/* Clear any pending timer interrupts */
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+	/* Enable decrementer interrupt */
+	mtspr(SPRN_TCR, TCR_DIE);
+}
+
+static int
+ebony_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "vendor\t\t: IBM\n");
+	seq_printf(m, "machine\t\t: Ebony\n");
+
+	return 0;
+}
+
+static inline int
+ebony_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	/*
+	 *	PCI IDSEL/INTPIN->INTLINE 
+	 * 	   A   B   C   D
+	 */
+	{
+		{ 23, 23, 23, 23 },	/* IDSEL 1 - PCI Slot 0 */
+		{ 24, 24, 24, 24 },	/* IDSEL 2 - PCI Slot 1 */
+		{ 25, 25, 25, 25 },	/* IDSEL 3 - PCI Slot 2 */
+		{ 26, 26, 26, 26 },	/* IDSEL 4 - PCI Slot 3 */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+#define PCIX_READW(offset) \
+	(readw((u32)pcix_reg_base+offset))
+
+#define PCIX_WRITEW(value, offset) \
+	(writew(value, (u32)pcix_reg_base+offset))
+
+#define PCIX_WRITEL(value, offset) \
+	(writel(value, (u32)pcix_reg_base+offset))
+
+/*
+ * FIXME: This is only here to "make it work".  This will move
+ * to a ibm_pcix.c which will contain a generic IBM PCIX bridge
+ * configuration library. -Matt
+ */
+static void __init
+ebony_setup_pcix(void)
+{
+	void *pcix_reg_base;
+
+	pcix_reg_base = ioremap64(PCIX0_REG_BASE, PCIX0_REG_SIZE);
+
+	/* Enable PCIX0 I/O, Mem, and Busmaster cycles */
+	PCIX_WRITEW(PCIX_READW(PCIX0_COMMAND) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, PCIX0_COMMAND);
+
+	/* Disable all windows */
+	PCIX_WRITEL(0, PCIX0_POM0SA);
+	PCIX_WRITEL(0, PCIX0_POM1SA);
+	PCIX_WRITEL(0, PCIX0_POM2SA);
+	PCIX_WRITEL(0, PCIX0_PIM0SA);
+	PCIX_WRITEL(0, PCIX0_PIM1SA);
+	PCIX_WRITEL(0, PCIX0_PIM2SA);
+	
+	/* Setup 2GB PLB->PCI outbound mem window (3_8000_0000->0_8000_0000) */
+	PCIX_WRITEL(0x00000003, PCIX0_POM0LAH);
+	PCIX_WRITEL(0x80000000, PCIX0_POM0LAL);
+	PCIX_WRITEL(0x00000000, PCIX0_POM0PCIAH);
+	PCIX_WRITEL(0x80000000, PCIX0_POM0PCIAL);
+	PCIX_WRITEL(0x80000001, PCIX0_POM0SA);
+
+	/* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
+	PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
+	PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
+	PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+
+	eieio();
+}
+
+static void __init
+ebony_setup_hose(void)
+{
+	struct pci_controller *hose;
+
+	/* Configure windows on the PCI-X host bridge */
+	ebony_setup_pcix();
+
+	hose = pcibios_alloc_controller();
+
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	hose->pci_mem_offset = EBONY_PCI_MEM_OFFSET;
+
+	pci_init_resource(&hose->io_resource,
+			EBONY_PCI_LOWER_IO,
+			EBONY_PCI_UPPER_IO,
+			IORESOURCE_IO,
+			"PCI host bridge");
+
+	pci_init_resource(&hose->mem_resources[0],
+			EBONY_PCI_LOWER_MEM,
+			EBONY_PCI_UPPER_MEM,
+			IORESOURCE_MEM,
+			"PCI host bridge");
+
+	hose->io_space.start = EBONY_PCI_LOWER_IO;
+	hose->io_space.end = EBONY_PCI_UPPER_IO;
+	hose->mem_space.start = EBONY_PCI_LOWER_MEM;
+	hose->mem_space.end = EBONY_PCI_UPPER_MEM;
+	isa_io_base =
+		(unsigned long)ioremap64(EBONY_PCI_IO_BASE, EBONY_PCI_IO_SIZE);
+	hose->io_base_virt = (void *)isa_io_base;
+
+	setup_indirect_pci(hose,
+			EBONY_PCI_CFGA_PLB32,
+			EBONY_PCI_CFGD_PLB32);
+	hose->set_cfg_type = 1;
+
+	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = ebony_map_irq;
+}
+
+TODC_ALLOC();
+
+static void __init
+ebony_early_serial_map(void)
+{
+	struct serial_struct serial_req;
+
+	/* Setup ioremapped serial port access */
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.line = 0;
+	serial_req.baud_base = BASE_BAUD;
+	serial_req.port = 0;
+	serial_req.irq = 0;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	serial_req.io_type = SERIAL_IO_MEM;
+	serial_req.iomem_base = ioremap64(PPC440GP_UART0_ADDR, 8);
+	serial_req.iomem_reg_shift = 0;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(0, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0) {
+		printk("Early serial init of port 0 failed\n");
+	}
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.port = 1;
+	serial_req.irq = 1; 
+	serial_req.iomem_base = ioremap64(PPC440GP_UART1_ADDR, 8);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(1, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0) {
+		printk("Early serial init of port 1 failed\n");
+	}
+}
+
+static void __init
+ebony_setup_arch(void)
+{
+	unsigned char * vpd_base;
+	struct ibm440gp_clocks clocks;
+	bd_t *bip = (bd_t *) __res;
+
+#if !defined(CONFIG_BDI_SWITCH)
+	/*
+	 * The Abatron BDI JTAG debugger does not tolerate others
+	 * mucking with the debug registers.
+	 */
+        mtspr(SPRN_DBCR0, (DBCR0_TDE | DBCR0_IDM));
+#endif
+
+	/* Retrieve MAC addresses */
+	vpd_base = ioremap64(EBONY_VPD_BASE, EBONY_VPD_SIZE);
+	memcpy(bip->bi_enetaddr[0],EBONY_NA0_ADDR(vpd_base),6);
+	memcpy(bip->bi_enetaddr[1],EBONY_NA1_ADDR(vpd_base),6);
+
+	/*
+	 * Determine various clocks.
+	 * To be completely correct we should get SysClk
+	 * from FPGA, because it can be changed by on-board switches
+	 * --ebs
+	 */
+	ibm440gp_get_clocks(&clocks, 33333333, 6 * 1843200);
+	bip->bi_opb_busfreq = clocks.opb;
+	
+	/* Use IIC in standard (100 kHz) mode */
+	bip->bi_iic_fast[0] = bip->bi_iic_fast[1] = 0;
+
+	/* Setup TODC access */
+	TODC_INIT(TODC_TYPE_DS1743,
+			0,
+			0,
+			ioremap64(EBONY_RTC_ADDR, EBONY_RTC_SIZE),
+			8);
+
+	/* init to some ~sane value until calibrate_delay() runs */
+        loops_per_jiffy = 50000000/HZ;
+
+	/* Setup PCI host bridge */
+	ebony_setup_hose();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = to_kdev_t(0x0100); /* /dev/ram */
+	else
+#endif
+#ifdef CONFIG_ROOT_NFS
+		ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs */
+#else
+		ROOT_DEV = to_kdev_t(0x0301); /* /dev/hda1 */
+#endif
+
+#ifdef CONFIG_VT
+	conswitchp = &dummy_con;
+#endif
+
+	ebony_early_serial_map();
+
+	ibm4xxPIC_InitSenses = ebony_IRQ_initsenses;
+	ibm4xxPIC_NumInitSenses = sizeof(ebony_IRQ_initsenses);
+
+	/* Identify the system */
+	printk("IBM Ebony port (MontaVista Software, Inc. (source@mvista.com))\n");
+}
+
+static void
+ebony_restart(char *cmd)
+{
+	local_irq_disable();
+	abort();
+}
+
+static void
+ebony_power_off(void)
+{
+	local_irq_disable();
+	for(;;);
+}
+
+static void
+ebony_halt(void)
+{
+	local_irq_disable();
+	for(;;);
+}
+
+/*
+ * Read the 440GP memory controller to get size of system memory.
+ */
+static unsigned long __init
+ebony_find_end_of_memory(void)
+{
+	u32 i, bank_config;
+	u32 mem_size = 0;
+
+	for (i=0; i<4; i++)
+	{
+		switch (i)
+		{
+			case 0:
+				mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B0CR);
+				break;
+			case 1:
+				mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B1CR);
+				break;
+			case 2:
+				mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B2CR);
+				break;
+			case 3:
+				mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B3CR);
+				break;
+		}
+
+		bank_config = mfdcr(DCRN_SDRAM0_CFGDATA);
+
+		if (!(bank_config & SDRAM_CONFIG_BANK_ENABLE))
+			continue;
+		switch (SDRAM_CONFIG_BANK_SIZE(bank_config))
+		{
+			case SDRAM_CONFIG_SIZE_8M:
+				mem_size += PPC44x_MEM_SIZE_8M;
+				break;
+			case SDRAM_CONFIG_SIZE_16M:
+				mem_size += PPC44x_MEM_SIZE_16M;
+				break;
+			case SDRAM_CONFIG_SIZE_32M:
+				mem_size += PPC44x_MEM_SIZE_32M;
+				break;
+			case SDRAM_CONFIG_SIZE_64M:
+				mem_size += PPC44x_MEM_SIZE_64M;
+				break;
+			case SDRAM_CONFIG_SIZE_128M:
+				mem_size += PPC44x_MEM_SIZE_128M;
+				break;
+			case SDRAM_CONFIG_SIZE_256M:
+				mem_size += PPC44x_MEM_SIZE_256M;
+				break;
+			case SDRAM_CONFIG_SIZE_512M:
+				mem_size += PPC44x_MEM_SIZE_512M;
+				break;
+		}
+	}
+	return mem_size;
+}
+
+static void __init
+ebony_init_irq(void)
+{
+	int i;
+
+	ppc4xx_pic_init();
+
+	for (i = 0; i < NR_IRQS; i++)
+		irq_desc[i].handler = ppc4xx_pic;
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4,
+	      unsigned long r5, unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	ppc_md.setup_arch = ebony_setup_arch;
+	ppc_md.show_cpuinfo = ebony_show_cpuinfo;
+	ppc_md.init_IRQ = ebony_init_irq;
+	ppc_md.get_irq = NULL;		/* Set in ppc4xx_pic_init() */
+
+	ppc_md.find_end_of_memory = ebony_find_end_of_memory;
+
+	ppc_md.restart = ebony_restart;
+	ppc_md.power_off = ebony_power_off;
+	ppc_md.halt = ebony_halt;
+
+	ppc_md.calibrate_decr = ebony_calibrate_decr;
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+#if defined(CONFIG_VT) 
+	ppc_md.kbd_setkeycode = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode = pckbd_getkeycode;
+	ppc_md.kbd_translate = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds = pckbd_leds;
+	ppc_md.kbd_init_hw = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#ifdef CONFIG_KGDB
+	ppc_md.early_serial_map = ebony_early_serial_map;
+#endif
+}
+
diff -Nru a/arch/ppc/platforms/ebony.h b/arch/ppc/platforms/ebony.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/ebony.h	Thu Aug 28 05:15:30 2003
@@ -0,0 +1,94 @@
+/*
+ * arch/ppc/platforms/ebony.h
+ *
+ * Ebony board definitions
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002 MontaVista Software 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_EBONY_H__
+#define __ASM_EBONY_H__
+
+#include <linux/config.h>
+#include <platforms/ibm440gp.h>
+
+/* F/W TLB mapping used in bootloader glue to reset EMAC */
+#define PPC44x_EMAC0_MR0	0xE0000800
+
+/* Macros to get at Ebony VPD info */
+#define EBONY_VPD_BASE		0x00000001fffffe00ULL
+#define EBONY_VPD_SIZE		0x24
+#define EBONY_NA0_OFFSET	0x0c
+#define EBONY_NA1_OFFSET	0x18
+#define EBONY_NA0_ADDR(base)	(base + EBONY_NA0_OFFSET)
+#define EBONY_NA1_ADDR(base)	(base + EBONY_NA1_OFFSET)
+
+/* Default clock rates for Rev. B and Rev. C silicon */
+#define EBONY_440GP_RB_SYSCLK	33000000
+#define EBONY_440GP_RC_SYSCLK	400000000
+
+/* RTC/NVRAM location */
+#define EBONY_RTC_ADDR		0x0000000148000000ULL
+#define EBONY_RTC_SIZE		0x2000
+
+/* Flash */
+#define EBONY_FPGA_ADDR		0x0000000148300000
+#define EBONY_BOOT_SMALL_FLASH(x)	(x & 0x20)
+#define EBONY_ONBRD_FLASH_EN(x)		(x & 0x02)
+#define EBONY_FLASH_SEL(x)		(x & 0x01)
+#define EBONY_SMALL_FLASH_LOW1	0x00000001ff800000
+#define EBONY_SMALL_FLASH_LOW2	0x00000001ff880000
+#define EBONY_SMALL_FLASH_HIGH1	0x00000001fff00000
+#define EBONY_SMALL_FLASH_HIGH2	0x00000001fff80000
+#define EBONY_SMALL_FLASH_SIZE	0x80000
+#define EBONY_LARGE_FLASH_LOW	0x00000001ff800000
+#define EBONY_LARGE_FLASH_HIGH	0x00000001ffc00000
+#define EBONY_LARGE_FLASH_SIZE	0x400000
+
+#define EBONY_SMALL_FLASH_BASE	0x00000001fff80000
+#define EBONY_LARGE_FLASH_BASE	0x00000001ff800000
+
+/*
+ * Serial port defines
+ */
+
+/* OpenBIOS defined UART mappings, used before early_serial_setup */
+#define UART0_IO_BASE	(u8 *) 0xE0000200
+#define UART1_IO_BASE	(u8 *) 0xE0000300
+
+#define BASE_BAUD	33000000/3/16
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM},
+
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(0)		\
+	STD_UART_OP(1)
+
+/* PCI support */
+#define EBONY_PCI_LOWER_IO	0x00000000
+#define EBONY_PCI_UPPER_IO	0x0000ffff
+#define EBONY_PCI_LOWER_MEM	0x80002000
+#define EBONY_PCI_UPPER_MEM	0xffffefff
+
+#define EBONY_PCI_CFGREGS_BASE	0x000000020ec00000
+#define EBONY_PCI_CFGA_PLB32	0x0ec00000
+#define EBONY_PCI_CFGD_PLB32	0x0ec00004
+
+#define EBONY_PCI_IO_BASE	0x0000000208000000ULL
+#define EBONY_PCI_IO_SIZE	0x00010000
+#define EBONY_PCI_MEM_OFFSET	0x00000000
+
+#endif				/* __ASM_EBONY_H__ */
+#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ibm440gp.c b/arch/ppc/platforms/ibm440gp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/ibm440gp.c	Fri Aug 29 03:37:49 2003
@@ -0,0 +1,129 @@
+/*
+ * arch/ppc/platforms/ibm440gp.c
+ *
+ * PPC440GP I/O descriptions
+ *
+ * Matt Porter <mporter@mvista.com>
+ * Copyright 2002-2003 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003 Zultys Technologies
+ *
+ * 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.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <platforms/ibm440gp.h>
+#include <asm/ocp.h>
+
+#if defined(EMAC_NUMS) && EMAC_NUMS > 0
+u32 emac_phy_map[EMAC_NUMS];
+EXPORT_SYMBOL(emac_phy_map);
+#endif
+
+static struct ocp_func_emac_data ibm440gp_emac0_def = {
+	.zmii_idx       = 0,            /* ZMII device index */
+	.zmii_mux       = 0,            /* ZMII input of this EMAC */
+	.mal_idx        = 0,            /* MAL device index */
+	.mal_rx_chan    = 0,            /* MAL rx channel number */
+	.mal_tx1_chan   = 0,            /* MAL tx channel 1 number */
+	.mal_tx2_chan   = 1,            /* MAL tx channel 2 number */
+	.wol_irq        = BL_MAC_WOL,   /* WOL interrupt number */
+	.mdio_idx       = -1,           /* No shared MDIO */
+};
+
+static struct ocp_func_emac_data ibm440gp_emac1_def = {
+	.zmii_idx       = 0,            /* ZMII device index */
+	.zmii_mux       = 1,            /* ZMII input of this EMAC */
+	.mal_idx        = 0,            /* MAL device index */
+	.mal_rx_chan    = 1,            /* MAL rx channel number */
+	.mal_tx1_chan   = 2,            /* MAL tx channel 1 number */
+	.mal_tx2_chan   = 3,            /* MAL tx channel 2 number */
+	.wol_irq        = BL_MAC_WOL1,   /* WOL interrupt number */
+	.mdio_idx       = -1,           /* No shared MDIO */
+};
+
+static struct ocp_func_mal_data ibm440gp_mal0_def = {
+	.num_tx_chans   = 2*EMAC_NUMS,  /* Number of TX channels */
+	.num_rx_chans   = EMAC_NUMS,    /* Number of RX channels */
+};
+
+struct ocp_def core_ocp[] __initdata = {
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_OPB,
+	  .index	= 0,
+	  .paddr	= PPC440GP_OPB_BASE_START,
+	  .irq		= OCP_IRQ_NA,
+	  .pm		= OCP_CPM_NA,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_16550,
+	  .index	= 0,
+	  .paddr	= PPC440GP_UART0_ADDR,
+	  .irq		= UART0_INT,
+	  .pm		= IBM_CPM_UART0,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_16550,
+	  .index	= 1,
+	  .paddr	= PPC440GP_UART1_ADDR,
+	  .irq		= UART1_INT,
+	  .pm		= IBM_CPM_UART1,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_IIC,
+	  .index	= 0,
+	  .paddr	= PPC440GP_IIC0_ADDR,
+	  .irq		= IIC0_IRQ,
+	  .pm		= IBM_CPM_IIC0,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_IIC,
+	  .index	= 1,
+	  .paddr	= PPC440GP_IIC1_ADDR,
+	  .irq		= IIC1_IRQ,
+	  .pm		= IBM_CPM_IIC1,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_GPIO,
+	  .index	= 0,
+	  .paddr	= PPC440GP_GPIO0_ADDR,
+	  .irq		= OCP_IRQ_NA,
+	  .pm		= IBM_CPM_GPIO0,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_MAL,
+	  .paddr	= OCP_PADDR_NA,
+	  .irq		= OCP_IRQ_NA,
+	  .pm		= OCP_CPM_NA,
+	  .additions	= &ibm440gp_mal0_def,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_EMAC,
+	  .index	= 0,
+	  .paddr	= PPC440GP_EMAC0_ADDR,
+	  .irq		= BL_MAC_ETH0,
+	  .pm		= OCP_CPM_NA,
+	  .additions	= &ibm440gp_emac0_def,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_EMAC,
+	  .index	= 1,
+	  .paddr	= PPC440GP_EMAC1_ADDR,
+	  .irq		= BL_MAC_ETH1,
+	  .pm		= OCP_CPM_NA,
+	  .additions	= &ibm440gp_emac1_def,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_ZMII,
+	  .paddr	= PPC440GP_ZMII_ADDR,
+	  .irq		= OCP_IRQ_NA,
+	  .pm		= OCP_CPM_NA,
+	},
+	{ .vendor	= OCP_VENDOR_INVALID
+	}
+};
diff -Nru a/arch/ppc/platforms/ibm440gp.h b/arch/ppc/platforms/ibm440gp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/ibm440gp.h	Fri Aug 29 03:37:49 2003
@@ -0,0 +1,103 @@
+/*
+ * arch/ppc/platforms/ibm440gp.h
+ *
+ * PPC440GP definitions
+ *
+ * Roland Dreier <roland@digitalvampire.org>
+ *
+ * Copyright 2002 Roland Dreier
+ *
+ * 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 file contains code that was originally in the files ibm44x.h
+ * and ebony.h, which were written by Matt Porter of MontaVista Software Inc.
+ */
+
+#ifdef __KERNEL__
+#ifndef __PPC_PLATFORMS_IBM440GP_H
+#define __PPC_PLATFORMS_IBM440GP_H
+
+#include <linux/config.h>
+
+#include <asm/ibm4xx.h>
+
+#define EMAC_NUMS		2
+#define UART_NUMS		2
+#define ZMII_NUMS		1
+#define IIC_NUMS		2
+#define IIC0_IRQ		2
+#define IIC1_IRQ		3
+#define GPIO_NUMS		1
+
+/* UART location */
+#define PPC440GP_UART0_ADDR	0x0000000140000200ULL
+#define PPC440GP_UART1_ADDR	0x0000000140000300ULL
+#define UART0_INT		0
+#define UART1_INT		1
+
+/* EMAC location */
+#define PPC440GP_EMAC0_ADDR	0x0000000140000800ULL
+#define PPC440GP_EMAC1_ADDR	0x0000000140000900ULL
+#define PPC440GP_EMAC_SIZE	0x70
+
+/* EMAC IRQ's */
+#define BL_MAC_WOL	61	/* WOL */
+#define BL_MAC_WOL1	63	/* WOL */
+#define BL_MAL_SERR	32	/* MAL SERR */
+#define BL_MAL_TXDE	33	/* MAL TXDE */
+#define BL_MAL_RXDE	34	/* MAL RXDE */
+#define BL_MAL_TXEOB	10	/* MAL TX EOB */
+#define BL_MAL_RXEOB	11	/* MAL RX EOB */
+#define BL_MAC_ETH0	60	/* MAC */
+#define BL_MAC_ETH1	62	/* MAC */
+
+/* ZMII location */
+#define PPC440GP_ZMII_ADDR	0x0000000140000780ULL
+#define PPC440GP_ZMII_SIZE	0x0c
+
+/* I2C location */
+#define PPC440GP_IIC0_ADDR	0x40000400
+#define PPC440GP_IIC1_ADDR	0x40000500
+
+/* GPIO location */
+#define PPC440GP_GPIO0_ADDR	0x0000000140000700ULL
+
+/* Clock and Power Management */
+#define IBM_CPM_IIC0		0x80000000	/* IIC interface */
+#define IBM_CPM_IIC1		0x40000000	/* IIC interface */
+#define IBM_CPM_PCI		0x20000000	/* PCI bridge */
+#define IBM_CPM_CPU		0x02000000	/* processor core */
+#define IBM_CPM_DMA		0x01000000	/* DMA controller */
+#define IBM_CPM_BGO		0x00800000	/* PLB to OPB bus arbiter */
+#define IBM_CPM_BGI		0x00400000	/* OPB to PLB bridge */
+#define IBM_CPM_EBC		0x00200000	/* External Bux Controller */
+#define IBM_CPM_EBM		0x00100000	/* Ext Bus Master Interface */
+#define IBM_CPM_DMC		0x00080000	/* SDRAM peripheral controller */
+#define IBM_CPM_PLB		0x00040000	/* PLB bus arbiter */
+#define IBM_CPM_SRAM		0x00020000	/* SRAM memory controller */
+#define IBM_CPM_PPM		0x00002000	/* PLB Performance Monitor */
+#define IBM_CPM_UIC1		0x00001000	/* Universal Interrupt Controller */
+#define IBM_CPM_GPIO0		0x00000800	/* General Purpose IO (??) */
+#define IBM_CPM_GPT		0x00000400	/* General Purpose Timers  */
+#define IBM_CPM_UART0		0x00000200	/* serial port 0 */
+#define IBM_CPM_UART1		0x00000100	/* serial port 1 */
+#define IBM_CPM_UIC0		0x00000080	/* Universal Interrupt Controller */
+#define IBM_CPM_TMRCLK		0x00000040	/* CPU timers */
+
+#define DFLT_IBM4xx_PM		~(IBM_CPM_UIC | IBM_CPM_UIC1 | IBM_CPM_CPU \
+				| IBM_CPM_EBC | IBM_CPM_SRAM | IBM_CPM_BGO \
+				| IBM_CPM_EBM | IBM_CPM_PLB | IBM_CPM_OPB \
+				| IBM_CPM_TMRCLK | IBM_CPM_DMA | IBM_CPM_PCI)
+
+#define PPC440GP_OPB_BASE_START	0x0000000140000000ULL
+
+/*
+ * Serial port defines
+ */
+#define RS_TABLE_SIZE	2
+
+#endif /* __PPC_PLATFORMS_IBM440GP_H */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ibm440gx.c b/arch/ppc/platforms/ibm440gx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/ibm440gx.c	Thu Aug 28 05:19:10 2003
@@ -0,0 +1,129 @@
+/*
+ * arch/ppc/platforms/4xx/ibm440gx.c
+ *
+ * PPC440GX I/O descriptions
+ *
+ * Matt Porter <mporter@mvista.com>
+ * Copyright 2002-2003 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003 Zultys Technologies
+ *
+ * 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.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <platforms/ibm440gx.h>
+#include <asm/ocp.h>
+
+#if defined(EMAC_NUMS) && EMAC_NUMS > 0
+u32 emac_phy_map[EMAC_NUMS];
+EXPORT_SYMBOL(emac_phy_map);
+#endif
+
+static struct ocp_func_emac_data ibm440gx_emac0_def = {
+	.zmii_idx       = 0,            /* ZMII device index */
+	.zmii_mux       = 0,            /* ZMII input of this EMAC */
+	.mal_idx        = 0,            /* MAL device index */
+	.mal_rx_chan    = 0,            /* MAL rx channel number */
+	.mal_tx1_chan   = 0,            /* MAL tx channel 1 number */
+	.mal_tx2_chan   = -1,           /* MAL tx channel 2 number */
+	.wol_irq        = BL_MAC_WOL,   /* WOL interrupt number */
+	.mdio_idx       = -1,           /* No shared MDIO */
+};
+
+static struct ocp_func_emac_data ibm440gx_emac1_def = {
+	.zmii_idx       = 0,            /* ZMII device index */
+	.zmii_mux       = 1,            /* ZMII input of this EMAC */
+	.mal_idx        = 0,            /* MAL device index */
+	.mal_rx_chan    = 1,            /* MAL rx channel number */
+	.mal_tx1_chan   = 1,            /* MAL tx channel 1 number */
+	.mal_tx2_chan   = -1,           /* MAL tx channel 2 number */
+	.wol_irq        = BL_MAC_WOL1,   /* WOL interrupt number */
+	.mdio_idx       = -1,           /* No shared MDIO */
+};
+
+static struct ocp_func_mal_data ibm440gx_mal0_def = {
+	.num_tx_chans   = 2*EMAC_NUMS,  /* Number of TX channels */
+	.num_rx_chans   = EMAC_NUMS,    /* Number of RX channels */
+};
+
+struct ocp_def core_ocp[] __initdata = {
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_OPB,
+	  .index	= 0,
+	  .paddr	= PPC440GX_OPB_BASE_START,
+	  .irq		= OCP_IRQ_NA,
+	  .pm		= OCP_CPM_NA,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_16550,
+	  .index	= 0,
+	  .paddr	= PPC440GX_UART0_ADDR,
+	  .irq		= UART0_INT,
+	  .pm		= IBM_CPM_UART0,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_16550,
+	  .index	= 1,
+	  .paddr	= PPC440GX_UART1_ADDR,
+	  .irq		= UART1_INT,
+	  .pm		= IBM_CPM_UART1,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_IIC,
+	  .index	= 0,
+	  .paddr	= PPC440GX_IIC0_ADDR,
+	  .irq		= IIC0_IRQ,
+	  .pm		= IBM_CPM_IIC0,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_IIC,
+	  .index	= 1,
+	  .paddr	= PPC440GX_IIC1_ADDR,
+	  .irq		= IIC1_IRQ,
+	  .pm		= IBM_CPM_IIC1,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_GPIO,
+	  .index	= 0,
+	  .paddr	= PPC440GX_GPIO0_ADDR,
+	  .irq		= OCP_IRQ_NA,
+	  .pm		= IBM_CPM_GPIO0,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_MAL,
+	  .paddr	= OCP_PADDR_NA,
+	  .irq		= OCP_IRQ_NA,
+	  .pm		= OCP_CPM_NA,
+	  .additions	= &ibm440gx_mal0_def,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_EMAC,
+	  .index	= 0,
+	  .paddr	= PPC440GX_EMAC0_ADDR,
+	  .irq		= BL_MAC_ETH0,
+	  .pm		= OCP_CPM_NA,
+	  .additions	= &ibm440gx_emac0_def,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_EMAC,
+	  .index	= 1,
+	  .paddr	= PPC440GX_EMAC1_ADDR,
+	  .irq		= BL_MAC_ETH1,
+	  .pm		= OCP_CPM_NA,
+	  .additions	= &ibm440gx_emac1_def,
+	},
+	{ .vendor	= OCP_VENDOR_IBM,
+	  .function	= OCP_FUNC_ZMII,
+	  .paddr	= PPC440GX_ZMII_ADDR,
+	  .irq		= OCP_IRQ_NA,
+	  .pm		= OCP_CPM_NA,
+	},
+	{ .vendor	= OCP_VENDOR_INVALID
+	}
+};
diff -Nru a/arch/ppc/platforms/ibm440gx.h b/arch/ppc/platforms/ibm440gx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/ibm440gx.h	Thu Aug 28 05:19:10 2003
@@ -0,0 +1,123 @@
+/*
+ * arch/ppc/platforms/ibm440gx.h
+ *
+ * PPC440GX definitions
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002 Roland Dreier
+ * Copyright 2003 MontaVista Software, 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.
+ * 
+ */
+
+#ifdef __KERNEL__
+#ifndef __PPC_PLATFORMS_IBM440GX_H
+#define __PPC_PLATFORMS_IBM440GX_H
+
+#include <linux/config.h>
+
+#include <asm/ibm44x.h>
+
+/* UART */
+#define PPC440GX_UART0_ADDR	0x0000000140000200
+#define PPC440GX_UART1_ADDR	0x0000000140000300
+#define UART0_INT		0
+#define UART1_INT		1
+
+/* EMAC */
+#define PPC440GX_EMAC0_ADDR	0x0000000140000800
+#define PPC440GX_EMAC1_ADDR	0x0000000140000900
+#define PPC440GX_EMAC2_ADDR	0x0000000140000C00
+#define PPC440GX_EMAC3_ADDR	0x0000000140000E00
+#define PPC440GX_EMAC_SIZE	0xFC
+#define EMAC_NUMS               2
+#define BL_MAC_WOL	61	/* WOL */
+#define BL_MAC_WOL1	63	/* WOL */
+#define BL_MAC_WOL2	65	/* WOL */
+#define BL_MAC_WOL3	67	/* WOL */
+#define BL_MAL_SERR	32	/* MAL SERR */
+#define BL_MAL_TXDE	33	/* MAL TXDE */
+#define BL_MAL_RXDE	34	/* MAL RXDE */
+#define BL_MAL_TXEOB	10	/* MAL TX EOB */
+#define BL_MAL_RXEOB	11	/* MAL RX EOB */
+#define BL_MAC_ETH0	60	/* MAC */
+#define BL_MAC_ETH1	62	/* MAC */
+#define BL_MAC_ETH2	64	/* MAC */
+#define BL_MAC_ETH3	66	/* MAC */
+#define BL_TAH0		68	/* TAH 0 */
+#define BL_TAH1		69	/* TAH 1 */
+
+/* TAH */
+#define PPC440GX_TAH0_ADDR	0x0000000140000B00
+#define PPC440GX_TAH1_ADDR	0x0000000140000D00
+#define PPC440GX_TAH_SIZE	0xFC
+
+/* ZMII */
+#define PPC440GX_ZMII_ADDR	0x0000000140000780
+#define PPC440GX_ZMII_SIZE	0x0c
+
+/* RGMII */
+#define PPC440GX_RGMII_ADDR	0x0000000140000790
+#define PPC440GX_RGMII_SIZE	0x0c
+
+/* IIC  */
+#define PPC440GX_IIC0_ADDR	0x40000400
+#define PPC440GX_IIC1_ADDR	0x40000500
+#define IIC0_IRQ		2
+#define IIC1_IRQ		3
+
+/* GPIO */
+#define PPC440GX_GPIO0_ADDR	0x0000000140000700
+
+/* Clock and Power Management */
+#define IBM_CPM_IIC0		0x80000000	/* IIC interface */
+#define IBM_CPM_IIC1		0x40000000	/* IIC interface */
+#define IBM_CPM_PCI		0x20000000	/* PCI bridge */
+#define IBM_CPM_RGMII		0x10000000	/* RGMII */
+#define IBM_CPM_TAHOE0		0x08000000	/* TAHOE 0 */
+#define IBM_CPM_TAHOE1		0x04000000	/* TAHOE 1 */
+#define IBM_CPM_CPU		    0x02000000	/* processor core */
+#define IBM_CPM_DMA		    0x01000000	/* DMA controller */
+#define IBM_CPM_BGO		    0x00800000	/* PLB to OPB bus arbiter */
+#define IBM_CPM_BGI		    0x00400000	/* OPB to PLB bridge */
+#define IBM_CPM_EBC		    0x00200000	/* External Bux Controller */
+#define IBM_CPM_EBM		    0x00100000	/* Ext Bus Master Interface */
+#define IBM_CPM_DMC		    0x00080000	/* SDRAM peripheral controller */
+#define IBM_CPM_PLB		    0x00040000	/* PLB bus arbiter */
+#define IBM_CPM_SRAM		0x00020000	/* SRAM memory controller */
+#define IBM_CPM_PPM		    0x00002000	/* PLB Performance Monitor */
+#define IBM_CPM_UIC1		0x00001000	/* Universal Interrupt Controller */
+#define IBM_CPM_GPIO0		0x00000800	/* General Purpose IO (??) */
+#define IBM_CPM_GPT		    0x00000400	/* General Purpose Timers  */
+#define IBM_CPM_UART0		0x00000200	/* serial port 0 */
+#define IBM_CPM_UART1		0x00000100	/* serial port 1 */
+#define IBM_CPM_UIC0		0x00000080	/* Universal Interrupt Controller */
+#define IBM_CPM_TMRCLK		0x00000040	/* CPU timers */
+#define IBM_CPM_EMAC0  		0x00000020	/* EMAC 0     */
+#define IBM_CPM_EMAC1  		0x00000010	/* EMAC 1     */
+#define IBM_CPM_EMAC2  		0x00000008	/* EMAC 2     */
+#define IBM_CPM_EMAC3  		0x00000004	/* EMAC 3     */
+
+#define DFLT_IBM4xx_PM		~(IBM_CPM_UIC | IBM_CPM_UIC1 | IBM_CPM_CPU \
+				| IBM_CPM_EBC | IBM_CPM_SRAM | IBM_CPM_BGO \
+				| IBM_CPM_EBM | IBM_CPM_PLB | IBM_CPM_OPB \
+				| IBM_CPM_TMRCLK | IBM_CPM_DMA | IBM_CPM_PCI \
+				| IBM_CPM_TAHOE0 | IBM_CPM_TAHOE1 \
+				| IBM_CPM_EMAC0 | IBM_CPM_EMAC1 \
+			  	| IBM_CPM_EMAC2 | IBM_CPM_EMAC3 )	
+
+/* OPB */
+#define PPC440GX_OPB_BASE_START	0x0000000140000000
+
+/*
+ * Serial port defines
+ */
+#define RS_TABLE_SIZE	2
+
+#endif /* __PPC_PLATFORMS_IBM440GX_H */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ocotea.c b/arch/ppc/platforms/ocotea.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/ocotea.c	Thu Aug 28 05:19:35 2003
@@ -0,0 +1,441 @@
+/*
+ * arch/ppc/platforms/ocotea.c
+ *
+ * Ocotea board specific routines
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2003 MontaVista Software 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/ppc4xx_pic.h>
+
+extern void abort(void);
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct serial_struct *);
+
+/* Global Variables */
+unsigned char __res[sizeof (bd_t)];
+
+static void __init
+ocotea_calibrate_decr(void)
+{
+	unsigned int freq;
+
+	freq = OCOTEA_SYSCLK;
+	
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+	/* Set the time base to zero */
+	mtspr(SPRN_TBWL, 0);
+	mtspr(SPRN_TBWU, 0);
+
+	/* Clear any pending timer interrupts */
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+	/* Enable decrementer interrupt */
+	mtspr(SPRN_TCR, TCR_DIE);
+}
+
+static int
+ocotea_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "vendor\t\t: IBM\n");
+	seq_printf(m, "machine\t\t: PPC440GX EVB (Ocotea)\n");
+
+	return 0;
+}
+static inline int
+ocotea_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	/*
+	 *	PCI IDSEL/INTPIN->INTLINE 
+	 * 	   A   B   C   D
+	 */
+	{
+		{ 23, 23, 23, 23 },	/* IDSEL 1 - PCI Slot 0 */
+		{ 24, 24, 24, 24 },	/* IDSEL 2 - PCI Slot 1 */
+		{ 25, 25, 25, 25 },	/* IDSEL 3 - PCI Slot 2 */
+		{ 26, 26, 26, 26 },	/* IDSEL 4 - PCI Slot 3 */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+#define PCIX_READW(offset) \
+	(readw((u32)pcix_reg_base+offset))
+
+#define PCIX_WRITEW(value, offset) \
+	(writew(value, (u32)pcix_reg_base+offset))
+
+#define PCIX_WRITEL(value, offset) \
+	(writel(value, (u32)pcix_reg_base+offset))
+
+/*
+ * FIXME: This is only here to "make it work".  This will move
+ * to a ibm_pcix.c which will contain a generic IBM PCIX bridge
+ * configuration library. -Matt
+ */
+static void __init
+ocotea_setup_pcix(void)
+{
+	void *pcix_reg_base;
+
+	pcix_reg_base = ioremap64(PCIX0_REG_BASE, PCIX0_REG_SIZE);
+
+	/* Enable PCIX0 I/O, Mem, and Busmaster cycles */
+	PCIX_WRITEW(PCIX_READW(PCIX0_COMMAND) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, PCIX0_COMMAND);
+
+	/* Disable all windows */
+	PCIX_WRITEL(0, PCIX0_POM0SA);
+	PCIX_WRITEL(0, PCIX0_POM1SA);
+	PCIX_WRITEL(0, PCIX0_POM2SA);
+	PCIX_WRITEL(0, PCIX0_PIM0SA);
+	PCIX_WRITEL(0, PCIX0_PIM0SAH);
+	PCIX_WRITEL(0, PCIX0_PIM1SA);
+	PCIX_WRITEL(0, PCIX0_PIM2SA);
+	PCIX_WRITEL(0, PCIX0_PIM2SAH);
+	
+	/* Setup 2GB PLB->PCI outbound mem window (3_8000_0000->0_8000_0000) */
+	PCIX_WRITEL(0x00000003, PCIX0_POM0LAH);
+	PCIX_WRITEL(0x80000000, PCIX0_POM0LAL);
+	PCIX_WRITEL(0x00000000, PCIX0_POM0PCIAH);
+	PCIX_WRITEL(0x80000000, PCIX0_POM0PCIAL);
+	PCIX_WRITEL(0x80000001, PCIX0_POM0SA);
+
+	/* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
+	PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
+	PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
+	PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+
+	eieio();
+}
+
+static void __init
+ocotea_setup_hose(void)
+{
+	struct pci_controller *hose;
+
+	/* Configure windows on the PCI-X host bridge */
+	ocotea_setup_pcix();
+
+	hose = pcibios_alloc_controller();
+
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	hose->pci_mem_offset = OCOTEA_PCI_MEM_OFFSET;
+
+	pci_init_resource(&hose->io_resource,
+			OCOTEA_PCI_LOWER_IO,
+			OCOTEA_PCI_UPPER_IO,
+			IORESOURCE_IO,
+			"PCI host bridge");
+
+	pci_init_resource(&hose->mem_resources[0],
+			OCOTEA_PCI_LOWER_MEM,
+			OCOTEA_PCI_UPPER_MEM,
+			IORESOURCE_MEM,
+			"PCI host bridge");
+
+	hose->io_space.start = OCOTEA_PCI_LOWER_IO;
+	hose->io_space.end = OCOTEA_PCI_UPPER_IO;
+	hose->mem_space.start = OCOTEA_PCI_LOWER_MEM;
+	hose->mem_space.end = OCOTEA_PCI_UPPER_MEM;
+	isa_io_base =
+		(unsigned long)ioremap64(OCOTEA_PCI_IO_BASE, OCOTEA_PCI_IO_SIZE);
+	hose->io_base_virt = (void *)isa_io_base;
+
+	setup_indirect_pci(hose,
+			OCOTEA_PCI_CFGA_PLB32,
+			OCOTEA_PCI_CFGD_PLB32);
+	hose->set_cfg_type = 1;
+
+	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = ocotea_map_irq;
+}
+
+
+TODC_ALLOC();
+
+static void __init
+ocotea_early_serial_map(void)
+{
+	struct serial_struct serial_req;
+
+	/* Setup ioremapped serial port access */
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.line = 0;
+	serial_req.baud_base = BASE_BAUD;
+	serial_req.port = 0;
+	serial_req.irq = 0;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	serial_req.io_type = SERIAL_IO_MEM;
+	serial_req.iomem_base = ioremap64(PPC440GX_UART0_ADDR, 8);
+	serial_req.iomem_reg_shift = 0;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(0, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0) {
+		printk("Early serial init of port 0 failed\n");
+	}
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.port = 1;
+	serial_req.irq = 1; 
+	serial_req.iomem_base = ioremap64(PPC440GX_UART1_ADDR, 8);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(1, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0) {
+		printk("Early serial init of port 1 failed\n");
+	}
+}
+
+static void __init
+ocotea_setup_arch(void)
+{
+	unsigned char *addr;
+	unsigned long long mac64;
+	bd_t *bip = (bd_t *) __res;
+
+	/* Retrieve MAC addresses from flash */
+	addr = ioremap64(OCOTEA_MAC_BASE, OCOTEA_MAC_SIZE);
+	mac64 = simple_strtoull(addr, 0, 16);
+	memcpy(bip->bi_enetaddr[0], (char *)&mac64+2, 6);
+	mac64 = simple_strtoull(addr+OCOTEA_MAC1_OFFSET, 0, 16);
+	memcpy(bip->bi_enetaddr[1], (char *)&mac64+2, 6);
+	iounmap(addr);
+
+	/* Set EMAC PHY map to not probe address 0x00 */
+	emac_phy_map[0] = 0x00000001;
+	emac_phy_map[1] = 0x00000001;
+
+#if !defined(CONFIG_BDI_SWITCH)
+	/*
+	 * The Abatron BDI JTAG debugger does not tolerate others
+	 * mucking with the debug registers.
+	 */
+        mtspr(SPRN_DBCR0, (DBCR0_TDE | DBCR0_IDM));
+#endif
+
+	/* Setup TODC access */
+	TODC_INIT(TODC_TYPE_DS1743,
+			0,
+			0,
+			ioremap64(OCOTEA_RTC_ADDR, OCOTEA_RTC_SIZE),
+			8);
+
+	/* init to some ~sane value until calibrate_delay() runs */
+        loops_per_jiffy = 50000000/HZ;
+
+	/* Setup PCI host bridge */
+	ocotea_setup_hose();
+	
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = to_kdev_t(0x0100); /* /dev/ram */
+	else
+#endif
+#ifdef CONFIG_ROOT_NFS
+		ROOT_DEV = to_kdev_t(0x00ff); /* /dev/nfs */
+#else
+		ROOT_DEV = to_kdev_t(0x0301); /* /dev/hda1 */
+#endif
+
+#ifdef CONFIG_VT
+	conswitchp = &dummy_con;
+#endif
+
+	ocotea_early_serial_map();
+
+	/* Identify the system */
+	printk("IBM Ocotea port (MontaVista Software, Inc. <source@mvista.com>)\n");
+}
+
+static void
+ocotea_restart(char *cmd)
+{
+	local_irq_disable();
+	abort();
+}
+
+static void
+ocotea_power_off(void)
+{
+	local_irq_disable();
+	for(;;);
+}
+
+static void
+ocotea_halt(void)
+{
+	local_irq_disable();
+	for(;;);
+}
+
+/*
+ * Read the 440GX memory controller to get size of system memory.
+ */
+static unsigned long __init
+ocotea_find_end_of_memory(void)
+{
+	u32 i, bank_config;
+	u32 mem_size = 0;
+
+	for (i=0; i<4; i++)
+	{
+		switch (i)
+		{
+			case 0:
+				mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B0CR);
+				break;
+			case 1:
+				mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B1CR);
+				break;
+			case 2:
+				mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B2CR);
+				break;
+			case 3:
+				mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B3CR);
+				break;
+		}
+
+		bank_config = mfdcr(DCRN_SDRAM0_CFGDATA);
+
+		if (!(bank_config & SDRAM_CONFIG_BANK_ENABLE))
+			continue;
+		switch (SDRAM_CONFIG_BANK_SIZE(bank_config))
+		{
+			case SDRAM_CONFIG_SIZE_8M:
+				mem_size += PPC44x_MEM_SIZE_8M;
+				break;
+			case SDRAM_CONFIG_SIZE_16M:
+				mem_size += PPC44x_MEM_SIZE_16M;
+				break;
+			case SDRAM_CONFIG_SIZE_32M:
+				mem_size += PPC44x_MEM_SIZE_32M;
+				break;
+			case SDRAM_CONFIG_SIZE_64M:
+				mem_size += PPC44x_MEM_SIZE_64M;
+				break;
+			case SDRAM_CONFIG_SIZE_128M:
+				mem_size += PPC44x_MEM_SIZE_128M;
+				break;
+			case SDRAM_CONFIG_SIZE_256M:
+				mem_size += PPC44x_MEM_SIZE_256M;
+				break;
+			case SDRAM_CONFIG_SIZE_512M:
+				mem_size += PPC44x_MEM_SIZE_512M;
+				break;
+		}
+	}
+	return mem_size;
+}
+
+static void __init
+ocotea_init_irq(void)
+{
+	int i;
+
+	/* Enable PPC440GP interrupt compatibility mode */
+	SDR_WRITE(DCRN_SDR_MFR,SDR_READ(DCRN_SDR_MFR) | DCRN_SDR_MFR_PCM);
+
+	ppc4xx_pic_init();
+
+	for (i = 0; i < NR_IRQS; i++)
+		irq_desc[i].handler = ppc4xx_pic;
+}
+
+void __init platform_init(unsigned long r3, unsigned long r4,
+		unsigned long r5, unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	ppc_md.setup_arch = ocotea_setup_arch;
+	ppc_md.show_cpuinfo = ocotea_show_cpuinfo;
+	ppc_md.init_IRQ = ocotea_init_irq;
+	ppc_md.get_irq = NULL;		/* Set in ppc4xx_pic_init() */
+
+	ppc_md.find_end_of_memory = ocotea_find_end_of_memory;
+
+	ppc_md.restart = ocotea_restart;
+	ppc_md.power_off = ocotea_power_off;
+	ppc_md.halt = ocotea_halt;
+
+	ppc_md.calibrate_decr = ocotea_calibrate_decr;
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+#if defined(CONFIG_VT) 
+	ppc_md.kbd_setkeycode = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode = pckbd_getkeycode;
+	ppc_md.kbd_translate = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds = pckbd_leds;
+	ppc_md.kbd_init_hw = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#ifdef CONFIG_KGDB
+	ppc_md.early_serial_map = ocotea_early_serial_map;
+#endif
+}
diff -Nru a/arch/ppc/platforms/ocotea.h b/arch/ppc/platforms/ocotea.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/ocotea.h	Fri Aug 29 03:37:49 2003
@@ -0,0 +1,84 @@
+/*
+ * arch/ppc/platforms/ocotea.h
+ *
+ * Ocotea board definitions
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2003 MontaVista Software 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.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_OCOTEA_H__
+#define __ASM_OCOTEA_H__
+
+#include <linux/config.h>
+#include <platforms/ibm440gx.h>
+
+/* F/W TLB mapping used in bootloader glue to reset EMAC */
+#define PPC44x_EMAC0_MR0	0xE0000800
+
+/* Location of MAC addresses in firmware */
+#define OCOTEA_MAC_BASE		(OCOTEA_SMALL_FLASH_HIGH+0xc0500)
+#define OCOTEA_MAC_SIZE		0x200
+#define OCOTEA_MAC1_OFFSET	0x100
+
+/* Default clock rate */
+#define OCOTEA_SYSCLK		25000000
+
+/* RTC/NVRAM location */
+#define OCOTEA_RTC_ADDR		0x0000000148000000ULL
+#define OCOTEA_RTC_SIZE		0x2000
+
+/* Flash */
+#define OCOTEA_FPGA_ADDR		0x0000000148300000ULL
+#define OCOTEA_BOOT_LARGE_FLASH(x)	(x & 0x40)
+#define OCOTEA_SMALL_FLASH_LOW		0x00000001ff900000ULL
+#define OCOTEA_SMALL_FLASH_HIGH		0x00000001fff00000ULL
+#define OCOTEA_SMALL_FLASH_SIZE		0x100000
+#define OCOTEA_LARGE_FLASH_LOW		0x00000001ff800000ULL
+#define OCOTEA_LARGE_FLASH_HIGH		0x00000001ffc00000ULL
+#define OCOTEA_LARGE_FLASH_SIZE		0x400000
+
+/*
+ * Serial port defines
+ */
+#define RS_TABLE_SIZE	2
+
+/* OpenBIOS defined UART mappings, used before early_serial_setup */
+#define UART0_IO_BASE	(u8 *) 0xE0000200
+#define UART1_IO_BASE	(u8 *) 0xE0000300
+
+#define BASE_BAUD	11059200/16
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM},
+
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(0)		\
+	STD_UART_OP(1)
+
+/* PCI support */
+#define OCOTEA_PCI_LOWER_IO	0x00000000
+#define OCOTEA_PCI_UPPER_IO	0x0000ffff
+#define OCOTEA_PCI_LOWER_MEM	0x80000000
+#define OCOTEA_PCI_UPPER_MEM	0xffffefff
+
+#define OCOTEA_PCI_CFGREGS_BASE	0x000000020ec00000ULL
+#define OCOTEA_PCI_CFGA_PLB32	0x0ec00000
+#define OCOTEA_PCI_CFGD_PLB32	0x0ec00004
+
+#define OCOTEA_PCI_IO_BASE	0x0000000208000000ULL
+#define OCOTEA_PCI_IO_SIZE	0x00010000
+#define OCOTEA_PCI_MEM_OFFSET	0x00000000
+
+#endif				/* __ASM_OCOTEA_H__ */
+#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc64/config.in b/arch/ppc64/config.in
--- a/arch/ppc64/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/ppc64/config.in	Fri Aug 29 16:12:33 2003
@@ -29,6 +29,7 @@
 bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_SMP" = "y" ]; then
   bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
+  int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
   if [ "$CONFIG_PPC_PSERIES" = "y" ]; then
     bool '  Hardware multithreading' CONFIG_HMT
   fi
@@ -262,4 +263,7 @@
    dep_bool '  LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP
    dep_bool '  LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
diff -Nru a/arch/ppc64/defconfig b/arch/ppc64/defconfig
--- a/arch/ppc64/defconfig	Tue Jun 17 13:32:15 2003
+++ b/arch/ppc64/defconfig	Wed Jun 19 10:26:35 2002
@@ -22,6 +22,7 @@
 CONFIG_PPC_PSERIES=y
 # CONFIG_PPC_ISERIES is not set
 CONFIG_SMP=y
+CONFIG_NR_CPUS=32
 CONFIG_IRQ_ALL_CPUS=y
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
diff -Nru a/arch/s390/config.in b/arch/s390/config.in
--- a/arch/s390/config.in	Mon Jul  7 08:05:42 2003
+++ b/arch/s390/config.in	Fri Aug 29 16:12:42 2003
@@ -32,6 +32,9 @@
 comment 'Processor type and features'
 bool 'Symmetric multi-processing support' CONFIG_SMP
 bool 'IEEE FPU emulation' CONFIG_MATHEMU
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
 endmenu
 
 mainmenu_option next_comment
@@ -77,6 +80,9 @@
 #  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
 #fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
 
 source crypto/Config.in
diff -Nru a/arch/s390/defconfig b/arch/s390/defconfig
--- a/arch/s390/defconfig	Fri Jun 27 04:39:06 2003
+++ b/arch/s390/defconfig	Wed Jun 19 10:26:35 2002
@@ -27,6 +27,7 @@
 #
 CONFIG_SMP=y
 CONFIG_MATHEMU=y
+CONFIG_NR_CPUS=32
 
 #
 # General setup
diff -Nru a/arch/s390x/config.in b/arch/s390x/config.in
--- a/arch/s390x/config.in	Mon Jul  7 08:05:42 2003
+++ b/arch/s390x/config.in	Fri Aug 29 16:12:55 2003
@@ -22,6 +22,9 @@
 mainmenu_option next_comment
 comment 'Processor type and features'
 bool 'Symmetric multi-processing support' CONFIG_SMP
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
 bool 'Kernel support for 31 bit emulation' CONFIG_S390_SUPPORT
 if [ "$CONFIG_S390_SUPPORT" = "y" ]; then
   tristate 'Kernel support for 31 bit ELF binaries' CONFIG_BINFMT_ELF32 
@@ -81,6 +84,9 @@
 #  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
 #fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
 
 source crypto/Config.in
diff -Nru a/arch/s390x/defconfig b/arch/s390x/defconfig
--- a/arch/s390x/defconfig	Fri Jun 27 04:39:06 2003
+++ b/arch/s390x/defconfig	Wed Jun 19 10:26:35 2002
@@ -21,6 +21,7 @@
 CONFIG_SMP=y
 CONFIG_S390_SUPPORT=y
 CONFIG_BINFMT_ELF32=y
+CONFIG_NR_CPUS=32
 
 #
 # Loadable module support
diff -Nru a/arch/sh/config.in b/arch/sh/config.in
--- a/arch/sh/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/sh/config.in	Fri Aug 29 16:13:01 2003
@@ -465,6 +465,9 @@
           8 CONFIG_KGDB_DEFBITS_8"	8
    endmenu
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
 
 source crypto/Config.in
diff -Nru a/arch/sh64/config.in b/arch/sh64/config.in
--- a/arch/sh64/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/sh64/config.in	Fri Aug 29 16:13:20 2003
@@ -301,6 +301,8 @@
 bool "Debug: audit page tables on return from syscall/exception/interrupt" CONFIG_SH64_PAGE_TABLE_AUDIT
 dep_bool "Debug: report TLB fill/purge activity through /proc/tlb" CONFIG_SH64_PROC_TLB $CONFIG_PROC_FS
 
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
 
 source lib/Config.in
diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in
--- a/arch/sparc/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/sparc/config.in	Fri Aug 29 16:13:29 2003
@@ -29,6 +29,10 @@
 
 bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP
 
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
+
 # Identify this as a Sparc32 build
 define_bool CONFIG_SPARC32 y
 
@@ -272,6 +276,8 @@
    bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
 
 endmenu
 
diff -Nru a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
--- a/arch/sparc/kernel/Makefile	Wed Apr 24 10:18:05 2002
+++ b/arch/sparc/kernel/Makefile	Sat Aug 30 22:21:12 2003
@@ -51,15 +51,11 @@
 	@echo "" >> asm_offsets.h
 	@echo "#include <linux/config.h>" >> asm_offsets.h
 	@echo "" >> asm_offsets.h
-	@echo "#ifndef CONFIG_SMP" >> asm_offsets.h
-	@echo "" >> asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
-	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
 	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
-	@echo "#undef CONFIG_SMP" >> check_asm_data.c
 	@echo "#include <linux/sched.h>" >> check_asm_data.c
 	@echo "unsigned int check_asm_data[] = {" >> check_asm_data.c
 	$(SH) ./check_asm.sh -data task tmp.i check_asm_data.c
@@ -82,42 +78,6 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo "" >> asm_offsets.h
-	@echo "#else /* CONFIG_SMP */" >> asm_offsets.h
-	@echo "" >> asm_offsets.h
-	@echo "#include <linux/config.h>" > tmp.c
-	@echo "#undef CONFIG_SMP" >> tmp.c
-	@echo "#define CONFIG_SMP 1" >> tmp.c
-	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
-	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
-	@echo "#include <linux/config.h>" >> check_asm_data.c
-	@echo "#undef CONFIG_SMP" >> check_asm_data.c
-	@echo "#define CONFIG_SMP 1" >> check_asm_data.c
-	@echo "#include <linux/sched.h>" >> check_asm_data.c
-	@echo "unsigned int check_asm_data[] = {" >> check_asm_data.c
-	$(SH) ./check_asm.sh -data task tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
-	@echo '};' >> check_asm_data.c
-	$(CC) $(CFLAGS) -S -o check_asm_data.s check_asm_data.c
-	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
-	@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
-	@echo "unsigned int check_asm_data[] = {" >> check_asm.c
-	$(SH) ./check_asm.sh -ints check_asm_data.s check_asm.c
-	@echo "};" >> check_asm.c
-	@echo 'int main(void) {' >> check_asm.c
-	@echo 'int i = 0;' >> check_asm.c
-	$(SH) ./check_asm.sh -printf task tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf mm tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf thread tmp.i check_asm.c
-	@echo 'return 0; }' >> check_asm.c
-	@rm -f tmp.[ci] check_asm_data.[cs]
-	$(HOSTCC) -o check_asm check_asm.c
-	./check_asm >> asm_offsets.h
-	@rm -f check_asm check_asm.c
-	@echo "" >> asm_offsets.h
-	@echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
 	@echo "" >> asm_offsets.h
 	@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
 	@if test -r $(HPATH)/asm/asm_offsets.h; then \
diff -Nru a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
--- a/arch/sparc/kernel/sun4d_smp.c	Thu Mar 21 21:46:54 2002
+++ b/arch/sparc/kernel/sun4d_smp.c	Thu Aug 28 00:12:31 2003
@@ -351,11 +351,11 @@
 			unsigned long a3 asm("i3") = arg3;
 			unsigned long a4 asm("i4") = arg4;
 			unsigned long a5 asm("i5") = arg5;
-					
-			__asm__ __volatile__("
-				std %0, [%6]
-				std %2, [%6 + 8]
-				std %4, [%6 + 16]" : : 
+
+			__asm__ __volatile__(
+				"std %0, [%6]\n\t"
+				"std %2, [%6 + 8]\n\t"
+				"std %4, [%6 + 16]\n\t" : :
 				"r"(f), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5),
 				"r" (&ccall_info.func));
 		}
diff -Nru a/arch/sparc/lib/checksum.S b/arch/sparc/lib/checksum.S
--- a/arch/sparc/lib/checksum.S	Tue Feb  5 09:40:23 2002
+++ b/arch/sparc/lib/checksum.S	Thu Aug 28 00:10:49 2003
@@ -145,36 +145,39 @@
 	.globl C_LABEL(__csum_partial_copy_start), C_LABEL(__csum_partial_copy_end)
 C_LABEL(__csum_partial_copy_start):
 
-#define EX(x,y,a,b,z)                           \
+/* Work around cpp -rob */
+#define ALLOC #alloc
+#define EXECINSTR #execinstr
+#define EX(x,y,a,b)				\
 98:     x,y;                                    \
-        .section .fixup,z##alloc,z##execinstr;  \
+        .section .fixup,ALLOC,EXECINSTR;	\
         .align  4;                              \
 99:     ba 30f;                                 \
          a, b, %o3;                             \
-        .section __ex_table,z##alloc;           \
+        .section __ex_table,ALLOC;		\
         .align  4;                              \
         .word   98b, 99b;                       \
         .text;                                  \
         .align  4
 
-#define EX2(x,y,z)                          	\
+#define EX2(x,y)				\
 98:     x,y;                                    \
-        .section __ex_table,z##alloc;           \
+        .section __ex_table,ALLOC;		\
         .align  4;                              \
         .word   98b, 30f;                       \
         .text;                                  \
         .align  4
 
-#define EX3(x,y,z)                          	\
+#define EX3(x,y)				\
 98:     x,y;                                    \
-        .section __ex_table,z##alloc;           \
+        .section __ex_table,ALLOC;		\
         .align  4;                              \
         .word   98b, 96f;                       \
         .text;                                  \
         .align  4
 
-#define EXT(start,end,handler,z)                \
-        .section __ex_table,z##alloc;           \
+#define EXT(start,end,handler)			\
+        .section __ex_table,ALLOC;		\
         .align  4;                              \
         .word   start, 0, end, handler;         \
         .text;                                  \
@@ -247,21 +250,21 @@
 cc_end_cruft:
 	be	1f
 	 andcc	%o3, 4, %g0
-	EX(ldd	[%o0 + 0x00], %g2, and %o3, 0xf,#)
+	EX(ldd	[%o0 + 0x00], %g2, and %o3, 0xf)
 	add	%o1, 8, %o1
 	addcc	%g2, %g7, %g7
 	add	%o0, 8, %o0
 	addxcc	%g3, %g7, %g7
-	EX2(st	%g2, [%o1 - 0x08],#)
+	EX2(st	%g2, [%o1 - 0x08])
 	addx	%g0, %g7, %g7
 	andcc	%o3, 4, %g0
-	EX2(st	%g3, [%o1 - 0x04],#)
+	EX2(st	%g3, [%o1 - 0x04])
 1:	be	1f
 	 andcc	%o3, 3, %o3
-	EX(ld	[%o0 + 0x00], %g2, add %o3, 4,#)
+	EX(ld	[%o0 + 0x00], %g2, add %o3, 4)
 	add	%o1, 4, %o1
 	addcc	%g2, %g7, %g7
-	EX2(st	%g2, [%o1 - 0x04],#)
+	EX2(st	%g2, [%o1 - 0x04])
 	addx	%g0, %g7, %g7
 	andcc	%o3, 3, %g0
 	add	%o0, 4, %o0
@@ -271,14 +274,14 @@
 	 subcc	%o3, 2, %o3
 	b	4f
 	 or	%g0, %g0, %o4
-2:	EX(lduh	[%o0 + 0x00], %o4, add %o3, 2,#)
+2:	EX(lduh	[%o0 + 0x00], %o4, add %o3, 2)
 	add	%o0, 2, %o0
-	EX2(sth	%o4, [%o1 + 0x00],#)
+	EX2(sth	%o4, [%o1 + 0x00])
 	be	6f
 	 add	%o1, 2, %o1
 	sll	%o4, 16, %o4
-4:	EX(ldub	[%o0 + 0x00], %o5, add %g0, 1,#)
-	EX2(stb	%o5, [%o1 + 0x00],#)
+4:	EX(ldub	[%o0 + 0x00], %o5, add %g0, 1)
+	EX2(stb	%o5, [%o1 + 0x00])
 	sll	%o5, 8, %o5
 	or	%o5, %o4, %o4
 6:	addcc	%o4, %g7, %g7
@@ -295,9 +298,9 @@
 	 andcc	%o0, 0x2, %g0
 	be	1f
 	 andcc	%o0, 0x4, %g0
-	EX(lduh	[%o0 + 0x00], %g4, add %g1, 0,#)
+	EX(lduh	[%o0 + 0x00], %g4, add %g1, 0)
 	sub	%g1, 2, %g1
-	EX2(sth	%g4, [%o1 + 0x00],#)
+	EX2(sth	%g4, [%o1 + 0x00])
 	add	%o0, 2, %o0
 	sll	%g4, 16, %g4
 	addcc	%g4, %g7, %g7
@@ -311,9 +314,9 @@
 	or	%g3, %g7, %g7
 1:	be	3f
 	 andcc	%g1, 0xffffff80, %g0
-	EX(ld	[%o0 + 0x00], %g4, add %g1, 0,#)
+	EX(ld	[%o0 + 0x00], %g4, add %g1, 0)
 	sub	%g1, 4, %g1
-	EX2(st	%g4, [%o1 + 0x00],#)
+	EX2(st	%g4, [%o1 + 0x00])
 	add	%o0, 4, %o0
 	addcc	%g4, %g7, %g7
 	add	%o1, 4, %o1
@@ -342,7 +345,7 @@
 	CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
 	CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
 	CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-10:	EXT(5b, 10b, 20f,#)		! note for exception handling
+10:	EXT(5b, 10b, 20f)		! note for exception handling
 	sub	%g1, 128, %g1		! detract from length
 	addx	%g0, %g7, %g7		! add in last carry bit
 	andcc	%g1, 0xffffff80, %g0	! more to csum?
@@ -367,7 +370,7 @@
 	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3,%g4,%g5)
 	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3,%g4,%g5)
 	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5)
-12:	EXT(cctbl, 12b, 22f,#)		! note for exception table handling
+12:	EXT(cctbl, 12b, 22f)		! note for exception table handling
 	addx	%g0, %g7, %g7
 	andcc	%o3, 0xf, %g0		! check for low bits set
 ccte:	bne	cc_end_cruft		! something left, handle it out of band
@@ -378,7 +381,7 @@
 	CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
 	CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
 	CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-11:	EXT(ccdbl, 11b, 21f,#)		! note for exception table handling
+11:	EXT(ccdbl, 11b, 21f)		! note for exception table handling
 	sub	%g1, 128, %g1		! detract from length
 	addx	%g0, %g7, %g7		! add in last carry bit
 	andcc	%g1, 0xffffff80, %g0	! more to csum?
@@ -395,9 +398,9 @@
 	be,a	1f
 	 srl	%g1, 1, %g4		
 	sub	%g1, 1, %g1	
-	EX(ldub	[%o0], %g5, add %g1, 1,#)
+	EX(ldub	[%o0], %g5, add %g1, 1)
 	add	%o0, 1, %o0	
-	EX2(stb	%g5, [%o1],#)
+	EX2(stb	%g5, [%o1])
 	srl	%g1, 1, %g4
 	add	%o1, 1, %o1
 1:	cmp	%g4, 0		
@@ -406,34 +409,34 @@
 	andcc	%o0, 2, %g0	
 	be,a	1f
 	 srl	%g4, 1, %g4
-	EX(lduh	[%o0], %o4, add %g1, 0,#)
+	EX(lduh	[%o0], %o4, add %g1, 0)
 	sub	%g1, 2, %g1	
 	srl	%o4, 8, %g2
 	sub	%g4, 1, %g4	
-	EX2(stb	%g2, [%o1],#)
+	EX2(stb	%g2, [%o1])
 	add	%o4, %g5, %g5
-	EX2(stb	%o4, [%o1 + 1],#)
+	EX2(stb	%o4, [%o1 + 1])
 	add	%o0, 2, %o0	
 	srl	%g4, 1, %g4
 	add	%o1, 2, %o1
 1:	cmp	%g4, 0		
 	be,a	2f
 	 andcc	%g1, 2, %g0
-	EX3(ld	[%o0], %o4,#)
+	EX3(ld	[%o0], %o4)
 5:	srl	%o4, 24, %g2
 	srl	%o4, 16, %g3
-	EX2(stb	%g2, [%o1],#)
+	EX2(stb	%g2, [%o1])
 	srl	%o4, 8, %g2
-	EX2(stb	%g3, [%o1 + 1],#)
+	EX2(stb	%g3, [%o1 + 1])
 	add	%o0, 4, %o0
-	EX2(stb	%g2, [%o1 + 2],#)
+	EX2(stb	%g2, [%o1 + 2])
 	addcc	%o4, %g5, %g5
-	EX2(stb	%o4, [%o1 + 3],#)
+	EX2(stb	%o4, [%o1 + 3])
 	addx	%g5, %g0, %g5	! I am now to lazy to optimize this (question it
 	add	%o1, 4, %o1	! is worthy). Maybe some day - with the sll/srl
 	subcc	%g4, 1, %g4	! tricks
 	bne,a	5b
-	 EX3(ld	[%o0], %o4,#)
+	 EX3(ld	[%o0], %o4)
 	sll	%g5, 16, %g2
 	srl	%g5, 16, %g5
 	srl	%g2, 16, %g2
@@ -441,19 +444,19 @@
 	add	%g2, %g5, %g5 
 2:	be,a	3f		
 	 andcc	%g1, 1, %g0
-	EX(lduh	[%o0], %o4, and %g1, 3,#)
+	EX(lduh	[%o0], %o4, and %g1, 3)
 	andcc	%g1, 1, %g0
 	srl	%o4, 8, %g2
 	add	%o0, 2, %o0	
-	EX2(stb	%g2, [%o1],#)
+	EX2(stb	%g2, [%o1])
 	add	%g5, %o4, %g5
-	EX2(stb	%o4, [%o1 + 1],#)
+	EX2(stb	%o4, [%o1 + 1])
 	add	%o1, 2, %o1
 3:	be,a	1f		
 	 sll	%g5, 16, %o4
-	EX(ldub	[%o0], %g2, add %g0, 1,#)
+	EX(ldub	[%o0], %g2, add %g0, 1)
 	sll	%g2, 8, %o4	
-	EX2(stb	%g2, [%o1],#)
+	EX2(stb	%g2, [%o1])
 	add	%g5, %o4, %g5
 	sll	%g5, 16, %o4
 1:	addcc	%o4, %g5, %g5
diff -Nru a/arch/sparc/lib/copy_user.S b/arch/sparc/lib/copy_user.S
--- a/arch/sparc/lib/copy_user.S	Tue Feb  5 09:40:23 2002
+++ b/arch/sparc/lib/copy_user.S	Thu Aug 28 00:10:49 2003
@@ -16,41 +16,44 @@
 #include <asm/asmmacro.h>
 #include <asm/page.h>
 
-#define EX(x,y,a,b,z) 				\
+/* Work around cpp -rob */
+#define ALLOC #alloc
+#define EXECINSTR #execinstr
+#define EX(x,y,a,b) 				\
 98: 	x,y;					\
-	.section .fixup,z##alloc,z##execinstr;	\
+	.section .fixup,ALLOC,EXECINSTR;	\
 	.align	4;				\
 99:	ba fixupretl;				\
 	 a, b, %g3;				\
-	.section __ex_table,z##alloc;		\
+	.section __ex_table,ALLOC;		\
 	.align	4;				\
 	.word	98b, 99b;			\
 	.text;					\
 	.align	4
 
-#define EX2(x,y,c,d,e,a,b,z) 			\
+#define EX2(x,y,c,d,e,a,b) 			\
 98: 	x,y;					\
-	.section .fixup,z##alloc,z##execinstr;	\
+	.section .fixup,ALLOC,EXECINSTR;	\
 	.align	4;				\
 99:	c, d, e;				\
 	ba fixupretl;				\
 	 a, b, %g3;				\
-	.section __ex_table,z##alloc;		\
+	.section __ex_table,ALLOC;		\
 	.align	4;				\
 	.word	98b, 99b;			\
 	.text;					\
 	.align	4
 
-#define EXO2(x,y,z) 				\
-98: 	x,##y;					\
-	.section __ex_table,z##alloc;		\
+#define EXO2(x,y) 				\
+98: 	x, y;					\
+	.section __ex_table,ALLOC;		\
 	.align	4;				\
 	.word	98b, 97f;			\
 	.text;					\
 	.align	4
 
-#define EXT(start,end,handler,z) 		\
-	.section __ex_table,z##alloc;		\
+#define EXT(start,end,handler)			\
+	.section __ex_table,ALLOC;		\
 	.align	4;				\
 	.word	start, 0, end, handler;		\
 	.text;					\
@@ -121,23 +124,23 @@
 	be	4f
 	 andcc	%o1, 2, %g0
 
-	EXO2(ldub [%o1], %g2,#)
+	EXO2(ldub [%o1], %g2)
 	add	%o1, 1, %o1
-	EXO2(stb %g2, [%o0],#)
+	EXO2(stb %g2, [%o0])
 	sub	%o2, 1, %o2
 	bne	3f
 	 add	%o0, 1, %o0
 
-	EXO2(lduh [%o1], %g2,#)
+	EXO2(lduh [%o1], %g2)
 	add	%o1, 2, %o1
-	EXO2(sth %g2, [%o0],#)
+	EXO2(sth %g2, [%o0])
 	sub	%o2, 2, %o2
 	b	3f
 	 add	%o0, 2, %o0
 4:
-	EXO2(lduh [%o1], %g2,#)
+	EXO2(lduh [%o1], %g2)
 	add	%o1, 2, %o1
-	EXO2(sth %g2, [%o0],#)
+	EXO2(sth %g2, [%o0])
 	sub	%o2, 2, %o2
 	b	3f
 	 add	%o0, 2, %o0
@@ -160,9 +163,9 @@
 	be	2f
 	 mov	%o2, %g1
 
-	EXO2(ld [%o1], %o4,#)
+	EXO2(ld [%o1], %o4)
 	sub	%g1, 4, %g1
-	EXO2(st %o4, [%o0],#)
+	EXO2(st %o4, [%o0])
 	add	%o1, 4, %o1
 	add	%o0, 4, %o0
 2:
@@ -177,7 +180,7 @@
 	MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
 80:
-	EXT(5b, 80b, 50f,#)
+	EXT(5b, 80b, 50f)
 	subcc	%g7, 128, %g7
 	add	%o1, 128, %o1
 	bne	5b
@@ -204,37 +207,37 @@
 	MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
 	MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
 copy_user_table_end:
-	EXT(copy_user_table, copy_user_table_end, 51f,#)
+	EXT(copy_user_table, copy_user_table_end, 51f)
 	be	copy_user_last7
 	 andcc	%g1, 4, %g0
 
-	EX(ldd	[%o1], %g2, and %g1, 0xf,#)
+	EX(ldd	[%o1], %g2, and %g1, 0xf)
 	add	%o0, 8, %o0
 	add	%o1, 8, %o1
-	EX(st	%g2, [%o0 - 0x08], and %g1, 0xf,#)
-	EX2(st	%g3, [%o0 - 0x04], and %g1, 0xf, %g1, sub %g1, 4,#)
+	EX(st	%g2, [%o0 - 0x08], and %g1, 0xf)
+	EX2(st	%g3, [%o0 - 0x04], and %g1, 0xf, %g1, sub %g1, 4)
 copy_user_last7:
 	be	1f
 	 andcc	%g1, 2, %g0
 
-	EX(ld	[%o1], %g2, and %g1, 7,#)
+	EX(ld	[%o1], %g2, and %g1, 7)
 	add	%o1, 4, %o1
-	EX(st	%g2, [%o0], and %g1, 7,#)
+	EX(st	%g2, [%o0], and %g1, 7)
 	add	%o0, 4, %o0
 1:
 	be	1f
 	 andcc	%g1, 1, %g0
 
-	EX(lduh	[%o1], %g2, and %g1, 3,#)
+	EX(lduh	[%o1], %g2, and %g1, 3)
 	add	%o1, 2, %o1
-	EX(sth	%g2, [%o0], and %g1, 3,#)
+	EX(sth	%g2, [%o0], and %g1, 3)
 	add	%o0, 2, %o0
 1:
 	be	1f
 	 nop
 
-	EX(ldub	[%o1], %g2, add %g0, 1,#)
-	EX(stb	%g2, [%o0], add %g0, 1,#)
+	EX(ldub	[%o1], %g2, add %g0, 1)
+	EX(stb	%g2, [%o0], add %g0, 1)
 1:
 	retl
  	 clr	%o0
@@ -245,7 +248,7 @@
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
 81:
-	EXT(ldd_std, 81b, 52f,#)
+	EXT(ldd_std, 81b, 52f)
 	subcc	%g7, 128, %g7
 	add	%o1, 128, %o1
 	bne	ldd_std
@@ -274,9 +277,9 @@
 	be	10f
 	 nop
 
-	EXO2(ldub [%o1], %g2,#)
+	EXO2(ldub [%o1], %g2)
 	add	%o1, 1, %o1
-	EXO2(stb %g2, [%o0],#)
+	EXO2(stb %g2, [%o0])
 	sub	%o2, 1, %o2
 	andcc	%o2, 0xfffffff0, %o3
 	be	short_end
@@ -285,7 +288,7 @@
 	MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
 	MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
 82:
-	EXT(10b, 82b, 53f,#)
+	EXT(10b, 82b, 53f)
 	subcc	%o3, 0x10, %o3
 	add	%o1, 0x10, %o1
 	bne	10b
@@ -303,7 +306,7 @@
 	MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
 	MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
 83:
-	EXT(byte_chunk, 83b, 54f,#)
+	EXT(byte_chunk, 83b, 54f)
 	subcc	%o3, 0x10, %o3
 	add	%o1, 0x10, %o1
 	bne	byte_chunk
@@ -328,11 +331,11 @@
 	MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
 	MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
 short_table_end:
-	EXT(84b, short_table_end, 55f,#)
+	EXT(84b, short_table_end, 55f)
 	be	1f
 	 nop
-	EX(ldub	[%o1], %g2, add %g0, 1,#)
-	EX(stb	%g2, [%o0], add %g0, 1,#)
+	EX(ldub	[%o1], %g2, add %g0, 1)
+	EX(stb	%g2, [%o0], add %g0, 1)
 1:
 	retl
  	 clr	%o0
@@ -344,11 +347,11 @@
 	be	1f
 	 andcc	%o2, 4, %g0
 
-	EXO2(ld	[%o1 + 0x00], %g2,#)
-	EXO2(ld	[%o1 + 0x04], %g3,#)
+	EXO2(ld	[%o1 + 0x00], %g2)
+	EXO2(ld	[%o1 + 0x04], %g3)
 	add	%o1, 8, %o1
-	EXO2(st	%g2, [%o0 + 0x00],#)
-	EX(st	%g3, [%o0 + 0x04], sub %o2, 4,#)
+	EXO2(st	%g2, [%o0 + 0x00])
+	EX(st	%g3, [%o0 + 0x04], sub %o2, 4)
 	add	%o0, 8, %o0
 1:
 	b	copy_user_last7
diff -Nru a/arch/sparc/lib/memset.S b/arch/sparc/lib/memset.S
--- a/arch/sparc/lib/memset.S	Mon Feb  4 23:39:16 2002
+++ b/arch/sparc/lib/memset.S	Thu Aug 28 00:10:49 2003
@@ -10,20 +10,23 @@
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
 
-#define EX(x,y,a,b,z) 				\
+/* Work around cpp -rob */
+#define ALLOC #alloc
+#define EXECINSTR #execinstr
+#define EX(x,y,a,b) 				\
 98: 	x,y;					\
-	.section .fixup,z##alloc,z##execinstr;	\
+	.section .fixup,ALLOC,EXECINSTR;	\
 	.align	4;				\
 99:	ba 30f;					\
 	 a, b, %o0;				\
-	.section __ex_table,z##alloc;		\
+	.section __ex_table,ALLOC;		\
 	.align	4;				\
 	.word	98b, 99b;			\
 	.text;					\
 	.align	4
 
-#define EXT(start,end,handler,z) 		\
-	.section __ex_table,z##alloc;		\
+#define EXT(start,end,handler) 			\
+	.section __ex_table,ALLOC;		\
 	.align	4;				\
 	.word	start, 0, end, handler;		\
 	.text;					\
@@ -74,13 +77,13 @@
 3:
 	cmp	%o2, 3
 	be	2f
-	 EX(stb	%g3, [%o0], sub %o1, 0,#)
+	 EX(stb	%g3, [%o0], sub %o1, 0)
 
 	cmp	%o2, 2
 	be	2f
-	 EX(stb	%g3, [%o0 + 0x01], sub %o1, 1,#)
+	 EX(stb	%g3, [%o0 + 0x01], sub %o1, 1)
 
-	EX(stb	%g3, [%o0 + 0x02], sub %o1, 2,#)
+	EX(stb	%g3, [%o0 + 0x02], sub %o1, 2)
 2:
 	sub	%o2, 4, %o2
 	add	%o1, %o2, %o1
@@ -101,7 +104,7 @@
 	be	2f
 	 mov	%g3, %g2
 
-	EX(st	%g3, [%o0], sub %o1, 0,#)
+	EX(st	%g3, [%o0], sub %o1, 0)
 	sub	%o1, 4, %o1
 	add	%o0, 4, %o0
 2:
@@ -113,7 +116,7 @@
 	subcc	%o3, 128, %o3
 	ZERO_BIG_BLOCK(%o0, 0x40, %g2)
 11:
-	EXT(10b, 11b, 20f,#)
+	EXT(10b, 11b, 20f)
 	bne	10b
 	 add	%o0, 128, %o0
 
@@ -138,17 +141,17 @@
 	be	1f
 	 andcc	%o1, 2, %g0
 
-	EX(st	%g3, [%o0], and %o1, 7,#)
+	EX(st	%g3, [%o0], and %o1, 7)
 	add	%o0, 4, %o0
 1:
 	be	1f
 	 andcc	%o1, 1, %g0
 
-	EX(sth	%g3, [%o0], and %o1, 3,#)
+	EX(sth	%g3, [%o0], and %o1, 3)
 	add	%o0, 2, %o0
 1:
 	bne,a	8f
-	 EX(stb	%g3, [%o0], and %o1, 1,#)
+	 EX(stb	%g3, [%o0], and %o1, 1)
 8:
 	retl
 	 clr	%o0
@@ -161,7 +164,7 @@
 	 add	%o0, 1, %o0
 	subcc	%o1, 1, %o1
 	bne,a	8b
-	 EX(stb	%g3, [%o0 - 1], add %o1, 1,#)
+	 EX(stb	%g3, [%o0 - 1], add %o1, 1)
 0:
 	retl
 	 clr	%o0
diff -Nru a/arch/sparc/math-emu/sfp-util.h b/arch/sparc/math-emu/sfp-util.h
--- a/arch/sparc/math-emu/sfp-util.h	Tue Feb  5 09:40:23 2002
+++ b/arch/sparc/math-emu/sfp-util.h	Thu Aug 28 00:11:19 2003
@@ -4,8 +4,8 @@
 #include <asm/byteorder.h>
 
 #define add_ssaaaa(sh, sl, ah, al, bh, bl) 				\
-  __asm__ ("addcc %r4,%5,%1
-	addx %r2,%3,%0"							\
+  __asm__ ("addcc %r4,%5,%1\n\t"						\
+	   "addx %r2,%3,%0\n"						\
 	   : "=r" ((USItype)(sh)),					\
 	     "=&r" ((USItype)(sl))					\
 	   : "%rJ" ((USItype)(ah)),					\
@@ -14,8 +14,8 @@
 	     "rI" ((USItype)(bl))					\
 	   : "cc")
 #define sub_ddmmss(sh, sl, ah, al, bh, bl) 				\
-  __asm__ ("subcc %r4,%5,%1
-	subx %r2,%3,%0"							\
+  __asm__ ("subcc %r4,%5,%1\n\t"						\
+	   "subx %r2,%3,%0\n"						\
 	   : "=r" ((USItype)(sh)),					\
 	     "=&r" ((USItype)(sl))					\
 	   : "rJ" ((USItype)(ah)),					\
@@ -25,46 +25,46 @@
 	   : "cc")
 
 #define umul_ppmm(w1, w0, u, v) \
-  __asm__ ("! Inlined umul_ppmm
-	wr	%%g0,%2,%%y	! SPARC has 0-3 delay insn after a wr
-	sra	%3,31,%%g2	! Don't move this insn
-	and	%2,%%g2,%%g2	! Don't move this insn
-	andcc	%%g0,0,%%g1	! Don't move this insn
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,%3,%%g1
-	mulscc	%%g1,0,%%g1
-	add	%%g1,%%g2,%0
-	rd	%%y,%1"							\
+  __asm__ ("! Inlined umul_ppmm\n\t"					\
+	"wr	%%g0,%2,%%y	! SPARC has 0-3 delay insn after a wr\n\t" \
+	"sra	%3,31,%%g2	! Don't move this insn\n\t"		\
+	"and	%2,%%g2,%%g2	! Don't move this insn\n\t"		\
+	"andcc	%%g0,0,%%g1	! Don't move this insn\n\t"		\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,%3,%%g1\n\t"					\
+	"mulscc	%%g1,0,%%g1\n\t" 					\
+	"add	%%g1,%%g2,%0\n\t" 					\
+	"rd	%%y,%1\n"						\
 	   : "=r" ((USItype)(w1)),					\
 	     "=r" ((USItype)(w0))					\
 	   : "%rI" ((USItype)(u)),					\
@@ -74,30 +74,30 @@
 /* It's quite necessary to add this much assembler for the sparc.
    The default udiv_qrnnd (in C) is more than 10 times slower!  */
 #define udiv_qrnnd(q, r, n1, n0, d) \
-  __asm__ ("! Inlined udiv_qrnnd
-	mov	32,%%g1
-	subcc	%1,%2,%%g0
-1:	bcs	5f
-	 addxcc %0,%0,%0	! shift n1n0 and a q-bit in lsb
-	sub	%1,%2,%1	! this kills msb of n
-	addx	%1,%1,%1	! so this can't give carry
-	subcc	%%g1,1,%%g1
-2:	bne	1b
-	 subcc	%1,%2,%%g0
-	bcs	3f
-	 addxcc %0,%0,%0	! shift n1n0 and a q-bit in lsb
-	b	3f
-	 sub	%1,%2,%1	! this kills msb of n
-4:	sub	%1,%2,%1
-5:	addxcc	%1,%1,%1
-	bcc	2b
-	 subcc	%%g1,1,%%g1
-! Got carry from n.  Subtract next step to cancel this carry.
-	bne	4b
-	 addcc	%0,%0,%0	! shift n1n0 and a 0-bit in lsb
-	sub	%1,%2,%1
-3:	xnor	%0,0,%0
-	! End of inline udiv_qrnnd"					\
+  __asm__ ("! Inlined udiv_qrnnd\n\t"					\
+	   "mov	32,%%g1\n\t"						\
+	   "subcc	%1,%2,%%g0\n\t"					\
+	   "1:	bcs	5f\n\t"						\
+	   "addxcc %0,%0,%0	! shift n1n0 and a q-bit in lsb\n\t"	\
+	   "sub	%1,%2,%1	! this kills msb of n\n\t"		\
+	   "addx	%1,%1,%1	! so this can't give carry\n\t"	\
+	   "subcc	%%g1,1,%%g1\n\t"				\
+	   "2:	bne	1b\n\t"						\
+	   "subcc	%1,%2,%%g0\n\t"					\
+	   "bcs	3f\n\t"							\
+	   "addxcc %0,%0,%0	! shift n1n0 and a q-bit in lsb\n\t"	\
+	   "b		3f\n\t"						\
+	   "sub	%1,%2,%1	! this kills msb of n\n\t"		\
+	   "4:	sub	%1,%2,%1\n\t"					\
+	   "5:	addxcc	%1,%1,%1\n\t"					\
+	   "bcc	2b\n\t"							\
+	   "subcc	%%g1,1,%%g1\n\t"				\
+	   "! Got carry from n.  Subtract next step to cancel this carry.\n\t" \
+	   "bne	4b\n\t"							\
+	   "addcc	%0,%0,%0	! shift n1n0 and a 0-bit in lsb\n\t" \
+	   "sub	%1,%2,%1\n\t"						\
+	   "3:	xnor	%0,0,%0\n\t"					\
+	   "! End of inline udiv_qrnnd\n"				\
 	   : "=&r" ((USItype)(q)),					\
 	     "=&r" ((USItype)(r))					\
 	   : "r" ((USItype)(d)),					\
diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c	Fri Apr 11 22:17:59 2003
+++ b/arch/sparc/mm/srmmu.c	Mon Jul 21 04:57:23 2003
@@ -126,6 +126,9 @@
 
 #define SRMMU_NOCACHE_BITMAP_SHIFT (PAGE_SHIFT - 4)
 
+/* The context table is a nocache user with the biggest alignment needs. */
+#define SRMMU_NOCACHE_ALIGN_MAX (sizeof(ctxd_t)*SRMMU_MAX_CONTEXTS)
+
 void *srmmu_nocache_pool;
 void *srmmu_nocache_bitmap;
 int srmmu_nocache_low;
@@ -260,6 +263,7 @@
 
 	/* we align on physical address */
 	if (align) {
+		BUG_ON(align > SRMMU_NOCACHE_ALIGN_MAX);
 		va_tmp = (SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT));
 		phys_tmp = (__nocache_pa(va_tmp) + align - 1) & ~(align - 1);
 		va_tmp = (unsigned long)__nocache_va(phys_tmp);
@@ -367,7 +371,8 @@
 	unsigned long paddr, vaddr;
 	unsigned long pteval;
 
-	srmmu_nocache_pool = __alloc_bootmem(srmmu_nocache_size, PAGE_SIZE, 0UL);
+	srmmu_nocache_pool = __alloc_bootmem(srmmu_nocache_size,
+		SRMMU_NOCACHE_ALIGN_MAX, 0UL);
 	memset(srmmu_nocache_pool, 0, srmmu_nocache_size);
 
 	srmmu_nocache_bitmap = __alloc_bootmem(srmmu_nocache_bitmap_size, SMP_CACHE_BYTES, 0UL);
diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in
--- a/arch/sparc64/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/sparc64/config.in	Fri Aug 29 16:13:34 2003
@@ -28,6 +28,10 @@
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
 
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
+
 # Identify this as a Sparc64 build
 define_bool CONFIG_SPARC64 y
 
@@ -306,6 +310,8 @@
 if [ "$CONFIG_STACK_DEBUG" = "y" ] ; then
    define_bool CONFIG_MCOUNT y
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
 
 endmenu
 
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Wed Jul 16 19:57:20 2003
+++ b/arch/sparc64/defconfig	Wed Jun 19 10:26:35 2002
@@ -58,6 +58,7 @@
 CONFIG_BINFMT_MISC=m
 # CONFIG_SUNOS_EMUL is not set
 CONFIG_SOLARIS_EMUL=m
+CONFIG_NR_CPUS=32
 
 #
 # Parallel port support
diff -Nru a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
--- a/arch/sparc64/kernel/Makefile	Tue Feb  4 01:01:46 2003
+++ b/arch/sparc64/kernel/Makefile	Sat Aug 30 22:21:12 2003
@@ -58,15 +58,11 @@
 	@echo >> asm_offsets.h
 	@echo "#include <linux/config.h>" >> asm_offsets.h
 	@echo >> asm_offsets.h
-	@echo "#ifndef CONFIG_SMP" >> asm_offsets.h
-	@echo >> asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
-	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
 	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
-	@echo "#undef CONFIG_SMP" >> check_asm_data.c
 	@echo "#include <linux/sched.h>" >> check_asm_data.c
 	@echo 'unsigned int check_asm_data[] = {' >> check_asm_data.c
 	$(SH) ./check_asm.sh -data task tmp.i check_asm_data.c
@@ -89,75 +85,6 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo >> asm_offsets.h
-	@echo "#else /* CONFIG_SMP */" >> asm_offsets.h
-	@echo "#ifndef CONFIG_DEBUG_SPINLOCK" >>asm_offsets.h
-	@echo >> asm_offsets.h
-	@echo "#include <linux/config.h>" > tmp.c
-	@echo "#undef CONFIG_SMP" >> tmp.c
-	@echo "#define CONFIG_SMP 1" >> tmp.c
-	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
-	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
-	@echo "#include <linux/config.h>" >> check_asm_data.c
-	@echo "#undef CONFIG_SMP" >> check_asm_data.c
-	@echo "#define CONFIG_SMP 1" >> check_asm_data.c
-	@echo "#include <linux/sched.h>" >> check_asm_data.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm_data.c
-	$(SH) ./check_asm.sh -data task tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
-	@echo '};' >> check_asm_data.c
-	$(CC) $(CPPFLAGS) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
-	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
-	@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm.c
-	$(SH) ./check_asm.sh -ints check_asm_data.s check_asm.c
-	@echo '};' >> check_asm.c
-	@echo 'int main(void) {' >> check_asm.c
-	@echo 'int i = 0;' >> check_asm.c
-	$(SH) ./check_asm.sh -printf task tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf mm tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf thread tmp.i check_asm.c
-	@echo 'return 0; }' >> check_asm.c
-	@rm -f tmp.[ci] check_asm_data.[cs]
-	$(HOSTCC) -o check_asm check_asm.c
-	./check_asm >> asm_offsets.h
-	@rm -f check_asm check_asm.c
-	@echo >> asm_offsets.h
-	@echo "#else /* CONFIG_DEBUG_SPINLOCK */" >> asm_offsets.h
-	@echo >> asm_offsets.h
-	@echo "#include <linux/sched.h>" > tmp.c
-	$(CPP) $(CPPFLAGS) -P -DCONFIG_DEBUG_SPINLOCK tmp.c -o tmp.i
-	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
-	@echo "#include <linux/config.h>" >> check_asm_data.c
-	@echo "#undef CONFIG_SMP" >> check_asm_data.c
-	@echo "#define CONFIG_SMP 1" >> check_asm_data.c
-	@echo "#include <linux/sched.h>" >> check_asm_data.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm_data.c
-	$(SH) ./check_asm.sh -data task tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
-	@echo '};' >> check_asm_data.c
-	$(CC) $(CPPFLAGS) -DCONFIG_DEBUG_SPINLOCK $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
-	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
-	@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm.c
-	$(SH) ./check_asm.sh -ints check_asm_data.s check_asm.c
-	@echo '};' >> check_asm.c
-	@echo 'int main(void) {' >> check_asm.c
-	@echo 'int i = 0;' >> check_asm.c
-	$(SH) ./check_asm.sh -printf task tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf mm tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf thread tmp.i check_asm.c
-	@echo 'return 0; }' >> check_asm.c
-	@rm -f tmp.[ci] check_asm_data.[cs]
-	$(HOSTCC) -o check_asm check_asm.c
-	./check_asm >> asm_offsets.h
-	@rm -f check_asm check_asm.c
-	@echo "#endif /* CONFIG_DEBUG_SPINLOCK */" >> asm_offsets.h
-	@echo >> asm_offsets.h
-	@echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
 	@echo >> asm_offsets.h
 	@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
 	@if test -r $(HPATH)/asm/asm_offsets.h; then \
diff -Nru a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
--- a/arch/sparc64/kernel/cpu.c	Wed Nov  6 17:35:59 2002
+++ b/arch/sparc64/kernel/cpu.c	Tue Aug 19 11:52:50 2003
@@ -37,6 +37,7 @@
   { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
   { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
   { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
+  { 0x3e, 0x16, 0, "UltraSparc IIIi integrated FPU"},
 };
 
 #define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -45,31 +46,25 @@
   { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
   { 0x22, 0x10, "TI UltraSparc I   (SpitFire)"},
   { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
-  { 0x17, 0x12, "TI UltraSparc IIi"},
-  { 0x17, 0x13, "TI UltraSparc IIe"},
+  { 0x17, 0x12, "TI UltraSparc IIi (Sabre)"},
+  { 0x17, 0x13, "TI UltraSparc IIe (Hummingbird)"},
   { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
   { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
+  { 0x3e, 0x16, "TI UltraSparc IIIi (Jalapeno)"},
 };
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
 
-#ifdef CONFIG_SMP
-char *sparc_cpu_type[64] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
-char *sparc_fpu_type[64] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
-#else
-char *sparc_cpu_type[64] = { "cpu-oops", };
-char *sparc_fpu_type[64] = { "fpu-oops", };
-#endif
+char *sparc_cpu_type = "cpu-oops";
+char *sparc_fpu_type = "fpu-oops";
 
 unsigned int fsr_storage;
 
 void __init cpu_probe(void)
 {
 	unsigned long ver, fpu_vers, manuf, impl, fprs;
-	int i, cpuid;
+	int i;
 	
-	cpuid = hard_smp_processor_id();
-
 	fprs = fprs_read();
 	fprs_write(FPRS_FEF);
 	__asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
@@ -86,7 +81,7 @@
 	for (i = 0; i < NSPARCCHIPS; i++) {
 		if (linux_sparc_chips[i].manuf == manuf) {
 			if (linux_sparc_chips[i].impl == impl) {
-				sparc_cpu_type[cpuid]
+				sparc_cpu_type
 					= linux_sparc_chips[i].cpu_name;
 				break;
 			}
@@ -105,14 +100,14 @@
 			printk("DEBUG: manuf[%lx] impl[%lx]\n",
 			       manuf, impl);
 		}
-		sparc_cpu_type[cpuid] = "Unknown CPU";
+		sparc_cpu_type = "Unknown CPU";
 	}
 
 	for (i = 0; i < NSPARCFPU; i++) {
 		if (linux_sparc_fpu[i].manuf == manuf &&
 		    linux_sparc_fpu[i].impl == impl) {
 			if (linux_sparc_fpu[i].fpu_vers == fpu_vers) {
-				sparc_fpu_type[cpuid]
+				sparc_fpu_type
 					= linux_sparc_fpu[i].fp_name;
 				break;
 			}
@@ -122,6 +117,6 @@
 	if (i == NSPARCFPU) {
 		printk("DEBUG: manuf[%lx] impl[%lx] fsr.vers[%lx]\n",
 		       manuf, impl, fpu_vers);
-		sparc_fpu_type[cpuid] = "Unknown FPU";
+		sparc_fpu_type = "Unknown FPU";
 	}
 }
diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
--- a/arch/sparc64/kernel/entry.S	Tue Apr 22 22:44:45 2003
+++ b/arch/sparc64/kernel/entry.S	Mon Jul 21 08:35:22 2003
@@ -911,10 +911,15 @@
 	sllx		%g1, 63, %g2;					\
 	or		%g4, %g2, %g4;					\
 	/* Get log entry pointer for this cpu at this trap level. */	\
+	BRANCH_IF_JALAPENO(g2,g3,50f)					\
 	ldxa		[%g0] ASI_SAFARI_CONFIG, %g2;			\
 	srlx		%g2, 17, %g2;					\
-	and		%g2, 0x3ff, %g2;				\
-	sllx		%g2, 9, %g2;					\
+	ba,pt		%xcc, 60f; 					\
+	 and		%g2, 0x3ff, %g2;				\
+50:	ldxa		[%g0] ASI_JBUS_CONFIG, %g2;			\
+	srlx		%g2, 17, %g2;					\
+	and		%g2, 0x1f, %g2;					\
+60:	sllx		%g2, 9, %g2;					\
 	sethi		%hi(cheetah_error_log), %g3;			\
 	ldx		[%g3 + %lo(cheetah_error_log)], %g3;		\
 	brz,pn		%g3, 80f;					\
diff -Nru a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
--- a/arch/sparc64/kernel/head.S	Wed Jul 16 01:13:34 2003
+++ b/arch/sparc64/kernel/head.S	Mon Jul 21 08:35:22 2003
@@ -647,10 +647,17 @@
 	 nop
 
 not_starfire:
+	BRANCH_IF_JALAPENO(g1,g5,is_jalapeno)
 	BRANCH_IF_ANY_CHEETAH(g1,g5,is_cheetah)
 
 	ba,pt	%xcc, not_cheetah
 	 nop
+
+is_jalapeno:
+	ldxa		[%g0] ASI_JBUS_CONFIG, %g1
+	srlx		%g1, 17, %g1
+	ba,pt		%xcc, set_worklist
+	 and		%g1, 0x1f, %g1		! 5bit JBUS ID
 
 is_cheetah:
 	ldxa		[%g0] ASI_SAFARI_CONFIG, %g1
diff -Nru a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
--- a/arch/sparc64/kernel/ioctl32.c	Tue Jun 24 13:24:17 2003
+++ b/arch/sparc64/kernel/ioctl32.c	Fri Aug  1 13:28:59 2003
@@ -1920,8 +1920,8 @@
 	    __cgc_do_ptr((void **) &cgc->sense, &cgc32->sense))
 		return -EFAULT;
 
-	if (get_user(dir, &cgc->data_direction) ||
-	    put_user(dir, &cgc32->data_direction))
+	if (get_user(dir, &cgc32->data_direction) ||
+	    put_user(dir, &cgc->data_direction))
 		return -EFAULT;
 
 	if (copy_in_user(&cgc->quiet, &cgc32->quiet,
diff -Nru a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
--- a/arch/sparc64/kernel/irq.c	Thu Mar 27 14:01:23 2003
+++ b/arch/sparc64/kernel/irq.c	Mon Jul 21 08:35:22 2003
@@ -148,12 +148,24 @@
 		return;
 
 	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		/* 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;
+		unsigned long ver;
+
+		__asm__ ("rdpr %%ver, %0" : "=r" (ver));
+		if ((ver >> 32) == 0x003e0016) {
+			/* We set it to our JBUS ID. */
+			__asm__ __volatile__("ldxa [%%g0] %1, %0"
+					     : "=r" (tid)
+					     : "i" (ASI_JBUS_CONFIG));
+			tid = ((tid & (0x1fUL<<17)) << 9);
+			tid &= IMAP_TID_JBUS;
+		} else {
+			/* 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"
diff -Nru a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
--- a/arch/sparc64/kernel/isa.c	Mon Feb  4 23:55:16 2002
+++ b/arch/sparc64/kernel/isa.c	Wed Jul 23 08:37:36 2003
@@ -20,22 +20,23 @@
 		printk(" [%s", isa_dev->prom_name);
 }
 
-static void __init isa_dev_get_resource(struct isa_device *isa_dev)
+static void __init isa_dev_get_resource(struct isa_device *isa_dev,
+					struct linux_prom_registers *pregs,
+					int pregs_size)
 {
-	struct linux_prom_registers regs[PROMREG_MAX];
 	unsigned long base, len;
 	int prop_len;
 
 	prop_len = prom_getproperty(isa_dev->prom_node, "reg",
-				    (char *) regs, sizeof(regs));
+				    (char *) pregs, pregs_size);
 
 	if (prop_len <= 0)
 		return;
 
 	/* Only the first one is interesting. */
-	len = regs[0].reg_size;
-	base = (((unsigned long)regs[0].which_io << 32) |
-		(unsigned long)regs[0].phys_addr);
+	len = pregs[0].reg_size;
+	base = (((unsigned long)pregs[0].which_io << 32) |
+		(unsigned long)pregs[0].phys_addr);
 	base += isa_dev->bus->parent->io_space.start;
 
 	isa_dev->resource.start = base;
@@ -53,6 +54,9 @@
  *
  * The P1275 standard for ISA devices seems to also have been
  * totally ignored.
+ *
+ * On later systems, an interrupt-map and interrupt-map-mask scheme
+ * akin to EBUS is used.
  */
 static struct {
 	int	obp_irq;
@@ -67,33 +71,72 @@
 	{ 0, 0x00 }	/* end of table */
 };
 
-static void __init isa_dev_get_irq(struct isa_device *isa_dev)
+static int __init isa_dev_get_irq_using_imap(struct isa_device *isa_dev,
+					     struct isa_bridge *isa_br,
+					     int *interrupt,
+					     struct linux_prom_registers *pregs)
+{
+	unsigned int hi, lo, irq;
+	int i;
+
+	hi = pregs->which_io & isa_br->isa_intmask.phys_hi;
+	lo = pregs->phys_addr & isa_br->isa_intmask.phys_lo;
+	irq = *interrupt & isa_br->isa_intmask.interrupt;
+	for (i = 0; i < isa_br->num_isa_intmap; i++) {
+		if ((isa_br->isa_intmap[i].phys_hi == hi) &&
+		    (isa_br->isa_intmap[i].phys_lo == lo) &&
+		    (isa_br->isa_intmap[i].interrupt == irq)) {
+			*interrupt = isa_br->isa_intmap[i].cinterrupt;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+static void __init isa_dev_get_irq(struct isa_device *isa_dev,
+				   struct linux_prom_registers *pregs)
 {
 	int irq_prop;
 
 	irq_prop = prom_getintdefault(isa_dev->prom_node,
 				      "interrupts", -1);
 	if (irq_prop <= 0) {
-		isa_dev->irq = PCI_IRQ_NONE;
+		goto no_irq;
 	} else {
+		struct pci_controller_info *pcic;
+		struct pci_pbm_info *pbm;
 		int i;
 
+		if (isa_dev->bus->num_isa_intmap) {
+			if (!isa_dev_get_irq_using_imap(isa_dev,
+							isa_dev->bus,
+							&irq_prop,
+							pregs))
+				goto route_irq;
+		}
+
 		for (i = 0; grover_irq_table[i].obp_irq != 0; i++) {
 			if (grover_irq_table[i].obp_irq == irq_prop) {
-				struct pci_controller_info *pcic;
-				struct pci_pbm_info *pbm;
 				int ino = grover_irq_table[i].pci_ino;
 
-				if (ino == 0) {
-					isa_dev->irq = PCI_IRQ_NONE;
-				} else {
-					pbm = isa_dev->bus->parent;
-					pcic = pbm->parent;
-					isa_dev->irq = pcic->irq_build(pbm, NULL, ino);
-				}
+				if (ino == 0)
+					goto no_irq;
+
+				irq_prop = ino;
+				goto route_irq;
 			}
 		}
+		goto no_irq;
+
+route_irq:
+		pbm = isa_dev->bus->parent;
+		pcic = pbm->parent;
+		isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop);
+		return;
 	}
+
+no_irq:
+	isa_dev->irq = PCI_IRQ_NONE;
 }
 
 static void __init isa_fill_children(struct isa_device *parent_isa_dev)
@@ -105,6 +148,7 @@
 
 	printk(" ->");
 	while (node != 0) {
+		struct linux_prom_registers regs[PROMREG_MAX];
 		struct isa_device *isa_dev;
 		int prop_len;
 
@@ -138,8 +182,8 @@
 		if (prop_len <= 0)
 			isa_dev->compatible[0] = '\0';
 
-		isa_dev_get_resource(isa_dev);
-		isa_dev_get_irq(isa_dev);
+		isa_dev_get_resource(isa_dev, regs, sizeof(regs));
+		isa_dev_get_irq(isa_dev, regs);
 
 		report_dev(isa_dev, 1);
 
@@ -152,6 +196,7 @@
 	int node = prom_getchild(isa_br->prom_node);
 
 	while (node != 0) {
+		struct linux_prom_registers regs[PROMREG_MAX];
 		struct isa_device *isa_dev;
 		int prop_len;
 
@@ -194,8 +239,8 @@
 		if (prop_len <= 0)
 			isa_dev->compatible[0] = '\0';
 
-		isa_dev_get_resource(isa_dev);
-		isa_dev_get_irq(isa_dev);
+		isa_dev_get_resource(isa_dev, regs, sizeof(regs));
+		isa_dev_get_irq(isa_dev, regs);
 
 		report_dev(isa_dev, 0);
 
@@ -259,6 +304,21 @@
 		else
 			isa_br->num_isa_ranges =
 				(prop_len / sizeof(struct linux_prom_isa_ranges));
+
+		prop_len = prom_getproperty(isa_br->prom_node,
+					    "interrupt-map",
+					    (char *) isa_br->isa_intmap,
+					    sizeof(isa_br->isa_intmap));
+		if (prop_len <= 0)
+			isa_br->num_isa_intmap = 0;
+		else
+			isa_br->num_isa_intmap =
+				(prop_len / sizeof(struct linux_prom_isa_intmap));
+
+		prop_len = prom_getproperty(isa_br->prom_node,
+					    "interrupt-map-mask",
+					    (char *) &(isa_br->isa_intmask),
+					    sizeof(isa_br->isa_intmask));
 
 		printk("isa%d:", isa_br->index);
 
diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
--- a/arch/sparc64/kernel/pci.c	Thu Jul 17 00:20:03 2003
+++ b/arch/sparc64/kernel/pci.c	Fri Jul 25 08:33:26 2003
@@ -81,6 +81,8 @@
 extern void sabre_init(int, char *);
 extern void psycho_init(int, char *);
 extern void schizo_init(int, char *);
+extern void schizo_plus_init(int, char *);
+extern void tomatillo_init(int, char *);
 
 static struct {
 	char *model_name;
@@ -92,7 +94,11 @@
 	{ "SUNW,psycho", psycho_init },
 	{ "pci108e,8000", psycho_init },
 	{ "SUNW,schizo", schizo_init },
-	{ "pci108e,8001", schizo_init }
+	{ "pci108e,8001", schizo_init },
+	{ "SUNW,schizo+", schizo_plus_init },
+	{ "pci108e,8002", schizo_plus_init },
+	{ "SUNW,tomatillo", tomatillo_init },
+	{ "pci108e,a801", tomatillo_init },
 };
 #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
 				  sizeof(pci_controller_table[0]))
diff -Nru a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
--- a/arch/sparc64/kernel/pci_common.c	Tue Mar 26 14:00:19 2002
+++ b/arch/sparc64/kernel/pci_common.c	Fri Jul 25 08:33:26 2003
@@ -54,6 +54,7 @@
 	    (pdev->vendor == PCI_VENDOR_ID_SUN) &&
 	    (pdev->device == PCI_DEVICE_ID_SUN_PBM ||
 	     pdev->device == PCI_DEVICE_ID_SUN_SCHIZO ||
+	     pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO ||
 	     pdev->device == PCI_DEVICE_ID_SUN_SABRE ||
 	     pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD)) {
 		*nregs = 0;
@@ -699,7 +700,7 @@
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	struct pci_pbm_info *pbm = pcp->pbm;
 	struct pci_controller_info *p = pbm->parent;
-	unsigned int portid = p->portid;
+	unsigned int portid = pbm->portid;
 	unsigned int prom_irq;
 	int prom_node = pcp->prom_node;
 	int err;
diff -Nru a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
--- a/arch/sparc64/kernel/pci_iommu.c	Mon Mar 31 05:46:30 2003
+++ b/arch/sparc64/kernel/pci_iommu.c	Sun Jul 27 21:19:59 2003
@@ -829,5 +829,8 @@
 		}
 	}
 
+	if (device_mask >= (1UL << 32UL))
+		return 0;
+
 	return (device_mask & dma_addr_mask) == dma_addr_mask;
 }
diff -Nru a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
--- a/arch/sparc64/kernel/pci_psycho.c	Wed Mar 20 15:59:25 2002
+++ b/arch/sparc64/kernel/pci_psycho.c	Sun Aug 24 02:38:14 2003
@@ -388,7 +388,6 @@
 					    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;
@@ -413,11 +412,11 @@
 	if (PIL_RESERVED(pil))
 		BUG();
 
-	imap = p->controller_regs + imap_off;
+	imap = pbm->controller_regs + imap_off;
 	imap += 4;
 
 	iclr_off = psycho_iclr_offset(ino);
-	iclr = p->controller_regs + iclr_off;
+	iclr = pbm->controller_regs + iclr_off;
 	iclr += 4;
 
 	if ((ino & 0x20) == 0)
@@ -484,7 +483,7 @@
 				   int is_pbm_a)
 {
 	struct pci_strbuf *strbuf = &pbm->stc;
-	unsigned long regbase = p->controller_regs;
+	unsigned long regbase = p->pbm_A.controller_regs;
 	unsigned long err_base, tag_base, line_base;
 	u64 control;
 	int i;
@@ -679,7 +678,7 @@
 		psycho_write(iommu->iommu_control,
 			     control | PSYCHO_IOMMU_CTRL_DENAB);
 		for (i = 0; i < 16; i++) {
-			unsigned long base = p->controller_regs;
+			unsigned long base = p->pbm_A.controller_regs;
 
 			iommu_tag[i] =
 				psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
@@ -756,8 +755,8 @@
 static void psycho_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 + PSYCHO_UE_AFSR;
-	unsigned long afar_reg = p->controller_regs + PSYCHO_UE_AFAR;
+	unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR;
+	unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
@@ -831,8 +830,8 @@
 static void psycho_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 + PSYCHO_CE_AFSR;
-	unsigned long afar_reg = p->controller_regs + PSYCHO_CE_AFAR;
+	unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR;
+	unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
@@ -911,6 +910,42 @@
 #define PSYCHO_PCI_AFAR_A	0x2018UL
 #define PSYCHO_PCI_AFAR_B	0x4018UL
 
+static void psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a)
+{
+	unsigned long csr_reg, csr, csr_error_bits;
+	u16 stat;
+
+	if (is_pbm_a) {
+		csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL;
+	} else {
+		csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL;
+	}
+	csr = psycho_read(csr_reg);
+	csr_error_bits =
+		csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
+	if (csr_error_bits) {
+		/* Clear the errors.  */
+		psycho_write(csr_reg, csr);
+
+		/* Log 'em.  */
+		if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
+			printk("%s: PCI streaming byte hole error asserted.\n",
+			       pbm->name);
+		if (csr_error_bits & PSYCHO_PCICTRL_SERR)
+			printk("%s: PCI SERR signal asserted.\n", pbm->name);
+	}
+	pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat);
+	if (stat & (PCI_STATUS_PARITY |
+		    PCI_STATUS_SIG_TARGET_ABORT |
+		    PCI_STATUS_REC_TARGET_ABORT |
+		    PCI_STATUS_REC_MASTER_ABORT |
+		    PCI_STATUS_SIG_SYSTEM_ERROR)) {
+		printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
+		       pbm->name, stat);
+		pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff);
+	}
+}
+
 static void psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct pci_pbm_info *pbm = dev_id;
@@ -921,11 +956,11 @@
 
 	is_pbm_a = (pbm == &pbm->parent->pbm_A);
 	if (is_pbm_a) {
-		afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_A;
-		afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_A;
+		afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A;
+		afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A;
 	} else {
-		afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_B;
-		afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_B;
+		afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B;
+		afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B;
 	}
 
 	/* Latch error status. */
@@ -939,7 +974,7 @@
 		 PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
 		 PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
 	if (!error_bits)
-		return;
+		return psycho_pcierr_intr_other(pbm, is_pbm_a);
 	psycho_write(afsr_reg, error_bits);
 
 	/* Log the error. */
@@ -1022,8 +1057,8 @@
 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;
+	unsigned long base = p->pbm_A.controller_regs;
+	unsigned int irq, portid = pbm->portid;
 	u64 tmp;
 
 	/* Build IRQs and register handlers. */
@@ -1043,6 +1078,7 @@
 		prom_halt();
 	}
 
+	pbm = &p->pbm_A;
 	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) {
@@ -1051,6 +1087,7 @@
 		prom_halt();
 	}
 
+	pbm = &p->pbm_B;
 	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) {
@@ -1310,26 +1347,26 @@
 	iommu->iommu_cur_ctx = 0;
 
 	/* Register addresses. */
-	iommu->iommu_control  = p->controller_regs + PSYCHO_IOMMU_CONTROL;
-	iommu->iommu_tsbbase  = p->controller_regs + PSYCHO_IOMMU_TSBBASE;
-	iommu->iommu_flush    = p->controller_regs + PSYCHO_IOMMU_FLUSH;
+	iommu->iommu_control  = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL;
+	iommu->iommu_tsbbase  = p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE;
+	iommu->iommu_flush    = p->pbm_A.controller_regs + PSYCHO_IOMMU_FLUSH;
 	/* PSYCHO's IOMMU lacks ctx flushing. */
 	iommu->iommu_ctxflush = 0;
 
 	/* We use the main control register of PSYCHO as the write
 	 * completion register.
 	 */
-	iommu->write_complete_reg = p->controller_regs + PSYCHO_CONTROL;
+	iommu->write_complete_reg = p->pbm_A.controller_regs + PSYCHO_CONTROL;
 
 	/*
 	 * Invalidate TLB Entries.
 	 */
-	control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL);
+	control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
 	control |= PSYCHO_IOMMU_CTRL_DENAB;
-	psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);
+	psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
 	for(i = 0; i < 16; i++) {
-		psycho_write(p->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-		psycho_write(p->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
+		psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
+		psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
 	}
 
 	/* Leave diag mode enabled for full-flushing done
@@ -1360,16 +1397,16 @@
 		iommu->alloc_info[i].next = 0;
 	}
 
-	psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase));
+	psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase));
 
-	control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL);
+	control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
 	control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
 	control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
-	psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);
+	psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
 
 	/* If necessary, hook us up for starfire IRQ translations. */
 	if(this_is_starfire)
-		p->starfire_cookie = starfire_hookup(p->portid);
+		p->starfire_cookie = starfire_hookup(p->pbm_A.portid);
 	else
 		p->starfire_cookie = NULL;
 }
@@ -1391,28 +1428,28 @@
 	u64 tmp;
 
 	/* PROM sets the IRQ retry value too low, increase it. */
-	psycho_write(p->controller_regs + PSYCHO_IRQ_RETRY, 0xff);
+	psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 0xff);
 
 	/* Enable arbiter for all PCI slots. */
-	tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_CTRL);
+	tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL);
 	tmp |= PSYCHO_PCICTRL_AEN;
-	psycho_write(p->controller_regs + PSYCHO_PCIA_CTRL, tmp);
+	psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL, tmp);
 
-	tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_CTRL);
+	tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL);
 	tmp |= PSYCHO_PCICTRL_AEN;
-	psycho_write(p->controller_regs + PSYCHO_PCIB_CTRL, tmp);
+	psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL, tmp);
 
 	/* Disable DMA write / PIO read synchronization on
 	 * both PCI bus segments.
 	 * [ U2P Erratum 1243770, STP2223BGA data sheet ]
 	 */
-	tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_DIAG);
+	tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG);
 	tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-	psycho_write(p->controller_regs + PSYCHO_PCIA_DIAG, tmp);
+	psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG, tmp);
 
-	tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_DIAG);
+	tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG);
 	tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-	psycho_write(p->controller_regs + PSYCHO_PCIB_DIAG, tmp);
+	psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp);
 }
 
 static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,
@@ -1435,7 +1472,7 @@
 				   struct pci_pbm_info *pbm,
 				   int is_pbm_a)
 {
-	unsigned long base = p->controller_regs;
+	unsigned long base = pbm->controller_regs;
 	u64 control;
 
 	if (is_pbm_a) {
@@ -1500,14 +1537,21 @@
 	if (is_pbm_a) {
 		pbm = &p->pbm_A;
 		pbm->pci_first_slot = 1;
-		pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_A;
-		pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_A;
+		pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_A;
+		pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_A;
 	} else {
 		pbm = &p->pbm_B;
 		pbm->pci_first_slot = 2;
-		pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_B;
-		pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_B;
+		pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_B;
+		pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_B;
 	}
+
+	pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
+	pbm->chip_version =
+		prom_getintdefault(prom_node, "version#", 0);
+	pbm->chip_revision =
+		prom_getintdefault(prom_node, "module-revision#", 0);
+
 	pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE;
 	pbm->io_space.flags = IORESOURCE_IO;
 	pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE;
@@ -1575,7 +1619,7 @@
 
 	spin_lock_irqsave(&pci_controller_lock, flags);
 	for(p = pci_controller_root; p; p = p->next) {
-		if (p->portid == upa_portid) {
+		if (p->pbm_A.portid == upa_portid) {
 			spin_unlock_irqrestore(&pci_controller_lock, flags);
 			is_pbm_a = (p->pbm_A.prom_node == 0);
 			psycho_pbm_init(p, node, is_pbm_a);
@@ -1603,7 +1647,8 @@
 	pci_controller_root = p;
 	spin_unlock_irqrestore(&pci_controller_lock, flags);
 
-	p->portid = upa_portid;
+	p->pbm_A.portid = upa_portid;
+	p->pbm_B.portid = upa_portid;
 	p->index = pci_num_controllers++;
 	p->pbms_same_domain = 0;
 	p->scan_bus = psycho_scan_bus;
@@ -1620,9 +1665,10 @@
 		prom_halt();
 	}
 
-	p->controller_regs = pr_regs[2].phys_addr;
+	p->pbm_A.controller_regs = pr_regs[2].phys_addr;
+	p->pbm_B.controller_regs = pr_regs[2].phys_addr;
 	printk("PCI: Found PSYCHO, control regs at %016lx\n",
-	       p->controller_regs);
+	       p->pbm_A.controller_regs);
 
 	p->pbm_A.config_space = p->pbm_B.config_space =
 		(pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
diff -Nru a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
--- a/arch/sparc64/kernel/pci_sabre.c	Thu Jul 17 23:30:15 2003
+++ b/arch/sparc64/kernel/pci_sabre.c	Sun Aug 24 02:38:14 2003
@@ -219,6 +219,7 @@
 	 ((unsigned long)(REG)))
 
 static int hummingbird_p;
+static struct pci_bus *sabre_root_bus;
 
 static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm,
 				     unsigned char bus,
@@ -630,7 +631,6 @@
 					   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;
@@ -655,11 +655,11 @@
 	if (PIL_RESERVED(pil))
 		BUG();
 
-	imap = p->controller_regs + imap_off;
+	imap = pbm->controller_regs + imap_off;
 	imap += 4;
 
 	iclr_off = sabre_iclr_offset(ino);
-	iclr = p->controller_regs + iclr_off;
+	iclr = pbm->controller_regs + iclr_off;
 	iclr += 4;
 
 	if ((ino & 0x20) == 0)
@@ -737,7 +737,7 @@
 		sabre_write(iommu->iommu_control,
 			    (control | SABRE_IOMMUCTRL_DENAB));
 		for (i = 0; i < 16; i++) {
-			unsigned long base = p->controller_regs;
+			unsigned long base = p->pbm_A.controller_regs;
 
 			iommu_tag[i] =
 				sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
@@ -786,8 +786,8 @@
 static void sabre_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 + SABRE_UE_AFSR;
-	unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR;
+	unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_UE_AFSR;
+	unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
@@ -844,8 +844,8 @@
 static void sabre_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 + SABRE_CE_AFSR;
-	unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR;
+	unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_CE_AFSR;
+	unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
@@ -895,6 +895,38 @@
 	printk("]\n");
 }
 
+static void sabre_pcierr_intr_other(struct pci_controller_info *p)
+{
+	unsigned long csr_reg, csr, csr_error_bits;
+	u16 stat;
+
+	csr_reg = p->pbm_A.controller_regs + SABRE_PCICTRL;
+	csr = sabre_read(csr_reg);
+	csr_error_bits =
+		csr & SABRE_PCICTRL_SERR;
+	if (csr_error_bits) {
+		/* Clear the errors.  */
+		sabre_write(csr_reg, csr);
+
+		/* Log 'em.  */
+		if (csr_error_bits & SABRE_PCICTRL_SERR)
+			printk("SABRE%d: PCI SERR signal asserted.\n",
+			       p->index);
+	}
+	pci_read_config_word(sabre_root_bus->self,
+			     PCI_STATUS, &stat);
+	if (stat & (PCI_STATUS_PARITY |
+		    PCI_STATUS_SIG_TARGET_ABORT |
+		    PCI_STATUS_REC_TARGET_ABORT |
+		    PCI_STATUS_REC_MASTER_ABORT |
+		    PCI_STATUS_SIG_SYSTEM_ERROR)) {
+		printk("SABRE%d: PCI bus error, PCI_STATUS[%04x]\n",
+		       p->index, stat);
+		pci_write_config_word(sabre_root_bus->self,
+				      PCI_STATUS, 0xffff);
+	}
+}
+
 static void sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct pci_controller_info *p = dev_id;
@@ -902,8 +934,8 @@
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
-	afsr_reg = p->controller_regs + SABRE_PIOAFSR;
-	afar_reg = p->controller_regs + SABRE_PIOAFAR;
+	afsr_reg = p->pbm_A.controller_regs + SABRE_PIOAFSR;
+	afar_reg = p->pbm_A.controller_regs + SABRE_PIOAFAR;
 
 	/* Latch error status. */
 	afar = sabre_read(afar_reg);
@@ -916,7 +948,7 @@
 		 SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
 		 SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
 	if (!error_bits)
-		return;
+		return sabre_pcierr_intr_other(p);
 	sabre_write(afsr_reg, error_bits);
 
 	/* Log the error. */
@@ -995,8 +1027,8 @@
 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;
+	unsigned long base = pbm->controller_regs;
+	unsigned long irq, portid = pbm->portid;
 	u64 tmp;
 
 	/* We clear the error bits in the appropriate AFSR before
@@ -1044,13 +1076,12 @@
 					 struct resource *root)
 {
 	struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number];
-	struct pci_controller_info *p = pbm->parent;
 	unsigned long base;
 
 	if (res->flags & IORESOURCE_IO)
-		base = p->controller_regs + SABRE_IOSPACE;
+		base = pbm->controller_regs + SABRE_IOSPACE;
 	else
-		base = p->controller_regs + SABRE_MEMSPACE;
+		base = pbm->controller_regs + SABRE_MEMSPACE;
 
 	res->start += base;
 	res->end += base;
@@ -1060,7 +1091,6 @@
 {
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	struct pci_pbm_info *pbm = pcp->pbm;
-	struct pci_controller_info *p = pbm->parent;
 	struct resource *res;
 	unsigned long base;
 	u32 reg;
@@ -1078,9 +1108,9 @@
 
 	is_64bit = 0;
 	if (res->flags & IORESOURCE_IO)
-		base = p->controller_regs + SABRE_IOSPACE;
+		base = pbm->controller_regs + SABRE_IOSPACE;
 	else {
-		base = p->controller_regs + SABRE_MEMSPACE;
+		base = pbm->controller_regs + SABRE_MEMSPACE;
 		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
 		    == PCI_BASE_ADDRESS_MEM_TYPE_64)
 			is_64bit = 1;
@@ -1197,6 +1227,8 @@
 	pci_fixup_host_bridge_self(sabre_bus);
 	sabre_bus->self->sysdata = cookie;
 
+	sabre_root_bus = sabre_bus;
+
 	apb_init(p, sabre_bus);
 
 	sabres_scanned = 0;
@@ -1256,21 +1288,21 @@
 	iommu->iommu_cur_ctx = 0;
 
 	/* Register addresses. */
-	iommu->iommu_control  = p->controller_regs + SABRE_IOMMU_CONTROL;
-	iommu->iommu_tsbbase  = p->controller_regs + SABRE_IOMMU_TSBBASE;
-	iommu->iommu_flush    = p->controller_regs + SABRE_IOMMU_FLUSH;
-	iommu->write_complete_reg = p->controller_regs + SABRE_WRSYNC;
+	iommu->iommu_control  = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL;
+	iommu->iommu_tsbbase  = p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE;
+	iommu->iommu_flush    = p->pbm_A.controller_regs + SABRE_IOMMU_FLUSH;
+	iommu->write_complete_reg = p->pbm_A.controller_regs + SABRE_WRSYNC;
 	/* Sabre's IOMMU lacks ctx flushing. */
 	iommu->iommu_ctxflush = 0;
                                         
 	/* Invalidate TLB Entries. */
-	control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL);
+	control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
 	control |= SABRE_IOMMUCTRL_DENAB;
-	sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
+	sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
 
 	for(i = 0; i < 16; i++) {
-		sabre_write(p->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
-		sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
+		sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
+		sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
 	}
 
 	/* Leave diag mode enabled for full-flushing done
@@ -1287,9 +1319,9 @@
 	iommu->dma_addr_mask = dma_mask;
 	memset((char *)tsbbase, 0, PAGE_SIZE << order);
 
-	sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase));
+	sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase));
 
-	control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL);
+	control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
 	control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
 	control |= SABRE_IOMMUCTRL_ENAB;
 	switch(tsbsize) {
@@ -1306,7 +1338,7 @@
 		prom_halt();
 		break;
 	}
-	sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
+	sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
 
 	/* We start with no consistent mappings. */
 	iommu->lowest_consistent_map =
@@ -1322,8 +1354,8 @@
 						   struct pci_pbm_info *pbm)
 {
 	char *name = pbm->name;
-	unsigned long ibase = p->controller_regs + SABRE_IOSPACE;
-	unsigned long mbase = p->controller_regs + SABRE_MEMSPACE;
+	unsigned long ibase = p->pbm_A.controller_regs + SABRE_IOSPACE;
+	unsigned long mbase = p->pbm_A.controller_regs + SABRE_MEMSPACE;
 	unsigned int devfn;
 	unsigned long first, last, i;
 	u8 *addr, map;
@@ -1416,6 +1448,7 @@
 			pbm = &p->pbm_B;
 		else
 			pbm = &p->pbm_A;
+		pbm->chip_type = PBM_CHIP_TYPE_SABRE;
 		pbm->parent = p;
 		pbm->prom_node = node;
 		pbm->pci_first_slot = 1;
@@ -1511,11 +1544,11 @@
 		pbm->io_space.name = pbm->mem_space.name = pbm->name;
 
 		/* Hack up top-level resources. */
-		pbm->io_space.start = p->controller_regs + SABRE_IOSPACE;
+		pbm->io_space.start = p->pbm_A.controller_regs + SABRE_IOSPACE;
 		pbm->io_space.end   = pbm->io_space.start + (1UL << 24) - 1UL;
 		pbm->io_space.flags = IORESOURCE_IO;
 
-		pbm->mem_space.start = p->controller_regs + SABRE_MEMSPACE;
+		pbm->mem_space.start = p->pbm_A.controller_regs + SABRE_MEMSPACE;
 		pbm->mem_space.end   = pbm->mem_space.start + (unsigned long)dma_begin - 1UL;
 		pbm->mem_space.flags = IORESOURCE_MEM;
 
@@ -1591,7 +1624,8 @@
 	pci_controller_root = p;
 	spin_unlock_irqrestore(&pci_controller_lock, flags);
 
-	p->portid = upa_portid;
+	p->pbm_A.portid = upa_portid;
+	p->pbm_B.portid = upa_portid;
 	p->index = pci_num_controllers++;
 	p->pbms_same_domain = 1;
 	p->scan_bus = sabre_scan_bus;
@@ -1614,30 +1648,31 @@
 	/*
 	 * First REG in property is base of entire SABRE register space.
 	 */
-	p->controller_regs = pr_regs[0].phys_addr;
-	pci_dma_wsync = p->controller_regs + SABRE_WRSYNC;
+	p->pbm_A.controller_regs = pr_regs[0].phys_addr;
+	p->pbm_B.controller_regs = pr_regs[0].phys_addr;
+	pci_dma_wsync = p->pbm_A.controller_regs + SABRE_WRSYNC;
 
 	printk("PCI: Found SABRE, main regs at %016lx, wsync at %016lx\n",
-	       p->controller_regs, pci_dma_wsync);
+	       p->pbm_A.controller_regs, pci_dma_wsync);
 
 	/* Clear interrupts */
 
 	/* PCI first */
 	for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
-		sabre_write(p->controller_regs + clear_irq, 0x0UL);
+		sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
 
 	/* Then OBIO */
 	for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
-		sabre_write(p->controller_regs + clear_irq, 0x0UL);
+		sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
 
 	/* Error interrupts are enabled later after the bus scan. */
-	sabre_write(p->controller_regs + SABRE_PCICTRL,
+	sabre_write(p->pbm_A.controller_regs + SABRE_PCICTRL,
 		    (SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |
 		     SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
 
 	/* Now map in PCI config space for entire SABRE. */
 	p->pbm_A.config_space = p->pbm_B.config_space =
-		(p->controller_regs + SABRE_CONFIGSPACE);
+		(p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
 	printk("SABRE: Shared PCI config space at %016lx\n",
 	       p->pbm_A.config_space);
 
diff -Nru a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
--- a/arch/sparc64/kernel/pci_schizo.c	Sun Sep 29 23:05:48 2002
+++ b/arch/sparc64/kernel/pci_schizo.c	Sun Aug 24 02:38:14 2003
@@ -1,7 +1,7 @@
 /* $Id: pci_schizo.c,v 1.23.2.2 2002/03/11 07:55:24 davem Exp $
- * pci_schizo.c: SCHIZO specific PCI controller support.
+ * pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
  *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com)
  */
 
 #include <linux/kernel.h>
@@ -45,13 +45,7 @@
  * 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 */
@@ -101,25 +95,21 @@
 {
 	if (!pbm)
 		return NULL;
+	bus -= pbm->pci_first_busno;
 	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.
- */
+/* Just make sure the bus number is in range.  */
 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));
+	if (bus < pbm->pci_first_busno ||
+	    bus > pbm->pci_last_busno)
+		return 1;
+	return 0;
 }
 
 /* SCHIZO PCI configuration space accessors. */
@@ -188,6 +178,15 @@
 	}
 
 	pci_config_read32(addr, value);
+	if (where == PCI_PRIMARY_BUS &&
+	    dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
+	    *value != 0xffffffff) {
+		u8 *busp = ((u8 *) value) + 1;
+		int i;
+
+		for (i = 0; i < 3; i++)
+			busp[i] += pbm->pci_first_busno;
+	}
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -251,6 +250,20 @@
 		       where);
 		return PCIBIOS_SUCCESSFUL;
 	}
+
+	if (where == PCI_PRIMARY_BUS &&
+	    dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		u8 *busp = ((u8 *) &value) + 1;
+		int i;
+
+		for (i = 0; i < 3; i++) {
+			if (busp[i] >= pbm->pci_first_busno)
+				busp[i] += pbm->pci_first_busno;
+			else
+				busp[i] = 0;
+		}
+	}
+
 	pci_config_write32(addr, value);
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -379,16 +392,10 @@
 					    struct pci_dev *pdev,
 					    unsigned int ino)
 {
-	struct pci_controller_info *p = pbm->parent;
 	struct ino_bucket *bucket;
-	unsigned long imap, iclr, pbm_off;
+	unsigned long imap, iclr;
 	unsigned long imap_off, iclr_off;
-	int pil;
-
-	if (pbm == &p->pbm_A)
-		pbm_off = SCHIZO_PBM_A_REGS_OFF;
-	else
-		pbm_off = SCHIZO_PBM_B_REGS_OFF;
+	int pil, ign_fixup;
 
 	ino &= PCI_IRQ_INO;
 	imap_off = schizo_imap_offset(ino);
@@ -399,11 +406,11 @@
 	if (PIL_RESERVED(pil))
 		BUG();
 
-	imap = p->controller_regs + pbm_off + imap_off;
+	imap = pbm->pbm_regs + imap_off;
 	imap += 4;
 
 	iclr_off = schizo_iclr_offset(ino);
-	iclr = p->controller_regs + pbm_off + iclr_off;
+	iclr = pbm->pbm_regs + iclr_off;
 	iclr += 4;
 
 	/* On Schizo, no inofixup occurs.  This is because each
@@ -411,8 +418,17 @@
 	 * there is only one IMAP register for each PCI slot even
 	 * though four different INOs can be generated by each
 	 * PCI slot.
+	 *
+	 * But, for JBUS variants (essentially, Tomatillo), we have
+	 * to fixup the lowest bit of the interrupt group number.
 	 */
-	bucket = __bucket(build_irq(pil, 0, iclr, imap));
+	ign_fixup = 0;
+	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
+		if (pbm->portid & 1)
+			ign_fixup = (1 << 6);
+	}
+
+	bucket = __bucket(build_irq(pil, ign_fixup, iclr, imap));
 	bucket->flags |= IBF_PCI;
 
 	return __irq(bucket);
@@ -428,6 +444,13 @@
 static unsigned long stc_tag_buf[16];
 static unsigned long stc_line_buf[16];
 
+/* These offsets look weird because I keep in pbm->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)
+
 static void schizo_clear_other_err_intr(int irq)
 {
 	struct ino_bucket *bucket = __bucket(irq);
@@ -459,19 +482,12 @@
 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 regbase = pbm->pbm_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;
@@ -517,8 +533,8 @@
 			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,
+				printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n",
+				       pbm->name,
 				       j,
 				       (errval & SCHIZO_STCERR_WRITE) ? 1 : 0,
 				       (errval & SCHIZO_STCERR_READ) ? 1 : 0);
@@ -527,8 +543,8 @@
 		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,
+			printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)R(%d)]\n",
+			       pbm->name,
 			       i,
 			       ((tagval & SCHIZO_STCTAG_PPN) >> 19UL),
 			       (tagval & SCHIZO_STCTAG_VPN),
@@ -536,9 +552,9 @@
 			       ((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)"
+			printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
 			       "V(%d)FOFN(%d)]\n",
-			       p->index, pbm_name,
+			       pbm->name,
 			       i,
 			       ((lineval & SCHIZO_STCLINE_LINDX) >> 23UL),
 			       ((lineval & SCHIZO_STCLINE_SPTR) >> 13UL),
@@ -574,13 +590,11 @@
 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);
@@ -608,8 +622,8 @@
 			type_string = "ECC Error";
 			break;
 		};
-		printk("SCHIZO%d: PBM-%c IOMMU Error, type[%s]\n",
-		       p->index, pbm_name, type_string);
+		printk("%s: IOMMU Error, type[%s]\n",
+		       pbm->name, type_string);
 
 		/* Put the IOMMU into diagnostic mode and probe
 		 * it's TLB for entries with error status.
@@ -624,11 +638,7 @@
 		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;
+		base = pbm->pbm_regs;
 
 		for (i = 0; i < 16; i++) {
 			iommu_tag[i] =
@@ -667,22 +677,23 @@
 				type_string = "ECC Error";
 				break;
 			};
-			printk("SCHIZO%d: PBM-%c IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) "
+			printk("%s: IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) "
 			       "sz(%dK) vpg(%08lx)]\n",
-			       p->index, pbm_name, i, type_string,
+			       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) << IOMMU_PAGE_SHIFT);
-			printk("SCHIZO%d: PBM-%c IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
-			       p->index, pbm_name, i,
+			printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
+			       pbm->name, i,
 			       ((data & SCHIZO_IOMMU_DATA_VALID) ? 1 : 0),
 			       ((data & SCHIZO_IOMMU_DATA_CACHE) ? 1 : 0),
 			       (data & SCHIZO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
 		}
 	}
-	__schizo_check_stc_error_pbm(pbm, type);
+	if (pbm->stc.strbuf_enabled)
+		__schizo_check_stc_error_pbm(pbm, type);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -697,26 +708,26 @@
 #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
+#define SCHIZO_UEAFSR_PPIO	0x8000000000000000UL /* Safari */
+#define SCHIZO_UEAFSR_PDRD	0x4000000000000000UL /* Safari/Tomatillo */
+#define SCHIZO_UEAFSR_PDWR	0x2000000000000000UL /* Safari */
+#define SCHIZO_UEAFSR_SPIO	0x1000000000000000UL /* Safari */
+#define SCHIZO_UEAFSR_SDMA	0x0800000000000000UL /* Safari/Tomatillo */
+#define SCHIZO_UEAFSR_ERRPNDG	0x0300000000000000UL /* Safari */
+#define SCHIZO_UEAFSR_BMSK	0x000003ff00000000UL /* Safari */
+#define SCHIZO_UEAFSR_QOFF	0x00000000c0000000UL /* Safari/Tomatillo */
+#define SCHIZO_UEAFSR_AID	0x000000001f000000UL /* Safari/Tomatillo */
+#define SCHIZO_UEAFSR_PARTIAL	0x0000000000800000UL /* Safari */
+#define SCHIZO_UEAFSR_OWNEDIN	0x0000000000400000UL /* Safari */
+#define SCHIZO_UEAFSR_MTAGSYND	0x00000000000f0000UL /* Safari */
+#define SCHIZO_UEAFSR_MTAG	0x000000000000e000UL /* Safari */
+#define SCHIZO_UEAFSR_ECCSYND	0x00000000000001ffUL /* Safari */
 
 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_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR;
+	unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported, limit;
 
@@ -741,7 +752,7 @@
 	schizo_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("SCHIZO%d: Uncorrectable Error, primary error type[%s]\n",
+	printk("PCI%d: Uncorrectable Error, primary error type[%s]\n",
 	       p->index,
 	       (((error_bits & SCHIZO_UEAFSR_PPIO) ?
 		 "PIO" :
@@ -749,20 +760,20 @@
 		  "DMA Read" :
 		  ((error_bits & SCHIZO_UEAFSR_PDWR) ?
 		   "DMA Write" : "???")))));
-	printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+	printk("PCI%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",
+	printk("PCI%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);
+	printk("PCI%d: UE AFAR [%016lx]\n", p->index, afar);
+	printk("PCI%d: UE Secondary errors [", p->index);
 	reported = 0;
 	if (afsr & SCHIZO_UEAFSR_SPIO) {
 		reported++;
@@ -803,8 +814,8 @@
 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_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR;
+	unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported, limit;
 
@@ -829,7 +840,7 @@
 	schizo_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("SCHIZO%d: Correctable Error, primary error type[%s]\n",
+	printk("PCI%d: Correctable Error, primary error type[%s]\n",
 	       p->index,
 	       (((error_bits & SCHIZO_CEAFSR_PPIO) ?
 		 "PIO" :
@@ -841,20 +852,20 @@
 	/* 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",
+	printk("PCI%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",
+	printk("PCI%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);
+	printk("PCI%d: CE AFAR [%016lx]\n", p->index, afar);
+	printk("PCI%d: CE Secondary errors [", p->index);
 	reported = 0;
 	if (afsr & SCHIZO_CEAFSR_SPIO) {
 		reported++;
@@ -874,23 +885,101 @@
 #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
+#define SCHIZO_PCIAFSR_PMA	0x8000000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_PTA	0x4000000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_PRTRY	0x2000000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_PPERR	0x1000000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_PTTO	0x0800000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_PUNUS	0x0400000000000000UL /* Schizo */
+#define SCHIZO_PCIAFSR_SMA	0x0200000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_STA	0x0100000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_SRTRY	0x0080000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_SPERR	0x0040000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_STTO	0x0020000000000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_SUNUS	0x0010000000000000UL /* Schizo */
+#define SCHIZO_PCIAFSR_BMSK	0x000003ff00000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_BLK	0x0000000080000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_CFG	0x0000000040000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_MEM	0x0000000020000000UL /* Schizo/Tomatillo */
+#define SCHIZO_PCIAFSR_IO	0x0000000010000000UL /* Schizo/Tomatillo */
+
+#define SCHIZO_PCI_CTRL		(0x2000UL)
+#define SCHIZO_PCICTRL_BUS_UNUS	(1UL << 63UL) /* Safari */
+#define SCHIZO_PCICTRL_ARB_PRIO (0x1ff << 52UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_ESLCK	(1UL << 51UL) /* Safari */
+#define SCHIZO_PCICTRL_ERRSLOT	(7UL << 48UL) /* Safari */
+#define SCHIZO_PCICTRL_TTO_ERR	(1UL << 38UL) /* Safari/Tomatillo */
+#define SCHIZO_PCICTRL_RTRY_ERR	(1UL << 37UL) /* Safari/Tomatillo */
+#define SCHIZO_PCICTRL_DTO_ERR	(1UL << 36UL) /* Safari/Tomatillo */
+#define SCHIZO_PCICTRL_SBH_ERR	(1UL << 35UL) /* Safari */
+#define SCHIZO_PCICTRL_SERR	(1UL << 34UL) /* Safari/Tomatillo */
+#define SCHIZO_PCICTRL_PCISPD	(1UL << 33UL) /* Safari */
+#define SCHIZO_PCICTRL_MRM_PREF	(1UL << 28UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_RDO_PREF	(1UL << 27UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_RDL_PREF	(1UL << 26UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_PTO	(3UL << 24UL) /* Safari/Tomatillo */
+#define SCHIZO_PCICTRL_PTO_SHIFT 24UL
+#define SCHIZO_PCICTRL_TRWSW	(7UL << 21UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_F_TGT_A	(1UL << 20UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_S_DTO_INT (1UL << 19UL) /* Safari */
+#define SCHIZO_PCICTRL_F_TGT_RT	(1UL << 19UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_SBH_INT	(1UL << 18UL) /* Safari */
+#define SCHIZO_PCICTRL_T_DTO_INT (1UL << 18UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_EEN	(1UL << 17UL) /* Safari/Tomatillo */
+#define SCHIZO_PCICTRL_PARK	(1UL << 16UL) /* Safari/Tomatillo */
+#define SCHIZO_PCICTRL_PCIRST	(1UL <<  8UL) /* Safari */
+#define SCHIZO_PCICTRL_ARB_S	(0x3fUL << 0UL) /* Safari */
+#define SCHIZO_PCICTRL_ARB_T	(0xffUL << 0UL) /* Tomatillo */
+
+static void schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
+{
+	unsigned long csr_reg, csr, csr_error_bits;
+	u16 stat;
+
+	csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL;
+	csr = schizo_read(csr_reg);
+	csr_error_bits =
+		csr & (SCHIZO_PCICTRL_BUS_UNUS |
+		       SCHIZO_PCICTRL_TTO_ERR |
+		       SCHIZO_PCICTRL_RTRY_ERR |
+		       SCHIZO_PCICTRL_DTO_ERR |
+		       SCHIZO_PCICTRL_SBH_ERR |
+		       SCHIZO_PCICTRL_SERR);
+	if (csr_error_bits) {
+		/* Clear the errors.  */
+		schizo_write(csr_reg, csr);
+
+		/* Log 'em.  */
+		if (csr_error_bits & SCHIZO_PCICTRL_BUS_UNUS)
+			printk("%s: Bus unusable error asserted.\n",
+			       pbm->name);
+		if (csr_error_bits & SCHIZO_PCICTRL_TTO_ERR)
+			printk("%s: PCI TRDY# timeout error asserted.\n",
+			       pbm->name);
+		if (csr_error_bits & SCHIZO_PCICTRL_RTRY_ERR)
+			printk("%s: PCI excessive retry error asserted.\n",
+			       pbm->name);
+		if (csr_error_bits & SCHIZO_PCICTRL_DTO_ERR)
+			printk("%s: PCI discard timeout error asserted.\n",
+			       pbm->name);
+		if (csr_error_bits & SCHIZO_PCICTRL_SBH_ERR)
+			printk("%s: PCI streaming byte hole error asserted.\n",
+			       pbm->name);
+		if (csr_error_bits & SCHIZO_PCICTRL_SERR)
+			printk("%s: PCI SERR signal asserted.\n",
+			       pbm->name);
+	}
+	pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat);
+	if (stat & (PCI_STATUS_PARITY |
+		    PCI_STATUS_SIG_TARGET_ABORT |
+		    PCI_STATUS_REC_TARGET_ABORT |
+		    PCI_STATUS_REC_MASTER_ABORT |
+		    PCI_STATUS_SIG_SYSTEM_ERROR)) {
+		printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
+		       pbm->name, stat);
+		pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff);
+	}
+}
 
 static void schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -899,16 +988,8 @@
 	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';
-	}
+	base = pbm->pbm_regs;
 
 	afsr_reg = base + SCHIZO_PCI_AFSR;
 	afar_reg = base + SCHIZO_PCI_AFAR;
@@ -926,12 +1007,12 @@
 		 SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
 		 SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
 	if (!error_bits)
-		return;
+		return schizo_pcierr_intr_other(pbm);
 	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,
+	printk("%s: PCI Error, primary error type[%s]\n",
+	       pbm->name,
 	       (((error_bits & SCHIZO_PCIAFSR_PMA) ?
 		 "Master Abort" :
 		 ((error_bits & SCHIZO_PCIAFSR_PTA) ?
@@ -944,8 +1025,8 @@
 		     "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,
+	printk("%s: bytemask[%04lx] was_block(%d) space(%s)\n",
+	       pbm->name,
 	       (afsr & SCHIZO_PCIAFSR_BMSK) >> 32UL,
 	       (afsr & SCHIZO_PCIAFSR_BLK) ? 1 : 0,
 	       ((afsr & SCHIZO_PCIAFSR_CFG) ?
@@ -954,10 +1035,10 @@
 		 "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);
+	printk("%s: PCI AFAR [%016lx]\n",
+	       pbm->name, afar);
+	printk("%s: PCI Secondary errors [",
+	       pbm->name);
 	reported = 0;
 	if (afsr & SCHIZO_PCIAFSR_SMA) {
 		reported++;
@@ -1020,24 +1101,37 @@
 
 #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
+#define BUS_ERROR_BADCMD	0x4000000000000000UL /* Schizo/Tomatillo */
+#define BUS_ERROR_SSMDIS	0x2000000000000000UL /* Safari */
+#define BUS_ERROR_BADMA		0x1000000000000000UL /* Safari */
+#define BUS_ERROR_BADMB		0x0800000000000000UL /* Safari */
+#define BUS_ERROR_BADMC		0x0400000000000000UL /* Safari */
+#define BUS_ERROR_SNOOP_GR	0x0000000000200000UL /* Tomatillo */
+#define BUS_ERROR_SNOOP_PCI	0x0000000000100000UL /* Tomatillo */
+#define BUS_ERROR_SNOOP_RD	0x0000000000080000UL /* Tomatillo */
+#define BUS_ERROR_SNOOP_RDS	0x0000000000020000UL /* Tomatillo */
+#define BUS_ERROR_SNOOP_RDSA	0x0000000000010000UL /* Tomatillo */
+#define BUS_ERROR_SNOOP_OWN	0x0000000000008000UL /* Tomatillo */
+#define BUS_ERROR_SNOOP_RDO	0x0000000000004000UL /* Tomatillo */
+#define BUS_ERROR_CPU1PS	0x0000000000002000UL /* Safari */
+#define BUS_ERROR_WDATA_PERR	0x0000000000002000UL /* Tomatillo */
+#define BUS_ERROR_CPU1PB	0x0000000000001000UL /* Safari */
+#define BUS_ERROR_CTRL_PERR	0x0000000000001000UL /* Tomatillo */
+#define BUS_ERROR_CPU0PS	0x0000000000000800UL /* Safari */
+#define BUS_ERROR_SNOOP_ERR	0x0000000000000800UL /* Tomatillo */
+#define BUS_ERROR_CPU0PB	0x0000000000000400UL /* Safari */
+#define BUS_ERROR_JBUS_ILL_B	0x0000000000000400UL /* Tomatillo */
+#define BUS_ERROR_CIQTO		0x0000000000000200UL /* Safari */
+#define BUS_ERROR_LPQTO		0x0000000000000100UL /* Safari */
+#define BUS_ERROR_JBUS_ILL_C	0x0000000000000100UL /* Tomatillo */
+#define BUS_ERROR_SFPQTO	0x0000000000000080UL /* Safari */
+#define BUS_ERROR_UFPQTO	0x0000000000000040UL /* Safari */
+#define BUS_ERROR_RD_PERR	0x0000000000000040UL /* Tomatillo */
+#define BUS_ERROR_APERR		0x0000000000000020UL /* Safari/Tomatillo */
+#define BUS_ERROR_UNMAP		0x0000000000000010UL /* Safari/Tomatillo */
+#define BUS_ERROR_BUSERR	0x0000000000000004UL /* Safari/Tomatillo */
+#define BUS_ERROR_TIMEOUT	0x0000000000000002UL /* Safari/Tomatillo */
+#define BUS_ERROR_ILL		0x0000000000000001UL /* Safari */
 
 /* We only expect UNMAP errors here.  The rest of the Safari errors
  * are marked fatal and thus cause a system reset.
@@ -1047,19 +1141,19 @@
 	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 = schizo_read(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG);
+	schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG,
 		     errlog & ~(SAFARI_ERRLOG_ERROUT));
 
-	if (!(errlog & SAFARI_ERROR_UNMAP)) {
-		printk("SCHIZO%d: Unexpected Safari error interrupt, errlog[%016lx]\n",
+	if (!(errlog & BUS_ERROR_UNMAP)) {
+		printk("PCI%d: Unexpected Safari/JBUS 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",
+	printk("PCI%d: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
 	       p->index);
 	schizo_check_iommu_error(p, SAFARI_ERR);
 
@@ -1083,131 +1177,279 @@
 #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_BUS_UNUS	(1UL << 63UL)
-#define SCHIZO_PCICTRL_ESLCK	(1UL << 51UL)
-#define SCHIZO_PCICTRL_ERRSLOT	(7UL << 48UL)
-#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_PCISPD	(1UL << 33UL)
-#define SCHIZO_PCICTRL_PTO	(3UL << 24UL)
-#define SCHIZO_PCICTRL_DTO_INT	(1UL << 19UL)
-#define SCHIZO_PCICTRL_SBH_INT	(1UL << 18UL)
-#define SCHIZO_PCICTRL_EEN	(1UL << 17UL)
-#define SCHIZO_PCICTRL_PARK	(1UL << 16UL)
-#define SCHIZO_PCICTRL_PCIRST	(1UL <<  8UL)
-#define SCHIZO_PCICTRL_ARB	(0x3fUL << 0UL)
+struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
+{
+	ino &= IMAP_INO;
+	if (p->pbm_A.ino_bitmap & (1UL << ino))
+		return &p->pbm_A;
+	if (p->pbm_B.ino_bitmap & (1UL << ino))
+		return &p->pbm_B;
+	prom_printf("TOMATILLO%d: No entry in ino bitmap for %d\n",
+		    p->index, ino);
+	prom_halt();
+	/* NOTREACHED */
+	return NULL;
+}
+
+/* How the Tomatillo IRQs are routed around is pure guesswork here.
+ *
+ * All the Tomatillo devices I see in prtconf dumps seem to have only
+ * a single PCI bus unit attached to it.  It would seem they are seperate
+ * devices because their PortID (ie. JBUS ID) values are all different
+ * and thus the registers are mapped to totally different locations.
+ *
+ * However, two Tomatillo's look "similar" in that the only difference
+ * in their PortID is the lowest bit.
+ *
+ * So if we were to ignore this lower bit, it certainly looks like two
+ * PCI bus units of the same Tomatillo.  I still have not really
+ * figured this out...
+ */
+static void __init tomatillo_register_error_handlers(struct pci_controller_info *p)
+{
+	struct pci_pbm_info *pbm;
+	unsigned int irq;
+	struct ino_bucket *bucket;
+	u64 tmp, err_mask, err_no_mask;
+
+	/* Build IRQs and register handlers. */
+	pbm = pbm_for_ino(p, SCHIZO_UE_INO);
+	irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO);
+	if (request_irq(irq, schizo_ue_intr,
+			SA_SHIRQ, "TOMATILLO UE", p) < 0) {
+		prom_printf("%s: Cannot register UE interrupt.\n",
+			    pbm->name);
+		prom_halt();
+	}
+	bucket = __bucket(irq);
+	tmp = readl(bucket->imap);
+	upa_writel(tmp, (pbm->pbm_regs +
+			 schizo_imap_offset(SCHIZO_UE_INO) + 4));
+
+	pbm = pbm_for_ino(p, SCHIZO_CE_INO);
+	irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO);
+	if (request_irq(irq, schizo_ce_intr,
+			SA_SHIRQ, "TOMATILLO CE", p) < 0) {
+		prom_printf("%s: Cannot register CE interrupt.\n",
+			    pbm->name);
+		prom_halt();
+	}
+	bucket = __bucket(irq);
+	tmp = upa_readl(bucket->imap);
+	upa_writel(tmp, (pbm->pbm_regs +
+			 schizo_imap_offset(SCHIZO_CE_INO) + 4));
+
+	pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
+	irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) |
+					   SCHIZO_PCIERR_A_INO));
+	if (request_irq(irq, schizo_pcierr_intr,
+			SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) {
+		prom_printf("%s: Cannot register PBM A PciERR interrupt.\n",
+			    pbm->name);
+		prom_halt();
+	}
+	bucket = __bucket(irq);
+	tmp = upa_readl(bucket->imap);
+	upa_writel(tmp, (pbm->pbm_regs +
+			 schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
+
+	pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
+	irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) |
+					    SCHIZO_PCIERR_B_INO));
+	if (request_irq(irq, schizo_pcierr_intr,
+			SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) {
+		prom_printf("%s: Cannot register PBM B PciERR interrupt.\n",
+			    pbm->name);
+		prom_halt();
+	}
+	bucket = __bucket(irq);
+	tmp = upa_readl(bucket->imap);
+	upa_writel(tmp, (pbm->pbm_regs +
+			 schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
+
+	pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
+	irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO);
+	if (request_irq(irq, schizo_safarierr_intr,
+			SA_SHIRQ, "TOMATILLO SERR", p) < 0) {
+		prom_printf("%s: Cannot register SafariERR interrupt.\n",
+			    pbm->name);
+		prom_halt();
+	}
+	bucket = __bucket(irq);
+	tmp = upa_readl(bucket->imap);
+	upa_writel(tmp, (pbm->pbm_regs +
+			 schizo_imap_offset(SCHIZO_SERR_INO) + 4));
+
+	/* Enable UE and CE interrupts for controller. */
+	schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
+		     (SCHIZO_ECCCTRL_EE |
+		      SCHIZO_ECCCTRL_UE |
+		      SCHIZO_ECCCTRL_CE));
+
+	schizo_write(p->pbm_B.controller_regs + SCHIZO_ECC_CTRL,
+		     (SCHIZO_ECCCTRL_EE |
+		      SCHIZO_ECCCTRL_UE |
+		      SCHIZO_ECCCTRL_CE));
+
+	/* Enable PCI Error interrupts and clear error
+	 * bits.
+	 */
+	err_mask = (SCHIZO_PCICTRL_BUS_UNUS |
+		    SCHIZO_PCICTRL_TTO_ERR |
+		    SCHIZO_PCICTRL_RTRY_ERR |
+		    SCHIZO_PCICTRL_SERR |
+		    SCHIZO_PCICTRL_EEN);
+
+	err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
+
+	tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
+	tmp |= err_mask;
+	tmp &= ~err_no_mask;
+	schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+
+	tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
+	tmp |= err_mask;
+	tmp &= ~err_no_mask;
+	schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+
+	err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+		    SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+		    SCHIZO_PCIAFSR_PTTO |
+		    SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+		    SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+		    SCHIZO_PCIAFSR_STTO);
+
+	schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+	schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+
+	err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
+		    BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
+		    BUS_ERROR_SNOOP_RDS | BUS_ERROR_SNOOP_RDSA |
+		    BUS_ERROR_SNOOP_OWN | BUS_ERROR_SNOOP_RDO |
+		    BUS_ERROR_WDATA_PERR | BUS_ERROR_CTRL_PERR |
+		    BUS_ERROR_SNOOP_ERR | BUS_ERROR_JBUS_ILL_B |
+		    BUS_ERROR_JBUS_ILL_C | BUS_ERROR_RD_PERR |
+		    BUS_ERROR_APERR | BUS_ERROR_UNMAP |
+		    BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
+
+	schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+		     (SCHIZO_SAFERRCTRL_EN | err_mask));
+	schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+		     (SCHIZO_SAFERRCTRL_EN | err_mask));
+
+	schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
+		     (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
+	schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_IRQCTRL,
+		     (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
+}
 
 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 pci_pbm_info *pbm;
+	unsigned int irq;
 	struct ino_bucket *bucket;
-	u64 tmp;
+	u64 tmp, err_mask, err_no_mask;
 
 	/* Build IRQs and register handlers. */
-	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_UE_INO);
+	pbm = pbm_for_ino(p, SCHIZO_UE_INO);
+	irq = schizo_irq_build(pbm, NULL, (pbm->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_printf("%s: Cannot register UE interrupt.\n",
+			    pbm->name);
 		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));
+	upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4));
 
-	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_CE_INO);
+	pbm = pbm_for_ino(p, SCHIZO_CE_INO);
+	irq = schizo_irq_build(pbm, NULL, (pbm->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_printf("%s: Cannot register CE interrupt.\n",
+			    pbm->name);
 		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));
+	upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_PCIERR_A_INO);
+	pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
+	irq = schizo_irq_build(pbm, NULL, (pbm->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);
+			SA_SHIRQ, "SCHIZO PCIERR", pbm) < 0) {
+		prom_printf("%s: Cannot register PBM A PciERR interrupt.\n",
+			    pbm->name);
 		prom_halt();
 	}
 	bucket = __bucket(irq);
 	tmp = upa_readl(bucket->imap);
-	upa_writel(tmp, (base + SCHIZO_PBM_A_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
+	upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
 
-	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO);
+	pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
+	irq = schizo_irq_build(pbm, NULL, (pbm->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);
+			SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_B) < 0) {
+		prom_printf("%s: Cannot register PBM B PciERR interrupt.\n",
+			    pbm->name);
 		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));
+	upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
 
-	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_SERR_INO);
+	pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
+	irq = schizo_irq_build(pbm, NULL, (pbm->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_printf("%s: Cannot register SafariERR interrupt.\n",
+			    pbm->name);
 		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));
+	upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4));
 
 	/* Enable UE and CE interrupts for controller. */
-	schizo_write(base + SCHIZO_ECC_CTRL,
+	schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
 		     (SCHIZO_ECCCTRL_EE |
 		      SCHIZO_ECCCTRL_UE |
 		      SCHIZO_ECCCTRL_CE));
 
+	err_mask = (SCHIZO_PCICTRL_BUS_UNUS |
+		    SCHIZO_PCICTRL_ESLCK |
+		    SCHIZO_PCICTRL_TTO_ERR |
+		    SCHIZO_PCICTRL_RTRY_ERR |
+		    SCHIZO_PCICTRL_SBH_ERR |
+		    SCHIZO_PCICTRL_SERR |
+		    SCHIZO_PCICTRL_SBH_INT |
+		    SCHIZO_PCICTRL_EEN);
+
+	err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
+
 	/* Enable PCI Error interrupts and clear error
 	 * bits for each PBM.
 	 */
-	tmp = schizo_read(base + SCHIZO_PCIA_CTRL);
-	tmp |= (SCHIZO_PCICTRL_BUS_UNUS |
-		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_BUS_UNUS |
-		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);
+	tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
+	tmp |= err_mask;
+	tmp &= ~err_no_mask;
+	schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
 
-	schizo_write(base + SCHIZO_PBM_A_REGS_OFF + SCHIZO_PCI_AFSR,
+	schizo_write(p->pbm_A.pbm_regs + 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,
+
+	tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
+	tmp |= err_mask;
+	tmp &= ~err_no_mask;
+	schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+
+	schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR,
 		     (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
 		      SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
 		      SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
@@ -1215,9 +1457,19 @@
 		      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.
+	/* Make all Safari error conditions fatal except unmapped
+	 * errors which we make generate interrupts.
 	 */
+	err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SSMDIS |
+		    BUS_ERROR_BADMA | BUS_ERROR_BADMB |
+		    BUS_ERROR_BADMC |
+		    BUS_ERROR_CPU1PS | BUS_ERROR_CPU1PB |
+		    BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB |
+		    BUS_ERROR_CIQTO |
+		    BUS_ERROR_LPQTO | BUS_ERROR_SFPQTO |
+		    BUS_ERROR_UFPQTO | BUS_ERROR_APERR |
+		    BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT |
+		    BUS_ERROR_ILL);
 #if 1
 	/* XXX Something wrong with some Excalibur systems
 	 * XXX Sun is shipping.  The behavior on a 2-cpu
@@ -1226,53 +1478,26 @@
 	 * XXX their error status bits are cleared.  Just
 	 * XXX ignore them for now.  -DaveM
 	 */
-	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_CIQTO |
-		       SAFARI_ERROR_LPQTO | SAFARI_ERROR_SFPQTO |
-		       SAFARI_ERROR_UFPQTO | SAFARI_ERROR_APERR |
-		       SAFARI_ERROR_BUSERR | SAFARI_ERROR_TIMEOUT |
-		       SAFARI_ERROR_ILL)));
-#else
-	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)));
+	err_mask &= ~(BUS_ERROR_CPU1PS | BUS_ERROR_CPU1PB |
+		      BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
 #endif
 
-	schizo_write(base + SCHIZO_SAFARI_IRQCTRL,
-		     (SCHIZO_SAFIRQCTRL_EN | (SAFARI_ERROR_UNMAP)));
+	schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+		     (SCHIZO_SAFERRCTRL_EN | err_mask));
+
+	schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
+		     (SCHIZO_SAFIRQCTRL_EN | (BUS_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;
+	u8 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;
@@ -1282,75 +1507,8 @@
 	} 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);
@@ -1379,7 +1537,7 @@
 	struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL);
 
 	if (!cookie) {
-		prom_printf("SCHIZO: Critical allocation failure.\n");
+		prom_printf("%s: Critical allocation failure.\n", pbm->name);
 		prom_halt();
 	}
 
@@ -1401,20 +1559,42 @@
 	pci_setup_busmastering(pbm, pbm->pci_bus);
 }
 
-static void __init schizo_scan_bus(struct pci_controller_info *p)
+static void __init __schizo_scan_bus(struct pci_controller_info *p,
+				     int chip_type)
 {
+	if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) {
+		printk("PCI: Only one PCI bus module of controller found.\n");
+		printk("PCI: Ignoring entire controller.\n");
+		return;
+	}
+
 	pbm_bridge_reconfigure(p);
 	pbm_config_busmastering(&p->pbm_B);
-	p->pbm_B.is_66mhz_capable = 0;
+	p->pbm_B.is_66mhz_capable =
+		prom_getbool(p->pbm_B.prom_node, "66mhz-capable");
 	pbm_config_busmastering(&p->pbm_A);
-	p->pbm_A.is_66mhz_capable = 1;
+	p->pbm_A.is_66mhz_capable =
+		prom_getbool(p->pbm_A.prom_node, "66mhz-capable");
 	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);
+	if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
+		tomatillo_register_error_handlers(p);
+	else
+		schizo_register_error_handlers(p);
+}
+
+static void __init schizo_scan_bus(struct pci_controller_info *p)
+{
+	__schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO);
+}
+
+static void __init tomatillo_scan_bus(struct pci_controller_info *p)
+{
+	__schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO);
 }
 
 static void __init schizo_base_address_update(struct pci_dev *pdev, int resource)
@@ -1470,68 +1650,72 @@
 	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.
+/* Use ranges property to determine where PCI MEM, I/O, and Config
+ * space are for this PCI bus module.
  */
+static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm)
+{
+	int i, saw_cfg, saw_mem, saw_io;
 
-#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
-
-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 a;
-
-	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;
+	saw_cfg = saw_mem = saw_io = 0;
+	for (i = 0; i < pbm->num_pbm_ranges; i++) {
+		struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i];
+		unsigned long a;
+		int type;
 
-	a = schizo_read(mem_match) & ~0x8000000000000000UL;
+		type = (pr->child_phys_hi >> 24) & 0x3;
+		a = (((unsigned long)pr->parent_phys_hi << 32UL) |
+		     ((unsigned long)pr->parent_phys_lo  <<  0UL));
 
-	/* It should be 2GB in size but the decode is set for the full
-	 * 4GB so we have to add the 2G by hand.
-	 */
-	pbm->mem_space.start = a;
-	pbm->mem_space.end = a + 0x80000000;
-	pbm->mem_space.flags = IORESOURCE_MEM;
+		switch (type) {
+		case 0:
+			/* PCI config space, 16MB */
+			pbm->config_space = a;
+			saw_cfg = 1;
+			break;
 
-	/* This 32MB area is divided into two pieces.  The first
-	 * 16MB is Config space, the next 16MB is I/O space.
-	 */
+		case 1:
+			/* 16-bit IO space, 16MB */
+			pbm->io_space.start = a;
+			pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL);
+			pbm->io_space.flags = IORESOURCE_IO;
+			saw_io = 1;
+			break;
 
-	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);
+		case 2:
+			/* 32-bit MEM space, 2GB */
+			pbm->mem_space.start = a;
+			pbm->mem_space.end = a + (0x80000000UL - 1UL);
+			pbm->mem_space.flags = IORESOURCE_MEM;
+			saw_mem = 1;
+			break;
+
+		default:
+			break;
+		};
+	}
 
-	a += (16UL * 1024UL * 1024UL);
-	pbm->io_space.start = a;
-	pbm->io_space.end = a + ((16UL * 1024UL * 1024UL) - 1UL);
-	pbm->io_space.flags = IORESOURCE_IO;
+	if (!saw_cfg || !saw_io || !saw_mem) {
+		prom_printf("%s: Fatal error, missing %s PBM range.\n",
+			    pbm->name,
+			    ((!saw_cfg ?
+			      "CFG" :
+			      (!saw_io ?
+			       "IO" : "MEM"))));
+		prom_halt();
+	}
+
+	printk("%s: PCI CFG[%lx] IO[%lx] MEM[%lx]\n",
+	       pbm->name,
+	       pbm->config_space,
+	       pbm->io_space.start,
+	       pbm->mem_space.start);
 }
 
 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;
+	pbm->io_space.name = pbm->mem_space.name = pbm->name;
 
 	request_resource(&ioport_resource, &pbm->io_space);
 	request_resource(&iomem_resource, &pbm->mem_space);
@@ -1539,40 +1723,29 @@
 				    &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)
+#define SCHIZO_STRBUF_CONTROL		(0x02800UL)
+#define SCHIZO_STRBUF_FLUSH		(0x02808UL)
+#define SCHIZO_STRBUF_FSYNC		(0x02810UL)
+#define SCHIZO_STRBUF_CTXFLUSH		(0x02818UL)
+#define SCHIZO_STRBUF_CTXMATCH		(0x10000UL)
+
+static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
 {
-	unsigned long base = p->controller_regs;
+	unsigned long base = pbm->pbm_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;
+	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
+		/* TOMATILLO lacks streaming cache.  */
+		return;
 	}
 
+	/* SCHIZO has context flushing. */
+	pbm->stc.strbuf_control		= base + SCHIZO_STRBUF_CONTROL;
+	pbm->stc.strbuf_pflush		= base + SCHIZO_STRBUF_FLUSH;
+	pbm->stc.strbuf_fsync		= base + SCHIZO_STRBUF_FSYNC;
+	pbm->stc.strbuf_ctxflush	= base + SCHIZO_STRBUF_CTXFLUSH;
+	pbm->stc.strbuf_ctxmatch_base	= base + SCHIZO_STRBUF_CTXMATCH;
+
 	pbm->stc.strbuf_flushflag = (volatile unsigned long *)
 		((((unsigned long)&pbm->stc.__flushflag_buf[0])
 		  + 63UL)
@@ -1594,48 +1767,63 @@
 	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)
+#define SCHIZO_IOMMU_CONTROL		(0x00200UL)
+#define SCHIZO_IOMMU_TSBBASE		(0x00208UL)
+#define SCHIZO_IOMMU_FLUSH		(0x00210UL)
+#define SCHIZO_IOMMU_CTXFLUSH		(0x00218UL)
+
+static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 {
 	struct pci_iommu *iommu = pbm->iommu;
-	unsigned long tsbbase, i, tagbase, database;
+	unsigned long tsbbase, i, tagbase, database, order;
+	u32 vdma[2], dma_mask;
 	u64 control;
+	int err, tsbsize;
+
+	err = prom_getproperty(pbm->prom_node, "virtual-dma",
+			       (char *)&vdma[0], sizeof(vdma));
+	if (err == 0 || err == -1) {
+		/* No property, use default values. */
+		vdma[0] = 0xc0000000;
+		vdma[1] = 0x40000000;
+	}
+
+	dma_mask = vdma[0];
+	switch (vdma[1]) {
+		case 0x20000000:
+			dma_mask |= 0x1fffffff;
+			tsbsize = 64;
+			break;
+
+		case 0x40000000:
+			dma_mask |= 0x3fffffff;
+			tsbsize = 128;
+			break;
+
+		case 0x80000000:
+			dma_mask |= 0x7fffffff;
+			tsbsize = 128;
+			break;
+
+		default:
+			prom_printf("SCHIZO: strange virtual-dma size.\n");
+			prom_halt();
+	};
 
 	/* 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;
-	}
+	iommu->iommu_control  = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
+	iommu->iommu_tsbbase  = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE;
+	iommu->iommu_flush    = pbm->pbm_regs + SCHIZO_IOMMU_FLUSH;
+	iommu->iommu_ctxflush = pbm->pbm_regs + SCHIZO_IOMMU_CTXFLUSH;
 
 	/* We use the main control/status register of SCHIZO as the write
 	 * completion register.
 	 */
-	iommu->write_complete_reg = p->controller_regs + 0x10000UL;
+	iommu->write_complete_reg = pbm->controller_regs + 0x10000UL;
 
 	/*
 	 * Invalidate TLB Entries.
@@ -1644,13 +1832,11 @@
 	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;
+	tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA;
+
 	for(i = 0; i < 16; i++) {
-		schizo_write(p->controller_regs + tagbase + (i * 8UL), 0);
-		schizo_write(p->controller_regs + database + (i * 8UL), 0);
+		schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0);
+		schizo_write(pbm->pbm_regs + database + (i * 8UL), 0);
 	}
 
 	/* Leave diag mode enabled for full-flushing done
@@ -1661,16 +1847,32 @@
 	 * table (128K ioptes * 8 bytes per iopte).  This is
 	 * page order 7 on UltraSparc.
 	 */
-	tsbbase = __get_free_pages(GFP_KERNEL, get_order(IO_TSB_SIZE));
+	order = get_order(tsbsize * 8 * 1024);
+	tsbbase = __get_free_pages(GFP_KERNEL, order);
 	if (!tsbbase) {
-		prom_printf("SCHIZO_IOMMU: Error, gfp(tsb) failed.\n");
+		prom_printf("%s: Error, gfp(tsb) failed.\n", pbm->name);
 		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, IO_TSB_SIZE);
+	iommu->page_table_map_base = vdma[0];
+	iommu->dma_addr_mask = dma_mask;
+	memset((char *)tsbbase, 0, PAGE_SIZE << order);
+
+	switch (tsbsize) {
+	case 64:
+		iommu->page_table_sz_bits = 16;
+		break;
+
+	case 128:
+		iommu->page_table_sz_bits = 17;
+		break;
+
+	default:
+		prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
+		prom_halt();
+		break;
+	};
 
 	/* We start with no consistent mappings. */
 	iommu->lowest_consistent_map =
@@ -1685,28 +1887,194 @@
 
 	control = schizo_read(iommu->iommu_control);
 	control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
-	control |= (SCHIZO_IOMMU_TSBSZ_128K | SCHIZO_IOMMU_CTRL_ENAB);
+	switch (tsbsize) {
+	case 64:
+		control |= SCHIZO_IOMMU_TSBSZ_64K;
+		break;
+	case 128:
+		control |= SCHIZO_IOMMU_TSBSZ_128K;
+		break;
+	};
+
+	control |= 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)
+#define SCHIZO_PCI_IRQ_RETRY	(0x1a00UL)
+#define  SCHIZO_IRQ_RETRY_INF	 0xffUL
+
+#define SCHIZO_PCI_DIAG			(0x2020UL)
+#define  SCHIZO_PCIDIAG_D_BADECC	(1UL << 10UL) /* Disable BAD ECC errors (Schizo) */
+#define  SCHIZO_PCIDIAG_D_BYPASS	(1UL <<  9UL) /* Disable MMU bypass mode (Schizo/Tomatillo) */
+#define  SCHIZO_PCIDIAG_D_TTO		(1UL <<  8UL) /* Disable TTO errors (Schizo/Tomatillo) */
+#define  SCHIZO_PCIDIAG_D_RTRYARB	(1UL <<  7UL) /* Disable retry arbitration (Schizo) */
+#define  SCHIZO_PCIDIAG_D_RETRY		(1UL <<  6UL) /* Disable retry limit (Schizo/Tomatillo) */
+#define  SCHIZO_PCIDIAG_D_INTSYNC	(1UL <<  5UL) /* Disable interrupt/DMA synch (Schizo/Tomatillo) */
+#define  SCHIZO_PCIDIAG_I_DMA_PARITY	(1UL <<  3UL) /* Invert DMA parity (Schizo/Tomatillo) */
+#define  SCHIZO_PCIDIAG_I_PIOD_PARITY	(1UL <<  2UL) /* Invert PIO data parity (Schizo/Tomatillo) */
+#define  SCHIZO_PCIDIAG_I_PIOA_PARITY	(1UL <<  1UL) /* Invert PIO address parity (Schizo/Tomatillo) */
+
+#define TOMATILLO_PCI_IOC_CSR		(0x2248UL)
+#define TOMATILLO_IOC_PART_WPENAB	0x0000000000080000UL
+#define TOMATILLO_IOC_RDMULT_PENAB	0x0000000000040000UL
+#define TOMATILLO_IOC_RDONE_PENAB	0x0000000000020000UL
+#define TOMATILLO_IOC_RDLINE_PENAB	0x0000000000010000UL
+#define TOMATILLO_IOC_RDMULT_PLEN	0x000000000000c000UL
+#define TOMATILLO_IOC_RDMULT_PLEN_SHIFT	14UL
+#define TOMATILLO_IOC_RDONE_PLEN	0x0000000000003000UL
+#define TOMATILLO_IOC_RDONE_PLEN_SHIFT	12UL
+#define TOMATILLO_IOC_RDLINE_PLEN	0x0000000000000c00UL
+#define TOMATILLO_IOC_RDLINE_PLEN_SHIFT	10UL
+#define TOMATILLO_IOC_PREF_OFF		0x00000000000003f8UL
+#define TOMATILLO_IOC_PREF_OFF_SHIFT	3UL
+#define TOMATILLO_IOC_RDMULT_CPENAB	0x0000000000000004UL
+#define TOMATILLO_IOC_RDONE_CPENAB	0x0000000000000002UL
+#define TOMATILLO_IOC_RDLINE_CPENAB	0x0000000000000001UL
+
+#define TOMATILLO_PCI_IOC_TDIAG		(0x2250UL)
+#define TOMATILLO_PCI_IOC_DDIAG		(0x2290UL)
+
+static void __init schizo_pbm_hw_init(struct pci_pbm_info *pbm)
 {
+	u64 tmp;
+
+	/* Set IRQ retry to infinity. */
+	schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY,
+		     SCHIZO_IRQ_RETRY_INF);
+
+	/* Enable arbiter for all PCI slots.  Also, disable PCI interval
+	 * timer so that DTO (Discard TimeOuts) are not reported because
+	 * some Schizo revisions report them erroneously.
+	 */
+	tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+	if (pbm->chip_type == PBM_CHIP_TYPE_SCHIZO_PLUS &&
+	    pbm->chip_version == 0x5 &&
+	    pbm->chip_revision == 0x1)
+		tmp |= 0x0f;
+	else
+		tmp |= 0xff;
+
+	tmp &= ~SCHIZO_PCICTRL_PTO;
+	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
+	    pbm->chip_version == 0x2)
+		tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
+	else
+		tmp |= 0x1UL << SCHIZO_PCICTRL_PTO_SHIFT;
+
+	if (!prom_getbool(pbm->prom_node, "no-bus-parking"))
+		tmp |= SCHIZO_PCICTRL_PARK;
+
+	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
+		tmp |= SCHIZO_PCICTRL_MRM_PREF;
+
+	schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+
+	tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG);
+	tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB |
+		 SCHIZO_PCIDIAG_D_RETRY |
+		 SCHIZO_PCIDIAG_D_INTSYNC);
+	schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp);
+
+	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
+		/* Clear prefetch lengths to workaround a bug in
+		 * Jalapeno...
+		 */
+		tmp = (TOMATILLO_IOC_PART_WPENAB |
+		       (1 << TOMATILLO_IOC_PREF_OFF_SHIFT) |
+		       TOMATILLO_IOC_RDMULT_CPENAB |
+		       TOMATILLO_IOC_RDONE_CPENAB |
+		       TOMATILLO_IOC_RDLINE_CPENAB);
+
+		schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR,
+			     tmp);
+	}
+}
+
+static void __init schizo_pbm_init(struct pci_controller_info *p,
+				   int prom_node, u32 portid,
+				   int chip_type)
+{
+	struct linux_prom64_registers pr_regs[4];
 	unsigned int busrange[2];
 	struct pci_pbm_info *pbm;
+	const char *chipset_name;
+	u32 ino_bitmap[2];
+	int is_pbm_a;
 	int err;
 
+	switch (chip_type) {
+	case PBM_CHIP_TYPE_TOMATILLO:
+		chipset_name = "TOMATILLO";
+		break;
+
+	case PBM_CHIP_TYPE_SCHIZO_PLUS:
+		chipset_name = "SCHIZO+";
+		break;
+
+	case PBM_CHIP_TYPE_SCHIZO:
+	default:
+		chipset_name = "SCHIZO";
+		break;
+	};
+
+	/* For SCHIZO, three OBP regs:
+	 * 1) PBM controller regs
+	 * 2) Schizo front-end controller regs (same for both PBMs)
+	 * 3) PBM PCI config space
+	 *
+	 * For TOMATILLO, four OBP regs:
+	 * 1) PBM controller regs
+	 * 2) Tomatillo front-end controller regs
+	 * 3) PBM PCI config space
+	 * 4) Ichip regs
+	 */
+	err = prom_getproperty(prom_node, "reg",
+			       (char *)&pr_regs[0],
+			       sizeof(pr_regs));
+	if (err == 0 || err == -1) {
+		prom_printf("%s: Fatal error, no reg property.\n",
+			    chipset_name);
+		prom_halt();
+	}
+
+	is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000);
+
 	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->portid = portid;
 	pbm->parent = p;
 	pbm->prom_node = prom_node;
 	pbm->pci_first_slot = 1;
+
+	pbm->chip_type = chip_type;
+	pbm->chip_version =
+		prom_getintdefault(prom_node, "version#", 0);
+	pbm->chip_revision =
+		prom_getintdefault(prom_node, "module-revision#", 0);
+
+	pbm->pbm_regs = pr_regs[0].phys_addr;
+	pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
+
+	sprintf(pbm->name,
+		(chip_type == PBM_CHIP_TYPE_TOMATILLO ?
+		 "TOMATILLO%d PBM%c" :
+		 "SCHIZO%d PBM%c"),
+		p->index,
+		(pbm == &p->pbm_A ? 'A' : 'B'));
+
+	printk("%s: ver[%x:%x], portid %x, "
+	       "cregs[%lx] pregs[%lx]\n",
+	       pbm->name,
+	       pbm->chip_version, pbm->chip_revision,
+	       pbm->portid,
+	       pbm->controller_regs,
+	       pbm->pbm_regs);
+
+	schizo_pbm_hw_init(pbm);
+
 	prom_getstring(prom_node, "name",
 		       pbm->prom_name,
 		       sizeof(pbm->prom_name));
@@ -1714,11 +2082,17 @@
 	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;
+	if (err == 0 || err == -1) {
+		prom_printf("%s: Fatal error, no ranges property.\n",
+			    pbm->name);
+		prom_halt();
+	}
+
+	pbm->num_pbm_ranges =
+		(err / sizeof(struct linux_prom_pci_ranges));
+
+	schizo_determine_mem_io_space(pbm);
+	pbm_register_toplevel_resources(p, pbm);
 
 	err = prom_getproperty(prom_node, "interrupt-map",
 			       (char *)pbm->pbm_intmap,
@@ -1729,8 +2103,8 @@
 				       (char *)&pbm->pbm_intmask,
 				       sizeof(pbm->pbm_intmask));
 		if (err == -1) {
-			prom_printf("SCHIZO-PBM: Fatal error, no "
-				    "interrupt-map-mask.\n");
+			prom_printf("%s: Fatal error, no "
+				    "interrupt-map-mask.\n", pbm->name);
 			prom_halt();
 		}
 	} else {
@@ -1738,95 +2112,65 @@
 		memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
 	}
 
+	err = prom_getproperty(prom_node, "ino-bitmap",
+			       (char *) &ino_bitmap[0],
+			       sizeof(ino_bitmap));
+	if (err == 0 || err == -1) {
+		prom_printf("%s: Fatal error, no ino-bitmap.\n", pbm->name);
+		prom_halt();
+	}
+	pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
+			   ((u64)ino_bitmap[0] <<  0UL));
+
 	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_printf("%s: Fatal error, no bus-range.\n", pbm->name);
 		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);
+	schizo_pbm_iommu_init(pbm);
+	schizo_pbm_strbuf_init(pbm);
 }
 
-#define SCHIZO_PCIA_IRQ_RETRY	(SCHIZO_PBM_A_REGS_OFF + 0x1a00UL)
-#define SCHIZO_PCIB_IRQ_RETRY	(SCHIZO_PBM_B_REGS_OFF + 0x1a00UL)
-#define  SCHIZO_IRQ_RETRY_INF	 0xffUL
-
-#define SCHIZO_PCIA_DIAG	(SCHIZO_PBM_A_REGS_OFF + 0x2020UL)
-#define SCHIZO_PCIB_DIAG	(SCHIZO_PBM_B_REGS_OFF + 0x2020UL)
-#define  SCHIZO_PCIDIAG_D_BADECC	(1UL << 10UL) /* Disable BAD ECC errors */
-#define  SCHIZO_PCIDIAG_D_BYPASS	(1UL <<  9UL) /* Disable MMU bypass mode */
-#define  SCHIZO_PCIDIAG_D_TTO		(1UL <<  8UL) /* Disable TTO errors */
-#define  SCHIZO_PCIDIAG_D_RTRYARB	(1UL <<  7UL) /* Disable retry arbitration */
-#define  SCHIZO_PCIDIAG_D_RETRY		(1UL <<  6UL) /* Disable retry limit */
-#define  SCHIZO_PCIDIAG_D_INTSYNC	(1UL <<  5UL) /* Disable interrupt/DMA synch */
-#define  SCHIZO_PCIDIAG_I_DMA_PARITY	(1UL <<  3UL) /* Invert DMA parity */
-#define  SCHIZO_PCIDIAG_I_PIOD_PARITY	(1UL <<  2UL) /* Invert PIO data parity */
-#define  SCHIZO_PCIDIAG_I_PIOA_PARITY	(1UL <<  1U)L /* Invert PIO address parity */
-
-static void schizo_controller_hwinit(struct pci_controller_info *p)
+static inline int portid_compare(u32 x, u32 y, int chip_type)
 {
-	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(p->controller_regs + SCHIZO_PCIA_IRQ_RETRY,
-		     SCHIZO_IRQ_RETRY_INF);
-	schizo_write(p->controller_regs + SCHIZO_PCIB_IRQ_RETRY,
-		     SCHIZO_IRQ_RETRY_INF);
-
-	/* Enable arbiter for all PCI slots.  Also, disable PCI interval
-	 * timer so that DTO (Discard TimeOuts) are not reported because
-	 * some Schizo revisions report them erroneously.
-	 */
-
-	tmp = schizo_read(p->controller_regs + SCHIZO_PCIA_CTRL);
-	tmp |= SCHIZO_PCICTRL_ARB;
-	tmp &= ~SCHIZO_PCICTRL_PTO;
-	schizo_write(p->controller_regs + SCHIZO_PCIA_CTRL, tmp);
-
-	tmp = schizo_read(p->controller_regs + SCHIZO_PCIB_CTRL);
-	tmp |= SCHIZO_PCICTRL_ARB;
-	tmp &= ~SCHIZO_PCICTRL_PTO;
-	schizo_write(p->controller_regs + SCHIZO_PCIB_CTRL, tmp);
-
-	/* Disable TTO error reporting (won't happen anyway since we
-	 * disabled the PCI interval timer above) and retry arbitration
-	 * (can cause hangs in some Schizo revisions).
-	 */
-	tmp = schizo_read(p->controller_regs + SCHIZO_PCIA_DIAG);
-	tmp |= (SCHIZO_PCIDIAG_D_TTO | SCHIZO_PCIDIAG_D_RTRYARB);
-	schizo_write(p->controller_regs + SCHIZO_PCIA_DIAG, tmp);
-
-	tmp = schizo_read(p->controller_regs + SCHIZO_PCIB_DIAG);
-	tmp |= (SCHIZO_PCIDIAG_D_TTO | SCHIZO_PCIDIAG_D_RTRYARB);
-	schizo_write(p->controller_regs + SCHIZO_PCIB_DIAG, tmp);
+	if (chip_type == PBM_CHIP_TYPE_TOMATILLO) {
+		if (x == (y ^ 1))
+			return 1;
+		return 0;
+	}
+	return (x == y);
 }
 
-void __init schizo_init(int node, char *model_name)
+static void __init __schizo_init(int node, char *model_name, int chip_type)
 {
-	struct linux_prom64_registers pr_regs[3];
 	struct pci_controller_info *p;
 	struct pci_iommu *iommu;
 	unsigned long flags;
+	int is_pbm_a;
 	u32 portid;
-	int is_pbm_a, err;
 
 	portid = prom_getintdefault(node, "portid", 0xff);
 
 	spin_lock_irqsave(&pci_controller_lock, flags);
 	for(p = pci_controller_root; p; p = p->next) {
-		if (p->portid == portid) {
+		struct pci_pbm_info *pbm;
+
+		if (p->pbm_A.prom_node && p->pbm_B.prom_node)
+			continue;
+
+		pbm = (p->pbm_A.prom_node ?
+		       &p->pbm_A :
+		       &p->pbm_B);
+
+		if (portid_compare(pbm->portid, portid, chip_type)) {
 			spin_unlock_irqrestore(&pci_controller_lock, flags);
 			is_pbm_a = (p->pbm_A.prom_node == 0);
-			schizo_pbm_init(p, node, is_pbm_a);
+			schizo_pbm_init(p, node, portid, chip_type);
 			return;
 		}
 	}
@@ -1860,38 +2204,33 @@
 	pci_controller_root = p;
 	spin_unlock_irqrestore(&pci_controller_lock, flags);
 
-	p->portid = portid;
 	p->index = pci_num_controllers++;
 	p->pbms_same_domain = 0;
-	p->scan_bus = schizo_scan_bus;
+	p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
+		       tomatillo_scan_bus :
+		       schizo_scan_bus);
 	p->irq_build = schizo_irq_build;
 	p->base_address_update = schizo_base_address_update;
 	p->resource_adjust = schizo_resource_adjust;
 	p->pci_ops = &schizo_ops;
 
-	/* Three OBP regs:
-	 * 1) PBM controller regs
-	 * 2) Schizo front-end controller regs (same for both PBMs)
-	 * 3) PBM PCI config space
-	 */
-	err = prom_getproperty(node, "reg",
-			       (char *)&pr_regs[0],
-			       sizeof(pr_regs));
-	if (err == 0 || err == -1) {
-		prom_printf("SCHIZO: Fatal error, no reg property.\n");
-		prom_halt();
-	}
-
-	p->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
-	printk("PCI: Found SCHIZO, control regs at %016lx\n",
-	       p->controller_regs);
-
 	/* Like PSYCHO we have a 2GB aligned area for memory space. */
 	pci_memspace_mask = 0x7fffffffUL;
 
-	/* Init core controller. */
-	schizo_controller_hwinit(p);
+	schizo_pbm_init(p, node, portid, chip_type);
+}
 
-	is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000);
-	schizo_pbm_init(p, node, is_pbm_a);
+void __init schizo_init(int node, char *model_name)
+{
+	__schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO);
+}
+
+void __init schizo_plus_init(int node, char *model_name)
+{
+	__schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
+}
+
+void __init tomatillo_init(int node, char *model_name)
+{
+	__schizo_init(node, model_name, PBM_CHIP_TYPE_TOMATILLO);
 }
diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
--- a/arch/sparc64/kernel/setup.c	Fri Aug 23 21:49:49 2002
+++ b/arch/sparc64/kernel/setup.c	Tue Aug 19 11:52:50 2003
@@ -604,8 +604,8 @@
 
 /* BUFFER is PAGE_SIZE bytes long. */
 
-extern char *sparc_cpu_type[];
-extern char *sparc_fpu_type[];
+extern char *sparc_cpu_type;
+extern char *sparc_fpu_type;
 
 extern void smp_info(struct seq_file *);
 extern void smp_bogo(struct seq_file *);
@@ -617,8 +617,6 @@
 
 static int show_cpuinfo(struct seq_file *m, void *__unused)
 {
-	int cpuid = smp_processor_id();
-
 	seq_printf(m, 
 		   "cpu\t\t: %s\n"
 		   "fpu\t\t: %s\n"
@@ -632,8 +630,8 @@
 		   "Cpu0ClkTck\t: %016lx\n"
 #endif
 		   ,
-		   sparc_cpu_type[cpuid],
-		   sparc_fpu_type[cpuid],
+		   sparc_cpu_type,
+		   sparc_fpu_type,
 		   prom_rev,
 		   prom_prev >> 16,
 		   (prom_prev >> 8) & 0xff,
diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
--- a/arch/sparc64/kernel/smp.c	Wed Apr 23 00:13:46 2003
+++ b/arch/sparc64/kernel/smp.c	Tue Aug 19 11:52:50 2003
@@ -133,7 +133,6 @@
 static volatile unsigned long callin_flag = 0;
 
 extern void inherit_locked_prom_mappings(int save_p);
-extern void cpu_probe(void);
 
 void __init smp_callin(void)
 {
@@ -153,8 +152,6 @@
 	__flush_cache_all();
 	__flush_tlb_all();
 
-	cpu_probe();
-
 	smp_setup_percpu_timer();
 
 	__sti();
@@ -537,12 +534,19 @@
 #endif
 static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, unsigned long mask)
 {
-	u64 pstate;
-	int nack_busy_id;
+	u64 pstate, ver;
+	int nack_busy_id, is_jalapeno;
 
 	if (!mask)
 		return;
 
+	/* Unfortunately, someone at Sun had the brilliant idea to make the
+	 * busy/nack fields hard-coded by ITID number for this Ultra-III
+	 * derivative processor.
+	 */
+	__asm__ ("rdpr %%ver, %0" : "=r" (ver));
+	is_jalapeno = ((ver >> 32) == 0x003e0016);
+
 	__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
 
 retry:
@@ -567,11 +571,13 @@
 			if (mask & (1UL << i)) {
 				u64 target = (i << 14) | 0x70;
 
-				target |= (nack_busy_id++ << 24);
+				if (!is_jalapeno)
+					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));
+				nack_busy_id++;
 				ncpus--;
 			}
 		}
@@ -618,7 +624,14 @@
 			 */
 			for (i = 0; i < NR_CPUS; i++) {
 				if (mask & (1UL << i)) {
-					if ((dispatch_stat & (0x2 << this_busy_nack)) == 0)
+					u64 check_mask;
+
+					if (is_jalapeno)
+						check_mask = (0x2UL << (2*i));
+					else
+						check_mask = (0x2UL <<
+							      this_busy_nack);
+					if ((dispatch_stat & check_mask) == 0)
 						mask &= ~(1UL << i);
 					this_busy_nack += 2;
 				}
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Sat Jul 12 00:25:34 2003
+++ b/arch/sparc64/kernel/sys_sparc32.c	Sat Aug 30 22:39:11 2003
@@ -415,7 +415,7 @@
  *
  * This is really horribly ugly.
  */
-#define IPCOP_MASK(__x)	(1UL << (__x))
+#define IPCOP_MASK(__x)	(1UL << ((__x)&~IPC_64))
 static int do_sys32_semctl(int first, int second, int third, void *uptr)
 {
 	union semun fourth;
@@ -427,7 +427,7 @@
 	err = -EFAULT;
 	if (get_user (pad, (u32 *)uptr))
 		goto out;
-	if(third == SETVAL)
+	if ((third & ~IPC_64) == SETVAL)
 		fourth.val = (int)pad;
 	else
 		fourth.__pad = (void *)A(pad);
diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
--- a/arch/sparc64/kernel/time.c	Mon Mar 31 10:25:45 2003
+++ b/arch/sparc64/kernel/time.c	Wed Jul 23 08:51:40 2003
@@ -775,6 +775,7 @@
 		    strcmp(model, "mk48t08") &&
 		    strcmp(model, "mk48t59") &&
 		    strcmp(model, "m5819") &&
+		    strcmp(model, "m5819p") &&
 		    strcmp(model, "ds1287")) {
 			if (cbus != NULL) {
 				prom_printf("clock_probe: Central bus lacks timer chip.\n");
@@ -833,7 +834,8 @@
 			}
 
 			if (!strcmp(model, "ds1287") ||
-			    !strcmp(model, "m5819")) {
+			    !strcmp(model, "m5819") ||
+			    !strcmp(model, "m5819p")) {
 				ds1287_regs = edev->resource[0].start;
 			} else {
 				mstk48t59_regs = edev->resource[0].start;
@@ -853,7 +855,8 @@
 				prom_halt();
 			}
 			if (!strcmp(model, "ds1287") ||
-			    !strcmp(model, "m5819")) {
+			    !strcmp(model, "m5819") ||
+			    !strcmp(model, "m5819p")) {
 				ds1287_regs = isadev->resource.start;
 			} else {
 				mstk48t59_regs = isadev->resource.start;
diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
--- a/arch/sparc64/kernel/traps.c	Sun May  4 10:19:50 2003
+++ b/arch/sparc64/kernel/traps.c	Mon Aug  4 00:14:22 2003
@@ -401,6 +401,179 @@
 };
 #define CHAFSR_INVALID		((u64)-1L)
 
+/* This table is ordered in priority of errors and matches the
+ * AFAR overwrite policy as well.
+ */
+
+struct afsr_error_table {
+	unsigned long mask;
+	const char *name;
+};
+
+static const char CHAFSR_PERR_msg[] =
+	"System interface protocol error";
+static const char CHAFSR_IERR_msg[] =
+	"Internal processor error";
+static const char CHAFSR_ISAP_msg[] =
+	"System request parity error on incoming addresss";
+static const char CHAFSR_UCU_msg[] =
+	"Uncorrectable E-cache ECC error for ifetch/data";
+static const char CHAFSR_UCC_msg[] =
+	"SW Correctable E-cache ECC error for ifetch/data";
+static const char CHAFSR_UE_msg[] =
+	"Uncorrectable system bus data ECC error for read";
+static const char CHAFSR_EDU_msg[] =
+	"Uncorrectable E-cache ECC error for stmerge/blkld";
+static const char CHAFSR_EMU_msg[] =
+	"Uncorrectable system bus MTAG error";
+static const char CHAFSR_WDU_msg[] =
+	"Uncorrectable E-cache ECC error for writeback";
+static const char CHAFSR_CPU_msg[] =
+	"Uncorrectable ECC error for copyout";
+static const char CHAFSR_CE_msg[] =
+	"HW corrected system bus data ECC error for read";
+static const char CHAFSR_EDC_msg[] =
+	"HW corrected E-cache ECC error for stmerge/blkld";
+static const char CHAFSR_EMC_msg[] =
+	"HW corrected system bus MTAG ECC error";
+static const char CHAFSR_WDC_msg[] =
+	"HW corrected E-cache ECC error for writeback";
+static const char CHAFSR_CPC_msg[] =
+	"HW corrected ECC error for copyout";
+static const char CHAFSR_TO_msg[] =
+	"Unmapped error from system bus";
+static const char CHAFSR_BERR_msg[] =
+	"Bus error response from system bus";
+static const char CHAFSR_IVC_msg[] =
+	"HW corrected system bus data ECC error for ivec read";
+static const char CHAFSR_IVU_msg[] =
+	"Uncorrectable system bus data ECC error for ivec read";
+static struct afsr_error_table __cheetah_error_table[] = {
+	{	CHAFSR_PERR,	CHAFSR_PERR_msg		},
+	{	CHAFSR_IERR,	CHAFSR_IERR_msg		},
+	{	CHAFSR_ISAP,	CHAFSR_ISAP_msg		},
+	{	CHAFSR_UCU,	CHAFSR_UCU_msg		},
+	{	CHAFSR_UCC,	CHAFSR_UCC_msg		},
+	{	CHAFSR_UE,	CHAFSR_UE_msg		},
+	{	CHAFSR_EDU,	CHAFSR_EDU_msg		},
+	{	CHAFSR_EMU,	CHAFSR_EMU_msg		},
+	{	CHAFSR_WDU,	CHAFSR_WDU_msg		},
+	{	CHAFSR_CPU,	CHAFSR_CPU_msg		},
+	{	CHAFSR_CE,	CHAFSR_CE_msg		},
+	{	CHAFSR_EDC,	CHAFSR_EDC_msg		},
+	{	CHAFSR_EMC,	CHAFSR_EMC_msg		},
+	{	CHAFSR_WDC,	CHAFSR_WDC_msg		},
+	{	CHAFSR_CPC,	CHAFSR_CPC_msg		},
+	{	CHAFSR_TO,	CHAFSR_TO_msg		},
+	{	CHAFSR_BERR,	CHAFSR_BERR_msg		},
+	/* These two do not update the AFAR. */
+	{	CHAFSR_IVC,	CHAFSR_IVC_msg		},
+	{	CHAFSR_IVU,	CHAFSR_IVU_msg		},
+	{	0,		NULL			},
+};
+static const char CHPAFSR_DTO_msg[] =
+	"System bus unmapped error for prefetch/storequeue-read";
+static const char CHPAFSR_DBERR_msg[] =
+	"System bus error for prefetch/storequeue-read";
+static const char CHPAFSR_THCE_msg[] =
+	"Hardware corrected E-cache Tag ECC error";
+static const char CHPAFSR_TSCE_msg[] =
+	"SW handled correctable E-cache Tag ECC error";
+static const char CHPAFSR_TUE_msg[] =
+	"Uncorrectable E-cache Tag ECC error";
+static const char CHPAFSR_DUE_msg[] =
+	"System bus uncorrectable data ECC error due to prefetch/store-fill";
+static struct afsr_error_table __cheetah_plus_error_table[] = {
+	{	CHAFSR_PERR,	CHAFSR_PERR_msg		},
+	{	CHAFSR_IERR,	CHAFSR_IERR_msg		},
+	{	CHAFSR_ISAP,	CHAFSR_ISAP_msg		},
+	{	CHAFSR_UCU,	CHAFSR_UCU_msg		},
+	{	CHAFSR_UCC,	CHAFSR_UCC_msg		},
+	{	CHAFSR_UE,	CHAFSR_UE_msg		},
+	{	CHAFSR_EDU,	CHAFSR_EDU_msg		},
+	{	CHAFSR_EMU,	CHAFSR_EMU_msg		},
+	{	CHAFSR_WDU,	CHAFSR_WDU_msg		},
+	{	CHAFSR_CPU,	CHAFSR_CPU_msg		},
+	{	CHAFSR_CE,	CHAFSR_CE_msg		},
+	{	CHAFSR_EDC,	CHAFSR_EDC_msg		},
+	{	CHAFSR_EMC,	CHAFSR_EMC_msg		},
+	{	CHAFSR_WDC,	CHAFSR_WDC_msg		},
+	{	CHAFSR_CPC,	CHAFSR_CPC_msg		},
+	{	CHAFSR_TO,	CHAFSR_TO_msg		},
+	{	CHAFSR_BERR,	CHAFSR_BERR_msg		},
+	{	CHPAFSR_DTO,	CHPAFSR_DTO_msg		},
+	{	CHPAFSR_DBERR,	CHPAFSR_DBERR_msg	},
+	{	CHPAFSR_THCE,	CHPAFSR_THCE_msg	},
+	{	CHPAFSR_TSCE,	CHPAFSR_TSCE_msg	},
+	{	CHPAFSR_TUE,	CHPAFSR_TUE_msg		},
+	{	CHPAFSR_DUE,	CHPAFSR_DUE_msg		},
+	/* These two do not update the AFAR. */
+	{	CHAFSR_IVC,	CHAFSR_IVC_msg		},
+	{	CHAFSR_IVU,	CHAFSR_IVU_msg		},
+	{	0,		NULL			},
+};
+static const char JPAFSR_JETO_msg[] =
+	"System interface protocol error, hw timeout caused";
+static const char JPAFSR_SCE_msg[] =
+	"Parity error on system snoop results";
+static const char JPAFSR_JEIC_msg[] =
+	"System interface protocol error, illegal command detected";
+static const char JPAFSR_JEIT_msg[] =
+	"System interface protocol error, illegal ADTYPE detected";
+static const char JPAFSR_OM_msg[] =
+	"Out of range memory error has occurred";
+static const char JPAFSR_ETP_msg[] =
+	"Parity error on L2 cache tag SRAM";
+static const char JPAFSR_UMS_msg[] =
+	"Error due to unsupported store";
+static const char JPAFSR_RUE_msg[] =
+	"Uncorrectable ECC error from remote cache/memory";
+static const char JPAFSR_RCE_msg[] =
+	"Correctable ECC error from remote cache/memory";
+static const char JPAFSR_BP_msg[] =
+	"JBUS parity error on returned read data";
+static const char JPAFSR_WBP_msg[] =
+	"JBUS parity error on data for writeback or block store";
+static const char JPAFSR_FRC_msg[] =
+	"Foreign read to DRAM incurring correctable ECC error";
+static const char JPAFSR_FRU_msg[] =
+	"Foreign read to DRAM incurring uncorrectable ECC error";
+static struct afsr_error_table __jalapeno_error_table[] = {
+	{	JPAFSR_JETO,	JPAFSR_JETO_msg		},
+	{	JPAFSR_SCE,	JPAFSR_SCE_msg		},
+	{	JPAFSR_JEIC,	JPAFSR_JEIC_msg		},
+	{	JPAFSR_JEIT,	JPAFSR_JEIT_msg		},
+	{	CHAFSR_PERR,	CHAFSR_PERR_msg		},
+	{	CHAFSR_IERR,	CHAFSR_IERR_msg		},
+	{	CHAFSR_ISAP,	CHAFSR_ISAP_msg		},
+	{	CHAFSR_UCU,	CHAFSR_UCU_msg		},
+	{	CHAFSR_UCC,	CHAFSR_UCC_msg		},
+	{	CHAFSR_UE,	CHAFSR_UE_msg		},
+	{	CHAFSR_EDU,	CHAFSR_EDU_msg		},
+	{	JPAFSR_OM,	JPAFSR_OM_msg		},
+	{	CHAFSR_WDU,	CHAFSR_WDU_msg		},
+	{	CHAFSR_CPU,	CHAFSR_CPU_msg		},
+	{	CHAFSR_CE,	CHAFSR_CE_msg		},
+	{	CHAFSR_EDC,	CHAFSR_EDC_msg		},
+	{	JPAFSR_ETP,	JPAFSR_ETP_msg		},
+	{	CHAFSR_WDC,	CHAFSR_WDC_msg		},
+	{	CHAFSR_CPC,	CHAFSR_CPC_msg		},
+	{	CHAFSR_TO,	CHAFSR_TO_msg		},
+	{	CHAFSR_BERR,	CHAFSR_BERR_msg		},
+	{	JPAFSR_UMS,	JPAFSR_UMS_msg		},
+	{	JPAFSR_RUE,	JPAFSR_RUE_msg		},
+	{	JPAFSR_RCE,	JPAFSR_RCE_msg		},
+	{	JPAFSR_BP,	JPAFSR_BP_msg		},
+	{	JPAFSR_WBP,	JPAFSR_WBP_msg		},
+	{	JPAFSR_FRC,	JPAFSR_FRC_msg		},
+	{	JPAFSR_FRU,	JPAFSR_FRU_msg		},
+	/* These two do not update the AFAR. */
+	{	CHAFSR_IVU,	CHAFSR_IVU_msg		},
+	{	0,		NULL			},
+};
+static struct afsr_error_table *cheetah_error_table;
+static unsigned long cheetah_afsr_errors;
+
 /* This is allocated at boot time based upon the largest hardware
  * cpu ID in the system.  We allocate two entries per cpu, one for
  * TL==0 logging and one for TL >= 1 logging.
@@ -436,7 +609,7 @@
 
 void cheetah_ecache_flush_init(void)
 {
-	unsigned long largest_size, smallest_linesize, order;
+	unsigned long largest_size, smallest_linesize, order, ver;
 	char type[16];
 	int node, highest_cpu, i;
 
@@ -522,6 +695,18 @@
 	for (i = 0; i < 2 * highest_cpu; i++)
 		cheetah_error_log[i].afsr = CHAFSR_INVALID;
 
+	__asm__ ("rdpr %%ver, %0" : "=r" (ver));
+	if ((ver >> 32) == 0x003e0016) {
+		cheetah_error_table = &__jalapeno_error_table[0];
+		cheetah_afsr_errors = JPAFSR_ERRORS;
+	} else if ((ver >> 32) == 0x003e0015) {
+		cheetah_error_table = &__cheetah_plus_error_table[0];
+		cheetah_afsr_errors = CHPAFSR_ERRORS;
+	} else {
+		cheetah_error_table = &__cheetah_error_table[0];
+		cheetah_afsr_errors = CHAFSR_ERRORS;
+	}
+
 	/* Now patch trap tables. */
 	memcpy(tl0_fecc, cheetah_fecc_trap_vector, (8 * 4));
 	memcpy(tl1_fecc, cheetah_fecc_trap_vector_tl1, (8 * 4));
@@ -720,36 +905,6 @@
        NONE, NONE
 };
 
-/* This table is ordered in priority of errors and matches the
- * AFAR overwrite policy as well.
- */
-static struct {
-	unsigned long mask;
-	char *name;
-} cheetah_error_table[] = {
-	{	CHAFSR_PERR,	"System interface protocol error"			},
-	{	CHAFSR_IERR,	"Internal processor error"				},
-	{	CHAFSR_ISAP,	"System request parity error on incoming addresss"	},
-	{	CHAFSR_UCU,	"Uncorrectable E-cache ECC error for ifetch/data"	},
-	{	CHAFSR_UCC,	"SW Correctable E-cache ECC error for ifetch/data"	},
-	{	CHAFSR_UE,	"Uncorrectable system bus data ECC error for read"	},
-	{	CHAFSR_EDU,	"Uncorrectable E-cache ECC error for stmerge/blkld"	},
-	{	CHAFSR_EMU,	"Uncorrectable system bus MTAG error"			},
-	{	CHAFSR_WDU,	"Uncorrectable E-cache ECC error for writeback"		},
-	{	CHAFSR_CPU,	"Uncorrectable ECC error for copyout"			},
-	{	CHAFSR_CE,	"HW corrected system bus data ECC error for read"	},
-	{	CHAFSR_EDC,	"HW corrected E-cache ECC error for stmerge/blkld"	},
-	{	CHAFSR_EMC,	"HW corrected system bus MTAG ECC error"		},
-	{	CHAFSR_WDC,	"HW corrected E-cache ECC error for writeback"		},
-	{	CHAFSR_CPC,	"HW corrected ECC error for copyout"			},
-	{	CHAFSR_TO,	"Unmapped error from system bus"			},
-	{	CHAFSR_BERR,	"Bus error response from system bus"			},
-	/* These two do not update the AFAR. */
-	{	CHAFSR_IVC,	"HW corrected system bus data ECC error for ivec read"	},
-	{	CHAFSR_IVU,	"Uncorrectable system bus data ECC error for ivec read"	},
-	{	0,		NULL							}
-};
-
 /* Return the highest priority error conditon mentioned. */
 static __inline__ unsigned long cheetah_get_hipri(unsigned long afsr)
 {
@@ -763,7 +918,7 @@
 	return tmp;
 }
 
-static char *cheetah_get_string(unsigned long bit)
+static const char *cheetah_get_string(unsigned long bit)
 {
 	int i;
 
@@ -876,7 +1031,7 @@
 	       info->ecache_data[2],
 	       info->ecache_data[3]);
 
-	afsr = (afsr & ~hipri) & CHAFSR_ERRORS;
+	afsr = (afsr & ~hipri) & cheetah_afsr_errors;
 	while (afsr != 0UL) {
 		unsigned long bit = cheetah_get_hipri(afsr);
 
@@ -899,7 +1054,7 @@
 	__asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
 			     : "=r" (afsr)
 			     : "i" (ASI_AFSR));
-	if ((afsr & CHAFSR_ERRORS) != 0) {
+	if ((afsr & cheetah_afsr_errors) != 0) {
 		if (logp != NULL) {
 			__asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
 					     : "=r" (afar)
@@ -1125,12 +1280,12 @@
 
 		flush_all = flush_line = 0;
 		if ((afsr & CHAFSR_EDC) != 0UL) {
-			if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDC)
+			if ((afsr & cheetah_afsr_errors) == CHAFSR_EDC)
 				flush_line = 1;
 			else
 				flush_all = 1;
 		} else if ((afsr & CHAFSR_CPC) != 0UL) {
-			if ((afsr & CHAFSR_ERRORS) == CHAFSR_CPC)
+			if ((afsr & cheetah_afsr_errors) == CHAFSR_CPC)
 				flush_line = 1;
 			else
 				flush_all = 1;
@@ -1253,12 +1408,12 @@
 
 		flush_all = flush_line = 0;
 		if ((afsr & CHAFSR_EDU) != 0UL) {
-			if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDU)
+			if ((afsr & cheetah_afsr_errors) == CHAFSR_EDU)
 				flush_line = 1;
 			else
 				flush_all = 1;
 		} else if ((afsr & CHAFSR_BERR) != 0UL) {
-			if ((afsr & CHAFSR_ERRORS) == CHAFSR_BERR)
+			if ((afsr & cheetah_afsr_errors) == CHAFSR_BERR)
 				flush_line = 1;
 			else
 				flush_all = 1;
diff -Nru a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
--- a/arch/sparc64/kernel/unaligned.c	Mon Feb  4 23:39:16 2002
+++ b/arch/sparc64/kernel/unaligned.c	Fri Jul 25 13:54:44 2003
@@ -479,7 +479,9 @@
 
 extern void do_fpother(struct pt_regs *regs);
 extern void do_privact(struct pt_regs *regs);
-extern void data_access_exception(struct pt_regs *regs);
+extern void data_access_exception(struct pt_regs *regs,
+				  unsigned long sfsr,
+				  unsigned long sfar);
 
 int handle_ldf_stq(u32 insn, struct pt_regs *regs)
 {
@@ -522,14 +524,14 @@
 				break;
 			}
 		default:
-			data_access_exception(regs);
+			data_access_exception(regs, 0, addr);
 			return 1;
 		}
 		if (put_user (first >> 32, (u32 *)addr) ||
 		    __put_user ((u32)first, (u32 *)(addr + 4)) ||
 		    __put_user (second >> 32, (u32 *)(addr + 8)) ||
 		    __put_user ((u32)second, (u32 *)(addr + 12))) {
-		    	data_access_exception(regs);
+		    	data_access_exception(regs, 0, addr);
 		    	return 1;
 		}
 	} else {
@@ -542,7 +544,7 @@
 			do_privact(regs);
 			return 1;
 		} else if (asi > ASI_SNFL) {
-			data_access_exception(regs);
+			data_access_exception(regs, 0, addr);
 			return 1;
 		}
 		switch (insn & 0x180000) {
@@ -559,7 +561,7 @@
 				err |= __get_user (data[i], (u32 *)(addr + 4*i));
 		}
 		if (err && !(asi & 0x2 /* NF */)) {
-			data_access_exception(regs);
+			data_access_exception(regs, 0, addr);
 			return 1;
 		}
 		if (asi & 0x8) /* Little */ {
@@ -662,7 +664,7 @@
 		*(u64 *)(f->regs + freg) = value;
 		current->thread.fpsaved[0] |= flag;
 	} else {
-daex:		data_access_exception(regs);
+daex:		data_access_exception(regs, sfsr, sfar);
 		return;
 	}
 	advance(regs);
@@ -706,7 +708,7 @@
 		    __put_user ((u32)value, (u32 *)(sfar + 4)))
 			goto daex;
 	} else {
-daex:		data_access_exception(regs);
+daex:		data_access_exception(regs, sfsr, sfar);
 		return;
 	}
 	advance(regs);
diff -Nru a/arch/x86_64/config.in b/arch/x86_64/config.in
--- a/arch/x86_64/config.in	Mon Jul 21 05:01:56 2003
+++ b/arch/x86_64/config.in	Fri Aug 29 16:13:46 2003
@@ -66,6 +66,7 @@
    define_bool CONFIG_X86_UP_IOAPIC y
 else
    define_bool CONFIG_HAVE_DEC_LOCK y
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
 fi
 
 bool 'Machine check support' CONFIG_MCE
@@ -244,6 +245,9 @@
    bool '  IOMMU leak tracing' CONFIG_IOMMU_LEAK
    bool '  Probalistic stack overflow check' CONFIG_DEBUG_STACKOVERFLOW
 fi
+
+int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+
 endmenu
 
 source lib/Config.in
diff -Nru a/arch/x86_64/defconfig b/arch/x86_64/defconfig
--- a/arch/x86_64/defconfig	Wed Jun 25 11:58:05 2003
+++ b/arch/x86_64/defconfig	Wed Jun 19 10:26:35 2002
@@ -41,6 +41,7 @@
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_MTRR=y
 # CONFIG_SMP is not set
+CONFIG_NR_CPUS=32
 CONFIG_HPET_TIMER=y
 CONFIG_GART_IOMMU=y
 CONFIG_X86_UP_IOAPIC=y
diff -Nru a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
--- a/arch/x86_64/kernel/io_apic.c	Tue Jun 24 13:45:14 2003
+++ b/arch/x86_64/kernel/io_apic.c	Fri Aug 22 03:38:16 2003
@@ -1762,7 +1762,7 @@
 }
 
 
-int io_apic_set_pci_routing (int ioapic, int pin, int irq)
+int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level ,int active_high_low)
 {
 	struct IO_APIC_route_entry entry;
 	unsigned long flags;
@@ -1785,18 +1785,21 @@
 	entry.dest_mode = INT_DELIVERY_MODE;
 	entry.dest.logical.logical_dest = TARGET_CPUS;
 	entry.mask = 1;					 /* Disabled (masked) */
-	entry.trigger = 1;				   /* Level sensitive */
-	entry.polarity = 1;					/* Low active */
+	entry.trigger = edge_level;	
+	entry.polarity = active_high_low;
 
 	add_pin_to_irq(irq, ioapic, pin);
 
 	entry.vector = assign_irq_vector(irq);
 
 	printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
-		"IRQ %d)\n", ioapic, 
-		mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq);
+		"IRQ %d) Mode:%i Active:%i\n", ioapic, 
+		mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low);
 
-	irq_desc[irq].handler = &ioapic_level_irq_type;
+	if (edge_level)
+		irq_desc[irq].handler = &ioapic_level_irq_type;
+	else
+		irq_desc[irq].handler = &ioapic_edge_irq_type;
 
 	set_intr_gate(entry.vector, interrupt[irq]);
 
diff -Nru a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
--- a/arch/x86_64/kernel/mpparse.c	Tue Jun 24 14:01:06 2003
+++ b/arch/x86_64/kernel/mpparse.c	Fri Aug 22 03:29:25 2003
@@ -923,7 +923,7 @@
 
 	ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start;
 
-	io_apic_set_pci_routing(ioapic, ioapic_pin, irq);
+	io_apic_set_pci_routing(ioapic, ioapic_pin, irq, 1, 1);
 }
 
 #endif /*CONFIG_ACPI_HT_ONLY*/
@@ -939,6 +939,8 @@
 	int			ioapic_pin = 0;
 	int			irq = 0;
 	int			idx, bit = 0;
+	int			edge_level = 0;
+	int			active_high_low = 0;
 
 	/*
 	 * Parsing through the PCI Interrupt Routing Table (PRT) and program
@@ -949,11 +951,14 @@
 
 		/* Need to get irq for dynamic entry */
 		if (entry->link.handle) {
-			irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index);
+			irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
 			if (!irq)
 				continue;
-		} else
+		} else {
+			edge_level = 1;
+			active_high_low = 1;
 			irq = entry->link.index;
+		}
 
 		irq = entry->link.index;
 		ioapic = mp_find_ioapic(irq);
@@ -983,7 +988,7 @@
 
 		mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
 
-		vector = io_apic_set_pci_routing(ioapic, ioapic_pin, irq);
+		vector = io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low);
 		if (vector)
 			entry->irq = irq;
 
diff -Nru a/crypto/Config.in b/crypto/Config.in
--- a/crypto/Config.in	Mon Jun 23 14:00:41 2003
+++ b/crypto/Config.in	Mon Aug 11 22:20:12 2003
@@ -70,6 +70,7 @@
   tristate       '  Twofish cipher algorithm' CONFIG_CRYPTO_TWOFISH
   tristate       '  Serpent cipher algorithm' CONFIG_CRYPTO_SERPENT
   tristate       '  AES cipher algorithms' CONFIG_CRYPTO_AES
+  tristate       '  CAST5 (CAST-128) cipher algorithm' CONFIG_CRYPTO_CAST5
   if [ "$CONFIG_INET_IPCOMP" = "y" -o \
        "$CONFIG_INET_IPCOMP" = "m" -o \
        "$CONFIG_INET6_IPCOMP" = "y" -o \
diff -Nru a/crypto/Makefile b/crypto/Makefile
--- a/crypto/Makefile	Mon Jun 23 13:59:36 2003
+++ b/crypto/Makefile	Mon Aug 11 22:20:12 2003
@@ -24,6 +24,7 @@
 obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
 obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
 obj-$(CONFIG_CRYPTO_AES) += aes.o
+obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
diff -Nru a/crypto/cast5.c b/crypto/cast5.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/crypto/cast5.c	Mon Aug 11 22:20:07 2003
@@ -0,0 +1,852 @@
+/* Kernel cryptographic api.
+* cast5.c - Cast5 cipher algorithm (rfc2144).
+*
+* Derived from GnuPG implementation of cast5.
+*
+* Major Changes.
+* 	Complete conformance to rfc2144.
+* 	Supports key size from 40 to 128 bits.
+*
+* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+* Copyright (C) 2003 Kartikey Mahendra Bhatt <kartik_me@hotmail.com>.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of GNU General Public License as published by the Free
+* Software Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* 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 <linux/init.h>
+#include <linux/crypto.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#define CAST5_BLOCK_SIZE 8
+#define CAST5_MIN_KEY_SIZE 5
+#define CAST5_MAX_KEY_SIZE 16
+
+struct cast5_ctx {
+	u32 Km[16];
+	u8 Kr[16];
+	int rr;	/* rr?number of rounds = 16:number of rounds = 12; (rfc 2144) */
+};
+
+
+static const u32 s1[256] = {
+	0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f,
+	0x9c004dd3, 0x6003e540, 0xcf9fc949,
+	0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0,
+	0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+	0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3,
+	0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+	0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1,
+	0xaa54166b, 0x22568e3a, 0xa2d341d0,
+	0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac,
+	0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+	0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0,
+	0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+	0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290,
+	0xe93b159f, 0xb48ee411, 0x4bff345d,
+	0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad,
+	0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+	0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f,
+	0xc59c5319, 0xb949e354, 0xb04669fe,
+	0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5,
+	0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+	0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5,
+	0xf61b1891, 0xbb72275e, 0xaa508167,
+	0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427,
+	0xa2d1936b, 0x2ad286af, 0xaa56d291,
+	0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d,
+	0x73e2bb14, 0xa0bebc3c, 0x54623779,
+	0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e,
+	0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+	0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf,
+	0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+	0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241,
+	0x051ef495, 0xaa573b04, 0x4a805d8d,
+	0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b,
+	0x50afd341, 0xa7c13275, 0x915a0bf5,
+	0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265,
+	0xab85c5f3, 0x1b55db94, 0xaad4e324,
+	0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3,
+	0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+	0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6,
+	0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+	0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6,
+	0x032268d4, 0xc9600acc, 0xce387e6d,
+	0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da,
+	0x4736f464, 0x5ad328d8, 0xb347cc96,
+	0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc,
+	0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+	0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f,
+	0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+	0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4,
+	0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+	0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af,
+	0x51c85f4d, 0x56907596, 0xa5bb15e6,
+	0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a,
+	0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+	0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf,
+	0x700b45e1, 0xd5ea50f1, 0x85a92872,
+	0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198,
+	0x0cd0ede7, 0x26470db8, 0xf881814c,
+	0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db,
+	0xab838653, 0x6e2f1e23, 0x83719c9e,
+	0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c,
+	0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+	0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c,
+	0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
+};
+static const u32 s2[256] = {
+	0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a,
+	0xeec5207a, 0x55889c94, 0x72fc0651,
+	0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef,
+	0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+	0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086,
+	0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+	0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb,
+	0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+	0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f,
+	0x77e83f4e, 0x79929269, 0x24fa9f7b,
+	0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154,
+	0x0d554b63, 0x5d681121, 0xc866c359,
+	0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181,
+	0x39f7627f, 0x361e3084, 0xe4eb573b,
+	0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c,
+	0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+	0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a,
+	0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+	0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c,
+	0x1d804366, 0x721d9bfd, 0xa58684bb,
+	0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1,
+	0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+	0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9,
+	0xe0b56714, 0x21f043b7, 0xe5d05860,
+	0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf,
+	0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+	0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c,
+	0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+	0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122,
+	0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+	0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402,
+	0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+	0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53,
+	0xe3214517, 0xb4542835, 0x9f63293c,
+	0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6,
+	0x30a22c95, 0x31a70850, 0x60930f13,
+	0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6,
+	0xa02b1741, 0x7cbad9a2, 0x2180036f,
+	0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676,
+	0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+	0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb,
+	0x846a3bae, 0x8ff77888, 0xee5d60f6,
+	0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54,
+	0x157fd7fa, 0xef8579cc, 0xd152de58,
+	0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5,
+	0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+	0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8,
+	0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+	0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc,
+	0x301e16e6, 0x273be979, 0xb0ffeaa6,
+	0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a,
+	0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+	0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e,
+	0x1a513742, 0xef6828bc, 0x520365d6,
+	0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb,
+	0x5eea29cb, 0x145892f5, 0x91584f7f,
+	0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4,
+	0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+	0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3,
+	0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+	0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589,
+	0xa345415e, 0x5c038323, 0x3e5d3bb9,
+	0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539,
+	0x73bfbe70, 0x83877605, 0x4523ecf1
+};
+static const u32 s3[256] = {
+	0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff,
+	0x369fe44b, 0x8c1fc644, 0xaececa90,
+	0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806,
+	0xf0ad0548, 0xe13c8d83, 0x927010d5,
+	0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820,
+	0xfade82e0, 0xa067268b, 0x8272792e,
+	0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee,
+	0x825b1bfd, 0x9255c5ed, 0x1257a240,
+	0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf,
+	0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+	0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1,
+	0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+	0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c,
+	0x4a012d6e, 0xc5884a28, 0xccc36f71,
+	0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850,
+	0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+	0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e,
+	0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+	0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0,
+	0x1eac5790, 0x796fb449, 0x8252dc15,
+	0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403,
+	0xe83ec305, 0x4f91751a, 0x925669c2,
+	0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574,
+	0x927985b2, 0x8276dbcb, 0x02778176,
+	0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83,
+	0x340ce5c8, 0x96bbb682, 0x93b4b148,
+	0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20,
+	0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+	0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e,
+	0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+	0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9,
+	0xbda8229c, 0x127dadaa, 0x438a074e,
+	0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff,
+	0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+	0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a,
+	0x76a2e214, 0xb9a40368, 0x925d958f,
+	0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623,
+	0x193cbcfa, 0x27627545, 0x825cf47a,
+	0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7,
+	0x8272a972, 0x9270c4a8, 0x127de50b,
+	0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb,
+	0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+	0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11,
+	0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+	0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c,
+	0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+	0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40,
+	0x7c34671c, 0x02717ef6, 0x4feb5536,
+	0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1,
+	0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+	0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33,
+	0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+	0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff,
+	0x856302e0, 0x72dbd92b, 0xee971b69,
+	0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2,
+	0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+	0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38,
+	0x0ff0443d, 0x606e6dc6, 0x60543a49,
+	0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f,
+	0x68458425, 0x99833be5, 0x600d457d,
+	0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31,
+	0x9c305a00, 0x52bce688, 0x1b03588a,
+	0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636,
+	0xa133c501, 0xe9d3531c, 0xee353783
+};
+static const u32 s4[256] = {
+	0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb,
+	0x64ad8c57, 0x85510443, 0xfa020ed1,
+	0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43,
+	0x6497b7b1, 0xf3641f63, 0x241e4adf,
+	0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30,
+	0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+	0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f,
+	0x0c13fefe, 0x081b08ca, 0x05170121,
+	0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f,
+	0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+	0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400,
+	0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+	0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061,
+	0x11b638e1, 0x72500e03, 0xf80eb2bb,
+	0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400,
+	0x6920318f, 0x081dbb99, 0xffc304a5,
+	0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea,
+	0x9f926f91, 0x9f46222f, 0x3991467d,
+	0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8,
+	0x3fb6180c, 0x18f8931e, 0x281658e6,
+	0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25,
+	0x79098b02, 0xe4eabb81, 0x28123b23,
+	0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9,
+	0x0014377b, 0x041e8ac8, 0x09114003,
+	0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de,
+	0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+	0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0,
+	0x56c8c391, 0x6b65811c, 0x5e146119,
+	0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d,
+	0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+	0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a,
+	0xeca1d7c7, 0x041afa32, 0x1d16625a,
+	0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb,
+	0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+	0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3,
+	0xedda04eb, 0x17a9be04, 0x2c18f4df,
+	0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254,
+	0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+	0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2,
+	0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+	0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86,
+	0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+	0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1,
+	0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+	0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca,
+	0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+	0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5,
+	0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+	0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415,
+	0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+	0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7,
+	0x0ce454a9, 0xd60acd86, 0x015f1919,
+	0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe,
+	0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+	0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb,
+	0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+	0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8,
+	0x296b299e, 0x492fc295, 0x9266beab,
+	0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee,
+	0xf65324e6, 0x6afce36c, 0x0316cc04,
+	0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979,
+	0x932bcdf6, 0xb657c34d, 0x4edfd282,
+	0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0,
+	0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
+};
+static const u32 s5[256] = {
+	0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff,
+	0x1dd358f5, 0x44dd9d44, 0x1731167f,
+	0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8,
+	0x386381cb, 0xacf6243a, 0x69befd7a,
+	0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640,
+	0x15b0a848, 0xe68b18cb, 0x4caadeff,
+	0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d,
+	0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+	0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7,
+	0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+	0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88,
+	0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+	0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a,
+	0x578535f2, 0x2261be02, 0xd642a0c9,
+	0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8,
+	0xc8adedb3, 0x28a87fc9, 0x3d959981,
+	0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1,
+	0x4fb96976, 0x90c79505, 0xb0a8a774,
+	0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f,
+	0x0ec50966, 0xdfdd55bc, 0x29de0655,
+	0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980,
+	0x524755f4, 0x03b63cc9, 0x0cc844b2,
+	0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449,
+	0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+	0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6,
+	0x50f5b616, 0xf24766e3, 0x8eca36c1,
+	0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9,
+	0x3063fcdf, 0xb6f589de, 0xec2941da,
+	0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401,
+	0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+	0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd,
+	0x9e0885f9, 0x68cb3e47, 0x086c010f,
+	0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3,
+	0xcbb3d550, 0x1793084d, 0xb0d70eba,
+	0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56,
+	0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+	0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280,
+	0x05687715, 0x646c6bd7, 0x44904db3,
+	0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f,
+	0x2cb6356a, 0x85808573, 0x4991f840,
+	0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8,
+	0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+	0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717,
+	0x7d161bba, 0x9cad9010, 0xaf462ba2,
+	0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e,
+	0x176d486f, 0x097c13ea, 0x631da5c7,
+	0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72,
+	0x6e5dd2f3, 0x20936079, 0x459b80a5,
+	0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572,
+	0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+	0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e,
+	0x75922283, 0x784d6b17, 0x58ebb16e,
+	0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf,
+	0xaaf47556, 0x5f46b02a, 0x2b092801,
+	0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874,
+	0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+	0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826,
+	0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+	0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9,
+	0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+	0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a,
+	0xeeb9491d, 0x34010718, 0xbb30cab8,
+	0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8,
+	0xb1534546, 0x6d47de08, 0xefe9e7d4
+};
+static const u32 s6[256] = {
+	0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7,
+	0x016843b4, 0xeced5cbc, 0x325553ac,
+	0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8,
+	0xde5ebe39, 0xf38ff732, 0x8989b138,
+	0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99,
+	0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+	0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d,
+	0x09a8486f, 0xa888614a, 0x2900af98,
+	0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932,
+	0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+	0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c,
+	0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+	0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01,
+	0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+	0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c,
+	0xb88153e2, 0x08a19866, 0x1ae2eac8,
+	0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3,
+	0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+	0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc,
+	0x221db3a6, 0x9a69a02f, 0x68818a54,
+	0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc,
+	0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+	0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1,
+	0xe8a11be9, 0x4980740d, 0xc8087dfc,
+	0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f,
+	0x9528cd89, 0xfd339fed, 0xb87834bf,
+	0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa,
+	0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+	0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff,
+	0xa8dc8af0, 0x7345c106, 0xf41e232f,
+	0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af,
+	0x692573e4, 0xe9a9d848, 0xf3160289,
+	0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063,
+	0x4576698d, 0xb6fad407, 0x592af950,
+	0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8,
+	0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+	0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d,
+	0x48b9d585, 0xdc049441, 0xc8098f9b,
+	0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6,
+	0x890072d6, 0x28207682, 0xa9a9f7be,
+	0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a,
+	0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+	0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a,
+	0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+	0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0,
+	0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+	0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9,
+	0x0c5ec241, 0x8809286c, 0xf592d891,
+	0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98,
+	0xb173ecc0, 0xbc60b42a, 0x953498da,
+	0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123,
+	0x257f0c3d, 0x9348af49, 0x361400bc,
+	0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57,
+	0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+	0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5,
+	0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+	0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88,
+	0x44136c76, 0x0404a8c8, 0xb8e5a121,
+	0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913,
+	0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+	0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1,
+	0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+	0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905,
+	0xa65b1db8, 0x851c97bd, 0xd675cf2f
+};
+static const u32 s7[256] = {
+	0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f,
+	0xab9bc912, 0xde6008a1, 0x2028da1f,
+	0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11,
+	0xb232e75c, 0x4b3695f2, 0xb28707de,
+	0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381,
+	0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+	0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be,
+	0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+	0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66,
+	0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+	0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a,
+	0xeb12ff82, 0xe3486911, 0xd34d7516,
+	0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce,
+	0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+	0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa,
+	0x4437f107, 0xb6e79962, 0x42d2d816,
+	0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7,
+	0xf9583745, 0xcf19df58, 0xbec3f756,
+	0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511,
+	0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+	0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f,
+	0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+	0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a,
+	0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+	0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85,
+	0x61fe033c, 0x16746233, 0x3c034c28,
+	0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a,
+	0x1626a49f, 0xeed82b29, 0x1d382fe3,
+	0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c,
+	0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+	0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32,
+	0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+	0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f,
+	0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+	0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0,
+	0x79d34217, 0x021a718d, 0x9ac6336a,
+	0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef,
+	0x4eeb8476, 0x488dcf25, 0x36c9d566,
+	0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6,
+	0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+	0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887,
+	0x2b9f4fd5, 0x625aba82, 0x6a017962,
+	0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22,
+	0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+	0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1,
+	0x19de7eae, 0x053e561a, 0x15ad6f8c,
+	0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0,
+	0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+	0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108,
+	0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+	0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f,
+	0x3d321c5d, 0xc3f5e194, 0x4b269301,
+	0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e,
+	0x296693f4, 0x3d1fce6f, 0xc61e45be,
+	0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d,
+	0xb5229301, 0xcfd2a87f, 0x60aeb767,
+	0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b,
+	0x589dd390, 0x5479f8e6, 0x1cb8d647,
+	0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad,
+	0x462e1b78, 0x6580f87e, 0xf3817914,
+	0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc,
+	0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+	0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7,
+	0x94e01be8, 0x90716f4b, 0x954b8aa3
+};
+static const u32 sb8[256] = {
+	0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7,
+	0xe6c1121b, 0x0e241600, 0x052ce8b5,
+	0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c,
+	0x76e38111, 0xb12def3a, 0x37ddddfc,
+	0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f,
+	0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+	0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831,
+	0x3f8f95e7, 0x72df191b, 0x7580330d,
+	0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a,
+	0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+	0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022,
+	0xce949ad4, 0xb84769ad, 0x965bd862,
+	0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f,
+	0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+	0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3,
+	0xae63aff2, 0x7e8bd632, 0x70108c0c,
+	0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53,
+	0x06918548, 0x58cb7e07, 0x3b74ef2e,
+	0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2,
+	0x19b47a38, 0x424f7618, 0x35856039,
+	0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd,
+	0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+	0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c,
+	0x3dd00db3, 0x708f8f34, 0x77d51b42,
+	0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e,
+	0x3e378160, 0x7895cda5, 0x859c15a5,
+	0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e,
+	0x31842e7b, 0x24259fd7, 0xf8bef472,
+	0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c,
+	0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+	0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187,
+	0xea7a6e98, 0x7cd16efc, 0x1436876c,
+	0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899,
+	0x92ecbae6, 0xdd67016d, 0x151682eb,
+	0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e,
+	0xe139673b, 0xefa63fb8, 0x71873054,
+	0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d,
+	0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+	0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428,
+	0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+	0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4,
+	0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+	0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2,
+	0x37df932b, 0xc4248289, 0xacf3ebc3,
+	0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e,
+	0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+	0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b,
+	0xdb485694, 0x38d7e5b2, 0x57720101,
+	0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282,
+	0x7523d24a, 0xe0779695, 0xf9c17a8f,
+	0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f,
+	0xad1163ed, 0xea7b5965, 0x1a00726e,
+	0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0,
+	0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+	0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca,
+	0x8951570f, 0xdf09822b, 0xbd691a6c,
+	0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f,
+	0x0d771c2b, 0x67cdb156, 0x350d8384,
+	0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61,
+	0x8360d87b, 0x1fa98b0c, 0x1149382c,
+	0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82,
+	0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+	0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80,
+	0xeaee6801, 0x8db2a283, 0xea8bf59e
+};
+
+
+#define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) )
+
+#define F1(D,m,r)  (  (I = ((m) + (D))), (I=rol((r),I)),   \
+    (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]) )
+#define F2(D,m,r)  (  (I = ((m) ^ (D))), (I=rol((r),I)),   \
+    (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]) )
+#define F3(D,m,r)  (  (I = ((m) - (D))), (I=rol((r),I)),   \
+    (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) )
+
+
+static void cast5_encrypt(void *ctx, u8 * outbuf, const u8 * inbuf)
+{
+	struct cast5_ctx *c = (struct cast5_ctx *) ctx;
+	u32 l, r, t;
+	u32 I;			/* used by the Fx macros */
+	u32 *Km;
+	u8 *Kr;
+
+	Km = c->Km;
+	Kr = c->Kr;
+
+	/* (L0,R0) <-- (m1...m64).  (Split the plaintext into left and
+	 * right 32-bit halves L0 = m1...m32 and R0 = m33...m64.)
+	 */
+	l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
+	r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
+
+	/* (16 rounds) for i from 1 to 16, compute Li and Ri as follows:
+	 *  Li = Ri-1;
+	 *  Ri = Li-1 ^ f(Ri-1,Kmi,Kri), where f is defined in Section 2.2
+	 * Rounds 1, 4, 7, 10, 13, and 16 use f function Type 1.
+	 * Rounds 2, 5, 8, 11, and 14 use f function Type 2.
+	 * Rounds 3, 6, 9, 12, and 15 use f function Type 3.
+	 */
+
+	if (!(c->rr)) {
+		t = l; l = r; r = t ^ F1(r, Km[0], Kr[0]);
+		t = l; l = r; r = t ^ F2(r, Km[1], Kr[1]);
+		t = l; l = r; r = t ^ F3(r, Km[2], Kr[2]);
+		t = l; l = r; r = t ^ F1(r, Km[3], Kr[3]);
+		t = l; l = r; r = t ^ F2(r, Km[4], Kr[4]);
+		t = l; l = r; r = t ^ F3(r, Km[5], Kr[5]);
+		t = l; l = r; r = t ^ F1(r, Km[6], Kr[6]);
+		t = l; l = r; r = t ^ F2(r, Km[7], Kr[7]);
+		t = l; l = r; r = t ^ F3(r, Km[8], Kr[8]);
+		t = l; l = r; r = t ^ F1(r, Km[9], Kr[9]);
+		t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
+		t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
+		t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
+		t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
+		t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
+		t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
+	} else {
+		t = l; l = r; r = t ^ F1(r, Km[0], Kr[0]);
+		t = l; l = r; r = t ^ F2(r, Km[1], Kr[1]);
+		t = l; l = r; r = t ^ F3(r, Km[2], Kr[2]);
+		t = l; l = r; r = t ^ F1(r, Km[3], Kr[3]);
+		t = l; l = r; r = t ^ F2(r, Km[4], Kr[4]);
+		t = l; l = r; r = t ^ F3(r, Km[5], Kr[5]);
+		t = l; l = r; r = t ^ F1(r, Km[6], Kr[6]);
+		t = l; l = r; r = t ^ F2(r, Km[7], Kr[7]);
+		t = l; l = r; r = t ^ F3(r, Km[8], Kr[8]);
+		t = l; l = r; r = t ^ F1(r, Km[9], Kr[9]);
+		t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
+		t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
+	}
+
+	/* c1...c64 <-- (R16,L16).  (Exchange final blocks L16, R16 and
+	 *  concatenate to form the ciphertext.) */
+	outbuf[0] = (r >> 24) & 0xff;
+	outbuf[1] = (r >> 16) & 0xff;
+	outbuf[2] = (r >> 8) & 0xff;
+	outbuf[3] = r & 0xff;
+	outbuf[4] = (l >> 24) & 0xff;
+	outbuf[5] = (l >> 16) & 0xff;
+	outbuf[6] = (l >> 8) & 0xff;
+	outbuf[7] = l & 0xff;
+}
+
+static void cast5_decrypt(void *ctx, u8 * outbuf, const u8 * inbuf)
+{
+	struct cast5_ctx *c = (struct cast5_ctx *) ctx;
+	u32 l, r, t;
+	u32 I;
+	u32 *Km;
+	u8 *Kr;
+
+	Km = c->Km;
+	Kr = c->Kr;
+
+	l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
+	r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
+
+	if (!(c->rr)) {
+		t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
+		t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
+		t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
+		t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
+		t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
+		t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
+		t = l; l = r; r = t ^ F1(r, Km[9], Kr[9]);
+		t = l; l = r; r = t ^ F3(r, Km[8], Kr[8]);
+		t = l; l = r; r = t ^ F2(r, Km[7], Kr[7]);
+		t = l; l = r; r = t ^ F1(r, Km[6], Kr[6]);
+		t = l; l = r; r = t ^ F3(r, Km[5], Kr[5]);
+		t = l; l = r; r = t ^ F2(r, Km[4], Kr[4]);
+		t = l; l = r; r = t ^ F1(r, Km[3], Kr[3]);
+		t = l; l = r; r = t ^ F3(r, Km[2], Kr[2]);
+		t = l; l = r; r = t ^ F2(r, Km[1], Kr[1]);
+		t = l; l = r; r = t ^ F1(r, Km[0], Kr[0]);
+	} else {
+		t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
+		t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
+		t = l; l = r; r = t ^ F1(r, Km[9], Kr[9]);
+		t = l; l = r; r = t ^ F3(r, Km[8], Kr[8]);
+		t = l; l = r; r = t ^ F2(r, Km[7], Kr[7]);
+		t = l; l = r; r = t ^ F1(r, Km[6], Kr[6]);
+		t = l; l = r; r = t ^ F3(r, Km[5], Kr[5]);
+		t = l; l = r; r = t ^ F2(r, Km[4], Kr[4]);
+		t = l; l = r; r = t ^ F1(r, Km[3], Kr[3]);
+		t = l; l = r; r = t ^ F3(r, Km[2], Kr[2]);
+		t = l; l = r; r = t ^ F2(r, Km[1], Kr[1]);
+		t = l; l = r; r = t ^ F1(r, Km[0], Kr[0]);
+	}
+
+	outbuf[0] = (r >> 24) & 0xff;
+	outbuf[1] = (r >> 16) & 0xff;
+	outbuf[2] = (r >> 8) & 0xff;
+	outbuf[3] = r & 0xff;
+	outbuf[4] = (l >> 24) & 0xff;
+	outbuf[5] = (l >> 16) & 0xff;
+	outbuf[6] = (l >> 8) & 0xff;
+	outbuf[7] = l & 0xff;
+}
+
+static void key_schedule(u32 * x, u32 * z, u32 * k)
+{
+
+#define xi(i)   ((x[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
+#define zi(i)   ((z[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
+
+	z[0] = x[0] ^ s5[xi(13)] ^ s6[xi(15)] ^ s7[xi(12)] ^ sb8[xi(14)] ^
+	    s7[xi(8)];
+	z[1] = x[2] ^ s5[zi(0)] ^ s6[zi(2)] ^ s7[zi(1)] ^ sb8[zi(3)] ^
+	    sb8[xi(10)];
+	z[2] = x[3] ^ s5[zi(7)] ^ s6[zi(6)] ^ s7[zi(5)] ^ sb8[zi(4)] ^
+	    s5[xi(9)];
+	z[3] = x[1] ^ s5[zi(10)] ^ s6[zi(9)] ^ s7[zi(11)] ^ sb8[zi(8)] ^
+	    s6[xi(11)];
+	k[0] = s5[zi(8)] ^ s6[zi(9)] ^ s7[zi(7)] ^ sb8[zi(6)] ^ s5[zi(2)];
+	k[1] = s5[zi(10)] ^ s6[zi(11)] ^ s7[zi(5)] ^ sb8[zi(4)] ^
+	    s6[zi(6)];
+	k[2] = s5[zi(12)] ^ s6[zi(13)] ^ s7[zi(3)] ^ sb8[zi(2)] ^
+	    s7[zi(9)];
+	k[3] = s5[zi(14)] ^ s6[zi(15)] ^ s7[zi(1)] ^ sb8[zi(0)] ^
+	    sb8[zi(12)];
+
+	x[0] = z[2] ^ s5[zi(5)] ^ s6[zi(7)] ^ s7[zi(4)] ^ sb8[zi(6)] ^
+	    s7[zi(0)];
+	x[1] = z[0] ^ s5[xi(0)] ^ s6[xi(2)] ^ s7[xi(1)] ^ sb8[xi(3)] ^
+	    sb8[zi(2)];
+	x[2] = z[1] ^ s5[xi(7)] ^ s6[xi(6)] ^ s7[xi(5)] ^ sb8[xi(4)] ^
+	    s5[zi(1)];
+	x[3] = z[3] ^ s5[xi(10)] ^ s6[xi(9)] ^ s7[xi(11)] ^ sb8[xi(8)] ^
+	    s6[zi(3)];
+	k[4] = s5[xi(3)] ^ s6[xi(2)] ^ s7[xi(12)] ^ sb8[xi(13)] ^
+	    s5[xi(8)];
+	k[5] = s5[xi(1)] ^ s6[xi(0)] ^ s7[xi(14)] ^ sb8[xi(15)] ^
+	    s6[xi(13)];
+	k[6] = s5[xi(7)] ^ s6[xi(6)] ^ s7[xi(8)] ^ sb8[xi(9)] ^ s7[xi(3)];
+	k[7] = s5[xi(5)] ^ s6[xi(4)] ^ s7[xi(10)] ^ sb8[xi(11)] ^
+	    sb8[xi(7)];
+
+	z[0] = x[0] ^ s5[xi(13)] ^ s6[xi(15)] ^ s7[xi(12)] ^ sb8[xi(14)] ^
+	    s7[xi(8)];
+	z[1] = x[2] ^ s5[zi(0)] ^ s6[zi(2)] ^ s7[zi(1)] ^ sb8[zi(3)] ^
+	    sb8[xi(10)];
+	z[2] = x[3] ^ s5[zi(7)] ^ s6[zi(6)] ^ s7[zi(5)] ^ sb8[zi(4)] ^
+	    s5[xi(9)];
+	z[3] = x[1] ^ s5[zi(10)] ^ s6[zi(9)] ^ s7[zi(11)] ^ sb8[zi(8)] ^
+	    s6[xi(11)];
+	k[8] = s5[zi(3)] ^ s6[zi(2)] ^ s7[zi(12)] ^ sb8[zi(13)] ^
+	    s5[zi(9)];
+	k[9] = s5[zi(1)] ^ s6[zi(0)] ^ s7[zi(14)] ^ sb8[zi(15)] ^
+	    s6[zi(12)];
+	k[10] = s5[zi(7)] ^ s6[zi(6)] ^ s7[zi(8)] ^ sb8[zi(9)] ^ s7[zi(2)];
+	k[11] = s5[zi(5)] ^ s6[zi(4)] ^ s7[zi(10)] ^ sb8[zi(11)] ^
+	    sb8[zi(6)];
+
+	x[0] = z[2] ^ s5[zi(5)] ^ s6[zi(7)] ^ s7[zi(4)] ^ sb8[zi(6)] ^
+	    s7[zi(0)];
+	x[1] = z[0] ^ s5[xi(0)] ^ s6[xi(2)] ^ s7[xi(1)] ^ sb8[xi(3)] ^
+	    sb8[zi(2)];
+	x[2] = z[1] ^ s5[xi(7)] ^ s6[xi(6)] ^ s7[xi(5)] ^ sb8[xi(4)] ^
+	    s5[zi(1)];
+	x[3] = z[3] ^ s5[xi(10)] ^ s6[xi(9)] ^ s7[xi(11)] ^ sb8[xi(8)] ^
+	    s6[zi(3)];
+	k[12] = s5[xi(8)] ^ s6[xi(9)] ^ s7[xi(7)] ^ sb8[xi(6)] ^ s5[xi(3)];
+	k[13] = s5[xi(10)] ^ s6[xi(11)] ^ s7[xi(5)] ^ sb8[xi(4)] ^
+	    s6[xi(7)];
+	k[14] = s5[xi(12)] ^ s6[xi(13)] ^ s7[xi(3)] ^ sb8[xi(2)] ^
+	    s7[xi(8)];
+	k[15] = s5[xi(14)] ^ s6[xi(15)] ^ s7[xi(1)] ^ sb8[xi(0)] ^
+	    sb8[xi(13)];
+
+#undef xi
+#undef zi
+}
+
+
+static int
+cast5_setkey(void *ctx, const u8 * key, unsigned key_len, u32 * flags)
+{
+	int i;
+	u32 x[4];
+	u32 z[4];
+	u32 k[16];
+	u8 p_key[16];
+	struct cast5_ctx *c = (struct cast5_ctx *) ctx;
+	
+	if (key_len < 5 || key_len > 16) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	c->rr = key_len <= 10 ? 1 : 0;
+
+	memset(p_key, 0, 16);
+	memcpy(p_key, key, key_len);
+
+
+	x[0] = p_key[0] << 24 | p_key[1] << 16 | p_key[2] << 8 | p_key[3];
+	x[1] = p_key[4] << 24 | p_key[5] << 16 | p_key[6] << 8 | p_key[7];
+	x[2] =
+	    p_key[8] << 24 | p_key[9] << 16 | p_key[10] << 8 | p_key[11];
+	x[3] =
+	    p_key[12] << 24 | p_key[13] << 16 | p_key[14] << 8 | p_key[15];
+
+	key_schedule(x, z, k);
+	for (i = 0; i < 16; i++)
+		c->Km[i] = k[i];
+	key_schedule(x, z, k);
+	for (i = 0; i < 16; i++)
+		c->Kr[i] = k[i] & 0x1f;
+	return 0;
+}
+
+static struct crypto_alg alg = {
+	.cra_name 	= "cast5",
+	.cra_flags 	= CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize 	= CAST5_BLOCK_SIZE,
+	.cra_ctxsize 	= sizeof(struct cast5_ctx),
+	.cra_module 	= THIS_MODULE,
+	.cra_list 	= LIST_HEAD_INIT(alg.cra_list),
+	.cra_u 		= {
+		.cipher = {
+			.cia_min_keysize = CAST5_MIN_KEY_SIZE,
+			.cia_max_keysize = CAST5_MAX_KEY_SIZE,
+			.cia_ivsize = CAST5_BLOCK_SIZE,
+			.cia_setkey = cast5_setkey,
+			.cia_encrypt = cast5_encrypt,
+			.cia_decrypt = cast5_decrypt
+		}
+	}
+};
+
+static int __init init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cast5 Cipher Algorithm");
+
diff -Nru a/crypto/tcrypt.c b/crypto/tcrypt.c
--- a/crypto/tcrypt.c	Mon Jun 23 14:00:32 2003
+++ b/crypto/tcrypt.c	Mon Aug 11 22:20:12 2003
@@ -2192,6 +2192,102 @@
 	crypto_free_tfm(tfm);
 }
 
+void
+test_cast5(void)
+{
+	unsigned int ret, i, tsize;
+	u8 *p, *q, *key;
+	struct crypto_tfm *tfm;
+	struct cast5_tv *c5_tv;
+	struct scatterlist sg[1];
+
+	printk("\ntesting cast5 encryption\n");
+
+	tfm = crypto_alloc_tfm("cast5", 0);
+	if (tfm == NULL) {
+		printk("failed to load transform for cast5 (default ecb)\n");
+		return;
+	}
+
+	tsize = sizeof (cast5_enc_tv_template);
+	if (tsize > TVMEMSIZE) {
+		printk("template (%u) too big for tvmem (%u)\n", tsize,
+		       TVMEMSIZE);
+		return;
+	}
+
+	memcpy(tvmem, cast5_enc_tv_template, tsize);
+	c5_tv = (void *) tvmem;
+	for (i = 0; i < CAST5_ENC_TEST_VECTORS; i++) {
+		printk("test %u (%d bit key):\n", i + 1, c5_tv[i].keylen * 8);
+		key = c5_tv[i].key;
+
+		ret = crypto_cipher_setkey(tfm, key, c5_tv[i].keylen);
+		if (ret) {
+			printk("setkey() failed flags=%x\n", tfm->crt_flags);
+
+			if (!c5_tv[i].fail)
+				goto out;
+		}
+
+		p = c5_tv[i].plaintext;
+		sg[0].page = virt_to_page(p);
+		sg[0].offset = ((long) p & ~PAGE_MASK);
+		sg[0].length = sizeof(c5_tv[i].plaintext);
+		ret = crypto_cipher_encrypt(tfm, sg, sg, sg[0].length);
+		if (ret) {
+			printk("encrypt() failed flags=%x\n", tfm->crt_flags);
+			goto out;
+		}
+
+		q = kmap(sg[0].page) + sg[0].offset;
+		hexdump(q, sizeof(c5_tv[i].ciphertext));
+
+		printk("%s\n", memcmp(q, c5_tv[i].ciphertext,
+			sizeof(c5_tv[i].ciphertext)) ? "fail" : "pass");
+	}
+	
+	tsize = sizeof (cast5_dec_tv_template);
+	if (tsize > TVMEMSIZE) {
+		printk("template (%u) too big for tvmem (%u)\n", tsize,
+		       TVMEMSIZE);
+		return;
+	}
+
+	memcpy(tvmem, cast5_dec_tv_template, tsize);
+	c5_tv = (void *) tvmem;
+	for (i = 0; i < CAST5_DEC_TEST_VECTORS; i++) {
+		printk("test %u (%d bit key):\n", i + 1, c5_tv[i].keylen * 8);
+		key = c5_tv[i].key;
+
+		ret = crypto_cipher_setkey(tfm, key, c5_tv[i].keylen);
+		if (ret) {
+			printk("setkey() failed flags=%x\n", tfm->crt_flags);
+
+			if (!c5_tv[i].fail)
+				goto out;
+		}
+
+		p = c5_tv[i].plaintext;
+		sg[0].page = virt_to_page(p);
+		sg[0].offset = ((long) p & ~PAGE_MASK);
+		sg[0].length = sizeof(c5_tv[i].plaintext);
+		ret = crypto_cipher_decrypt(tfm, sg, sg, sg[0].length);
+		if (ret) {
+			printk("decrypt() failed flags=%x\n", tfm->crt_flags);
+			goto out;
+		}
+
+		q = kmap(sg[0].page) + sg[0].offset;
+		hexdump(q, sizeof(c5_tv[i].ciphertext));
+
+		printk("%s\n", memcmp(q, c5_tv[i].ciphertext,
+			sizeof(c5_tv[i].ciphertext)) ? "fail" : "pass");
+	}
+out:
+	crypto_free_tfm (tfm);
+}
+
 static void
 test_deflate(void)
 {
@@ -2304,6 +2400,7 @@
 		test_sha384();
 		test_sha512();
 		test_deflate();
+		test_cast5();
 #ifdef CONFIG_CRYPTO_HMAC
 		test_hmac_md5();
 		test_hmac_sha1();
@@ -2361,6 +2458,10 @@
 
 	case 13:
 		test_deflate();
+		break;
+
+	case 14:
+		test_cast5();
 		break;
 
 #ifdef CONFIG_CRYPTO_HMAC
diff -Nru a/crypto/tcrypt.h b/crypto/tcrypt.h
--- a/crypto/tcrypt.h	Mon Jun 23 13:59:36 2003
+++ b/crypto/tcrypt.h	Mon Aug 11 22:20:12 2003
@@ -1682,6 +1682,74 @@
 	},
 };
 
+/* Cast5 test vectors from RFC 2144 */
+#define CAST5_ENC_TEST_VECTORS	3
+#define CAST5_DEC_TEST_VECTORS	3
+
+struct cast5_tv {
+	unsigned keylen;
+	unsigned fail;
+	u8 key[16];
+	u8 plaintext[8];
+	u8 ciphertext[8];
+};
+
+struct cast5_tv cast5_enc_tv_template[] =
+{
+	{
+		16,
+		0,
+		{ 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
+		  0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A },
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		{ 0x23, 0x8b, 0x4f, 0xe5, 0x84, 0x7e, 0x44, 0xb2 },
+
+	},
+	{
+		10,
+		0,
+		{ 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
+		  0x23, 0x45 },
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		{ 0xeb, 0x6a, 0x71, 0x1a, 0x2c, 0x02, 0x27, 0x1b },
+	},
+	{
+		5,
+		0,
+		{ 0x01, 0x23, 0x45, 0x67, 0x12 },
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+		{ 0x7a, 0xc8, 0x16, 0xd1, 0x6e, 0x9b, 0x30, 0x2e },
+	}
+};
+
+struct cast5_tv cast5_dec_tv_template[] =
+{
+	{
+		16,
+		0,
+		{ 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
+		  0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A },
+		{ 0x23, 0x8b, 0x4f, 0xe5, 0x84, 0x7e, 0x44, 0xb2 },
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+
+	},
+	{
+		10,
+		0,
+		{ 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
+		  0x23, 0x45 },
+		{ 0xeb, 0x6a, 0x71, 0x1a, 0x2c, 0x02, 0x27, 0x1b },
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+	},
+	{
+		5,
+		0,
+		{ 0x01, 0x23, 0x45, 0x67, 0x12 },
+		{ 0x7a, 0xc8, 0x16, 0xd1, 0x6e, 0x9b, 0x30, 0x2e },
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
+	}
+};
+
 /*
  * Compression stuff.
  */
diff -Nru a/drivers/atm/Makefile b/drivers/atm/Makefile
--- a/drivers/atm/Makefile	Wed May  7 01:57:29 2003
+++ b/drivers/atm/Makefile	Mon Jul 28 07:35:31 2003
@@ -59,8 +59,6 @@
   obj-$(CONFIG_ATM_HE)		+= suni.o
 endif
 
-EXTRA_CFLAGS=-g
-
 list-multi	:= fore_200e.o
 fore_200e-objs	:= fore200e.o $(FORE200E_FW_OBJS)
 
diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c
--- a/drivers/atm/he.c	Wed Jul  9 20:28:40 2003
+++ b/drivers/atm/he.c	Fri Aug  1 17:06:08 2003
@@ -89,7 +89,7 @@
 
 /* compatibility */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69)
+#ifndef IRQ_HANDLED
 typedef void irqreturn_t;
 #define IRQ_NONE
 #define IRQ_HANDLED
diff -Nru a/drivers/block/Config.in b/drivers/block/Config.in
--- a/drivers/block/Config.in	Tue Aug  6 17:57:28 2002
+++ b/drivers/block/Config.in	Fri Aug 29 08:21:37 2003
@@ -36,6 +36,7 @@
 dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI
 dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI 
 dep_mbool '       SCSI tape drive support for Smart Array 5xxx' CONFIG_CISS_SCSI_TAPE $CONFIG_BLK_CPQ_CISS_DA $CONFIG_SCSI
+dep_mbool '       Enable monitor thread' CONFIG_CISS_MONITOR_THREAD $CONFIG_BLK_CPQ_CISS_DA
 dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
 dep_tristate 'Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)' CONFIG_BLK_DEV_UMEM $CONFIG_PCI $CONFIG_EXPERIMENTAL
 
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Thu Jul 17 09:33:11 2003
+++ b/drivers/block/cciss.c	Fri Aug 29 08:21:37 2003
@@ -38,6 +38,7 @@
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <linux/smp_lock.h>
 
 #include <linux/blk.h>
 #include <linux/blkdev.h>
@@ -109,6 +110,16 @@
 
 #define CCISS_DMA_MASK 0xFFFFFFFFFFFFFFFF /* 64 bit DMA */
 
+#ifdef CONFIG_CISS_MONITOR_THREAD
+static int cciss_monitor(void *ctlr);
+static int start_monitor_thread(ctlr_info_t *h, unsigned char *cmd, 
+		unsigned long count, int (*cciss_monitor)(void *), int *rc);
+static u32 heartbeat_timer = 0;
+#else
+#define cciss_monitor(x)
+#define kill_monitor_thead(x)
+#endif
+
 static ctlr_info_t *hba[MAX_CTLR];
 
 static struct proc_dir_entry *proc_cciss;
@@ -188,7 +199,11 @@
  		"Current # commands on controller: %d\n"
  		"Max Q depth since init: %d\n"
 		"Max # commands on controller since init: %d\n"
-		"Max SG entries since init: %d\n\n",
+		"Max SG entries since init: %d\n"
+		MONITOR_PERIOD_PATTERN 
+		MONITOR_DEADLINE_PATTERN
+		MONITOR_STATUS_PATTERN 
+		"\n",
   		h->devname,
   		h->product_name,
   		(unsigned long)h->board_id,
@@ -196,7 +211,10 @@
   		(unsigned int)h->intr,
   		h->num_luns, 
   		h->Qdepth, h->commands_outstanding,
-  		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+		h->maxQsinceinit, h->max_outstanding, h->maxSG,
+		MONITOR_PERIOD_VALUE(h),
+		MONITOR_DEADLINE_VALUE(h),
+		CTLR_STATUS(h));
   
 	pos += size; len += size;
 	cciss_proc_tape_report(ctlr, buffer, &pos, &len);
@@ -231,10 +249,8 @@
 {
 	unsigned char cmd[80];
 	int len;
-#ifdef CONFIG_CISS_SCSI_TAPE
 	ctlr_info_t *h = (ctlr_info_t *) data;
 	int rc;
-#endif
 
 	if (count > sizeof(cmd)-1) 
 		return -EINVAL;
@@ -244,6 +260,7 @@
 	len = strlen(cmd);	
 	if (cmd[len-1] == '\n')
 		cmd[--len] = '\0';
+
 #	ifdef CONFIG_CISS_SCSI_TAPE
 		if (strcmp("engage scsi", cmd)==0) {
 			rc = cciss_engage_scsi(h->ctlr);
@@ -254,6 +271,10 @@
 		/* might be nice to have "disengage" too, but it's not
 		   safely possible. (only 1 module use count, lock issues.) */
 #	endif
+
+	if (START_MONITOR_THREAD(h, cmd, count, cciss_monitor, &rc) == 0)
+		return rc;
+	
 	return -EINVAL;
 }
 
@@ -407,7 +428,7 @@
 	printk(KERN_DEBUG "cciss_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk);
 #endif /* CCISS_DEBUG */ 
 
-	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
+	if (ctlr > MAX_CTLR || hba[ctlr] == NULL || !CTLR_IS_ALIVE(hba[ctlr]))
 		return -ENXIO;
 	/*
 	 * Root is allowed to open raw volume zero even if its not configured
@@ -1107,7 +1128,8 @@
 	size_t	size,
 	unsigned int use_unit_num,
 	unsigned int log_unit,
-	__u8	page_code )
+	__u8	page_code,
+	__u8 cmdtype)
 {
 	ctlr_info_t *h = hba[ctlr];
 	CommandList_struct *c;
@@ -1131,6 +1153,9 @@
 	}
 	c->Header.Tag.lower = c->busaddr;  /* tag is phys addr of cmd */
 	/* Fill in Request block */
+	c->Request.CDB[0] = cmd;
+	c->Request.Type.Type = cmdtype;
+	if (cmdtype == TYPE_CMD) {
 	switch (cmd) {
 		case  CISS_INQUIRY:
 			/* If the logical unit number is 0 then, this is going
@@ -1150,11 +1175,9 @@
 				c->Request.CDB[2] = page_code;
 			}
 			c->Request.CDBLen = 6;
-			c->Request.Type.Type =  TYPE_CMD;
 			c->Request.Type.Attribute = ATTR_SIMPLE;
 			c->Request.Type.Direction = XFER_READ; /* Read */
 			c->Request.Timeout = 0; /* Don't time out */
-			c->Request.CDB[0] =  CISS_INQUIRY;
 			c->Request.CDB[4] = size  & 0xFF;
 		break;
 		case CISS_REPORT_LOG:
@@ -1163,11 +1186,9 @@
 				So we have nothing to write.
 			*/
 			c->Request.CDBLen = 12;
-			c->Request.Type.Type =  TYPE_CMD;
 			c->Request.Type.Attribute = ATTR_SIMPLE;
 			c->Request.Type.Direction = XFER_READ; /* Read */
 			c->Request.Timeout = 0; /* Don't time out */
-			c->Request.CDB[0] = CISS_REPORT_LOG;
 			c->Request.CDB[6] = (size >> 24) & 0xFF;  /* MSB */
 			c->Request.CDB[7] = (size >> 16) & 0xFF;
 			c->Request.CDB[8] = (size >> 8) & 0xFF;
@@ -1178,18 +1199,38 @@
 				hba[ctlr]->drv[log_unit].LunID;
 			c->Header.LUN.LogDev.Mode = 1;
 			c->Request.CDBLen = 10;
-			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
 			c->Request.Type.Attribute = ATTR_SIMPLE;
 			c->Request.Type.Direction = XFER_READ; /* Read */
 			c->Request.Timeout = 0; /* Don't time out */
-			c->Request.CDB[0] = CCISS_READ_CAPACITY;
 		break;
 		default:
 			printk(KERN_WARNING
 				"cciss:  Unknown Command 0x%x sent attempted\n",				cmd);
 			cmd_free(h, c, 1);
 			return IO_ERROR;
-	};
+		}
+	} else if (cmdtype == TYPE_MSG) {
+		switch (cmd) {
+		case 3: /* No-Op message */
+			c->Request.CDBLen = 1;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_WRITE;
+			c->Request.Timeout = 0;
+			c->Request.CDB[0] = cmd;
+			break;
+		default:
+			printk(KERN_WARNING
+				"cciss%d: unknown message type %d\n",
+					ctlr, cmd);
+			cmd_free(h, c, 1);
+			return IO_ERROR;
+		}
+	} else {
+		printk(KERN_WARNING
+			"cciss%d: unknown command type %d\n", ctlr, cmdtype);
+		cmd_free(h, c, 1);
+		return IO_ERROR;
+	}
 
 	/* Fill in the scatter gather information */
 	if (size > 0) {
@@ -1352,7 +1393,7 @@
 	}
 
 	return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
-			sizeof(ReportLunData_struct), 0, 0, 0 );
+			sizeof(ReportLunData_struct), 0, 0, 0, TYPE_CMD);
 
 	if (return_code == IO_OK) {
 		listlength = be32_to_cpu(*((__u32 *) &ld_buff->LUNListLength[0]));
@@ -1451,7 +1492,7 @@
 	memset(size_buff, 0, sizeof(ReadCapdata_struct));
 	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr,
 			size_buff, sizeof(ReadCapdata_struct), 1,
-			logvol, 0 );
+			logvol, 0, TYPE_CMD);
 	if (return_code == IO_OK) {
 		total_size = (0xff &
 			(unsigned int) size_buff->total_size[0]) << 24;
@@ -1482,7 +1523,7 @@
 	/* Execute the command to read the disk geometry */
 	memset(inq_buff, 0, sizeof(InquiryData_struct));
 	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
-		sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+		sizeof(InquiryData_struct), 1, logvol ,0xC1, TYPE_CMD);
 	if (return_code == IO_OK) {
 		if (inq_buff->data_byte[8] == 0xFF) {
 			printk(KERN_WARNING
@@ -1590,7 +1631,8 @@
 	}
 	memset(size_buff, 0, sizeof(ReadCapdata_struct));
 	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, size_buff,
-				sizeof( ReadCapdata_struct), 1, logvol, 0 );
+				sizeof( ReadCapdata_struct), 1, logvol, 0, 
+				TYPE_CMD);
 	if (return_code == IO_OK) {
 		total_size = (0xff &
 			(unsigned int)(size_buff->total_size[0])) << 24;
@@ -1619,7 +1661,7 @@
 	/* Execute the command to read the disk geometry */
 	memset(inq_buff, 0, sizeof(InquiryData_struct));
 	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
-			sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+			sizeof(InquiryData_struct), 1, logvol ,0xC1, TYPE_CMD);
 	if (return_code == IO_OK) {
 		if (inq_buff->data_byte[8] == 0xFF) {
 			printk(KERN_WARNING "cciss: reading geometry failed, "
@@ -2236,6 +2278,15 @@
 		goto startio;
         }
 
+	/* make sure controller is alive. */
+	if (!CTLR_IS_ALIVE(h)) {
+                printk(KERN_WARNING "cciss%d: I/O quit ", h->ctlr);
+                blkdev_dequeue_request(creq);
+                complete_buffers(creq->bh, 0);
+		end_that_request_last(creq);
+		return;
+	}
+
 	if (( c = cmd_alloc(h, 1)) == NULL)
 		goto startio;
 
@@ -2833,7 +2884,174 @@
 	kfree(hba[i]);
 	hba[i]=NULL;
 }
+#ifdef CONFIG_CISS_MONITOR_THREAD
+static void fail_all_cmds(unsigned long ctlr)
+{
+	/* If we get here, the board is apparently dead. */
+	ctlr_info_t *h = hba[ctlr];
+	CommandList_struct *c;
+	unsigned long flags;
+
+	printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
+	h->alive = 0;	/* the controller apparently died... */ 
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	pci_disable_device(h->pdev); /* Make sure it is really dead. */
 
+	/* move everything off the request queue onto the completed queue */
+	while( (c = h->reqQ) != NULL ) {
+		removeQ(&(h->reqQ), c);
+		h->Qdepth--;
+		addQ (&(h->cmpQ), c); 
+	}
+
+	/* Now, fail everything on the completed queue with a HW error */
+	while( (c = h->cmpQ) != NULL ) {
+		removeQ(&h->cmpQ, c);
+		c->err_info->CommandStatus = CMD_HARDWARE_ERR;
+		if (c->cmd_type == CMD_RWREQ) {
+			complete_command(h, c, 0);
+		} else if (c->cmd_type == CMD_IOCTL_PEND)
+			complete(c->waiting);
+#		ifdef CONFIG_CISS_SCSI_TAPE
+			else if (c->cmd_type == CMD_SCSI)
+				complete_scsi_command(c, 0, 0);
+#		endif
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return;
+}
+static int cciss_monitor(void *ctlr)
+{
+	/* If the board fails, we ought to detect that.  So we periodically 
+	send down a No-Op message and expect it to complete quickly.  If it 
+	doesn't, then we assume the board is dead, and fail all commands.  
+	This is useful mostly in a multipath configuration, so that failover
+	will happen. */
+
+	int rc;
+	ctlr_info_t *h = (ctlr_info_t *) ctlr;
+	unsigned long flags;
+	u32 current_timer;
+
+	daemonize();
+	exit_files(current);
+	reparent_to_init();
+
+	printk("cciss%d: Monitor thread starting.\n", h->ctlr); 
+
+	/* only listen to signals if the HA was loaded as a module.  */
+#define SHUTDOWN_SIGS   (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
+	siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+	sprintf(current->comm, "ccissmon%d", h->ctlr);
+	h->monitor_thread = current;
+
+	init_timer(&h->watchdog); 
+	h->watchdog.function = fail_all_cmds;
+	h->watchdog.data = (unsigned long) h->ctlr;
+	while (1) {
+  		/* check heartbeat timer */
+                current_timer = readl(&h->cfgtable->HeartBeat);
+  		current_timer &= 0x0fffffff;
+  		if (heartbeat_timer == current_timer) {
+  			fail_all_cmds(h->ctlr);
+  			break;
+  		}
+  		else
+  			heartbeat_timer = current_timer;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(h->monitor_period * HZ);
+		h->watchdog.expires = jiffies + HZ * h->monitor_deadline;
+		add_timer(&h->watchdog);
+		/* send down a trivial command (no op message) to ctlr */
+		rc = sendcmd_withirq(3, h->ctlr, NULL, 0, 0, 0, 0, TYPE_MSG);
+		del_timer(&h->watchdog);
+		if (!CTLR_IS_ALIVE(h))
+			break;
+		if (signal_pending(current)) {
+			printk(KERN_WARNING "%s received signal.\n",
+				current->comm);
+			break;
+		}
+		if (h->monitor_period == 0) /* zero period means exit thread */
+			break;
+	}
+	printk(KERN_INFO "%s exiting.\n", current->comm);
+	spin_lock_irqsave(&io_request_lock, flags);
+	h->monitor_started = 0;
+	h->monitor_thread = NULL;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 0;
+}
+static int start_monitor_thread(ctlr_info_t *h, unsigned char *cmd, 
+		unsigned long count, int (*cciss_monitor)(void *), int *rc)
+{
+	unsigned long flags;
+	unsigned int new_period, old_period, new_deadline, old_deadline;
+
+	if (strncmp("monitor", cmd, 7) == 0) {
+		new_period = simple_strtol(cmd + 8, NULL, 10);
+		spin_lock_irqsave(&io_request_lock, flags);
+		new_deadline = h->monitor_deadline;
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	} else if (strncmp("deadline", cmd, 8) == 0) {
+		new_deadline = simple_strtol(cmd + 9, NULL, 10);
+		spin_lock_irqsave(&io_request_lock, flags);
+		new_period = h->monitor_period;
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	} else
+		return -1;
+	if (new_period != 0 && new_period < CCISS_MIN_PERIOD)
+		new_period = CCISS_MIN_PERIOD;
+	if (new_period > CCISS_MAX_PERIOD)
+		new_period = CCISS_MAX_PERIOD;
+	if (new_deadline >= new_period) {
+		new_deadline = new_period - 5;
+		printk(KERN_INFO "setting deadline to %d\n", new_deadline);
+	}
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (h->monitor_started != 0)  {
+		old_period = h->monitor_period;
+		old_deadline = h->monitor_deadline;
+		h->monitor_period = new_period;
+		h->monitor_deadline = new_deadline;
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		if (new_period == 0) {
+			printk(KERN_INFO "cciss%d: stopping monitor thread\n",
+				h->ctlr);
+			*rc = count;
+			return 0;
+		}
+		if (new_period != old_period) 
+			printk(KERN_INFO "cciss%d: adjusting monitor thread "
+				"period from %d to %d seconds\n",
+				h->ctlr, old_period, new_period);
+		if (new_deadline != old_deadline) 
+			printk(KERN_INFO "cciss%d: adjusting monitor thread "
+				"deadline from %d to %d seconds\n",
+				h->ctlr, old_deadline, new_deadline);
+		*rc = count;
+		return 0;
+	}
+	h->monitor_started = 1;
+	h->monitor_period = new_period;
+	h->monitor_deadline = new_deadline;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	kernel_thread(cciss_monitor, h, 0);
+	*rc = count;
+	return 0;
+}
+
+static void kill_monitor_thread(ctlr_info_t *h)
+{
+	if (h->monitor_thread)
+		send_sig(SIGKILL, h->monitor_thread, 1);
+}
+#else
+#define kill_monitor_thread(h)
+#endif
 /*
  *  This is it.  Find all the controllers and register them.  I really hate
  *  stealing all these major device numbers.
@@ -2861,6 +3079,7 @@
 	sprintf(hba[i]->devname, "cciss%d", i);
 	hba[i]->ctlr = i;
 	hba[i]->pdev = pdev;
+	ASSERT_CTLR_ALIVE(hba[i]);
 
 	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops)) {
 		printk(KERN_ERR "cciss:  Unable to get major number "
@@ -2993,14 +3212,17 @@
 			"already be removed \n");
 		return;
 	}
- 	/* Turn board interrupts off  and send the flush cache command */
- 	/* sendcmd will turn off interrupt, and send the flush...
- 	 * To write all data in the battery backed cache to disks */
+	kill_monitor_thread(hba[i]);
+	/* no sense in trying to flush a dead board's cache. */
+	if (CTLR_IS_ALIVE(hba[i])) {
+		/* Turn board interrupts off and flush the cache */
+		/* write all data in the battery backed cache to disks */
  	memset(flush_buf, 0, 4);
- 	return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4,0,0,0, NULL);
- 	if (return_code != IO_OK) {
+		return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf,
+					4, 0, 0, 0, NULL);
+		if (return_code != IO_OK)
  		printk(KERN_WARNING 
-			"Error Flushing cache on controller %d\n", i);
+				"cciss%d: Error flushing cache\n", i);
  	}
 	free_irq(hba[i]->intr, hba[i]);
 	pci_set_drvdata(pdev, NULL);
diff -Nru a/drivers/block/cciss.h b/drivers/block/cciss.h
--- a/drivers/block/cciss.h	Thu Jul 17 09:39:04 2003
+++ b/drivers/block/cciss.h	Fri Aug 29 08:21:37 2003
@@ -91,6 +91,40 @@
 #ifdef CONFIG_CISS_SCSI_TAPE
 	void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
+#ifdef CONFIG_CISS_MONITOR_THREAD
+	struct timer_list watchdog;
+	struct task_struct *monitor_thread; 
+	unsigned int monitor_period;
+	unsigned int monitor_deadline;
+	unsigned char alive;
+	unsigned char monitor_started;
+#define CCISS_MIN_PERIOD 10
+#define CCISS_MAX_PERIOD 3600 
+#define CTLR_IS_ALIVE(h) (h->alive)
+#define ASSERT_CTLR_ALIVE(h) {	h->alive = 1; \
+				h->monitor_period = 0; \
+				h->monitor_started = 0; }
+#define MONITOR_STATUS_PATTERN "Status: %s\n"
+#define CTLR_STATUS(h) CTLR_IS_ALIVE(h) ? "operational" : "failed"
+#define MONITOR_PERIOD_PATTERN "Monitor thread period: %d\n"
+#define MONITOR_PERIOD_VALUE(h) (h->monitor_period)
+#define MONITOR_DEADLINE_PATTERN "Monitor thread deadline: %d\n"
+#define MONITOR_DEADLINE_VALUE(h) (h->monitor_deadline)
+#define START_MONITOR_THREAD(h, cmd, count, cciss_monitor, rc) \
+	start_monitor_thread(h, cmd, count, cciss_monitor, rc)
+#else
+
+#define MONITOR_PERIOD_PATTERN "%s"
+#define MONITOR_PERIOD_VALUE(h) ""
+#define MONITOR_DEADLINE_PATTERN "%s"
+#define MONITOR_DEADLINE_VALUE(h) ""
+#define MONITOR_STATUS_PATTERN "%s\n"
+#define CTLR_STATUS(h) ""
+#define CTLR_IS_ALIVE(h) (1)
+#define ASSERT_CTLR_ALIVE(h)
+#define START_MONITOR_THREAD(a,b,c,d,rc) (*rc == 0)
+
+#endif
 };
 
 /*  Defining the diffent access_menthods */
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
--- a/drivers/char/Config.in	Tue Jul 29 06:55:03 2003
+++ b/drivers/char/Config.in	Tue Aug 26 10:13:59 2003
@@ -105,6 +105,12 @@
      fi
   fi
 fi
+if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ] ; then
+  bool 'SGI SN2 l1 serial port support' CONFIG_SGI_L1_SERIAL
+  if [ "$CONFIG_SGI_L1_SERIAL" = "y" ]; then
+    bool '  SGI SN2 l1 Console support' CONFIG_SGI_L1_SERIAL_CONSOLE
+  fi
+fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
    tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
 fi
@@ -267,6 +273,10 @@
 if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
    dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
 fi
+if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o \
+     "$CONFIG_X86_64" = "y" ]; then
+   dep_tristate 'Intel/AMD/VIA HW Random Number Generator support' CONFIG_HW_RANDOM $CONFIG_PCI
+fi
 dep_tristate 'AMD 76x native power management (Experimental)' CONFIG_AMD_PM768 $CONFIG_PCI
 tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
@@ -317,6 +327,8 @@
    fi
 fi
 
+mainmenu_option next_comment
+comment 'Direct Rendering Manager (XFree86 DRI support)'
 bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
 if [ "$CONFIG_DRM" = "y" ]; then
    bool '  Build drivers for old (XFree 4.0) DRM' CONFIG_DRM_OLD
@@ -329,6 +341,7 @@
       source drivers/char/drm/Config.in
    fi
 fi
+endmenu
 
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/char/pcmcia/Config.in
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Fri Apr  4 19:30:09 2003
+++ b/drivers/char/Makefile	Wed Aug 27 13:07:37 2003
@@ -211,6 +211,7 @@
 obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o
 obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
 obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o
+obj-$(CONFIG_SGI_L1_SERIAL) += sn_serial.o
 
 subdir-$(CONFIG_RIO) += rio
 subdir-$(CONFIG_INPUT) += joystick
@@ -247,6 +248,7 @@
 obj-$(CONFIG_DS1620) += ds1620.o
 obj-$(CONFIG_INTEL_RNG) += i810_rng.o
 obj-$(CONFIG_AMD_RNG) += amd768_rng.o
+obj-$(CONFIG_HW_RANDOM) += hw_random.o
 obj-$(CONFIG_AMD_PM768) += amd76x_pm.o
 obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
 
diff -Nru a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
--- a/drivers/char/agp/agp.h	Sun Jun 29 08:10:02 2003
+++ b/drivers/char/agp/agp.h	Tue Jul 15 02:28:34 2003
@@ -223,6 +223,12 @@
 #ifndef PCI_DEVICE_ID_INTEL_860_0
 #define PCI_DEVICE_ID_INTEL_860_0     0x2531
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_7205_0
+#define PCI_DEVICE_ID_INTEL_7205_0     0x255d
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_7505_0
+#define PCI_DEVICE_ID_INTEL_7505_0     0x2550
+#endif
 #ifndef PCI_DEVICE_ID_INTEL_810_DC100_0
 #define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122
 #endif
@@ -365,6 +371,10 @@
 /* intel i860 registers */
 #define INTEL_I860_MCHCFG	0x50
 #define INTEL_I860_ERRSTS	0xc8
+
+/* intel i7505 registers */
+#define INTEL_I7505_MCHCFG	0x50
+#define INTEL_I7505_ERRSTS	0x42
 
 /* intel i810 registers */
 #define I810_GMADDR 0x10
diff -Nru a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
--- a/drivers/char/agp/agpgart_be.c	Wed Jul 30 03:29:03 2003
+++ b/drivers/char/agp/agpgart_be.c	Tue Jul 15 02:31:11 2003
@@ -1817,6 +1817,37 @@
 }
 
 
+static int intel_7505_configure(void)
+{
+	u32 temp;
+	u16 temp2;
+	aper_size_info_8 *current_size;
+
+	current_size = A_SIZE_8(agp_bridge.current_size);
+
+	/* aperture size */
+	pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+			      current_size->size_value);
+
+	/* address to map to */
+	pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+	/* attbase - aperture base */
+	pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+			       agp_bridge.gatt_bus_addr);
+
+	/* agpctrl */
+	pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
+
+	/* mcgcfg */
+	pci_read_config_word(agp_bridge.dev, INTEL_I7505_MCHCFG, &temp2);
+	pci_write_config_word(agp_bridge.dev, INTEL_I7505_MCHCFG,
+			      temp2 | (1 << 9));
+	return 0;
+}
+
+
 static unsigned long intel_mask_memory(unsigned long addr, int type)
 {
 	/* Memory type is ignored */
@@ -2126,6 +2157,38 @@
 	(void) pdev; /* unused */
 }
 
+static int __init intel_7505_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = intel_generic_masks;
+	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
+	agp_bridge.size_type = U8_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 7;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = intel_7505_configure;
+	agp_bridge.fetch_size = intel_8xx_fetch_size;
+	agp_bridge.cleanup = intel_8xx_cleanup;
+	agp_bridge.tlb_flush = intel_8xx_tlbflush;
+	agp_bridge.mask_memory = intel_mask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+	agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+	agp_bridge.insert_memory = agp_generic_insert_memory;
+	agp_bridge.remove_memory = agp_generic_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.suspend = agp_generic_suspend;
+	agp_bridge.resume = agp_generic_resume;
+	agp_bridge.cant_use_aperture = 0;
+
+	return 0;
+
+	(void) pdev; /* unused */
+}
+
 #endif /* CONFIG_AGP_INTEL */
 
 #ifdef CONFIG_AGP_VIA
@@ -4942,6 +5005,18 @@
 		"Intel",
 		"i860",
 		intel_860_setup },
+	{ PCI_DEVICE_ID_INTEL_7205_0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_I7205,
+		"Intel",
+		"i7205",
+		intel_7505_setup },
+	{ PCI_DEVICE_ID_INTEL_7505_0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_I7505,
+		"Intel",
+		"i7505",
+		intel_7505_setup },
 	{ 0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_GENERIC,
diff -Nru a/drivers/char/amd76x_pm.c b/drivers/char/amd76x_pm.c
--- a/drivers/char/amd76x_pm.c	Mon Aug 25 09:51:20 2003
+++ b/drivers/char/amd76x_pm.c	Mon Aug 25 04:22:01 2003
@@ -577,16 +577,18 @@
 	int found;
 
 	/* Find northbridge */
-	found = pci_module_init(&amd_nb_driver);
-	if (found < 0) {
+	found = pci_register_driver(&amd_nb_driver);
+	if (found <= 0) {
 		printk(KERN_ERR "amd76x_pm: Could not find northbridge\n");
+		pci_unregister_driver(&amd_nb_driver);
 		return 1;
 	}
 
 	/* Find southbridge */
-	found = pci_module_init(&amd_sb_driver);
-	if (found < 0) {
+	found = pci_register_driver(&amd_sb_driver);
+	if (found <= 0) {
 		printk(KERN_ERR "amd76x_pm: Could not find southbridge\n");
+		pci_unregister_driver(&amd_sb_driver);
 		pci_unregister_driver(&amd_nb_driver);
 		return 1;
 	}
@@ -620,6 +622,8 @@
 #ifndef AMD76X_NTH
 	if (!amd76x_pm_cfg.curr_idle) {
 		printk(KERN_ERR "amd76x_pm: Idle function not changed\n");
+		pci_unregister_driver(&amd_nb_driver);
+		pci_unregister_driver(&amd_sb_driver);
 		return 1;
 	}
 
diff -Nru a/drivers/char/amd7xx_tco.c b/drivers/char/amd7xx_tco.c
--- a/drivers/char/amd7xx_tco.c	Tue Aug  6 07:42:07 2002
+++ b/drivers/char/amd7xx_tco.c	Thu Jul 31 06:36:31 2003
@@ -1,6 +1,6 @@
 /*
  *	AMD 766/768 TCO Timer Driver
- *	(c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
+ *	(c) Copyright 2002 Zwane Mwaikambo <zwane@holomorphy.com>
  *	All Rights Reserved.
  *
  *	Parts from;
@@ -34,35 +34,48 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 
-#define AMDTCO_MODULE_VER	"build 20020601"
+#define AMDTCO_MODULE_VER	"build 20021116"
 #define AMDTCO_MODULE_NAME	"amd7xx_tco"
 #define PFX			AMDTCO_MODULE_NAME ": "
 
-#define	MAX_TIMEOUT	38	/* max of 38 seconds */
+#define	MAX_TIMEOUT	38	/* max of 38 seconds, although the system will only
+				 * reset itself after the second timeout */
 
 /* pmbase registers */
-#define GLOBAL_SMI_REG	0x2a
-#define TCO_EN		(1 << 1)	/* bit 1 in global SMI register */
 #define TCO_RELOAD_REG	0x40		/* bits 0-5 are current count, 6-7 are reserved */
 #define TCO_INITVAL_REG	0x41		/* bits 0-5 are value to load, 6-7 are reserved */
 #define TCO_TIMEOUT_MASK	0x3f
+#define TCO_STATUS1_REG 0x44
 #define TCO_STATUS2_REG	0x46
 #define NDTO_STS2	(1 << 1)	/* we're interested in the second timeout */ 
 #define BOOT_STS	(1 << 2)	/* will be set if NDTO_STS2 was set before reboot */
 #define TCO_CTRL1_REG	0x48
 #define TCO_HALT	(1 << 11)
+#define NO_REBOOT	(1 << 10)	/* in DevB:3x48 */
 
-static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER;
+static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER "\n";
 static int timeout = 38;
 static u32 pmbase;		/* PMxx I/O base */
 static struct pci_dev *dev;
 static struct semaphore open_sem;
-spinlock_t amdtco_lock;	/* only for device access */
+static spinlock_t amdtco_lock;	/* only for device access */
 static int expect_close = 0;
 
 MODULE_PARM(timeout, "i");
 MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38");
 
+static inline u8 seconds_to_ticks(int seconds)
+{
+	/* the internal timer is stored as ticks which decrement
+	 * every 0.6 seconds */
+	return (seconds * 10) / 6;
+}
+
+static inline int ticks_to_seconds(u8 ticks)
+{
+	return (ticks * 6) / 10;
+}
+
 static inline int amdtco_status(void)
 {
 	u16 reg;
@@ -81,28 +94,19 @@
 
 static inline void amdtco_ping(void)
 {
-	u8 reg;
-
-	spin_lock(&amdtco_lock);
-	reg = inb(pmbase+TCO_RELOAD_REG);
-	outb(1 | reg, pmbase+TCO_RELOAD_REG);
-	spin_unlock(&amdtco_lock);
+	outb(1, pmbase+TCO_RELOAD_REG);
 }
 
 static inline int amdtco_gettimeout(void)
 {
-	return inb(TCO_RELOAD_REG) & TCO_TIMEOUT_MASK;
+	u8 reg = inb(pmbase+TCO_RELOAD_REG) & TCO_TIMEOUT_MASK;
+	return ticks_to_seconds(reg);
 }
 
 static inline void amdtco_settimeout(unsigned int timeout)
 {
-	u8 reg;
-
-	spin_lock(&amdtco_lock);
-	reg = inb(pmbase+TCO_INITVAL_REG);
-	reg |= timeout & TCO_TIMEOUT_MASK;
+	u8 reg = seconds_to_ticks(timeout) & TCO_TIMEOUT_MASK;
 	outb(reg, pmbase+TCO_INITVAL_REG);
-	spin_unlock(&amdtco_lock);
 }
 
 static inline void amdtco_global_enable(void)
@@ -110,9 +114,12 @@
 	u16 reg;
 
 	spin_lock(&amdtco_lock);
-	reg = inw(pmbase+GLOBAL_SMI_REG);
-	reg |= TCO_EN;
-	outw(reg, pmbase+GLOBAL_SMI_REG);
+
+	/* clear NO_REBOOT on DevB:3x48 p97 */
+	pci_read_config_word(dev, 0x48, &reg);
+	reg &= ~NO_REBOOT;
+	pci_write_config_word(dev, 0x48, reg);
+
 	spin_unlock(&amdtco_lock);
 }
 
@@ -150,10 +157,12 @@
 	if (timeout > MAX_TIMEOUT)
 		timeout = MAX_TIMEOUT;
 
+	amdtco_disable();
 	amdtco_settimeout(timeout);	
 	amdtco_global_enable();
+	amdtco_enable();
 	amdtco_ping();
-	printk(KERN_INFO PFX "Watchdog enabled, timeout = %d/%d seconds",
+	printk(KERN_INFO PFX "Watchdog enabled, timeout = %ds of %ds\n",
 		amdtco_gettimeout(), timeout);
 	
 	return 0;
@@ -202,7 +211,7 @@
 
 		case WDIOC_GETTIMEOUT:
 			return put_user(amdtco_gettimeout(), (int *)arg);
-	
+		
 		case WDIOC_SETOPTIONS:
 			if (copy_from_user(&tmp, (int *)arg, sizeof tmp))
                                 return -EFAULT;
@@ -225,7 +234,7 @@
 		printk(KERN_INFO PFX "Watchdog disabled\n");
 	} else {
 		amdtco_ping();
-		printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds)\n", timeout);
+		printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds\n", timeout);
 	}	
 	
 	up(&open_sem);
@@ -253,10 +262,9 @@
 		}
 #endif
 		amdtco_ping();
-		return len;
 	}
 
-	return 0;
+	return len;
 }
 
 
@@ -291,7 +299,6 @@
 };
 
 static struct pci_device_id amdtco_pci_tbl[] __initdata = {
-	/* AMD 766 PCI_IDs here */
 	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, }
 };
@@ -361,6 +368,9 @@
 	if (ints[0] > 0)
 		timeout = ints[1];
 
+	if (!timeout || timeout > 38)
+		timeout = MAX_TIMEOUT;
+
 	return 1;
 }
 
@@ -370,7 +380,7 @@
 module_init(amdtco_init);
 module_exit(amdtco_exit);
 
-MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
+MODULE_AUTHOR("Zwane Mwaikambo <zwane@holomorphy.com>");
 MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver");
 MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
diff -Nru a/drivers/char/console.c b/drivers/char/console.c
--- a/drivers/char/console.c	Fri Sep 27 06:01:00 2002
+++ b/drivers/char/console.c	Sun Jul 21 05:24:31 2002
@@ -112,6 +112,8 @@
 
 const struct consw *conswitchp;
 
+static void __console_callback(void);
+
 /* A bitmap for codes <32. A bit of 1 indicates that the code
  * corresponding to that bit number invokes some special action
  * (such as cursor movement) and should not be displayed as a
@@ -242,9 +244,16 @@
 	schedule_console_callback();
 }
 
+extern int machine_paniced; 
+
 void schedule_console_callback(void)
 {
-	schedule_task(&console_callback_tq);
+	/* Don't care about locking after panic - but I want to switch the console
+	   NOW */ 
+	if (machine_paniced)
+		__console_callback(); 
+	else
+		schedule_task(&console_callback_tq);
 }
 
 static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
@@ -2039,10 +2048,15 @@
  * with other console code and prevention of re-entrancy is
  * ensured with console_sem.
  */
-static void console_callback(void *ignored)
+static void console_callback(void *unused) 
 {
 	acquire_console_sem();
+	__console_callback(); 
+	release_console_sem();	
+} 
 
+static void __console_callback(void)
+{
 	if (want_console >= 0) {
 		if (want_console != fg_console && vc_cons_allocated(want_console)) {
 			hide_cursor(fg_console);
@@ -2064,8 +2078,6 @@
 			sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta);
 		scrollback_delta = 0;
 	}
-
-	release_console_sem();
 }
 
 void set_console(int nr)
@@ -2763,6 +2775,12 @@
 static void blank_screen(unsigned long dummy)
 {
 	timer_do_blank_screen(0, 1);
+}
+
+void disable_console_blank(void)
+{
+	del_timer_sync(&console_timer);
+	blankinterval = 0;
 }
 
 void poke_blanked_console(void)
diff -Nru a/drivers/char/hw_random.c b/drivers/char/hw_random.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/hw_random.c	Thu Aug  7 19:37:56 2003
@@ -0,0 +1,631 @@
+/*
+ 	Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+	(c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ 
+ 	derived from
+ 
+        Hardware driver for the AMD 768 Random Number Generator (RNG)
+        (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+
+ 	derived from
+ 
+	Hardware driver for Intel i810 Random Number Generator (RNG)
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+
+	Please read Documentation/hw_random.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.
+
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/miscdevice.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#ifdef __i386__
+#include <asm/msr.h>
+#include <asm/cpufeature.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+/*
+ * core module and version information
+ */
+#define RNG_VERSION "1.0.0"
+#define RNG_MODULE_NAME "hw_random"
+#define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
+#define PFX RNG_MODULE_NAME ": "
+
+
+/*
+ * debugging macros
+ */
+#undef RNG_DEBUG /* define to enable copious debugging info */
+
+#ifdef RNG_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define RNG_NDEBUG        /* define to disable lightweight runtime checks */
+#ifdef RNG_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+        if(!(expr)) {                                   \
+        printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+        #expr,__FILE__,__FUNCTION__,__LINE__);          \
+        }
+#endif
+
+#define RNG_MISCDEV_MINOR		183 /* official */
+
+static int rng_dev_open (struct inode *inode, struct file *filp);
+static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size,
+			     loff_t * offp);
+
+static int __init intel_init (struct pci_dev *dev);
+static void intel_cleanup(void);
+static unsigned int intel_data_present (void);
+static u32 intel_data_read (void);
+
+static int __init amd_init (struct pci_dev *dev);
+static void amd_cleanup(void);
+static unsigned int amd_data_present (void);
+static u32 amd_data_read (void);
+
+static int __init via_init(struct pci_dev *dev);
+static void via_cleanup(void);
+static unsigned int via_data_present (void);
+static u32 via_data_read (void);
+
+struct rng_operations {
+	int (*init) (struct pci_dev *dev);
+	void (*cleanup) (void);
+	unsigned int (*data_present) (void);
+	u32 (*data_read) (void);
+	unsigned int n_bytes; /* number of bytes per ->data_read */
+};
+static struct rng_operations *rng_ops;
+
+static struct file_operations rng_chrdev_ops = {
+	.owner		= THIS_MODULE,
+	.open		= rng_dev_open,
+	.read		= rng_dev_read,
+};
+
+
+static struct miscdevice rng_miscdev = {
+	RNG_MISCDEV_MINOR,
+	RNG_MODULE_NAME,
+	&rng_chrdev_ops,
+};
+
+enum {
+	rng_hw_none,
+	rng_hw_intel,
+	rng_hw_amd,
+	rng_hw_via,
+};
+
+static struct rng_operations rng_vendor_ops[] = {
+	/* rng_hw_none */
+	{ },
+
+	/* rng_hw_intel */
+	{ intel_init, intel_cleanup, intel_data_present,
+	  intel_data_read, 1 },
+
+	/* rng_hw_amd */
+	{ amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 },
+
+	/* rng_hw_via */
+	{ via_init, via_cleanup, via_data_present, via_data_read, 1 },
+};
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id rng_pci_tbl[] __initdata = {
+	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
+	{ 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
+
+	{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+	{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+	{ 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+	{ 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+	{ 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+
+	{ 0, },	/* terminate list */
+};
+MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
+
+
+/***********************************************************************
+ *
+ * Intel RNG operations
+ *
+ */
+
+/*
+ * RNG registers (offsets from rng_mem)
+ */
+#define INTEL_RNG_HW_STATUS			0
+#define         INTEL_RNG_PRESENT		0x40
+#define         INTEL_RNG_ENABLED		0x01
+#define INTEL_RNG_STATUS			1
+#define         INTEL_RNG_DATA_PRESENT		0x01
+#define INTEL_RNG_DATA				2
+
+/*
+ * Magic address at which Intel PCI bridges locate the RNG
+ */
+#define INTEL_RNG_ADDR				0xFFBC015F
+#define INTEL_RNG_ADDR_LEN			3
+
+/* token to our ioremap'd RNG register area */
+static void *rng_mem;
+
+static inline u8 intel_hwstatus (void)
+{
+	assert (rng_mem != NULL);
+	return readb (rng_mem + INTEL_RNG_HW_STATUS);
+}
+
+static inline u8 intel_hwstatus_set (u8 hw_status)
+{
+	assert (rng_mem != NULL);
+	writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS);
+	return intel_hwstatus ();
+}
+
+static unsigned int intel_data_present(void)
+{
+	assert (rng_mem != NULL);
+
+	return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ?
+		1 : 0;
+}
+
+static u32 intel_data_read(void)
+{
+	assert (rng_mem != NULL);
+
+	return readb (rng_mem + INTEL_RNG_DATA);
+}
+
+static int __init intel_init (struct pci_dev *dev)
+{
+	int rc;
+	u8 hw_status;
+
+	DPRINTK ("ENTER\n");
+
+	rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
+	if (rng_mem == NULL) {
+		printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
+		rc = -EBUSY;
+		goto err_out;
+	}
+
+	/* Check for Intel 82802 */
+	hw_status = intel_hwstatus ();
+	if ((hw_status & INTEL_RNG_PRESENT) == 0) {
+		printk (KERN_ERR PFX "RNG not detected\n");
+		rc = -ENODEV;
+		goto err_out_free_map;
+	}
+
+	/* turn RNG h/w on, if it's off */
+	if ((hw_status & INTEL_RNG_ENABLED) == 0)
+		hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED);
+	if ((hw_status & INTEL_RNG_ENABLED) == 0) {
+		printk (KERN_ERR PFX "cannot enable RNG, aborting\n");
+		rc = -EIO;
+		goto err_out_free_map;
+	}
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+
+err_out_free_map:
+	iounmap (rng_mem);
+	rng_mem = NULL;
+err_out:
+	DPRINTK ("EXIT, returning %d\n", rc);
+	return rc;
+}
+
+static void intel_cleanup(void)
+{
+	u8 hw_status;
+
+	hw_status = intel_hwstatus ();
+	if (hw_status & INTEL_RNG_ENABLED)
+		intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED);
+	else
+		printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
+	iounmap(rng_mem);
+	rng_mem = NULL;
+}
+
+/***********************************************************************
+ *
+ * AMD RNG operations
+ *
+ */
+
+static u32 pmbase;			/* PMxx I/O base */
+static struct pci_dev *amd_dev;
+
+static unsigned int amd_data_present (void)
+{
+      	return inl(pmbase + 0xF4) & 1;
+}
+
+
+static u32 amd_data_read (void)
+{
+	return inl(pmbase + 0xF0);
+}
+
+static int __init amd_init (struct pci_dev *dev)
+{
+	int rc;
+	u8 rnen;
+
+	DPRINTK ("ENTER\n");
+
+	pci_read_config_dword(dev, 0x58, &pmbase);
+
+	pmbase &= 0x0000FF00;
+
+	if (pmbase == 0)
+	{
+		printk (KERN_ERR PFX "power management base not set\n");
+		rc = -EIO;
+		goto err_out;
+	}
+
+	pci_read_config_byte(dev, 0x40, &rnen);
+	rnen |= (1 << 7);	/* RNG on */
+	pci_write_config_byte(dev, 0x40, rnen);
+
+	pci_read_config_byte(dev, 0x41, &rnen);
+	rnen |= (1 << 7);	/* PMIO enable */
+	pci_write_config_byte(dev, 0x41, rnen);
+
+	printk(KERN_INFO PFX "AMD768 system management I/O registers at 0x%X.\n", pmbase);
+
+	amd_dev = dev;
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+
+err_out:
+	DPRINTK ("EXIT, returning %d\n", rc);
+	return rc;
+}
+
+static void amd_cleanup(void)
+{
+	u8 rnen;
+
+	pci_read_config_byte(amd_dev, 0x40, &rnen);
+	rnen &= ~(1 << 7);	/* RNG off */
+	pci_write_config_byte(amd_dev, 0x40, rnen);
+
+	/* FIXME: twiddle pmio, also? */
+}
+
+/***********************************************************************
+ *
+ * VIA RNG operations
+ *
+ */
+
+enum {
+	VIA_STRFILT_CNT_SHIFT	= 16,
+	VIA_STRFILT_FAIL	= (1 << 15),
+	VIA_STRFILT_ENABLE	= (1 << 14),
+	VIA_RAWBITS_ENABLE	= (1 << 13),
+	VIA_RNG_ENABLE		= (1 << 6),
+	VIA_XSTORE_CNT_MASK	= 0x0F,
+
+	VIA_RNG_CHUNK_8		= 0x00,	/* 64 rand bits, 64 stored bits */
+	VIA_RNG_CHUNK_4		= 0x01,	/* 32 rand bits, 32 stored bits */
+	VIA_RNG_CHUNK_4_MASK	= 0xFFFFFFFF,
+	VIA_RNG_CHUNK_2		= 0x02,	/* 16 rand bits, 32 stored bits */
+	VIA_RNG_CHUNK_2_MASK	= 0xFFFF,
+	VIA_RNG_CHUNK_1		= 0x03,	/* 8 rand bits, 32 stored bits */
+	VIA_RNG_CHUNK_1_MASK	= 0xFF,
+};
+
+u32 via_rng_datum;
+
+/*
+ * Investigate using the 'rep' prefix to obtain 32 bits of random data
+ * in one insn.  The upside is potentially better performance.  The
+ * downside is that the instruction becomes no longer atomic.  Due to
+ * this, just like familiar issues with /dev/random itself, the worst
+ * case of a 'rep xstore' could potentially pause a cpu for an
+ * unreasonably long time.  In practice, this condition would likely
+ * only occur when the hardware is failing.  (or so we hope :))
+ *
+ * Another possible performance boost may come from simply buffering
+ * until we have 4 bytes, thus returning a u32 at a time,
+ * instead of the current u8-at-a-time.
+ */
+
+static inline u32 xstore(u32 *addr, u32 edx_in)
+{
+	u32 eax_out;
+
+	asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
+		:"=m"(*addr), "=a"(eax_out)
+		:"D"(addr), "d"(edx_in));
+
+	return eax_out;
+}
+
+static unsigned int via_data_present(void)
+{
+	u32 bytes_out;
+
+	/* We choose the recommended 1-byte-per-instruction RNG rate,
+	 * for greater randomness at the expense of speed.  Larger
+	 * values 2, 4, or 8 bytes-per-instruction yield greater
+	 * speed at lesser randomness.
+	 *
+	 * If you change this to another VIA_CHUNK_n, you must also
+	 * change the ->n_bytes values in rng_vendor_ops[] tables.
+	 * VIA_CHUNK_8 requires further code changes.
+	 *
+	 * A copy of MSR_VIA_RNG is placed in eax_out when xstore
+	 * completes.
+	 */
+	via_rng_datum = 0; /* paranoia, not really necessary */
+	bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK;
+	if (bytes_out == 0)
+		return 0;
+
+	return 1;
+}
+
+static u32 via_data_read(void)
+{
+	return via_rng_datum;
+}
+
+static int __init via_init(struct pci_dev *dev)
+{
+	u32 lo, hi, old_lo;
+
+	/* Control the RNG via MSR.  Tread lightly and pay very close
+	 * close attention to values written, as the reserved fields
+	 * are documented to be "undefined and unpredictable"; but it
+	 * does not say to write them as zero, so I make a guess that
+	 * we restore the values we find in the register.
+	 */
+	rdmsr(MSR_VIA_RNG, lo, hi);
+
+	old_lo = lo;
+	lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
+	lo &= ~VIA_XSTORE_CNT_MASK;
+	lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
+	lo |= VIA_RNG_ENABLE;
+
+	if (lo != old_lo)
+		wrmsr(MSR_VIA_RNG, lo, hi);
+
+	/* perhaps-unnecessary sanity check; remove after testing if
+	   unneeded */
+	rdmsr(MSR_VIA_RNG, lo, hi);
+	if ((lo & VIA_RNG_ENABLE) == 0) {
+		printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void via_cleanup(void)
+{
+	u32 lo, hi;
+
+	rdmsr(MSR_VIA_RNG, lo, hi);
+	lo &= ~VIA_RNG_ENABLE;
+	wrmsr(MSR_VIA_RNG, lo, hi);
+}
+
+
+/***********************************************************************
+ *
+ * /dev/hwrandom character device handling (major 10, minor 183)
+ *
+ */
+
+static int rng_dev_open (struct inode *inode, struct file *filp)
+{
+	/* enforce read-only access to this chrdev */
+	if ((filp->f_mode & FMODE_READ) == 0)
+		return -EINVAL;
+	if (filp->f_mode & FMODE_WRITE)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+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;
+	unsigned int have_data;
+	u32 data = 0;
+	ssize_t ret = 0;
+
+	while (size) {
+		spin_lock(&rng_lock);
+
+		have_data = 0;
+		if (rng_ops->data_present()) {
+			data = rng_ops->data_read();
+			have_data = rng_ops->n_bytes;
+		}
+
+		spin_unlock (&rng_lock);
+
+		while (have_data && size) {
+			if (put_user((u8)data, buf++)) {
+				ret = ret ? : -EFAULT;
+				break;
+			}
+			size--;
+			ret++;
+			have_data--;
+			data>>=8;
+		}
+
+		if (filp->f_flags & O_NONBLOCK)
+			return ret ? : -EAGAIN;
+
+		if(need_resched())
+		{
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+		else
+			udelay(200);	/* FIXME: We could poll for 250uS ?? */
+
+		if (signal_pending (current))
+			return ret ? : -ERESTARTSYS;
+	}
+	return ret;
+}
+
+
+
+/*
+ * rng_init_one - look for and attempt to init a single RNG
+ */
+static int __init rng_init_one (struct pci_dev *dev)
+{
+	int rc;
+
+	DPRINTK ("ENTER\n");
+
+	assert(rng_ops != NULL);
+
+	rc = rng_ops->init(dev);
+	if (rc)
+		goto err_out;
+
+	rc = misc_register (&rng_miscdev);
+	if (rc) {
+		printk (KERN_ERR PFX "misc device register failed\n");
+		goto err_out_cleanup_hw;
+	}
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+
+err_out_cleanup_hw:
+	rng_ops->cleanup();
+err_out:
+	DPRINTK ("EXIT, returning %d\n", rc);
+	return rc;
+}
+
+
+
+MODULE_AUTHOR("The Linux Kernel team");
+MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * rng_init - initialize RNG module
+ */
+static int __init rng_init (void)
+{
+	int rc;
+	struct pci_dev *pdev = NULL;
+	const struct pci_device_id *ent;
+
+	DPRINTK ("ENTER\n");
+
+	/* Probe for Intel, AMD RNGs */
+	while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+		ent = pci_match_device (rng_pci_tbl, pdev);
+		if (ent) {
+			rng_ops = &rng_vendor_ops[ent->driver_data];
+			goto match;
+		}
+	}
+
+#ifdef __i386__
+	/* Probe for VIA RNG */
+	if (cpu_has_xstore) {
+		rng_ops = &rng_vendor_ops[rng_hw_via];
+		pdev = NULL;
+		goto match;
+	}
+#endif
+
+	DPRINTK ("EXIT, returning -ENODEV\n");
+	return -ENODEV;
+
+match:
+	rc = rng_init_one (pdev);
+	if (rc)
+		return rc;
+
+	printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+/*
+ * rng_init - shutdown RNG module
+ */
+static void __exit rng_cleanup (void)
+{
+	DPRINTK ("ENTER\n");
+
+	misc_deregister (&rng_miscdev);
+
+	if (rng_ops->cleanup)
+		rng_ops->cleanup();
+
+	DPRINTK ("EXIT\n");
+}
+
+
+module_init (rng_init);
+module_exit (rng_cleanup);
diff -Nru a/drivers/char/i810-tco.c b/drivers/char/i810-tco.c
--- a/drivers/char/i810-tco.c	Sun Sep 29 12:29:59 2002
+++ b/drivers/char/i810-tco.c	Thu Jul 31 06:40:23 2003
@@ -25,7 +25,8 @@
  *	82801AA & 82801AB  chip : document number 290655-003, 290677-004,
  *	82801BA & 82801BAM chip : document number 290687-002, 298242-005,
  *	82801CA & 82801CAM chip : document number 290716-001, 290718-001,
- *	82801DB & 82801E   chip : document number 290744-001, 273599-001
+ *	82801DB & 82801E   chip : document number 290744-001, 273599-001,
+ *	82801EB & 82801ER  chip : document number 252516-001
  *
  *  20000710 Nils Faerber
  *	Initial Version 0.01
@@ -42,9 +43,11 @@
  *	     clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
  *	     WDIOC_SETOPTIONS), made i810tco_getdevice __init,
  *	     removed boot_status, removed tco_timer_read,
- *	     added support for 82801DB and 82801E chipset, general cleanup.
+ *	     added support for 82801DB and 82801E chipset,
+ *	     added support for 82801EB and 8280ER chipset,
+ *	     general cleanup.
  */
- 
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -167,7 +170,7 @@
  * Reload (trigger) the timer. Lock is needed so we dont reload it during
  * a reprogramming event
  */
- 
+
 static void tco_timer_reload (void)
 {
 	spin_lock(&tco_lock);
@@ -310,6 +313,7 @@
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl);
diff -Nru a/drivers/char/i810-tco.h b/drivers/char/i810-tco.h
--- a/drivers/char/i810-tco.h	Sat Jun 22 09:47:22 2002
+++ b/drivers/char/i810-tco.h	Thu Jul 31 06:40:23 2003
@@ -1,5 +1,5 @@
 /*
- *	i810-tco 0.05:	TCO timer driver for i8xx chipsets
+ *	i810-tco:	TCO timer driver for i8xx chipsets
  *
  *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
  *				http://www.kernelconcepts.de
@@ -8,7 +8,7 @@
  *	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 kernel concepts nor Nils Faerber admit liability nor provide
  *	warranty for any of this software. This material is provided
  *	"AS-IS" and at no charge.
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	Fri Jul  4 20:50:23 2003
+++ b/drivers/char/keyboard.c	Thu Aug 28 09:00:08 2003
@@ -198,6 +198,7 @@
 	unsigned char keycode;
 	char up_flag = down ? 0 : 0200;
 	char raw_mode;
+	char have_keycode;
 
 	pm_access(pm_kbd);
 	add_keyboard_randomness(scancode | up_flag);
@@ -214,16 +215,30 @@
 		tty = NULL;
 	}
 	kbd = kbd_table + fg_console;
-	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
+	/*
+	 *  Convert scancode to keycode
+	 */
+	raw_mode = (kbd->kbdmode == VC_RAW);
+	have_keycode = kbd_translate(scancode, &keycode, raw_mode);
+	if (raw_mode) {
 		/*
 		 *	The following is a workaround for hardware
 		 *	which sometimes send the key release event twice 
 		 */
 		unsigned char next_scancode = scancode|up_flag;
-		if (up_flag && next_scancode==prev_scancode) {
+		if (have_keycode && up_flag && next_scancode==prev_scancode) {
 			/* unexpected 2nd release event */
 		} else {
-			prev_scancode=next_scancode;
+			/* 
+			 * Only save previous scancode if it was a key-up
+			 * and had a single-byte scancode.  
+			 */
+			if (!have_keycode)
+				prev_scancode = 1;
+			else if (!up_flag || prev_scancode == 1)
+				prev_scancode = 0;
+			else
+				prev_scancode = next_scancode;
 			put_queue(next_scancode);
 		}
 		/* we do not return yet, because we want to maintain
@@ -231,10 +246,7 @@
 		   values when finishing RAW mode or when changing VT's */
 	}
 
-	/*
-	 *  Convert scancode to keycode
-	 */
-	if (!kbd_translate(scancode, &keycode, raw_mode))
+	if (!have_keycode)
 		goto out;
 
 	/*
diff -Nru a/drivers/char/pcwd.c b/drivers/char/pcwd.c
--- a/drivers/char/pcwd.c	Sun Sep 29 12:29:59 2002
+++ b/drivers/char/pcwd.c	Mon Aug 25 10:20:56 2003
@@ -933,8 +933,7 @@
 
 	release_region (pcwd_info.io_addr, pcwd_info.card_info->io_size);
 
-	if (pcwd_info.flags & PCWD_PCI_REG)
-		pci_unregister_driver (&pcwd_driver);
+	pci_unregister_driver (&pcwd_driver);
 
 	return;
 }
diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c
--- a/drivers/char/rocket.c	Mon Feb  4 23:45:46 2002
+++ b/drivers/char/rocket.c	Wed Aug 13 06:22:04 2003
@@ -1052,7 +1052,7 @@
 		restore_flags(flags);
 		return;
 	}
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((atomic_read(&tty->count) == 1) && (info->count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * structure will be freed.  Info->count should always
@@ -1944,6 +1944,10 @@
 		str = "8J";
 		max_num_aiops = 1;
 		break;
+	case PCI_DEVICE_ID_RP4J:
+		str = "4J";
+		max_num_aiops = 1;
+		break;
 	case PCI_DEVICE_ID_RP16INTF:
 		str = "16";
 		max_num_aiops = 2;
@@ -2006,6 +2010,10 @@
 			PCI_DEVICE_ID_RP8J, i, &bus, &device_fn)) 
 			if (register_PCI(count+boards_found, bus, device_fn))
 				count++;
+		if (!pcibios_find_device(PCI_VENDOR_ID_RP,
+			PCI_DEVICE_ID_RP4J, i, &bus, &device_fn)) 
+			if (register_PCI(count+boards_found, bus, device_fn))
+				count++;
 		if(!pcibios_find_device(PCI_VENDOR_ID_RP,
 			PCI_DEVICE_ID_RP8OCTA, i, &bus, &device_fn)) 
 			if(register_PCI(count+boards_found, bus, device_fn))
@@ -2028,6 +2036,10 @@
 				count++;
 		if(!pcibios_find_device(PCI_VENDOR_ID_RP,
 			PCI_DEVICE_ID_RP8J, i, &bus, &device_fn)) 
+			if(register_PCI(count+boards_found, bus, device_fn))
+				count++;
+		if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+			PCI_DEVICE_ID_RP4J, i, &bus, &device_fn)) 
 			if(register_PCI(count+boards_found, bus, device_fn))
 				count++;
 		if(!pcibios_find_device(PCI_VENDOR_ID_RP,
diff -Nru a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
--- a/drivers/char/rocket_int.h	Sun Jun 29 09:27:44 2003
+++ b/drivers/char/rocket_int.h	Wed Aug 13 11:57:54 2003
@@ -1200,6 +1200,9 @@
 #ifndef PCI_DEVICE_ID_RP8J
 #define PCI_DEVICE_ID_RP8J		0x0006
 #endif
+#ifndef PCI_DEVICE_ID_RP4J
+#define PCI_DEVICE_ID_RP4J		0x0007
+#endif
 #ifndef PCI_DEVICE_ID_RPP4
 #define PCI_DEVICE_ID_RPP4		0x000A
 #endif
diff -Nru a/drivers/char/rtc.c b/drivers/char/rtc.c
--- a/drivers/char/rtc.c	Mon Mar  3 02:25:15 2003
+++ b/drivers/char/rtc.c	Sat Aug 30 01:07:05 2003
@@ -242,10 +242,10 @@
 		return -EINVAL;
 
 	add_wait_queue(&rtc_wait, &wait);
-
-	current->state = TASK_INTERRUPTIBLE;
 		
 	do {
+		__set_current_state(TASK_INTERRUPTIBLE);
+
 		/* First make it right. Then make it fast. Putting this whole
 		 * block within the parentheses of a while would be too
 		 * confusing. And no, xchg() is not the answer. */
diff -Nru a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c
--- a/drivers/char/sbc60xxwdt.c	Sun Sep 29 12:29:59 2002
+++ b/drivers/char/sbc60xxwdt.c	Fri Aug  8 07:11:35 2003
@@ -335,7 +335,7 @@
 	release_region(WDT_START,1);
 err_out_region1:
 	release_region(WDT_STOP,1);
-err_out:
+/* err_out: */
 	return rc;
 }
 
diff -Nru a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
--- a/drivers/char/ser_a2232.c	Mon Feb  4 23:45:17 2002
+++ b/drivers/char/ser_a2232.c	Mon Dec  2 18:10:12 2002
@@ -776,7 +776,7 @@
 	volatile u_char *to;
 	volatile struct a2232memory *mem;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	return -ENODEV;	/* This driver is not SMP aware. Is there an SMP ZorroII-bus-machine? */
 #endif
 
diff -Nru a/drivers/char/sn_serial.c b/drivers/char/sn_serial.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/sn_serial.c	Wed Aug 27 13:07:37 2003
@@ -0,0 +1,1190 @@
+/*
+ * C-Brick Serial Port (and console) driver for SGI Altix machines.
+ *
+ * This driver is NOT suitable for talking to the l1-controller for
+ * anything other than 'console activities' --- please use the l1
+ * driver for that.
+ *
+ *
+ * Copyright (c) 2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
+#include <linux/string.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn2/intr.h>
+#include <asm/sn/sn2/sn_private.h>
+#include <asm/sn/clksupport.h>
+
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#include <asm/sn/uart16550.h>
+
+/*
+ * The following KDB configuration info is borrowed from
+ * linux/drivers/char/serial.c:
+ */
+
+/*
+ * "kdb_serial_str[] is the sequence that the user must enter on the serial
+ * console to invoke kdb.  It can be a single character such as "\001"
+ * (control-A) or multiple characters such as "\eKdB".  NOTE: All except the
+ * last character are passed through to the application reading from the serial
+ * console.
+ *
+ * I tried to make the sequence a CONFIG_ option but most of CML1 cannot cope
+ * with '\' in strings, CML2 should be able to do it.  KAO."
+ */
+
+static int  kdb_serial_line = -1;
+static const char kdb_serial_str[] = "\eKDB";
+static char *kdb_serial_ptr = kdb_serial_str;
+#endif /* CONFIG_KDB */
+
+#if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+static char sysrq_serial_str[] = "\eSYS";
+static char *sysrq_serial_ptr = sysrq_serial_str;
+static unsigned long sysrq_requested;
+#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */
+
+static char *serial_revdate = "2003-07-31";
+
+/* driver subtype - what does this mean? */
+#define SN_SAL_SUBTYPE 1
+
+/* minor device number */
+#define SN_SAL_MINOR 64
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 128
+
+/* number of characters we can transmit to the SAL console at a time */
+#define SN_SAL_MAX_CHARS 120
+
+/* event types for our task queue -- so far just one */
+#define SN_SAL_EVENT_WRITE_WAKEUP 0
+
+#define CONSOLE_RESTART 1
+
+/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
+ * avoid losing chars, (always has to be a power of 2) */
+#if 1
+#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
+#else
+#define SN_SAL_BUFFER_SIZE (64)
+#endif
+
+#define SN_SAL_UART_FIFO_DEPTH 16
+#define SN_SAL_UART_FIFO_SPEED_CPS 9600/10
+
+/* we don't kmalloc/get_free_page these as we want them available
+ * before either of those are initialized */
+static volatile char xmit_buff_mem[SN_SAL_BUFFER_SIZE];
+
+struct volatile_circ_buf {
+	volatile char *buf;
+	int head;
+	int tail;
+};
+
+static volatile struct volatile_circ_buf xmit = { .buf = xmit_buff_mem };
+static char sal_tmp_buffer[SN_SAL_BUFFER_SIZE];
+
+static volatile struct tty_struct *sn_sal_tty;
+
+static struct timer_list sn_sal_timer;
+static int sn_sal_event; /* event type for task queue */
+static int sn_sal_refcount;
+
+static volatile int sn_sal_is_asynch;
+static volatile int sn_sal_irq;
+static spinlock_t sn_sal_lock = SPIN_LOCK_UNLOCKED;
+static volatile int tx_count;
+static volatile int rx_count;
+
+static struct tty_struct *sn_sal_table;
+static struct termios *sn_sal_termios;
+static struct termios *sn_sal_termios_locked;
+
+static void sn_sal_tasklet_action(unsigned long data);
+static DECLARE_TASKLET(sn_sal_tasklet, sn_sal_tasklet_action, 0);
+
+static volatile unsigned long interrupt_timeout;
+
+extern u64 master_node_bedrock_address;
+
+int debug_printf(const char *fmt, ...);
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTF(x...) debug_printf(x)
+#else
+#define DPRINTF(x...) do { } while (0)
+#endif
+
+static void intr_transmit_chars(void);
+static void poll_transmit_chars(void);
+static int sn_sal_write(struct tty_struct *tty, int from_user,
+			const unsigned char *buf, int count);
+
+struct sn_sal_ops {
+	int (*puts)(const char *s, int len);
+	int (*getc)(void);
+	int (*input_pending)(void);
+	void (*wakeup_transmit)(void);
+};
+
+static volatile struct sn_sal_ops *sn_sal_ops;
+
+
+/* the console does output in two distinctly different ways:
+ * synchronous and asynchronous (buffered).  initally, early_printk
+ * does synchronous output.  any data written goes directly to the SAL
+ * to be output (incidentally, it is internally buffered by the SAL)
+ * after interrupts and timers are initialized and available for use,
+ * the console init code switches to asynchronous output.  this is
+ * also the earliest opportunity to begin polling for console input.
+ * after console initialization, console output and tty (serial port)
+ * output is buffered and sent to the SAL asynchronously (either by
+ * timer callback or by UART interrupt) */
+
+
+/* routines for running the console in polling mode */
+
+static int hw_puts(const char *s, int len)
+{
+	/* looking at the PROM source code, putb calls the flush
+	 * routine, so if we send characters in FIFO sized chunks, it
+	 * should go out by the next time the timer gets called */
+	return ia64_sn_console_putb(s, len);
+}
+
+static int poll_getc(void)
+{
+	int ch;
+	ia64_sn_console_getc(&ch);
+	return ch;
+}
+
+static int poll_input_pending(void)
+{
+	int status, input;
+
+	status = ia64_sn_console_check(&input);
+	return !status && input;
+}
+
+static struct sn_sal_ops poll_ops = {
+	.puts = hw_puts,
+	.getc = poll_getc,
+	.input_pending = poll_input_pending
+};
+
+
+/* routines for running the console on the simulator */
+
+static int sim_puts(const char *str, int count)
+{
+	int counter = count;
+
+#ifdef FLAG_DIRECT_CONSOLE_WRITES
+	/* This is an easy way to pre-pend the output to know whether the output
+	 * was done via sal or directly */
+	writeb('[', master_node_bedrock_address + (UART_TX << 3));
+	writeb('+', master_node_bedrock_address + (UART_TX << 3));
+	writeb(']', master_node_bedrock_address + (UART_TX << 3));
+	writeb(' ', master_node_bedrock_address + (UART_TX << 3));
+#endif /* FLAG_DIRECT_CONSOLE_WRITES */
+	while (counter > 0) {
+		writeb(*str, master_node_bedrock_address + (UART_TX << 3));
+		counter--;
+		str++;
+	}
+
+	return count;
+}
+
+static int sim_getc(void)
+{
+	return readb(master_node_bedrock_address + (UART_RX << 3));
+}
+
+static int sim_input_pending(void)
+{
+	return readb(master_node_bedrock_address + (UART_LSR << 3)) & UART_LSR_DR;
+}
+
+static struct sn_sal_ops sim_ops = {
+	.puts = sim_puts,
+	.getc = sim_getc,
+	.input_pending = sim_input_pending
+};
+
+
+/* routines for an interrupt driven console (normal) */
+
+static int intr_getc(void)
+{
+	return ia64_sn_console_readc();
+}
+
+static int intr_input_pending(void)
+{
+	return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
+}
+
+static struct sn_sal_ops intr_ops = {
+	.puts = hw_puts,
+	.getc = intr_getc,
+	.input_pending = intr_input_pending,
+	.wakeup_transmit = intr_transmit_chars
+};
+
+extern void early_sn_setup(void);
+
+void
+early_printk_sn_sal(const char *s, unsigned count)
+{
+	if (!sn_sal_ops) {
+		if (IS_RUNNING_ON_SIMULATOR())
+			sn_sal_ops = &sim_ops;
+		else
+			sn_sal_ops = &poll_ops;
+
+		early_sn_setup();
+	}
+	sn_sal_ops->puts(s, count);
+}
+
+/* this is as "close to the metal" as we can get, used when the driver
+ * itself may be broken */
+int debug_printf(const char *fmt, ...)
+{
+	static char printk_buf[1024];
+	int printed_len;
+	va_list args;
+	va_start(args, fmt);
+	printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
+	early_printk_sn_sal(printk_buf, printed_len);
+	va_end(args);
+	return printed_len;
+}
+
+/*********************************************************************
+ * Interrupt handling routines.
+ */
+
+static void
+sn_sal_sched_event(int event)
+{
+	sn_sal_event |= (1 << event);
+	tasklet_schedule(&sn_sal_tasklet);
+}
+
+/* receive_chars can be called before sn_sal_tty is initialized.  in
+ * that case, its only use is to trigger sysrq and kdb */
+static void
+receive_chars(struct pt_regs *regs)
+{
+	int ch;
+
+	while (sn_sal_ops->input_pending()) {
+		ch = sn_sal_ops->getc();
+		if (ch < 0) {
+			printk(KERN_ERR "sn_serial: An error occured while "
+			       "obtaining data from the console (0x%0x)\n", ch);
+			break;
+		}
+#ifdef CONFIG_KDB
+		if (kdb_on) {
+			if (ch == *kdb_serial_ptr) {
+				if (!(*++kdb_serial_ptr)) {
+					if (!regs)
+						KDB_ENTER();	/* to get some registers */
+					else
+						kdb(KDB_REASON_KEYBOARD, 0, regs);
+					kdb_serial_ptr = kdb_serial_str;
+					break;
+				}
+			} else
+				kdb_serial_ptr = kdb_serial_str;
+		}
+#endif /* CONFIG_KDB */
+
+#if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+		if (sysrq_requested) {
+			unsigned long sysrq_timeout = sysrq_requested + HZ*5;
+			sysrq_requested = 0;
+			if (ch && time_before(jiffies, sysrq_timeout)) {
+				spin_unlock(&sn_sal_lock);
+				handle_sysrq(ch, regs, NULL, NULL);
+				spin_lock(&sn_sal_lock);
+				/* don't record this char */
+				continue;
+			}
+		}
+		if (ch == *sysrq_serial_ptr) {
+			if (!(*++sysrq_serial_ptr)) {
+				sysrq_requested = jiffies;
+				sysrq_serial_ptr = sysrq_serial_str;
+			}
+		} else
+			sysrq_serial_ptr = sysrq_serial_str;
+#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */
+
+		/* record the character to pass up to the tty layer */
+		if (sn_sal_tty) {
+			*sn_sal_tty->flip.char_buf_ptr = ch;
+			sn_sal_tty->flip.char_buf_ptr++;
+			sn_sal_tty->flip.count++;
+			if (sn_sal_tty->flip.count == TTY_FLIPBUF_SIZE)
+				break;
+		}
+		rx_count++;
+	}
+
+	if (sn_sal_tty)
+		tty_flip_buffer_push(sn_sal_tty);
+}
+
+
+/* synch_flush_xmit must be called with sn_sal_lock */
+static void
+synch_flush_xmit(void)
+{
+	int xmit_count, tail, head, loops, ii;
+	int result;
+	char *start;
+
+	if (xmit.head == xmit.tail)
+		/* Nothing to do. */
+		return;
+
+	head = xmit.head;
+	tail = xmit.tail;
+	start = &xmit.buf[tail];
+
+	/* twice around gets the tail to the end of the buffer and
+	 * then to the head, if needed */
+	loops = (head < tail) ? 2 : 1;
+
+	for (ii = 0; ii < loops; ii++) {
+		xmit_count = (head < tail) ?
+			(SN_SAL_BUFFER_SIZE - tail) : (head - tail);
+
+		if (xmit_count > 0) {
+			result = sn_sal_ops->puts(start, xmit_count);
+			if (!result)
+				debug_printf("\n*** synch_flush_xmit failed to flush\n");
+			if (result > 0) {
+				xmit_count -= result;
+				tx_count += result;
+				tail += result;
+				tail &= SN_SAL_BUFFER_SIZE - 1;
+				xmit.tail = tail;
+				start = &xmit.buf[tail];
+			}
+		}
+	}
+
+}
+
+/* must be called with a lock protecting the circular buffer and
+ * sn_sal_tty */
+static void
+poll_transmit_chars(void)
+{
+	int xmit_count, tail, head;
+	int result;
+	char *start;
+
+	BUG_ON(!sn_sal_is_asynch);
+
+	if (xmit.head == xmit.tail ||
+	    (sn_sal_tty && (sn_sal_tty->stopped || sn_sal_tty->hw_stopped))) {
+		/* Nothing to do. */
+		return;
+	}
+
+	head = xmit.head;
+	tail = xmit.tail;
+	start = &xmit.buf[tail];
+
+	xmit_count = (head < tail) ?
+		(SN_SAL_BUFFER_SIZE - tail) : (head - tail);
+
+	if (xmit_count == 0)
+		debug_printf("\n*** empty xmit_count\n");
+
+	if (xmit_count > SN_SAL_UART_FIFO_DEPTH)
+		xmit_count = SN_SAL_UART_FIFO_DEPTH;
+	
+	/* use the ops, as we could be on the simulator */
+	result = sn_sal_ops->puts(start, xmit_count);
+	if (!result)
+		debug_printf("\n*** error in synchronous puts\n");
+	/* XXX chadt clean this up */
+	if (result > 0) {
+		xmit_count -= result;
+		tx_count += result;
+		tail += result;
+		tail &= SN_SAL_BUFFER_SIZE - 1;
+		xmit.tail = tail;
+		start = &xmit.buf[tail];
+	}
+
+	/* if there's few enough characters left in the xmit buffer
+	 * that we could stand for the upper layer to send us some
+	 * more, ask for it. */
+	if (sn_sal_tty)
+		if (CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE) < WAKEUP_CHARS)
+			sn_sal_sched_event(SN_SAL_EVENT_WRITE_WAKEUP);
+}
+
+
+/* must be called with a lock protecting the circular buffer and
+ * sn_sal_tty */
+static void
+intr_transmit_chars(void)
+{
+	int xmit_count, tail, head, loops, ii;
+	int result;
+	char *start;
+
+	BUG_ON(!sn_sal_is_asynch);
+
+	if (xmit.head == xmit.tail ||
+	    (sn_sal_tty && (sn_sal_tty->stopped || sn_sal_tty->hw_stopped))) {
+		/* Nothing to do. */
+		return;
+	}
+
+	head = xmit.head;
+	tail = xmit.tail;
+	start = &xmit.buf[tail];
+
+	/* twice around gets the tail to the end of the buffer and
+	 * then to the head, if needed */
+	loops = (head < tail) ? 2 : 1;
+
+	for (ii = 0; ii < loops; ii++) {
+		xmit_count = (head < tail) ?
+			(SN_SAL_BUFFER_SIZE - tail) : (head - tail);
+
+		if (xmit_count > 0) {
+			result = ia64_sn_console_xmit_chars(start, xmit_count);
+#ifdef DEBUG
+			if (!result)
+				debug_printf("`");
+#endif
+			if (result > 0) {
+				xmit_count -= result;
+				tx_count += result;
+				tail += result;
+				tail &= SN_SAL_BUFFER_SIZE - 1;
+				xmit.tail = tail;
+				start = &xmit.buf[tail];
+			}
+		}
+	}
+
+	/* if there's few enough characters left in the xmit buffer
+	 * that we could stand for the upper layer to send us some
+	 * more, ask for it. */
+	if (sn_sal_tty)
+		if (CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE) < WAKEUP_CHARS)
+			sn_sal_sched_event(SN_SAL_EVENT_WRITE_WAKEUP);
+}
+
+
+static void
+sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* this call is necessary to pass the interrupt back to the
+	 * SAL, since it doesn't intercept the UART interrupts
+	 * itself */
+	int status = ia64_sn_console_intr_status();
+
+	spin_lock(&sn_sal_lock);
+	if (status & SAL_CONSOLE_INTR_RECV)
+		receive_chars(regs);
+	if (status & SAL_CONSOLE_INTR_XMIT)
+		intr_transmit_chars();
+	spin_unlock(&sn_sal_lock);
+}
+
+
+/* returns the console irq if interrupt is successfully registered,
+ * else 0 */
+static int
+sn_sal_connect_interrupt(void)
+{
+	cpuid_t intr_cpuid;
+	unsigned int intr_cpuloc;
+	nasid_t console_nasid;
+	unsigned int console_irq;
+	int result;
+
+	/* if it is an old prom, run in poll mode */
+	if ((sn_sal_rev_major() <= 1) && (sn_sal_rev_minor() <= 3)) {
+		/* before version 1.06 doesn't work */
+		printk(KERN_INFO "sn_serial: old prom version %x.%02x"
+		       " - running in polled mode\n",
+		       sn_sal_rev_major(), sn_sal_rev_minor());
+		return 0;
+	}
+
+	console_nasid = ia64_sn_get_console_nasid();
+	intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))
+		->node_first_cpu;
+	intr_cpuloc = cpu_physical_id(intr_cpuid);
+	console_irq = CPU_VECTOR_TO_IRQ(intr_cpuloc, SGI_UART_VECTOR);
+
+	result = intr_connect_level(intr_cpuid, SGI_UART_VECTOR,
+				    0 /*not used*/, 0 /*not used*/);
+	BUG_ON(result != SGI_UART_VECTOR);
+
+	result = request_irq(console_irq, sn_sal_interrupt,
+			     SA_INTERRUPT,  "SAL console driver", &sn_sal_tty);
+	if (result >= 0)
+		return console_irq;
+
+	printk(KERN_INFO "sn_serial: console proceeding in polled mode\n");
+	return 0;
+}
+
+/*
+ * End of the interrupt routines.
+ *********************************************************************/
+
+
+static void
+sn_sal_tasklet_action(unsigned long data)
+{
+	unsigned long flags;
+
+	if (sn_sal_tty) {
+		spin_lock_irqsave(&sn_sal_lock, flags);
+		if (sn_sal_tty)
+			if (test_and_clear_bit(SN_SAL_EVENT_WRITE_WAKEUP, &sn_sal_event)) {
+				if ((sn_sal_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+				    sn_sal_tty->ldisc.write_wakeup)
+					(sn_sal_tty->ldisc.write_wakeup)(sn_sal_tty);
+				wake_up_interruptible(&sn_sal_tty->write_wait);
+			}
+		spin_unlock_irqrestore(&sn_sal_lock, flags);
+	}
+}
+
+
+/*
+ * This function handles polled mode.
+ */
+static void
+sn_sal_timer_poll(unsigned long dummy)
+{
+	if (!sn_sal_irq) {
+		spin_lock(&sn_sal_lock);
+		receive_chars(NULL);
+		poll_transmit_chars();
+		spin_unlock(&sn_sal_lock);
+		mod_timer(&sn_sal_timer, jiffies + interrupt_timeout);
+	}
+}
+
+static void
+sn_sal_timer_restart(unsigned long dummy)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	sn_sal_interrupt(0, NULL, NULL);
+	local_irq_restore(flags);
+	mod_timer(&sn_sal_timer, jiffies + interrupt_timeout);
+}
+
+/*
+ * End of "sofware interrupt" routines.
+ *********************************************************************/
+
+
+/*********************************************************************
+ * User-level console routines
+ */
+
+static int
+sn_sal_open(struct tty_struct *tty, struct file *filp)
+{
+	unsigned long flags;
+
+	DPRINTF("sn_sal_open: sn_sal_tty = %p, tty = %p, filp = %p\n",
+		sn_sal_tty, tty, filp);
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if (!sn_sal_tty)
+		sn_sal_tty = tty;
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+
+	return 0;
+}
+
+
+/* We're keeping all our resources.  We're keeping interrupts turned
+ * on.  Maybe just let the tty layer finish its stuff...? GMSH
+ */
+static void
+sn_sal_close(struct tty_struct *tty, struct file * filp)
+{
+	if (atomic_read(&tty->count) == 1) {
+		unsigned long flags;
+		tty->closing = 1;
+		if (tty->driver.flush_buffer)
+			tty->driver.flush_buffer(tty);
+		if (tty->ldisc.flush_buffer)
+			tty->ldisc.flush_buffer(tty);
+		tty->closing = 0;
+		spin_lock_irqsave(&sn_sal_lock, flags);
+		sn_sal_tty = NULL;
+		spin_unlock_irqrestore(&sn_sal_lock, flags);
+	}
+}
+
+
+static int
+sn_sal_write(struct tty_struct *tty, int from_user,
+	     const unsigned char *buf, int count)
+{
+	int c, ret = 0;
+	unsigned long flags;
+
+	if (from_user) {
+		while (1) {
+			int c1;
+			c = CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+					      SN_SAL_BUFFER_SIZE);
+
+			if (count < c)
+				c = count;
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(sal_tmp_buffer, buf, c);
+			if (!c) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+
+			/* Turn off interrupts and see if the xmit buffer has
+			 * moved since the last time we looked.
+			 */
+			spin_lock_irqsave(&sn_sal_lock, flags);
+			c1 = CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+					       SN_SAL_BUFFER_SIZE);
+
+			if (c1 < c)
+				c = c1;
+
+			memcpy(xmit.buf + xmit.head, sal_tmp_buffer, c);
+			xmit.head = ((xmit.head + c) & (SN_SAL_BUFFER_SIZE - 1));
+			spin_unlock_irqrestore(&sn_sal_lock, flags);
+
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+	} else {
+		/* The buffer passed in isn't coming from userland,
+		 * so cut out the middleman (sal_tmp_buffer).
+		 */
+		spin_lock_irqsave(&sn_sal_lock, flags);
+		while (1) {
+			c = CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+					      SN_SAL_BUFFER_SIZE);
+
+			if (count < c)
+				c = count;
+			if (c <= 0) {
+				break;
+			}
+			memcpy(xmit.buf + xmit.head, buf, c);
+			xmit.head = ((xmit.head + c) & (SN_SAL_BUFFER_SIZE - 1));
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		spin_unlock_irqrestore(&sn_sal_lock, flags);
+	}
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if (xmit.head != xmit.tail &&
+	    !(tty && (tty->stopped || tty->hw_stopped)))
+		if (sn_sal_ops->wakeup_transmit)
+			sn_sal_ops->wakeup_transmit();
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+
+	return ret;
+}
+
+
+static void
+sn_sal_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if (CIRC_SPACE(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE) != 0) {
+		xmit.buf[xmit.head] = ch;
+		xmit.head = (xmit.head + 1) & (SN_SAL_BUFFER_SIZE-1);
+		sn_sal_ops->wakeup_transmit();
+	}
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+}
+
+
+static void
+sn_sal_flush_chars(struct tty_struct *tty)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if (CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE))
+		if (sn_sal_ops->wakeup_transmit)
+			sn_sal_ops->wakeup_transmit();
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+}
+
+
+static int
+sn_sal_write_room(struct tty_struct *tty)
+{
+	unsigned long flags;
+	int space;
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	space = CIRC_SPACE(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE);
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+	return space;
+}
+
+
+static int
+sn_sal_chars_in_buffer(struct tty_struct *tty)
+{
+	unsigned long flags;
+	int space;
+
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	space = CIRC_CNT(xmit.head, xmit.tail, SN_SAL_BUFFER_SIZE);
+	DPRINTF("<%d>", space);
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+	return space;
+}
+
+
+static int
+sn_sal_ioctl(struct tty_struct *tty, struct file *file,
+	       unsigned int cmd, unsigned long arg)
+{
+	/* nothing supported */
+
+	return -ENOIOCTLCMD;
+}
+
+
+static void
+sn_sal_flush_buffer(struct tty_struct *tty)
+{
+	unsigned long flags;
+
+	/* drop everything */
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	xmit.head = xmit.tail = 0;
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+
+	/* wake up tty level */
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+
+static void
+sn_sal_hangup(struct tty_struct *tty)
+{
+	sn_sal_flush_buffer(tty);
+}
+
+
+static void
+sn_sal_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	/* this is SAL's problem */
+	DPRINTF("<sn_serial: should wait until sent>");
+}
+
+
+/*
+ * sn_sal_read_proc
+ *
+ * Console /proc interface
+ */
+
+static int
+sn_sal_read_proc(char *page, char **start, off_t off, int count,
+		   int *eof, void *data)
+{
+	int len = 0;
+	off_t	begin = 0;
+	extern nasid_t get_console_nasid(void);
+
+	len += sprintf(page, "sn_serial: revision:%s nasid:%d irq:%d tx:%d rx:%d\n",
+		       serial_revdate, get_console_nasid(), sn_sal_irq,
+		       tx_count, rx_count);
+	*eof = 1;
+
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+
+	return count < begin+len-off ? count : begin+len-off;
+}
+
+
+static struct tty_driver sn_sal_driver = {
+	.magic = TTY_DRIVER_MAGIC,
+	.driver_name = "sn_serial",
+#if defined(CONFIG_DEVFS_FS)
+	.name = "tts/%d",
+#else
+	.name = "ttyS",
+#endif
+	.major = TTY_MAJOR,
+	.minor_start = SN_SAL_MINOR,
+	.num = 1,
+	.type = TTY_DRIVER_TYPE_SERIAL,
+	.subtype = SN_SAL_SUBTYPE,
+	.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+	.refcount = &sn_sal_refcount,
+	.table = &sn_sal_table,
+	.termios = &sn_sal_termios,
+	.termios_locked = &sn_sal_termios_locked,
+
+	.open = sn_sal_open,
+	.close = sn_sal_close,
+	.write = sn_sal_write,
+	.put_char = sn_sal_put_char,
+	.flush_chars = sn_sal_flush_chars,
+	.write_room = sn_sal_write_room,
+	.chars_in_buffer = sn_sal_chars_in_buffer,
+	.ioctl = sn_sal_ioctl,
+	.hangup = sn_sal_hangup,
+	.wait_until_sent = sn_sal_wait_until_sent,
+	.read_proc = sn_sal_read_proc,
+};
+
+/* sn_sal_init wishlist:
+ * - allocate sal_tmp_buffer
+ * - fix up the tty_driver struct
+ * - turn on receive interrupts
+ * - do any termios twiddling once and for all
+ */
+
+/*
+ * Boot-time initialization code
+ */
+
+static void __init
+sn_sal_switch_to_asynch(void)
+{
+	debug_printf("sn_serial: about to switch to asynchronous console\n");
+
+	/* without early_printk, we may be invoked late enough to race
+	 * with other cpus doing console IO at this point, however
+	 * console interrupts will never be enabled */
+	spin_lock(&sn_sal_lock);
+
+	/* early_printk invocation may have done this for us */
+	if (!sn_sal_ops) {
+		if (IS_RUNNING_ON_SIMULATOR())
+			sn_sal_ops = &sim_ops;
+		else
+			sn_sal_ops = &poll_ops;
+	}
+
+	/* we can't turn on the console interrupt (as request_irq
+	 * calls kmalloc, which isn't set up yet), so we rely on a
+	 * timer to poll for input and push data from the console
+	 * buffer.
+	 */
+	init_timer(&sn_sal_timer);
+	sn_sal_timer.function = sn_sal_timer_poll;
+
+	if (IS_RUNNING_ON_SIMULATOR())
+		interrupt_timeout = 6;
+	else
+		/* 960cps / 16 char FIFO = 60HZ 
+		   HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
+		interrupt_timeout = HZ * SN_SAL_UART_FIFO_DEPTH / 
+			SN_SAL_UART_FIFO_SPEED_CPS;
+
+	mod_timer(&sn_sal_timer, jiffies + interrupt_timeout);
+
+	sn_sal_is_asynch = 1;
+	spin_unlock(&sn_sal_lock);
+}
+
+static void __init
+sn_sal_switch_to_interrupts(void)
+{
+	int irq;
+
+	debug_printf("sn_serial: switching to interrupt driven console\n");
+
+	irq = sn_sal_connect_interrupt();
+	if (irq) {
+		unsigned long flags;
+		spin_lock_irqsave(&sn_sal_lock, flags);
+		/* sn_sal_irq is a global variable.  When it's set to
+		 * a non-zero value, we stop polling for input (since
+		 * interrupts should now be enabled). */
+		sn_sal_irq = irq;
+		sn_sal_ops = &intr_ops;
+		/* turn on receive interrupts */
+		ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
+
+		/* the polling timer is already set up, we just change the
+		 * frequency.  if we've successfully enabled interrupts (and
+		 * CONSOLE_RESTART isn't defined) the next timer expiration
+		 * will be the last, otherwise we continue polling */
+		if (CONSOLE_RESTART) {
+			/* kick the console every once in a while in
+			 * case we miss an interrupt */
+			interrupt_timeout = 20*HZ;
+			sn_sal_timer.function = sn_sal_timer_restart;
+			mod_timer(&sn_sal_timer, jiffies + interrupt_timeout);
+		}
+		spin_unlock_irqrestore(&sn_sal_lock, flags);
+	}
+}
+
+static int __init
+sn_sal_module_init(void)
+{
+	int retval;
+
+	printk("sn_serial: sn_sal_module_init\n");
+
+	if (!ia64_platform_is("sn2"))
+		return -ENODEV;
+
+	/* when this driver is compiled in, the console initialization
+	 * will have already switched us into asynchronous operation
+	 * before we get here through the module initcalls */
+	if (!sn_sal_is_asynch)
+		sn_sal_switch_to_asynch();
+
+	/* at this point (module_init) we can try to turn on
+	 * interrupts */
+	if (!IS_RUNNING_ON_SIMULATOR())
+	    sn_sal_switch_to_interrupts();
+
+	sn_sal_driver.init_termios = tty_std_termios;
+	sn_sal_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+	if ((retval = tty_register_driver(&sn_sal_driver))) {
+		printk(KERN_ERR "sn_serial: Unable to register tty driver\n");
+		return retval;
+	}
+
+	tty_register_devfs(&sn_sal_driver, 0, sn_sal_driver.minor_start);
+
+	return 0;
+}
+
+
+static void __exit
+sn_sal_module_exit(void)
+{
+	unsigned long flags;
+	int e;
+
+	del_timer_sync(&sn_sal_timer);
+	spin_lock_irqsave(&sn_sal_lock, flags);
+	if ((e = tty_unregister_driver(&sn_sal_driver)))
+		printk(KERN_ERR "sn_serial: failed to unregister driver (%d)\n", e);
+
+	spin_unlock_irqrestore(&sn_sal_lock, flags);
+}
+
+module_init(sn_sal_module_init);
+module_exit(sn_sal_module_exit);
+
+/*
+ * End of user-level console routines.
+ *********************************************************************/
+
+
+/*********************************************************************
+ * Kernel console definitions
+ */
+
+#ifdef CONFIG_SGI_L1_SERIAL_CONSOLE
+/*
+ * Print a string to the SAL console.  The console_lock must be held
+ * when we get here.
+ */
+static void
+sn_sal_console_write(struct console *co, const char *s, unsigned count)
+{
+	BUG_ON(!sn_sal_is_asynch);
+
+	if (count > CIRC_SPACE_TO_END(xmit.head, xmit.tail,
+				      SN_SAL_BUFFER_SIZE))
+		debug_printf("\n*** SN_SAL_BUFFER_SIZE too small, lost chars\n");
+
+	/* somebody really wants this output, might be an
+	 * oops, kdb, panic, etc.  make sure they get it. */
+	if (spin_is_locked(&sn_sal_lock)) {
+		synch_flush_xmit();
+		sn_sal_ops->puts(s, count);
+	} else if (in_interrupt()) {
+		spin_lock(&sn_sal_lock);
+		synch_flush_xmit();
+		spin_unlock(&sn_sal_lock);
+		sn_sal_ops->puts(s, count);
+	} else
+		sn_sal_write(NULL, 0, s, count);
+}
+
+static kdev_t
+sn_sal_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static int __init
+sn_sal_console_setup(struct console *co, char *options)
+{
+#ifdef CONFIG_KDB
+	/*
+	 * Remember the line number of the first serial
+	 * console.  We'll make this the kdb serial console too.
+	 */
+	if (kdb_serial_line == -1) {
+		kdb_serial_line = co->index;
+	}
+#endif /* CONFIG_KDB */
+
+	return 0;
+}
+
+
+static struct console sal_console = {
+	.name = "ttyS",
+	.write = sn_sal_console_write,
+	.device = sn_sal_console_device,
+	.setup = sn_sal_console_setup,
+	.index = -1
+};
+
+/*
+ * End of kernel console definitions.
+ *********************************************************************/
+
+
+void __init
+sn_sal_serial_console_init(void)
+{
+	if (ia64_platform_is("sn2")) {
+		sn_sal_switch_to_asynch();
+		register_console(&sal_console);
+	}
+}
+
+
+#ifdef	CONFIG_KDB
+int
+l1_control_in_polled(int offset)
+{
+	int sal_call_status = 0, input;
+	int ret = 0;
+
+	if (IS_RUNNING_ON_SIMULATOR()) {
+		ret = readb((unsigned long)master_node_bedrock_address +
+			    (offset<< 3));
+		return(ret);
+	}		
+	if (offset == REG_LSR) {
+		ret = (LSR_XHRE | LSR_XSRE);	/* can send anytime */
+		sal_call_status = ia64_sn_console_check(&input);
+		if (!sal_call_status && input) {
+			/* input pending */
+			ret |= LSR_RCA;
+		}
+	}
+	return ret;
+}
+
+int
+l1_serial_in_polled(void)
+{
+	int ch;
+
+	if (IS_RUNNING_ON_SIMULATOR()) {
+		return readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+	}		
+
+	if (!ia64_sn_console_getc(&ch))
+		return ch;
+	else
+		return 0;
+}
+#endif /* CONFIG_KDB */
+
+#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE */
diff -Nru a/drivers/char/softdog.c b/drivers/char/softdog.c
--- a/drivers/char/softdog.c	Sun Sep 29 12:29:59 2002
+++ b/drivers/char/softdog.c	Thu Jul 31 06:18:58 2003
@@ -124,7 +124,7 @@
 	 *	Shut off the timer.
 	 * 	Lock it in if it's a module and we set nowayout
 	 */
-	if (expect_close) {
+	if (expect_close || nowayout == 0) {
 		del_timer(&watchdog_ticktock);
 	} else {
 		printk(KERN_CRIT "SOFTDOG: WDT device closed unexpectedly.  WDT will not stop!\n");
diff -Nru a/drivers/char/sonypi.c b/drivers/char/sonypi.c
--- a/drivers/char/sonypi.c	Sun Jun 29 08:10:02 2003
+++ b/drivers/char/sonypi.c	Fri Aug  1 05:35:17 2003
@@ -308,7 +308,7 @@
 	int i, j;
 
 	v1 = inb_p(sonypi_device.ioport1);
-	v2 = inb_p(sonypi_device.ioport2);
+	v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset);
 
 	for (i = 0; sonypi_eventtypes[i].model; i++) {
 		if (sonypi_device.model != sonypi_eventtypes[i].model)
@@ -665,11 +665,13 @@
 	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
 		ioport_list = sonypi_type2_ioport_list;
 		sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
+		sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
 		irq_list = sonypi_type2_irq_list;
 	}
 	else {
 		ioport_list = sonypi_type1_ioport_list;
 		sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
+		sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
 		irq_list = sonypi_type1_irq_list;
 	}
 
diff -Nru a/drivers/char/sonypi.h b/drivers/char/sonypi.h
--- a/drivers/char/sonypi.h	Sun Jun 29 09:27:44 2003
+++ b/drivers/char/sonypi.h	Tue Aug 26 04:52:33 2003
@@ -56,12 +56,14 @@
 #define SONYPI_BASE			0x50
 #define SONYPI_G10A			(SONYPI_BASE+0x14)
 #define SONYPI_TYPE1_REGION_SIZE	0x08
+#define SONYPI_TYPE1_EVTYPE_OFFSET	0x04
 
 /* type2 series specifics */
 #define SONYPI_SIRQ			0x9b
 #define SONYPI_SLOB			0x9c
 #define SONYPI_SHIB			0x9d
 #define SONYPI_TYPE2_REGION_SIZE	0x20
+#define SONYPI_TYPE2_EVTYPE_OFFSET	0x12
 
 /* battery / brightness addresses */
 #define SONYPI_BAT_FLAGS	0x81
@@ -167,6 +169,7 @@
 #define SONYPI_THUMBPHRASE_MASK			0x00000200
 #define SONYPI_MEYE_MASK			0x00000400
 #define SONYPI_MEMORYSTICK_MASK			0x00000800
+#define SONYPI_BATTERY_MASK			0x00001000
 
 struct sonypi_event {
 	u8	data;
@@ -293,6 +296,13 @@
 	{ 0, 0 }
 };
 
+/* The set of possible battery events */
+static struct sonypi_event sonypi_batteryev[] = {
+	{ 0x20, SONYPI_EVENT_BATTERY_INSERT },
+	{ 0x30, SONYPI_EVENT_BATTERY_REMOVE },
+	{ 0, 0 }
+};
+
 struct sonypi_eventtypes {
 	int			model;
 	u8			data;
@@ -307,19 +317,22 @@
 	{ SONYPI_DEVICE_MODEL_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
 	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
 	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
 
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0, 0xffffffff, sonypi_releaseev },
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
-	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_JOGGER_MASK, sonypi_joggerev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_CAPTURE_MASK, sonypi_captureev },
-	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
-	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
-	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_BACK_MASK, sonypi_backev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev },
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_ZOOM_MASK, sonypi_zoomev },
 	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
-	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
 
 	{ 0, 0, 0, 0 }
 };
@@ -354,6 +367,7 @@
 	u16 ioport1;
 	u16 ioport2;
 	u16 region_size;
+	u16 evtype_offset;
 	int camera_power;
 	int bluetooth_power;
 	struct semaphore lock;
@@ -380,30 +394,17 @@
 }
 
 #ifdef CONFIG_ACPI
-#include <linux/acpi.h>
-#if (ACPI_CA_VERSION > 0x20021121)
-#ifdef CONFIG_ACPI_EC
-#define SONYPI_USE_ACPI
-#endif
-#endif
-#endif /* CONFIG_ACPI */
-
-#ifdef CONFIG_ACPI
-#ifdef SONYPI_USE_ACPI
 extern int acpi_disabled;
 #define SONYPI_ACPI_ACTIVE (!acpi_disabled)
 #else
-#define SONYPI_ACPI_ACTIVE 1
-#endif
-#else /* CONFIG_ACPI */
 #define SONYPI_ACPI_ACTIVE 0
 #endif /* CONFIG_ACPI */
 
 extern int verbose;
 
 static inline int sonypi_ec_write(u8 addr, u8 value) {
-#ifdef SONYPI_USE_ACPI
-	if (!acpi_disabled)
+#ifdef CONFIG_ACPI_EC
+	if (SONYPI_ACPI_ACTIVE)
 		return ec_write(addr, value);
 #endif
 	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
@@ -417,8 +418,8 @@
 }
 
 static inline int sonypi_ec_read(u8 addr, u8 *value) {
-#ifdef SONYPI_USE_ACPI
-	if (!acpi_disabled)
+#ifdef CONFIG_ACPI_EC
+	if (SONYPI_ACPI_ACTIVE)
 		return ec_read(addr, value);
 #endif
 	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Fri Jul  4 20:50:23 2003
+++ b/drivers/char/tty_io.c	Sat Aug 30 01:02:01 2003
@@ -154,6 +154,7 @@
 extern void rs285_console_init(void);
 extern void sa1100_rs_console_init(void);
 extern void sgi_serial_console_init(void);
+extern void sn_sal_serial_console_init(void);
 extern void sci_console_init(void);
 extern void dec_serial_console_init(void);
 extern void tx3912_console_init(void);
@@ -1048,7 +1049,7 @@
 		}
 		o_tty->magic = 0;
 		(*o_tty->driver.refcount)--;
-		list_del(&o_tty->tty_files);
+		list_del_init(&o_tty->tty_files);
 		free_tty_struct(o_tty);
 	}
 
@@ -1060,7 +1061,7 @@
 	}
 	tty->magic = 0;
 	(*tty->driver.refcount)--;
-	list_del(&tty->tty_files);
+	list_del_init(&tty->tty_files);
 	free_tty_struct(tty);
 }
 
@@ -2391,6 +2392,12 @@
 	kbd_init();
 #endif
 
+#ifdef CONFIG_SGI_L1_SERIAL_CONSOLE
+	if (ia64_platform_is("sn2")) {
+		sn_sal_serial_console_init();
+		return; /* only one console right now for SN2 */
+	}
+#endif
 #ifdef CONFIG_ESPSERIAL  /* init ESP before rs, so rs doesn't see the port */
 	espserial_init();
 #endif
diff -Nru a/drivers/hotplug/acpiphp.h b/drivers/hotplug/acpiphp.h
--- a/drivers/hotplug/acpiphp.h	Tue Jun 17 17:37:55 2003
+++ b/drivers/hotplug/acpiphp.h	Thu Aug 28 04:21:26 2003
@@ -1,12 +1,12 @@
 /*
  * ACPI PCI Hot Plug Controller Driver
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
- * Copyright (c) 2002,2003 NEC Corporation
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002,2003 NEC Corporation
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/acpiphp_core.c b/drivers/hotplug/acpiphp_core.c
--- a/drivers/hotplug/acpiphp_core.c	Tue Jun 17 17:37:55 2003
+++ b/drivers/hotplug/acpiphp_core.c	Thu Aug 28 04:21:26 2003
@@ -1,12 +1,12 @@
 /*
  * ACPI PCI Hot Plug Controller Driver
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
- * Copyright (c) 2002,2003 NEC Corporation
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002,2003 NEC Corporation
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/acpiphp_glue.c b/drivers/hotplug/acpiphp_glue.c
--- a/drivers/hotplug/acpiphp_glue.c	Tue Jun 17 17:37:55 2003
+++ b/drivers/hotplug/acpiphp_glue.c	Thu Aug 28 04:21:26 2003
@@ -1,9 +1,9 @@
 /*
  * ACPI PCI HotPlug glue functions to ACPI CA subsystem
  *
- * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002,2003 NEC Corporation
+ * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002,2003 NEC Corporation
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/acpiphp_pci.c b/drivers/hotplug/acpiphp_pci.c
--- a/drivers/hotplug/acpiphp_pci.c	Tue Jun 17 17:37:55 2003
+++ b/drivers/hotplug/acpiphp_pci.c	Thu Aug 28 04:21:26 2003
@@ -1,12 +1,12 @@
 /*
  * ACPI PCI HotPlug PCI configuration space management
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001,2002 IBM Corp.
- * Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 IBM Corp.
+ * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002 NEC Corporation
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/acpiphp_res.c b/drivers/hotplug/acpiphp_res.c
--- a/drivers/hotplug/acpiphp_res.c	Tue Jun 17 17:37:55 2003
+++ b/drivers/hotplug/acpiphp_res.c	Thu Aug 28 04:21:26 2003
@@ -1,12 +1,12 @@
 /*
  * ACPI PCI HotPlug Utility functions
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
- * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
- * Copyright (c) 2002 NEC Corporation
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002 NEC Corporation
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/cpqphp.h b/drivers/hotplug/cpqphp.h
--- a/drivers/hotplug/cpqphp.h	Fri May  2 04:32:35 2003
+++ b/drivers/hotplug/cpqphp.h	Wed Aug 20 20:08:28 2003
@@ -1,9 +1,9 @@
 /*
  * Compaq Hot Plug Controller Driver
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM
  *
  * All rights reserved.
  *
@@ -747,7 +747,7 @@
 		return 1;
 
 	hp_slot = slot->device - ctrl->slot_device_offset;
-	dbg(__FUNCTION__": slot->device = %d, ctrl->slot_device_offset = %d \n", slot->device, ctrl->slot_device_offset);
+	dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n", __FUNCTION__, slot->device, ctrl->slot_device_offset);
 
 	status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot));
 
@@ -785,7 +785,7 @@
         DECLARE_WAITQUEUE(wait, current);
 	int retval = 0;
 
-	dbg(__FUNCTION__" - start\n");
+	dbg("%s - start\n", __FUNCTION__);
 	add_wait_queue(&ctrl->queue, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	/* Sleep for up to 1 second to wait for the LED to change. */
@@ -795,7 +795,7 @@
 	if (signal_pending(current))
 		retval =  -EINTR;
 
-	dbg(__FUNCTION__" - end\n");
+	dbg("%s - end\n", __FUNCTION__);
 	return retval;
 }
 
diff -Nru a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c
--- a/drivers/hotplug/cpqphp_core.c	Fri May  2 04:32:35 2003
+++ b/drivers/hotplug/cpqphp_core.c	Wed Aug 20 20:08:28 2003
@@ -1,9 +1,9 @@
 /*
  * Compaq Hot Plug Controller Driver
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
  *
  * All rights reserved.
  *
@@ -320,7 +320,7 @@
 	void *slot_entry= NULL;
 	int result;
 
-	dbg(__FUNCTION__"\n");
+	dbg("%s\n", __FUNCTION__);
 
 	tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
 
@@ -482,7 +482,7 @@
 
 	u8 tbus, tdevice, tslot, bridgeSlot;
 
-	dbg(__FUNCTION__" %p, %d, %d, %p\n", ops, bus_num, dev_num, slot);
+	dbg("%s %p, %d, %d, %p\n", __FUNCTION__, ops, bus_num, dev_num, slot);
 
 	bridgeSlot = 0xFF;
 
@@ -598,7 +598,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -633,7 +633,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -673,7 +673,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -701,7 +701,7 @@
 	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
 	struct controller *ctrl;
 
-	dbg(__FUNCTION__"\n");
+	dbg("%s\n", __FUNCTION__);
 
 	if (slot == NULL)
 		return -ENODEV;
@@ -722,7 +722,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -740,7 +740,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -758,7 +758,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -777,7 +777,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -865,7 +865,7 @@
 		// TODO: This code can be made to support non-Compaq or Intel subsystem IDs
 		rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid);
 		if (rc) {
-			err(__FUNCTION__" : pci_read_config_word failed\n");
+			err("%s : pci_read_config_word failed\n", __FUNCTION__);
 			return rc;
 		}
 		dbg("Subsystem Vendor ID: %x\n", subsystem_vid);
@@ -876,14 +876,14 @@
 
 		ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
 		if (!ctrl) {
-			err(__FUNCTION__" : out of memory\n");
+			err("%s : out of memory\n", __FUNCTION__);
 			return -ENOMEM;
 		}
 		memset(ctrl, 0, sizeof(struct controller));
 
 		rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid);
 		if (rc) {
-			err(__FUNCTION__" : pci_read_config_word failed\n");
+			err("%s : pci_read_config_word failed\n", __FUNCTION__);
 			goto err_free_ctrl;
 		}
 
@@ -1139,7 +1139,7 @@
 	// Store PCI Config Space for all devices on this bus
 	rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK));
 	if (rc) {
-		err(__FUNCTION__": unable to save PCI configuration data, error %d\n", rc);
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
 		goto err_iounmap;
 	}
 
@@ -1169,7 +1169,7 @@
 	rc = ctrl_slot_setup(ctrl, smbios_start, smbios_table);
 	if (rc) {
 		err(msg_initialization_err, 6);
-		err(__FUNCTION__": unable to save PCI configuration data, error %d\n", rc);
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
 		goto err_iounmap;
 	}
 	
diff -Nru a/drivers/hotplug/cpqphp_ctrl.c b/drivers/hotplug/cpqphp_ctrl.c
--- a/drivers/hotplug/cpqphp_ctrl.c	Fri May  2 04:32:35 2003
+++ b/drivers/hotplug/cpqphp_ctrl.c	Wed Aug 20 20:08:28 2003
@@ -1,9 +1,9 @@
 /*
  * Compaq Hot Plug Controller Driver
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
  *
  * All rights reserved.
  *
@@ -771,13 +771,13 @@
 		return(NULL);
 
 	for (node = *head; node; node = node->next) {
-		dbg(__FUNCTION__": req_size =%x node=%p, base=%x, length=%x\n",
-		    size, node, node->base, node->length);
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
+		    __FUNCTION__, size, node, node->base, node->length);
 		if (node->length < size)
 			continue;
 
 		if (node->base & (size - 1)) {
-			dbg(__FUNCTION__": not aligned\n");
+			dbg("%s: not aligned\n", __FUNCTION__);
 			// this one isn't base aligned properly
 			// so we'll make a new entry and split it up
 			temp_dword = (node->base | (size-1)) + 1;
@@ -803,7 +803,7 @@
 
 		// Don't need to check if too small since we already did
 		if (node->length > size) {
-			dbg(__FUNCTION__": too big\n");
+			dbg("%s: too big\n", __FUNCTION__);
 			// this one is longer than we need
 			// so we'll make a new entry and split it up
 			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
@@ -820,7 +820,7 @@
 			node->next = split_node;
 		}  // End of too big on top end
 
-		dbg(__FUNCTION__": got one!!!\n");
+		dbg("%s: got one!!!\n", __FUNCTION__);
 		// If we got here, then it is the right size
 		// Now take it out of the list
 		if (*head == node) {
@@ -855,7 +855,7 @@
 	struct pci_resource *node2;
 	int out_of_order = 1;
 
-	dbg(__FUNCTION__": head = %p, *head = %p\n", head, *head);
+	dbg("%s: head = %p, *head = %p\n",__FUNCTION__, head, *head);
 
 	if (!(*head))
 		return(1);
@@ -942,7 +942,7 @@
 		// Read to clear posted writes
 		misc = readw(ctrl->hpc_reg + MISC);
 
-		dbg (__FUNCTION__" - waking up\n");
+		dbg ("%s - waking up\n", __FUNCTION__);
 		wake_up_interruptible(&ctrl->queue);
 	}
 
@@ -1394,8 +1394,8 @@
 	struct resource_lists res_lists;
 
 	hp_slot = func->device - ctrl->slot_device_offset;
-	dbg(__FUNCTION__": func->device, slot_offset, hp_slot = %d, %d ,%d\n",
-	    func->device, ctrl->slot_device_offset, hp_slot);
+	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n",
+	    __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
 	
 	// Wait for exclusive access to hardware
 	down(&ctrl->crit_sect);
@@ -1444,55 +1444,55 @@
 	// turn on board and blink green LED
 
 	// Wait for exclusive access to hardware
-	dbg(__FUNCTION__": before down\n");
+	dbg("%s: before down\n", __FUNCTION__);
 	down(&ctrl->crit_sect);
-	dbg(__FUNCTION__": after down\n");
+	dbg("%s: after down\n", __FUNCTION__);
 
-	dbg(__FUNCTION__": before slot_enable\n");
+	dbg("%s: before slot_enable\n", __FUNCTION__);
 	slot_enable (ctrl, hp_slot);
 
-	dbg(__FUNCTION__": before green_LED_blink\n");
+	dbg("%s: before green_LED_blink\n", __FUNCTION__);
 	green_LED_blink (ctrl, hp_slot);
 
-	dbg(__FUNCTION__": before amber_LED_blink\n");
+	dbg("%s: before amber_LED_blink\n", __FUNCTION__);
 	amber_LED_off (ctrl, hp_slot);
 
-	dbg(__FUNCTION__": before set_SOGO\n");
+	dbg("%s: before set_SOGO\n", __FUNCTION__);
 	set_SOGO(ctrl);
 
 	// Wait for SOBS to be unset
-	dbg(__FUNCTION__": before wait_for_ctrl_irq\n");
+	dbg("%s: before wait_for_ctrl_irq\n", __FUNCTION__);
 	wait_for_ctrl_irq (ctrl);
-	dbg(__FUNCTION__": after wait_for_ctrl_irq\n");
+	dbg("%s: after wait_for_ctrl_irq\n", __FUNCTION__);
 
 	// Done with exclusive hardware access
-	dbg(__FUNCTION__": before up\n");
+	dbg("%s: before up\n", __FUNCTION__);
 	up(&ctrl->crit_sect);
-	dbg(__FUNCTION__": after up\n");
+	dbg("%s: after up\n", __FUNCTION__);
 
 	// Wait for ~1 second because of hot plug spec
-	dbg(__FUNCTION__": before long_delay\n");
+	dbg("%s: before long_delay\n", __FUNCTION__);
 	long_delay(1*HZ);
-	dbg(__FUNCTION__": after long_delay\n");
+	dbg("%s: after long_delay\n", __FUNCTION__);
 
-	dbg(__FUNCTION__": func status = %x\n", func->status);
+	dbg("%s: func status = %x\n", __FUNCTION__, func->status);
 	// Check for a power fault
 	if (func->status == 0xFF) {
 		// power fault occurred, but it was benign
 		temp_register = 0xFFFFFFFF;
-		dbg(__FUNCTION__": temp register set to %x by power fault\n", temp_register);
+		dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
 		rc = POWER_FAILURE;
 		func->status = 0;
 	} else {
 		// Get vendor/device ID u32
 		rc = pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_VENDOR_ID, &temp_register);
-		dbg(__FUNCTION__": pci_read_config_dword returns %d\n", rc);
-		dbg(__FUNCTION__": temp_register is %x\n", temp_register);
+		dbg("%s: pci_read_config_dword returns %d\n", __FUNCTION__, rc);
+		dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register);
 
 		if (rc != 0) {
 			// Something's wrong here
 			temp_register = 0xFFFFFFFF;
-			dbg(__FUNCTION__": temp register set to %x by error\n", temp_register);
+			dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register);
 		}
 		// Preset return code.  It will be changed later if things go okay.
 		rc = NO_ADAPTER_PRESENT;
@@ -1508,7 +1508,7 @@
 
 		rc = configure_new_device(ctrl, func, 0, &res_lists);
 
-		dbg(__FUNCTION__": back from configure_new_device\n");
+		dbg("%s: back from configure_new_device\n", __FUNCTION__);
 		ctrl->io_head = res_lists.io_head;
 		ctrl->mem_head = res_lists.mem_head;
 		ctrl->p_mem_head = res_lists.p_mem_head;
@@ -1545,7 +1545,7 @@
 		func->is_a_board = 0x01;
 
 		//next, we will instantiate the linux pci_dev structures (with appropriate driver notification, if already present)
-		dbg(__FUNCTION__": configure linux pci_dev structure\n");
+		dbg("%s: configure linux pci_dev structure\n", __FUNCTION__);
 		index = 0;
 		do {
 			new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++);
@@ -1612,7 +1612,7 @@
 	device = func->device;
 
 	hp_slot = func->device - ctrl->slot_device_offset;
-	dbg("In "__FUNCTION__", hp_slot = %d\n", hp_slot);
+	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
 
 	// When we get here, it is safe to change base Address Registers.
 	// We will attempt to save the base Address Register Lengths
@@ -1942,7 +1942,7 @@
 		func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0);
 		dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl);
 		if (!func) {
-			dbg("Error! func NULL in "__FUNCTION__"\n");
+			dbg("Error! func NULL in %s\n", __FUNCTION__);
 			return ;
 		}
 
@@ -1966,7 +1966,7 @@
 		func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0);
 		dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl);
 		if (!func) {
-			dbg("Error! func NULL in "__FUNCTION__"\n");
+			dbg("Error! func NULL in %s\n", __FUNCTION__);
 			return ;
 		}
 
@@ -2081,7 +2081,7 @@
 	}
 
 	if (rc) {
-		dbg(__FUNCTION__": rc = %d\n", rc);
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
 	}
 
 	if (p_slot)
@@ -2347,11 +2347,11 @@
 
 	new_slot = func;
 
-	dbg(__FUNCTION__"\n");
+	dbg("%s\n", __FUNCTION__);
 	// Check for Multi-function device
 	rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0E, &temp_byte);
 	if (rc) {
-		dbg(__FUNCTION__": rc = %d\n", rc);
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
 		return rc;
 	}
 
diff -Nru a/drivers/hotplug/cpqphp_nvram.c b/drivers/hotplug/cpqphp_nvram.c
--- a/drivers/hotplug/cpqphp_nvram.c	Tue Aug  6 07:42:18 2002
+++ b/drivers/hotplug/cpqphp_nvram.c	Wed Aug 20 20:08:28 2003
@@ -1,9 +1,9 @@
 /*
  * Compaq Hot Plug Controller Driver
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
  *
  * All rights reserved.
  *
@@ -160,7 +160,7 @@
 	    (temp6 == 'Q')) {
 		result = 1;
 	}
-	dbg (__FUNCTION__" - returned %d\n", result);
+	dbg ("%s - returned %d\n",__FUNCTION__, result);
 	return result;
 }
 
diff -Nru a/drivers/hotplug/cpqphp_nvram.h b/drivers/hotplug/cpqphp_nvram.h
--- a/drivers/hotplug/cpqphp_nvram.h	Tue Feb  5 12:32:38 2002
+++ b/drivers/hotplug/cpqphp_nvram.h	Thu Aug 28 04:21:26 2003
@@ -1,8 +1,8 @@
 /*
  * Compaq Hot Plug Controller Driver
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/cpqphp_pci.c b/drivers/hotplug/cpqphp_pci.c
--- a/drivers/hotplug/cpqphp_pci.c	Wed Oct  9 02:55:09 2002
+++ b/drivers/hotplug/cpqphp_pci.c	Wed Aug 20 20:08:28 2003
@@ -1,9 +1,9 @@
 /*
  * Compaq Hot Plug Controller Driver
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
  *
  * All rights reserved.
  *
@@ -139,7 +139,7 @@
 		//We did not even find a hotplug rep of the function, create it
 		//This code might be taken out if we can guarantee the creation of functions
 		//in parallel (hotplug and Linux at the same time).
-		dbg("@@@@@@@@@@@ cpqhp_slot_create in "__FUNCTION__"\n");
+		dbg("@@@@@@@@@@@ cpqhp_slot_create in %s\n", __FUNCTION__);
 		temp_func = cpqhp_slot_create(bus->number);
 		if (temp_func == NULL)
 			return -ENOMEM;
@@ -306,7 +306,7 @@
 	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
 	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
 
-	dbg(__FUNCTION__": bus/dev/func = %x/%x/%x\n",func->bus, func->device, func->function);
+	dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function);
 
 	for (j=0; j<8 ; j++) {
 		struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j);
@@ -354,10 +354,10 @@
 	fakedev.devfn = dev_num << 3;
 	fakedev.bus = &fakebus;
 	fakebus.number = bus_num;
-	dbg(__FUNCTION__": dev %d, bus %d, pin %d, num %d\n",
-	    dev_num, bus_num, int_pin, irq_num);
+	dbg("%s: dev %d, bus %d, pin %d, num %d\n",
+	    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
 	rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);
-	dbg(__FUNCTION__":rc %d\n", rc);
+	dbg("%s:rc %d\n", __FUNCTION__, rc);
 	if (!rc)
 		return !rc;
 
@@ -1585,7 +1585,7 @@
 	int rc = 0;
 	struct pci_resource *node;
 	struct pci_resource *t_node;
-	dbg(__FUNCTION__"\n");
+	dbg("%s\n", __FUNCTION__);
 
 	if (!func)
 		return(1);
diff -Nru a/drivers/hotplug/cpqphp_proc.c b/drivers/hotplug/cpqphp_proc.c
--- a/drivers/hotplug/cpqphp_proc.c	Thu Feb 28 05:57:22 2002
+++ b/drivers/hotplug/cpqphp_proc.c	Thu Aug 28 04:21:26 2003
@@ -1,9 +1,9 @@
 /*
  * Compaq Hot Plug Controller Driver
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/ibmphp.h b/drivers/hotplug/ibmphp.h
--- a/drivers/hotplug/ibmphp.h	Fri Sep 13 10:56:25 2002
+++ b/drivers/hotplug/ibmphp.h	Thu Aug 28 04:21:26 2003
@@ -6,8 +6,8 @@
  *
  * Written By: Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation
  *
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001,2002 IBM Corp.
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 IBM Corp.
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c
--- a/drivers/hotplug/ibmphp_core.c	Thu Oct 10 14:42:15 2002
+++ b/drivers/hotplug/ibmphp_core.c	Thu Aug 28 04:21:26 2003
@@ -3,8 +3,8 @@
  *
  * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation
  *
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001,2002 IBM Corp.
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 IBM Corp.
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/ibmphp_ebda.c b/drivers/hotplug/ibmphp_ebda.c
--- a/drivers/hotplug/ibmphp_ebda.c	Sun Jul  6 11:43:56 2003
+++ b/drivers/hotplug/ibmphp_ebda.c	Thu Aug 28 04:21:26 2003
@@ -3,8 +3,8 @@
  *
  * Written By: Tong Yu, IBM Corporation
  *
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001,2002 IBM Corp.
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 IBM Corp.
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/ibmphp_hpc.c b/drivers/hotplug/ibmphp_hpc.c
--- a/drivers/hotplug/ibmphp_hpc.c	Fri Sep 13 10:56:26 2002
+++ b/drivers/hotplug/ibmphp_hpc.c	Thu Aug 28 04:21:26 2003
@@ -3,7 +3,7 @@
  *
  * Written By: Jyoti Shah, IBM Corporation
  *
- * Copyright (c) 2001-2002 IBM Corp.
+ * Copyright (C) 2001-2002 IBM Corp.
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/ibmphp_pci.c b/drivers/hotplug/ibmphp_pci.c
--- a/drivers/hotplug/ibmphp_pci.c	Fri Sep 13 03:14:21 2002
+++ b/drivers/hotplug/ibmphp_pci.c	Thu Aug 28 04:21:26 2003
@@ -3,8 +3,8 @@
  * 
  * Written By: Irene Zubarev, IBM Corporation
  * 
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001,2002 IBM Corp.
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 IBM Corp.
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/ibmphp_res.c b/drivers/hotplug/ibmphp_res.c
--- a/drivers/hotplug/ibmphp_res.c	Fri Sep 13 10:56:26 2002
+++ b/drivers/hotplug/ibmphp_res.c	Thu Aug 28 04:21:26 2003
@@ -3,8 +3,8 @@
  *
  * Written By: Irene Zubarev, IBM Corporation
  *
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001,2002 IBM Corp.
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 IBM Corp.
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h
--- a/drivers/hotplug/pci_hotplug.h	Sat Dec 14 07:57:20 2002
+++ b/drivers/hotplug/pci_hotplug.h	Thu Aug 28 04:21:26 2003
@@ -1,9 +1,9 @@
 /*
  * PCI HotPlug Core Functions
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
  *
  * All rights reserved.
  *
diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
--- a/drivers/hotplug/pci_hotplug_core.c	Sun Sep 29 11:55:11 2002
+++ b/drivers/hotplug/pci_hotplug_core.c	Wed Aug 20 20:08:28 2003
@@ -1,8 +1,8 @@
 /*
  * PCI HotPlug Controller Core
  *
- * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001-2002 IBM Corp.
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2002 IBM Corp.
  *
  * All rights reserved.
  *
@@ -49,7 +49,7 @@
 	#define MY_NAME	THIS_MODULE->name
 #endif
 
-#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0)
+#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0)
 #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
 #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
diff -Nru a/drivers/hotplug/pci_hotplug_util.c b/drivers/hotplug/pci_hotplug_util.c
--- a/drivers/hotplug/pci_hotplug_util.c	Sat Dec 14 07:56:12 2002
+++ b/drivers/hotplug/pci_hotplug_util.c	Wed Aug 20 20:08:28 2003
@@ -1,9 +1,9 @@
 /*
  * PCI HotPlug Utility functions
  *
- * Copyright (c) 1995,2001 Compaq Computer Corporation
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
  *
  * All rights reserved.
  *
@@ -41,7 +41,7 @@
 	#define MY_NAME	THIS_MODULE->name
 #endif
 
-#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0)
+#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0)
 #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
 #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in
--- a/drivers/ide/Config.in	Wed Aug 13 08:41:19 2003
+++ b/drivers/ide/Config.in	Wed Aug 27 13:07:27 2003
@@ -71,6 +71,9 @@
 	    dep_tristate '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
 	    dep_tristate '    SCx200 chipset support' CONFIG_BLK_DEV_SC1200 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_tristate '    ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI
+	    if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ] ; then
+		dep_tristate '    SGI IOC4 chipset support' CONFIG_BLK_DEV_SGIIOC4 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    fi
 	    dep_tristate '    Silicon Image chipset support' CONFIG_BLK_DEV_SIIMAGE $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_tristate '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
 	    dep_tristate '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI
diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile
--- a/drivers/ide/Makefile	Wed Aug 13 08:41:19 2003
+++ b/drivers/ide/Makefile	Sat Aug  9 08:07:32 2003
@@ -48,8 +48,6 @@
 
 obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
 
-obj-$(CONFIG_BLK_DEV_IDE_SIBYTE)	+= ide-sibyte.o
-
 ifeq ($(CONFIG_BLK_DEV_IDE),y)
   obj-y		+= legacy/idedriver-legacy.o
   obj-y		+= ppc/idedriver-ppc.o
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Fri Aug 22 17:49:07 2003
+++ b/drivers/ide/ide-cd.c	Thu Aug 28 09:00:29 2003
@@ -3262,7 +3262,7 @@
 		}
 		if (ide_register_subdriver(drive, 
 				&ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
-			printk("%s: Failed to register the driver with "
+			printk("ide-cd: %s: Failed to register the driver with "
 				"ide.c\n", drive->name);
 			kfree(info);
 			continue;
diff -Nru a/drivers/ide/ide-default.c b/drivers/ide/ide-default.c
--- a/drivers/ide/ide-default.c	Sun Jun 29 08:10:16 2003
+++ b/drivers/ide/ide-default.c	Fri Aug 15 07:53:24 2003
@@ -40,6 +40,21 @@
 {
 }
 
+static int idedefault_open(struct inode *inode, struct file *filp, ide_drive_t *drive)
+{
+	MOD_INC_USE_COUNT;
+	if(filp->f_flags & O_NDELAY)
+		return 0;
+	MOD_DEC_USE_COUNT;
+	drive->usage--;
+	return -ENXIO;
+}
+
+static void idedefault_release(struct inode *inode, struct file *filp, ide_drive_t *drive)
+{
+	MOD_DEC_USE_COUNT;
+}
+
 int idedefault_init (void);
 int idedefault_attach(ide_drive_t *drive);
 
@@ -56,6 +71,8 @@
 	supports_dsc_overlap:	0,
 	init:			idedefault_init,
 	attach:			idedefault_attach,
+	open:			idedefault_open,
+	release:		idedefault_release
 };
 
 static ide_module_t idedefault_module = {
diff -Nru a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
--- a/drivers/ide/ide-geometry.c	Tue Feb 11 09:38:26 2003
+++ b/drivers/ide/ide-geometry.c	Fri Aug 15 06:33:49 2003
@@ -83,7 +83,6 @@
 }
 
 
-extern ide_drive_t * get_info_ptr(kdev_t);
 extern unsigned long current_capacity (ide_drive_t *);
 
 /*
@@ -156,7 +155,7 @@
 	int transl = 1;		/* try translation */
 	int ret = 0;
 
-	drive = get_info_ptr(i_rdev);
+	drive = ide_info_ptr(i_rdev, 0);
 	if (!drive)
 		return 0;
 
diff -Nru a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
--- a/drivers/ide/ide-io.c	Sun Jun 29 08:10:16 2003
+++ b/drivers/ide/ide-io.c	Fri Aug 15 06:42:40 2003
@@ -56,38 +56,6 @@
 
 #include "ide_modes.h"
 
-#if (DISK_RECOVERY_TIME > 0)
-
-Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43
-Does anyone ever use this anyway ??
-
-/*
- * For really screwy hardware (hey, at least it *can* be used with Linux)
- * we can enforce a minimum delay time between successive operations.
- */
-static unsigned long read_timer (ide_hwif_t *hwif)
-{
-	unsigned long t, flags;
-	int i;
-	
-	/* FIXME this is completely unsafe! */
-	local_irq_save(flags);
-	t = jiffies * 11932;
-	outb_p(0, 0x43);
-	i = inb_p(0x40);
-	i |= inb_p(0x40) << 8;
-	local_irq_restore(flags);
-	return (t - i);
-}
-#endif /* DISK_RECOVERY_TIME */
-
-static inline void set_recovery_timer (ide_hwif_t *hwif)
-{
-#if (DISK_RECOVERY_TIME > 0)
-	hwif->last_time = read_timer(hwif);
-#endif /* DISK_RECOVERY_TIME */
-}
-
 /*
  *	ide_end_request		-	complete an IDE I/O
  *	@drive: IDE device for the I/O
@@ -237,6 +205,7 @@
  *	by read a sector's worth of data from the drive.  Of course,
  *	this may not help if the drive is *waiting* for data from *us*.
  */
+
 void try_to_flush_leftover_data (ide_drive_t *drive)
 {
 	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
@@ -573,9 +542,9 @@
 EXPORT_SYMBOL(execute_drive_cmd);
 
 /**
- *	start_request	-	start of I/O and command issuing for IDE
+ *	ide_start_request	-	start of I/O and command issuing for IDE
  *
- *	start_request() initiates handling of a new I/O request. It
+ *	ide_start_request() initiates handling of a new I/O request. It
  *	accepts commands and I/O (read/write) requests. It also does
  *	the final remapping for weird stuff like EZDrive. Once 
  *	device mapper can work sector level the EZDrive stuff can go away
@@ -583,7 +552,7 @@
  *	FIXME: this function needs a rename
  */
  
-ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t ide_start_request (ide_drive_t *drive, struct request *rq)
 {
 	ide_startstop_t startstop;
 	unsigned long block, blockend;
@@ -591,12 +560,12 @@
 	ide_hwif_t *hwif = HWIF(drive);
 
 #ifdef DEBUG
-	printk("%s: start_request: current=0x%08lx\n",
+	printk("%s: ide_start_request: current=0x%08lx\n",
 		hwif->name, (unsigned long) rq);
 #endif
 
 	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+	if (!drive->present || (drive->max_failures && (drive->failures > drive->max_failures))) {
 		goto kill_rq;
 	}
 
@@ -636,10 +605,6 @@
 	if (block == 0 && drive->remap_0_to_1 == 1)
 		block = 1;  /* redirect MBR access to EZ-Drive partn table */
 
-#if (DISK_RECOVERY_TIME > 0)
-	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
-#endif
-
 	SELECT_DRIVE(drive);
 	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
 		printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
@@ -663,16 +628,6 @@
 	return ide_stopped;
 }
 
-EXPORT_SYMBOL(start_request);
-
-int restart_request (ide_drive_t *drive, struct request *rq)
-{
-	(void) start_request(drive, rq);
-	return 0;
-}
-
-EXPORT_SYMBOL(restart_request);
-
 /**
  *	ide_stall_queue		-	pause an IDE device
  *	@drive: drive to stall
@@ -865,7 +820,7 @@
 		spin_unlock(&io_request_lock);
 		local_irq_enable();
 			/* allow other IRQs while we start this request */
-		startstop = start_request(drive, rq);
+		startstop = ide_start_request(drive, rq);
 		spin_lock_irq(&io_request_lock);
 		if (hwif->irq != masked_irq)
 			enable_irq(hwif->irq);
@@ -1043,7 +998,6 @@
 					startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
 				}
 			}
-			set_recovery_timer(hwif);
 			drive->service_time = jiffies - drive->service_start;
 			spin_lock_irq(&io_request_lock);
 			enable_irq(hwif->irq);
@@ -1236,7 +1190,6 @@
 	 * same irq as is currently being serviced here, and Linux
 	 * won't allow another of the same (on any CPU) until we return.
 	 */
-	set_recovery_timer(HWIF(drive));
 	drive->service_time = jiffies - drive->service_start;
 	if (startstop == ide_stopped) {
 		if (hwgroup->handler == NULL) {	/* paranoia */
@@ -1256,7 +1209,7 @@
  * get_info_ptr() returns the (ide_drive_t *) for a given device number.
  * It returns NULL if the given device number does not match any present drives.
  */
-ide_drive_t *get_info_ptr (kdev_t i_rdev)
+ide_drive_t *ide_info_ptr (kdev_t i_rdev, int force)
 {
 	int		major = MAJOR(i_rdev);
 	unsigned int	h;
@@ -1267,7 +1220,7 @@
 			unsigned unit = DEVICE_NR(i_rdev);
 			if (unit < MAX_DRIVES) {
 				ide_drive_t *drive = &hwif->drives[unit];
-				if (drive->present)
+				if (drive->present || force)
 					return drive;
 			}
 			break;
@@ -1276,7 +1229,7 @@
 	return NULL;
 }
 
-EXPORT_SYMBOL(get_info_ptr);
+EXPORT_SYMBOL(ide_info_ptr);
 
 /**
  *	ide_init_drive_cmd	-	initialize a drive command request
diff -Nru a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
--- a/drivers/ide/ide-iops.c	Sun Apr  6 04:29:19 2003
+++ b/drivers/ide/ide-iops.c	Sat Aug  9 07:48:39 2003
@@ -741,6 +741,10 @@
 
 int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
+	/* SATA has no cable restrictions */
+	if (HWIF(drive)->sata)
+		return 0;
+		
 	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
 	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
 	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Fri Jul  4 10:12:45 2003
+++ b/drivers/ide/ide-probe.c	Tue Aug  5 05:04:13 2003
@@ -553,7 +553,7 @@
 }
 
 /**
- *	probe_for_drives	-	upper level drive probe
+ *	ide_probe_for_drives	-	upper level drive probe
  *	@drive: drive to probe for
  *
  *	probe_for_drive() tests for existence of a given drive using do_probe()
@@ -564,7 +564,7 @@
  *			   still be 0)
  */
  
-static inline u8 probe_for_drive (ide_drive_t *drive)
+u8 ide_probe_for_drive (ide_drive_t *drive)
 {
 	/*
 	 *	In order to keep things simple we have an id
@@ -687,9 +687,6 @@
 
 //EXPORT_SYMBOL(hwif_register);
 
-/* Enable code below on all archs later, for now, I want it on PPC
- */
-#ifdef CONFIG_PPC
 /*
  * This function waits for the hwif to report a non-busy status
  * see comments in probe_hwif()
@@ -716,7 +713,7 @@
 	return ((stat & BUSY_STAT) == 0) ? 0 : -EBUSY;
 }
 
-static int wait_hwif_ready(ide_hwif_t *hwif)
+int ide_wait_hwif_ready(ide_hwif_t *hwif)
 {
 	int rc;
 
@@ -751,7 +748,67 @@
 	
 	return rc;
 }
-#endif /* CONFIG_PPC */
+
+void ide_probe_reset(ide_hwif_t *hwif)
+{
+	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
+		unsigned long timeout = jiffies + WAIT_WORSTCASE;
+		u8 stat;
+
+		printk(KERN_WARNING "%s: reset\n", hwif->name);
+		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		udelay(10);
+		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		do {
+			ide_delay_50ms();
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
+	}
+}
+
+void ide_tune_drives(ide_hwif_t *hwif)
+{
+	int unit;
+	
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+		int enable_dma = 1;
+
+		if (drive->present) {
+			if (hwif->tuneproc != NULL && 
+				drive->autotune == IDE_TUNE_AUTO)
+				/* auto-tune PIO mode */
+				hwif->tuneproc(drive, 255);
+
+#ifdef CONFIG_IDEDMA_ONLYDISK
+			if (drive->media != ide_disk)
+				enable_dma = 0;
+#endif
+			/*
+			 * MAJOR HACK BARF :-/
+			 *
+			 * FIXME: chipsets own this cruft!
+			 */
+			/*
+			 * Move here to prevent module loading clashing.
+			 */
+	//		drive->autodma = hwif->autodma;
+			if ((hwif->ide_dma_check) &&
+				((drive->autotune == IDE_TUNE_DEFAULT) ||
+				(drive->autotune == IDE_TUNE_AUTO))) {
+				/*
+				 * Force DMAing for the beginning of the check.
+				 * Some chipsets appear to do interesting
+				 * things, if not checked and cleared.
+				 *   PARANOIA!!!
+				 */
+				hwif->ide_dma_off_quietly(drive);
+				if (enable_dma)
+					hwif->ide_dma_check(drive);
+			}
+		}
+	}
+}
 
 /*
  * This routine only knows how to look for drive units 0 and 1
@@ -834,7 +891,7 @@
 		ide_drive_t *drive = &hwif->drives[unit];
 		drive->dn = ((hwif->channel ? 2 : 0) + unit);
 		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
-		(void) probe_for_drive(drive);
+		(void) ide_probe_for_drive(drive);
 		if (drive->present && !hwif->present) {
 			hwif->present = 1;
 			if (hwif->chipset != ide_4drives ||
@@ -844,20 +901,8 @@
 			}
 		}
 	}
-	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
-		unsigned long timeout = jiffies + WAIT_WORSTCASE;
-		u8 stat;
-
-		printk(KERN_WARNING "%s: reset\n", hwif->name);
-		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		udelay(10);
-		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		do {
-			ide_delay_50ms();
-			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
-		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
-
-	}
+	
+	ide_probe_reset(hwif);
 	local_irq_restore(flags);
 	/*
 	 * Use cached IRQ number. It might be (and is...) changed by probe
@@ -865,45 +910,9 @@
 	 */
 	if (irqd)
 		enable_irq(irqd);
+		
+	ide_tune_drives(hwif);
 
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-		int enable_dma = 1;
-
-		if (drive->present) {
-			if (hwif->tuneproc != NULL && 
-				drive->autotune == IDE_TUNE_AUTO)
-				/* auto-tune PIO mode */
-				hwif->tuneproc(drive, 255);
-
-#ifdef CONFIG_IDEDMA_ONLYDISK
-			if (drive->media != ide_disk)
-				enable_dma = 0;
-#endif
-			/*
-			 * MAJOR HACK BARF :-/
-			 *
-			 * FIXME: chipsets own this cruft!
-			 */
-			/*
-			 * Move here to prevent module loading clashing.
-			 */
-	//		drive->autodma = hwif->autodma;
-			if ((hwif->ide_dma_check) &&
-				((drive->autotune == IDE_TUNE_DEFAULT) ||
-				(drive->autotune == IDE_TUNE_AUTO))) {
-				/*
-				 * Force DMAing for the beginning of the check.
-				 * Some chipsets appear to do interesting
-				 * things, if not checked and cleared.
-				 *   PARANOIA!!!
-				 */
-				hwif->ide_dma_off_quietly(drive);
-				if (enable_dma)
-					hwif->ide_dma_check(drive);
-			}
-		}
-	}
 }
 
 EXPORT_SYMBOL(probe_hwif);
@@ -1334,13 +1343,6 @@
 }
 
 EXPORT_SYMBOL(export_ide_init_queue);
-
-u8 export_probe_for_drive (ide_drive_t *drive)
-{
-	return probe_for_drive(drive);
-}
-
-EXPORT_SYMBOL(export_probe_for_drive);
 
 #ifndef HWIF_PROBE_CLASSIC_METHOD
 int probe_hwif_init (ide_hwif_t *hwif)
diff -Nru a/drivers/ide/ide-sibyte.c b/drivers/ide/ide-sibyte.c
--- a/drivers/ide/ide-sibyte.c	Mon Aug 18 18:20:49 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
- *
- * 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.
- */
-
-/*  Derived loosely from ide-pmac.c, so:
- *  
- *  Copyright (C) 1998 Paul Mackerras.
- *  Copyright (C) 1995-1998 Mark Lord
- */
-#include <linux/kernel.h>
-#include <linux/ide.h>
-
-#include <asm/sibyte/board.h>
-
-#define SIBYTE_IDE_BASE        (IO_SPACE_BASE + IDE_PHYS - mips_io_port_base)
-#define SIBYTE_IDE_REG(pcaddr) (SIBYTE_IDE_BASE + ((pcaddr) << 5))
-
-extern void sibyte_set_ideops(ide_hwif_t *hwif);
-
-void __init sibyte_ide_probe(void)
-{
-	int i;
-	ide_hwif_t *hwif = NULL;
-
-	/* 
-	 * Find the first untaken slot in hwifs.  Also set the io ops
-	 * to the non-swapping SiByte versions.  XXXKW It would be
-	 * nice to find a safe place to do this outside of
-	 * ide-sibyte.c so PCI-IDE would work without the SiByte
-	 * driver.
-	 */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		sibyte_set_ideops(&ide_hwifs[i]);
-		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET] && (hwif == NULL)) {
-			hwif = &ide_hwifs[i];
-		}
-	}
-	if (hwif == NULL) {
-		printk("No space for SiByte onboard IDE driver in ide_hwifs[].  Not enabled.\n");
-		return;
-	}
-
-	/*
-	 * Set up our stuff; we're a little odd because our io_ports
-	 * aren't in the usual place, and byte-swapping isn't
-	 * necessary.
-	 */
-	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SIBYTE_IDE_REG(0x1f0);
-	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SIBYTE_IDE_REG(0x1f1);
-	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SIBYTE_IDE_REG(0x1f2);
-	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SIBYTE_IDE_REG(0x1f3);
-	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f4);
-	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f5);
-	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SIBYTE_IDE_REG(0x1f6);
-	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SIBYTE_IDE_REG(0x1f7);
-	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SIBYTE_IDE_REG(0x3f6);
-	hwif->hw.irq                          = K_INT_GB_IDE;
-	hwif->irq                             = hwif->hw.irq;
-	hwif->noprobe                         = 0;
-	hwif->hw.ack_intr                     = NULL;
-	hwif->mmio                            = 2;
-
-	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-	printk("SiByte onboard IDE configured as device %i\n", hwif-ide_hwifs);
-}
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Wed Aug  6 05:53:35 2003
+++ b/drivers/ide/ide.c	Sat Aug 16 07:19:59 2003
@@ -248,6 +248,7 @@
 	hwif->ultra_mask = 0x80;	/* disable all ultra */
 	hwif->mwdma_mask = 0x80;	/* disable all mwdma */
 	hwif->swdma_mask = 0x80;	/* disable all swdma */
+	hwif->sata = 0;			/* assume PATA */
 
 	default_hwif_iops(hwif);
 	default_hwif_transport(hwif);
@@ -458,7 +459,7 @@
 	unsigned int p, major, minor;
 	unsigned long flags;
 
-	if ((drive = get_info_ptr(i_rdev)) == NULL)
+	if ((drive = ide_info_ptr(i_rdev, 0)) == NULL)
 		return -ENODEV;
 	major = MAJOR(i_rdev);
 	minor = drive->select.b.unit << PARTN_BITS;
@@ -547,30 +548,48 @@
 static int ide_open (struct inode * inode, struct file * filp)
 {
 	ide_drive_t *drive;
+	int force = 1/*FIXME 0*/;
+	
+	if(capable(CAP_SYS_ADMIN) && (filp->f_flags & O_NDELAY))
+		force = 1;
 
-	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
+	if ((drive = ide_info_ptr(inode->i_rdev, force)) == NULL)
 		return -ENXIO;
-	if (drive->driver == &idedefault_driver)
-		ide_driver_module(1);
-	if (drive->driver == &idedefault_driver) {
-		if (drive->media == ide_disk)
-			(void) request_module("ide-disk");
-		if (drive->scsi)
-			(void) request_module("ide-scsi");
-		if (drive->media == ide_cdrom)
-			(void) request_module("ide-cd");
-		if (drive->media == ide_tape)
-			(void) request_module("ide-tape");
-		if (drive->media == ide_floppy)
-			(void) request_module("ide-floppy");
+	
+	/*
+	 *	If the device is present make sure that we attach any
+	 *	needed driver
+	 */	
+
+	if (drive->present)
+	{
+		if (drive->driver == &idedefault_driver)
+			ide_driver_module(1);
+		if (drive->driver == &idedefault_driver) {
+			if (drive->media == ide_disk)
+				(void) request_module("ide-disk");
+			if (drive->scsi)
+				(void) request_module("ide-scsi");
+			if (drive->media == ide_cdrom)
+				(void) request_module("ide-cd");
+			if (drive->media == ide_tape)
+				(void) request_module("ide-tape");
+			if (drive->media == ide_floppy)
+				(void) request_module("ide-floppy");
+		}
+	
+		/* The locking here isnt enough, but this is hard to fix
+		   in the 2.4 cases */
+		while (drive->busy)
+			sleep_on(&drive->wqueue);
 	}
 	
-	/* The locking here isnt enough, but this is hard to fix
-	   in the 2.4 cases */
-	while (drive->busy)
-		sleep_on(&drive->wqueue);
+	/*
+	 *	Now do the actual open
+	 */
+	 
 	drive->usage++;
-	if (!drive->dead)
+	if (!drive->dead || force)
 		return DRIVER(drive)->open(inode, filp, drive);
 	printk(KERN_WARNING "%s: driver not present\n", drive->name);
 	drive->usage--;
@@ -585,7 +604,7 @@
 {
 	ide_drive_t *drive;
 
-	if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
+	if ((drive = ide_info_ptr(inode->i_rdev, 1)) != NULL) {
 		drive->usage--;
 		DRIVER(drive)->release(inode, file, drive);
 	}
@@ -636,6 +655,179 @@
 
 extern void init_hwif_data(unsigned int index);
 
+/**
+ *	ide_prepare_tristate	-	prepare interface for warm unplug
+ *	@drive: drive on this hwif we are using
+ *
+ *	Prepares a drive for shutdown after a bus tristate. The
+ *	drives must be quiescent and the only user the calling ioctl
+ */
+ 
+static int ide_prepare_tristate(ide_drive_t *our_drive)
+{
+	ide_drive_t *drive;
+	int unit;
+	unsigned long flags;
+	int minor;
+	int p;
+	int i;
+	ide_hwif_t *hwif = HWIF(our_drive);
+		
+	if(our_drive->busy)
+		printk("HUH? We are busy.\n");
+		
+	if (!hwif->present)
+		BUG();
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	/* Abort if anything is busy */
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		drive = &hwif->drives[unit];
+		if (!drive->present)
+			continue;
+		if (drive == our_drive && drive->usage != 1)
+			goto abort;
+		if (drive != our_drive && drive->usage)
+			goto abort;
+		if (drive->busy)
+			goto abort;
+	}
+	/* Commit to shutdown sequence */
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		drive = &hwif->drives[unit];
+		if (!drive->present)
+			continue;
+		if (drive != our_drive && DRIVER(drive)->shutdown(drive))
+			goto abort;
+	}
+	/* We hold the lock here.. which is important as we need to play
+	   with usage counts beyond the scenes */
+	   
+	our_drive->usage--;
+	i = DRIVER(our_drive)->shutdown(our_drive);
+	if(i)
+		goto abort_fix;
+	/* Drive shutdown sequence done */
+	/* Prevent new opens ?? */
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	/*
+	 * Flush kernel side caches, and dump the /proc files
+	 */
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		drive = &hwif->drives[unit];
+		if (!drive->present)
+			continue;
+		DRIVER(drive)->cleanup(drive);
+		minor = drive->select.b.unit << PARTN_BITS;
+		for (p = 0; p < (1<<PARTN_BITS); ++p) {
+			if (drive->part[p].nr_sects > 0) {
+				kdev_t devp = MKDEV(hwif->major, minor+p);
+				invalidate_device(devp, 0);
+			}
+		}
+#ifdef CONFIG_PROC_FS
+		destroy_proc_ide_drives(hwif);
+#endif
+	}
+	spin_lock_irqsave(&io_request_lock, flags);
+	our_drive->usage++;
+	for (i = 0; i < MAX_DRIVES; ++i) {
+		drive = &hwif->drives[i];
+		if (drive->de) {
+			devfs_unregister(drive->de);
+			drive->de = NULL;
+		}
+		if (!drive->present)
+			continue;
+		if (drive->id != NULL) {
+			kfree(drive->id);
+			drive->id = NULL;
+		}
+		drive->present = 0;
+		/* Safe to clear now */
+		drive->dead = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 0;
+
+abort_fix:
+	our_drive->usage++;
+abort:
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return -EBUSY;
+}
+
+
+/**
+ *	ide_resume_hwif		-	return a hwif to active mode
+ *	@hwif: interface to resume
+ *	
+ *	Restore a dead interface from tristate back to normality. At this
+ *	point the hardware driver busproc has reconnected the bus, but
+ *	nothing else has happened
+ */
+ 
+static int ide_resume_hwif(ide_drive_t *our_drive)
+{
+	ide_hwif_t *hwif = HWIF(our_drive);
+	int err = ide_wait_hwif_ready(hwif);
+	int irqd;
+	int present = 0;
+	int unit;
+		
+	if(err)
+	{
+		printk(KERN_ERR "%s: drives not ready.\n", our_drive->name);
+		return err;
+	}
+		
+	/* The drives are now taking commands */
+	
+	irqd = hwif->irq;
+	if(irqd)
+		disable_irq(irqd);
+		
+	/* Identify and probe the drives */
+	
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+		drive->dn = ((hwif->channel ? 2 : 0) + unit);
+		drive->usage = 0;
+		drive->busy = 0;
+		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		(void) ide_probe_for_drive(drive);
+		if (drive->present)
+			present = 1;
+	}
+	ide_probe_reset(hwif);
+	if(irqd)
+		enable_irq(irqd);
+	
+	if(present)
+		printk(KERN_INFO "ide: drives found on hot-added interface.\n");
+			
+	/*
+	 *	Set up the drive modes (Even if we didnt swap drives
+	 *	we may have lost settings when we disconnected the bus)
+	 */
+	 
+	ide_tune_drives(hwif);
+	if(present)
+		hwif->present = 1;
+		
+	/*
+	 *	Reattach the devices to drivers
+	 */
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+		if(drive->present && !drive->dead)
+			ide_attach_drive(drive);
+	}
+	our_drive->usage++;
+	return 0;
+}
+
 int ide_unregister (unsigned int index)
 {
 	struct gendisk *gd;
@@ -798,7 +990,7 @@
 	hwif->swdma_mask		= old_hwif.swdma_mask;
 
 	hwif->chipset			= old_hwif.chipset;
-	hwif->hold                      = old_hwif.hold;
+	hwif->hold			= old_hwif.hold;
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	hwif->pci_dev			= old_hwif.pci_dev;
@@ -1534,11 +1726,22 @@
 	struct request rq;
 	kdev_t dev;
 	ide_settings_t *setting;
-
+	int force = 0;
+	
 	if (!inode || !(dev = inode->i_rdev))
 		return -EINVAL;
+		
+	switch(cmd)
+	{
+		case HDIO_GET_BUSSTATE:
+		case HDIO_SET_BUSSTATE:
+		case HDIO_SCAN_HWIF:
+		case HDIO_UNREGISTER_HWIF:
+			force = 1;
+	}
+	
 	major = MAJOR(dev); minor = MINOR(dev);
-	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
+	if ((drive = ide_info_ptr(inode->i_rdev, force)) == NULL)
 		return -ENODEV;
 
 	down(&ide_setting_sem);
@@ -1737,11 +1940,42 @@
 			return 0;
 
 		case HDIO_SET_BUSSTATE:
+		{
+			ide_hwif_t *hwif =  HWIF(drive);
+			
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
-			if (HWIF(drive)->busproc)
+#ifdef OLD_STUFF
+			if (hwif->busproc)
 				return HWIF(drive)->busproc(drive, (int)arg);
 			return -EOPNOTSUPP;
+#else
+			if(hwif->bus_state == arg)
+				return 0;
+				
+			if(hwif->bus_state == BUSSTATE_ON)
+			{
+				/* "drive" may vanish beyond here */
+				if((err = ide_prepare_tristate(drive)) != 0)
+					return err;
+				hwif->bus_state = arg;
+			}
+			if (hwif->busproc)
+			{
+				err = hwif->busproc(drive, (int)arg);
+				if(err)
+					return err;
+			}
+			if(arg != BUSSTATE_OFF)
+			{
+				err = ide_resume_hwif(drive);
+				hwif->bus_state = arg;
+				if(err)
+					return err;
+			}
+			return 0;
+#endif			
+		}				
 
 		default:
 			return DRIVER(drive)->ioctl(drive, inode, file, cmd, arg);
@@ -1753,7 +1987,7 @@
 {
 	ide_drive_t *drive;
 
-	if ((drive = get_info_ptr(i_rdev)) == NULL)
+	if ((drive = ide_info_ptr(i_rdev, 0)) == NULL)
 		return -ENODEV;
 	return DRIVER(drive)->media_change(drive);
 }
diff -Nru a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
--- a/drivers/ide/legacy/Makefile	Thu Dec  5 07:04:15 2002
+++ b/drivers/ide/legacy/Makefile	Thu Aug 28 09:02:35 2003
@@ -17,7 +17,10 @@
 obj-$(CONFIG_BLK_DEV_MAC_IDE)		+= macide.o
 obj-$(CONFIG_BLK_DEV_Q40IDE)		+= q40ide.o
 
+obj-$(CONFIG_BLK_DEV_IDE_SIBYTE)	+= sibyte.o
+
 obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
+
 
 # Last of all
 obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
diff -Nru a/drivers/ide/legacy/sibyte.c b/drivers/ide/legacy/sibyte.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/sibyte.c	Thu Aug 28 09:01:47 2003
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
+ *
+ * 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.
+ */
+
+/*  Derived loosely from ide-pmac.c, so:
+ *  
+ *  Copyright (C) 1998 Paul Mackerras.
+ *  Copyright (C) 1995-1998 Mark Lord
+ */
+#include <linux/kernel.h>
+#include <linux/ide.h>
+
+#include <asm/sibyte/board.h>
+
+#define SIBYTE_IDE_BASE        (IO_SPACE_BASE + IDE_PHYS - mips_io_port_base)
+#define SIBYTE_IDE_REG(pcaddr) (SIBYTE_IDE_BASE + ((pcaddr) << 5))
+
+extern void sibyte_set_ideops(ide_hwif_t *hwif);
+
+void __init sibyte_ide_probe(void)
+{
+	int i;
+	ide_hwif_t *hwif = NULL;
+
+	/* 
+	 * Find the first untaken slot in hwifs.  Also set the io ops
+	 * to the non-swapping SiByte versions.  XXXKW It would be
+	 * nice to find a safe place to do this outside of
+	 * ide-sibyte.c so PCI-IDE would work without the SiByte
+	 * driver.
+	 */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		sibyte_set_ideops(&ide_hwifs[i]);
+		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET] && (hwif == NULL)) {
+			hwif = &ide_hwifs[i];
+		}
+	}
+	if (hwif == NULL) {
+		printk("No space for SiByte onboard IDE driver in ide_hwifs[].  Not enabled.\n");
+		return;
+	}
+
+	/*
+	 * Set up our stuff; we're a little odd because our io_ports
+	 * aren't in the usual place, and byte-swapping isn't
+	 * necessary.
+	 */
+	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SIBYTE_IDE_REG(0x1f0);
+	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SIBYTE_IDE_REG(0x1f1);
+	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SIBYTE_IDE_REG(0x1f2);
+	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SIBYTE_IDE_REG(0x1f3);
+	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f4);
+	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f5);
+	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SIBYTE_IDE_REG(0x1f6);
+	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SIBYTE_IDE_REG(0x1f7);
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SIBYTE_IDE_REG(0x3f6);
+	hwif->hw.irq                          = K_INT_GB_IDE;
+	hwif->irq                             = hwif->hw.irq;
+	hwif->noprobe                         = 0;
+	hwif->hw.ack_intr                     = NULL;
+	hwif->mmio                            = 2;
+
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	printk(KERN_INFO "SiByte onboard IDE configured as device %i\n", hwif-ide_hwifs);
+}
diff -Nru a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
--- a/drivers/ide/pci/Makefile	Tue Mar 11 11:29:21 2003
+++ b/drivers/ide/pci/Makefile	Wed Aug 27 13:07:27 2003
@@ -25,6 +25,7 @@
 obj-$(CONFIG_BLK_DEV_RZ1000)		+= rz1000.o
 obj-$(CONFIG_BLK_DEV_SVWKS)		+= serverworks.o
 obj-$(CONFIG_BLK_DEV_SC1200)		+= sc1200.o
+obj-$(CONFIG_BLK_DEV_SGIIOC4)		+= sgiioc4.o
 obj-$(CONFIG_BLK_DEV_SIIMAGE)		+= siimage.o
 obj-$(CONFIG_BLK_DEV_SIS5513)		+= sis5513.o
 obj-$(CONFIG_BLK_DEV_SL82C105)		+= sl82c105.o
diff -Nru a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
--- a/drivers/ide/pci/piix.c	Sat May  3 10:48:58 2003
+++ b/drivers/ide/pci/piix.c	Tue Aug  5 04:56:56 2003
@@ -599,6 +599,65 @@
 }
 
 /**
+ *	ich3_busproc		-	bus isolation ioctl
+ *	@drive: drive to isolate/restore
+ *	@state: bus state to set
+ *
+ *	Used by the ICH3 to handle bus isolation. We have to do
+ *	a little bit of fixing to keep the hardware happy.
+ */
+ 
+static int ich3_busproc (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 sig_mode;
+	int shift;
+	int bits;
+	
+	if(hwif->channel == 0)
+		shift = 17;
+	else
+		shift = 19;
+		
+	switch (state) {
+		case BUSSTATE_ON:
+			bits = 0x00;
+			hwif->drives[0].failures = 0;
+			hwif->drives[1].failures = 0;
+			break;
+		case BUSSTATE_OFF:
+			bits = 0x01;
+			break;
+		case BUSSTATE_TRISTATE:
+			bits = 0x10;
+			break;
+		default:
+			return -EINVAL;
+	}
+	
+	if(bits)
+	{
+		int port = hwif->channel == 0 ? 0x40 : 0x42;
+		u16 reg;
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		/* Turn off IORDY checking to avoid hangs */
+		pci_read_config_word(hwif->pci_dev, port, &reg);
+		reg&=~(1<<5)|(1<<1);
+		pci_write_config_word(hwif->pci_dev, port, reg);
+	}
+	/* Todo: Check locking */
+	pci_read_config_dword(hwif->pci_dev, 0x54, &sig_mode);
+	sig_mode&=~(3<<shift);
+	sig_mode|=(bits<<shift);
+	pci_write_config_dword(hwif->pci_dev, 0x54, sig_mode);
+
+	hwif->bus_state = state;
+	return 0;
+}
+
+
+/**
  *	init_chipset_piix	-	set up the PIIX chipset
  *	@dev: PCI device to set up
  *	@name: Name of the device
@@ -693,6 +752,10 @@
 		case PCI_DEVICE_ID_INTEL_82801AB_1:
 			hwif->ultra_mask = 0x07;
 			break;
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+			hwif->busproc = ich3_busproc;
+			/* fall through */
 		default:
 			pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
 			pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
diff -Nru a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/sgiioc4.c	Wed Aug 27 13:07:27 2003
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <asm/io.h>
+#include "sgiioc4.h"
+
+extern int dma_timer_expiry(ide_drive_t * drive);
+
+#ifdef CONFIG_PROC_FS
+static u8 sgiioc4_proc;
+#endif /* CONFIG_PROC_FS */
+
+static int n_sgiioc4_devs ;
+
+static inline void
+xide_delay(long ticks)
+{
+	if (!ticks)
+		return;
+
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(ticks);
+}
+
+static void __init
+sgiioc4_ide_setup_pci_device(struct pci_dev *dev, const char *name)
+{
+	unsigned long base = 0, ctl = 0, dma_base = 0, irqport = 0;
+	ide_hwif_t *hwif = NULL;
+	int h = 0;
+
+	/*  Get the CmdBlk and CtrlBlk Base Registers */
+	base = pci_resource_start(dev, 0) + IOC4_CMD_OFFSET;
+	ctl = pci_resource_start(dev, 0) + IOC4_CTRL_OFFSET;
+	irqport = pci_resource_start(dev, 0) + IOC4_INTR_OFFSET;
+	dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
+
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		/* Find an empty HWIF */
+		if (hwif->chipset == ide_unknown)
+			break;
+	}
+
+	if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+		/* Initialize the IO registers */
+		sgiioc4_init_hwif_ports(&hwif->hw, base, ctl, irqport);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof (hwif->io_ports));
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+	}
+
+	hwif->chipset = ide_pci;
+	hwif->pci_dev = dev;
+	hwif->channel = 0;	/* Single Channel chip */
+	hwif->hw.ack_intr = &sgiioc4_checkirq;	/* MultiFunction Chip */
+
+	/* Initializing chipset IRQ Registers */
+	hwif->OUTL(0x03, irqport + IOC4_INTR_SET * 4);
+
+	(void) ide_init_sgiioc4(hwif);
+
+	if (dma_base)
+		ide_dma_sgiioc4(hwif, dma_base);
+	else
+		printk(KERN_INFO "%s: %s Bus-Master DMA disabled \n", hwif->name, name);
+}
+
+/* XXX Hack to ensure we can build this for generic kernels without
+ * having all the SN2 code sync'd and merged.  For now this is
+ * acceptable but this should be resolved ASAP. PV#: 896401 */
+
+pciio_endian_t __attribute__((weak)) snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, pciio_endian_t desired_end);
+
+static unsigned int __init
+pci_init_sgiioc4(struct pci_dev *dev, const char *name)
+{
+
+	if (pci_enable_device(dev)) {
+		printk(KERN_INFO "Failed to enable device %s at slot %s \n",name,dev->slot_name);
+		return 1;
+	}
+	pci_set_master(dev);
+
+	/* Enable Byte Swapping in the PIC... */
+	if (snia_pciio_endian_set) {
+		/* ... if the symbol exists (hack to get this to build
+		 * for SuSE before we merge the SN2 code */
+		snia_pciio_endian_set(dev, PCIDMA_ENDIAN_LITTLE, PCIDMA_ENDIAN_BIG);
+	} else {
+		printk(KERN_INFO "Failed to set endianness for device %s at slot %s \n", name, dev->slot_name);
+		return 1;
+	}
+
+#ifdef CONFIG_PROC_FS
+	sgiioc4_devs[n_sgiioc4_devs++] = dev;
+	if (!sgiioc4_proc) {
+		sgiioc4_proc = 1;
+		ide_pci_register_host_proc(&sgiioc4_procs[0]);
+	}
+#endif
+	sgiioc4_ide_setup_pci_device(dev, name);
+	return 0;
+}
+
+static void
+sgiioc4_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port,
+			ide_ioreg_t ctrl_port, ide_ioreg_t irq_port)
+{
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw->io_ports[i] = reg + i * 4;	/* Registers are word (32 bit) aligned */
+
+	if (ctrl_port)
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+
+	if (irq_port)
+		hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+}
+
+static void
+sgiioc4_resetproc(ide_drive_t * drive)
+{
+	sgiioc4_ide_dma_end(drive);
+	sgiioc4_clearirq(drive);
+}
+
+static void
+sgiioc4_maskproc(ide_drive_t * drive, int mask)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2), IDE_CONTROL_REG);
+}
+
+static void __init
+ide_init_sgiioc4(ide_hwif_t * hwif)
+{
+	hwif->autodma = 1;
+	hwif->index = 0;	/* Channel 0 */
+	hwif->channel = 0;
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x0;	/* Disable Ultra DMA */
+	hwif->mwdma_mask = 0x2;	/* Multimode-2 DMA  */
+	hwif->swdma_mask = 0x2;
+	hwif->identify = NULL;
+	hwif->tuneproc = NULL;	/* Sets timing for PIO mode */
+	hwif->speedproc = NULL;	/* Sets timing for DMA &/or PIO modes */
+	hwif->selectproc = NULL;	/* Use the default selection routine to select drive */
+	hwif->reset_poll = NULL;	/* No HBA specific reset_poll needed */
+	hwif->pre_reset = NULL;	/* No HBA specific pre_set needed */
+	hwif->resetproc = &sgiioc4_resetproc;	/* Reset the IOC4 DMA engine, clear interrupts etc */
+	hwif->intrproc = NULL;	/* Enable or Disable interrupt from drive */
+	hwif->maskproc = &sgiioc4_maskproc;	/* Mask on/off NIEN register */
+	hwif->quirkproc = NULL;
+	hwif->busproc = NULL;
+
+	hwif->ide_dma_read = &sgiioc4_ide_dma_read;
+	hwif->ide_dma_write = &sgiioc4_ide_dma_write;
+	hwif->ide_dma_begin = &sgiioc4_ide_dma_begin;
+	hwif->ide_dma_end = &sgiioc4_ide_dma_end;
+	hwif->ide_dma_check = &sgiioc4_ide_dma_check;
+	hwif->ide_dma_on = &sgiioc4_ide_dma_on;
+	hwif->ide_dma_off = &sgiioc4_ide_dma_off;
+	hwif->ide_dma_off_quietly = &sgiioc4_ide_dma_off_quietly;
+	hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
+	hwif->ide_dma_host_on = &sgiioc4_ide_dma_host_on;
+	hwif->ide_dma_host_off = &sgiioc4_ide_dma_host_off;
+	hwif->ide_dma_bad_drive = &__ide_dma_bad_drive;
+	hwif->ide_dma_good_drive = &__ide_dma_good_drive;
+	hwif->ide_dma_count = &sgiioc4_ide_dma_count;
+	hwif->ide_dma_verbose = &sgiioc4_ide_dma_verbose;
+	hwif->ide_dma_retune = &__ide_dma_retune;
+	hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &sgiioc4_ide_dma_timeout;
+	hwif->INB = &sgiioc4_INB;
+}
+
+static int
+sgiioc4_ide_dma_read(ide_drive_t * drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	unsigned int count = 0;
+
+	if (!(count = sgiioc4_build_dma_table(drive, rq, PCI_DMA_FROMDEVICE))) {
+		/* try PIO instead of DMA */
+		return 1;
+	}
+	/* Writes FROM the IOC4 TO Main Memory */
+	sgiioc4_configure_for_dma(IOC4_DMA_WRITE, drive);
+
+	return 0;
+}
+
+static int
+sgiioc4_ide_dma_write(ide_drive_t * drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	unsigned int count = 0;
+
+	if (!(count = sgiioc4_build_dma_table(drive, rq, PCI_DMA_TODEVICE))) {
+		/* try PIO instead of DMA */
+		return 1;
+	}
+
+	sgiioc4_configure_for_dma(IOC4_DMA_READ, drive);
+	/* Writes TO the IOC4 FROM Main Memory */
+
+	return 0;
+}
+
+static int
+sgiioc4_ide_dma_begin(ide_drive_t * drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned int reg = hwif->INL(hwif->dma_base + IOC4_DMA_CTRL * 4);
+	unsigned int temp_reg = reg | IOC4_S_DMA_START;
+
+	hwif->OUTL(temp_reg, hwif->dma_base + IOC4_DMA_CTRL * 4);
+
+	return 0;
+}
+
+/* Stops the IOC4 DMA Engine */
+static int
+sgiioc4_ide_dma_end(ide_drive_t * drive)
+{
+	u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0;
+	ide_hwif_t *hwif = HWIF(drive);
+	uint64_t dma_base = hwif->dma_base;
+	int dma_stat = 0, count;
+	unsigned long *ending_dma = (unsigned long *) hwif->dma_base2;
+
+	hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
+
+	count = 0;
+	do {
+		xide_delay(count);
+		ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+		count += 10;
+	} while ((ioc4_dma & IOC4_S_DMA_STOP) && (count < 100));
+
+	if (ioc4_dma & IOC4_S_DMA_STOP) {
+		printk(KERN_ERR "sgiioc4_stopdma(%s): IOC4 DMA STOP bit is still 1 : ioc4_dma_reg 0x%x\n", drive->name, ioc4_dma);
+		dma_stat = 1;
+	}
+
+	if (ending_dma) {
+		do {
+			for (num = 0; num < 16; num++) {
+				if (ending_dma[num] & (~0ul)) {
+					valid = 1;
+					break;
+				}
+			}
+			xide_delay(cnt);
+		} while ((cnt++ < 100) && (!valid));
+	}
+
+	if (!valid)
+		printk(KERN_INFO "sgiioc4_ide_dma_end(%s) : Stale DMA Data in Memory\n", drive->name);
+
+	bc_dev = hwif->INL(dma_base + IOC4_BC_DEV * 4);
+	bc_mem = hwif->INL(dma_base + IOC4_BC_MEM * 4);
+
+	if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) {
+		if (bc_dev > bc_mem + 8) {
+			printk(KERN_ERR "sgiioc4_ide_dma_end(%s) : WARNING!!! byte_count_at_dev %d != byte_count_at_mem %d\n",
+			       drive->name, bc_dev, bc_mem);
+		}
+	}
+
+	drive->waiting_for_dma = 0;
+	ide_destroy_dmatable(drive);
+
+	return dma_stat;
+}
+
+static int
+sgiioc4_ide_dma_check(ide_drive_t * drive)
+{
+	if (ide_config_drive_speed(drive,XFER_MW_DMA_2)!=0) {
+		printk(KERN_INFO "Couldnot set %s in Multimode-2 DMA mode | Drive %s using PIO instead\n",
+				drive->name, drive->name);
+		drive->using_dma = 0;
+	} else
+		drive->using_dma = 1;
+
+	return 0;
+}
+
+static int
+sgiioc4_ide_dma_on(ide_drive_t * drive)
+{
+	drive->using_dma = 1;
+
+	return HWIF(drive)->ide_dma_host_on(drive);
+}
+
+static int
+sgiioc4_ide_dma_off(ide_drive_t * drive)
+{
+	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
+
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+static int
+sgiioc4_ide_dma_off_quietly(ide_drive_t * drive)
+{
+	drive->using_dma = 0;
+
+	return HWIF(drive)->ide_dma_host_off(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int
+sgiioc4_ide_dma_test_irq(ide_drive_t * drive)
+{
+	return sgiioc4_checkirq(HWIF(drive));
+}
+
+static int
+sgiioc4_ide_dma_host_on(ide_drive_t * drive)
+{
+	if (drive->using_dma)
+		return 0;
+
+	return 1;
+}
+
+static int
+sgiioc4_ide_dma_host_off(ide_drive_t * drive)
+{
+	sgiioc4_clearirq(drive);
+
+	return 0;
+}
+
+static int
+sgiioc4_ide_dma_count(ide_drive_t * drive)
+{
+	return HWIF(drive)->ide_dma_begin(drive);
+}
+
+static int
+sgiioc4_ide_dma_verbose(ide_drive_t * drive)
+{
+	if (drive->using_dma == 1)
+		printk(", UDMA(16)");
+	else
+		printk(", PIO");
+
+	return 1;
+}
+
+static int
+sgiioc4_ide_dma_lostirq(ide_drive_t * drive)
+{
+	HWIF(drive)->resetproc(drive);
+
+	return __ide_dma_lostirq(drive);
+}
+
+static int
+sgiioc4_ide_dma_timeout(ide_drive_t * drive)
+{
+	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+	if (HWIF(drive)->ide_dma_test_irq(drive))
+		return 0;
+
+	return HWIF(drive)->ide_dma_end(drive);
+}
+
+static u8
+sgiioc4_INB(unsigned long port)
+{
+	u8 reg = (u8) inb(port);
+
+	if ((port & 0xFFF) == 0x11C) {	/* Status register of IOC4 */
+		if (reg & 0x51) {	/* Not busy...check for interrupt */
+			unsigned long other_ir = port - 0x110;
+			unsigned int intr_reg = (u32) inl(other_ir);
+
+			if (intr_reg & 0x03) {
+				/* Clear the Interrupt, Error bits on the IOC4 */
+				outl(0x03, other_ir);
+				intr_reg = (u32) inl(other_ir);
+			}
+		}
+	}
+
+	return reg;
+}
+
+/* Creates a dma map for the scatter-gather list entries */
+static void __init
+ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
+{
+	int num_ports = sizeof (ioc4_dma_regs_t);
+
+	printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name, dma_base, dma_base + num_ports - 1);
+
+	if (!request_region(dma_base, num_ports, hwif->name)) {
+		printk(KERN_ERR "ide_dma_sgiioc4(%s) -- Error, Port Addresses 0x%p to 0x%p ALREADY in use\n",
+		       hwif->name, (void *)dma_base, (void *)dma_base + num_ports - 1);
+		return;
+	}
+
+	hwif->dma_base = dma_base;
+	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+						  IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,	/* 1 Page */
+						  &hwif->dmatable_dma);
+
+	if (!hwif->dmatable_cpu)
+		goto dma_alloc_failure;
+
+	hwif->sg_table = kmalloc(sizeof (struct scatterlist) * IOC4_PRD_ENTRIES, GFP_KERNEL);
+
+	if (!hwif->sg_table) {
+		pci_free_consistent(hwif->pci_dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, hwif->dmatable_cpu, hwif->dmatable_dma);
+		goto dma_alloc_failure;
+	}
+
+	hwif->dma_base2 = (unsigned long) pci_alloc_consistent(hwif->pci_dev, IOC4_IDE_CACHELINE_SIZE,
+							       (dma_addr_t*)&(hwif->dma_status));
+
+	if (!hwif->dma_base2) {
+		pci_free_consistent(hwif->pci_dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, hwif->dmatable_cpu, hwif->dmatable_dma);
+		kfree(hwif->sg_table);
+		goto dma_alloc_failure;
+	}
+
+	return;
+
+ dma_alloc_failure:
+	printk(KERN_INFO "ide_dma_sgiioc4() -- Error! Unable to allocate DMA Maps for drive %s\n", hwif->name);
+	printk(KERN_INFO "Changing from DMA to PIO mode for Drive %s \n", hwif->name);
+
+	/* Disable DMA because we couldnot allocate any DMA maps */
+	hwif->autodma = 0;
+	hwif->atapi_dma = 0;
+}
+
+/* Initializes the IOC4 DMA Engine */
+static void
+sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
+{
+	u32 ioc4_dma;
+	int count;
+	ide_hwif_t *hwif = HWIF(drive);
+	uint64_t dma_base = hwif->dma_base;
+	uint32_t dma_addr, ending_dma_addr;
+
+	ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+
+	if (ioc4_dma & IOC4_S_DMA_ACTIVE) {
+		printk(KERN_WARNING "sgiioc4_configure_for_dma(%s):Warning!! IOC4 DMA from previous transfer was still active\n",
+			drive->name);
+		hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
+		count = 0;
+		do {
+			xide_delay(count);
+			ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+			count += 10;
+		} while ((ioc4_dma & IOC4_S_DMA_STOP) && (count < 100));
+
+		if (ioc4_dma & IOC4_S_DMA_STOP)
+			printk(KERN_ERR "sgiioc4_configure_for__dma(%s) : IOC4 Dma STOP bit is still 1\n", drive->name);
+	}
+
+	ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+	if (ioc4_dma & IOC4_S_DMA_ERROR) {
+		printk(KERN_WARNING "sgiioc4_configure_for__dma(%s) : Warning!! - DMA Error during Previous transfer | status 0x%x \n",
+		       drive->name, ioc4_dma);
+		hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
+		count = 0;
+		do {
+			ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+			xide_delay(count);
+			count += 10;
+		} while ((ioc4_dma & IOC4_S_DMA_STOP) && (count < 100));
+
+		if (ioc4_dma & IOC4_S_DMA_STOP)
+			printk(KERN_ERR "sgiioc4_configure_for__dma(%s) : IOC4 DMA STOP bit is still 1\n", drive->name);
+	}
+
+	/* Address of the Scatter Gather List */
+	dma_addr = cpu_to_le32(hwif->dmatable_dma);
+	hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4);
+
+	/* Address of the Ending DMA */
+	memset((unsigned int *) hwif->dma_base2, 0,IOC4_IDE_CACHELINE_SIZE);
+	ending_dma_addr = cpu_to_le32(hwif->dma_status);
+	hwif->OUTL(ending_dma_addr,dma_base + IOC4_DMA_END_ADDR * 4);
+
+	hwif->OUTL(dma_direction, dma_base + IOC4_DMA_CTRL * 4);
+	drive->waiting_for_dma = 1;
+}
+
+/* IOC4 Scatter Gather list Format 						*/
+/* 128 Bit entries to support 64 bit addresses in the future			*/
+/* The Scatter Gather list Entry should be in the BIG-ENDIAN Format		*/
+/* ---------------------------------------------------------------------------	*/
+/* | Upper 32 bits - Zero 		| 	Lower 32 bits- address	     |	*/
+/* ---------------------------------------------------------------------------	*/
+/* | Upper 32 bits - Zero		|EOL|	 16 Bit Data Length	     |	*/
+/* ---------------------------------------------------------------------------	*/
+
+/* Creates the scatter gather list, DMA Table */
+static unsigned int
+sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned int *table = hwif->dmatable_cpu;
+	unsigned int count = 0, i = 1;
+	struct scatterlist *sg;
+
+	if (rq->cmd == IDE_DRIVE_TASKFILE)
+		hwif->sg_nents = i = sgiioc4_ide_raw_build_sglist(hwif, rq);
+	else
+		hwif->sg_nents = i = sgiioc4_ide_build_sglist(hwif, rq, ddir);
+
+	if (!i)
+		return 0;	/* sglist of length Zero */
+
+	sg = hwif->sg_table;
+	while (i && sg_dma_len(sg)) {
+		dma_addr_t cur_addr;
+		int cur_len;
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			if (count++ >= IOC4_PRD_ENTRIES) {
+				printk(KERN_WARNING "%s: DMA table too small\n", drive->name);
+				goto use_pio_instead;
+			} else {
+				uint32_t xcount, bcount = 0x10000 - (cur_addr & 0xffff);
+
+				if (bcount > cur_len)
+					bcount = cur_len;
+
+				/* put the addr, length in the IOC4 dma-table format */
+				*table = 0x0;
+				table++;
+				*table = cpu_to_be32(cur_addr);
+				table++;
+				*table = 0x0;
+				table++;
+
+				xcount = bcount & 0xffff;
+				*table = cpu_to_be32(xcount);
+				table++;
+
+				cur_addr += bcount;
+				cur_len -= bcount;
+			}
+		}
+
+		sg++;
+		i--;
+	}
+
+	if (count) {
+		table--;
+		*table |= cpu_to_be32(0x80000000);
+		return count;
+	}
+
+      use_pio_instead:
+	pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents, hwif->sg_dma_direction);
+	hwif->sg_dma_active = 0;
+
+	return 0;		/* revert to PIO for this request */
+}
+
+static int
+sgiioc4_checkirq(ide_hwif_t * hwif)
+{
+	uint8_t intr_reg = hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4);
+
+	if (intr_reg & 0x03)
+		return 1;
+
+	return 0;
+}
+
+static int
+sgiioc4_clearirq(ide_drive_t * drive)
+{
+	u32 intr_reg;
+	ide_hwif_t *hwif = HWIF(drive);
+	ide_ioreg_t other_ir = hwif->io_ports[IDE_IRQ_OFFSET] + (IOC4_INTR_REG << 2);
+
+	/* Code to check for PCI error conditions */
+	intr_reg = hwif->INL(other_ir);
+	if (intr_reg & 0x03) {
+		/* Valid IOC4-IDE interrupt */
+		u8 stat = hwif->INB(IDE_STATUS_REG);
+		int count = 0;
+		do {
+			xide_delay(count);
+			stat = hwif->INB(IDE_STATUS_REG);	/* Removes Interrupt from IDE Device */
+		} while ((stat & 0x80) && (count++ < 1024));
+
+		if (intr_reg & 0x02) {
+			/* Error when transferring DMA data on PCI bus */
+			uint32_t pci_err_addr_low, pci_err_addr_high, pci_stat_cmd_reg;
+
+			pci_err_addr_low = hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET]);
+			pci_err_addr_high = hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + 4);
+			pci_read_config_dword(hwif->pci_dev, PCI_COMMAND, &pci_stat_cmd_reg);
+			printk(KERN_ERR "sgiioc4_clearirq(%s) : PCI Bus Error when doing DMA : status-cmd reg is 0x%x \n", drive->name, pci_stat_cmd_reg);
+			printk(KERN_ERR "sgiioc4_clearirq(%s) : PCI Error Address is 0x%x%x \n", drive->name, pci_err_addr_high, pci_err_addr_low);
+			/* Clear the PCI Error indicator */
+			pci_write_config_dword(hwif->pci_dev, PCI_COMMAND, 0x00000146);
+		}
+
+		hwif->OUTL(0x03, other_ir);	/* Clear the Interrupt, Error bits on the IOC4 */
+
+		intr_reg = hwif->INL(other_ir);
+	}
+
+	return intr_reg;
+}
+
+/* XXX: duplicated code. See PV#: 896400 */
+
+/**
+ * 	"Copied from drivers/ide/ide-dma.c"
+ *	sgiioc4_ide_build_sglist - map IDE scatter gather for DMA I/O
+ *	@hwif: the interface to build the DMA table for
+ *	@rq: the request holding the sg list
+ *	@ddir: data direction
+ *
+ *	Perform the PCI mapping magic neccessary to access the source
+ *	or target buffers of a request via PCI DMA. The lower layers
+ *	of the kernel provide the neccessary cache management so that
+ *	we can operate in a portable fashion.
+ *
+ *	This code is identical to ide_build_sglist in ide-dma.c
+ *	however that it not exported and even if it were would create
+ *	dependancy problems for modular drivers.
+ */
+static int
+sgiioc4_ide_build_sglist(ide_hwif_t * hwif, struct request *rq, int ddir)
+{
+	struct buffer_head *bh;
+	struct scatterlist *sg = hwif->sg_table;
+	unsigned long lastdataend = ~0UL;
+	int nents = 0;
+
+	if (hwif->sg_dma_active)
+		BUG();
+
+	bh = rq->bh;
+	do {
+		int contig = 0;
+
+		if (bh->b_page) {
+			if (bh_phys(bh) == lastdataend)
+				contig = 1;
+		} else {
+			if ((unsigned long) bh->b_data == lastdataend)
+				contig = 1;
+		}
+
+		if (contig) {
+			sg[nents - 1].length += bh->b_size;
+			lastdataend += bh->b_size;
+			continue;
+		}
+
+		if (nents >= PRD_ENTRIES)
+			return 0;
+
+		memset(&sg[nents], 0, sizeof (*sg));
+
+		if (bh->b_page) {
+			sg[nents].page = bh->b_page;
+			sg[nents].offset = bh_offset(bh);
+			lastdataend = bh_phys(bh) + bh->b_size;
+		} else {
+			if ((unsigned long) bh->b_data < PAGE_SIZE)
+				BUG();
+
+			sg[nents].address = bh->b_data;
+			lastdataend = (unsigned long) bh->b_data + bh->b_size;
+		}
+
+		sg[nents].length = bh->b_size;
+		nents++;
+	} while ((bh = bh->b_reqnext) != NULL);
+
+	if (nents == 0)
+		BUG();
+
+	hwif->sg_dma_direction = ddir;
+	return pci_map_sg(hwif->pci_dev, sg, nents, ddir);
+}
+
+/* XXX: duplicated code. See PV#: 896400 */
+
+/**
+ * 	Copied from drivers/ide/ide-dma.c
+ *	sgiioc4_ide_raw_build_sglist	-	map IDE scatter gather for DMA
+ *	@hwif: the interface to build the DMA table for
+ *	@rq: the request holding the sg list
+ *
+ *	Perform the PCI mapping magic neccessary to access the source or
+ *	target buffers of a taskfile request via PCI DMA. The lower layers
+ *	of the  kernel provide the neccessary cache management so that we can
+ *	operate in a portable fashion
+ *
+ *	This code is identical to ide_raw_build_sglist in ide-dma.c
+ *	however that it not exported and even if it were would create
+ *	dependancy problems for modular drivers.
+ */
+static int
+sgiioc4_ide_raw_build_sglist(ide_hwif_t * hwif, struct request *rq)
+{
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+	u8 *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+#if 1
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof (*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = 128 * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof (*sg));
+	sg[nents].address = virt_addr;
+	sg[nents].length = sector_count * SECTOR_SIZE;
+	nents++;
+#else
+	while (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof (*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = 128 * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	};
+	memset(&sg[nents], 0, sizeof (*sg));
+	sg[nents].address = virt_addr;
+	sg[nents].length = sector_count * SECTOR_SIZE;
+	nents++;
+#endif
+	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int
+sgiioc4_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	unsigned int class_rev;
+	int i = 0;
+
+	while (i < n_sgiioc4_devs) {
+		pci_read_config_dword(sgiioc4_devs[i], PCI_CLASS_REVISION,
+				      &class_rev);
+		class_rev &= 0xff;
+
+		if (sgiioc4_devs[i]->device == PCI_DEVICE_ID_SGI_IOC4) {
+			p += sprintf(p, "\n	SGI IOC4 Chipset rev %d. ", class_rev);
+			p += sprintf(p, "\n	Chipset has 1 IDE channel and supports 2 devices on that channel.");
+			p += sprintf(p, "\n	Chipset supports DMA in MultiMode-2 data transfer protocol.\n");
+			/* Do we need more info. here? */
+		}
+		i++;
+	}
+
+	return p - buffer;
+}
+
+#endif /* CONFIG_PROC_FS */
+
+static int __devinit
+sgiioc4_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	unsigned int class_rev;
+	ide_pci_device_t *d = &sgiioc4_chipsets[id->driver_data];
+	if (dev->device != d->device) {
+		printk(KERN_ERR "Error in sgiioc4_init_one(dev 0x%p | id 0x%p )\n", (void *) dev, (void *) id);
+		BUG();
+	}
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) {
+		printk(KERN_INFO "Disabling the IOC4 IDE Part due to unsupported Firmware Rev (%d). \n",class_rev);
+		printk(KERN_INFO "Please upgrade to Firmware Rev 46 or higher \n");
+		return 0;
+	}
+
+	printk(KERN_INFO "%s: IDE controller at PCI slot %s\n", d->name, dev->slot_name);
+
+	if (pci_init_sgiioc4(dev, d->name))
+		return 0;
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static struct pci_device_id sgiioc4_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID, PCI_ANY_ID, 0x0b4000, 0xFFFFFF, 0 },
+	{ 0 }
+};
+
+static struct pci_driver driver = {
+	.name = "SGI-IOC4 IDE",
+	.id_table = sgiioc4_pci_tbl,
+	.probe = sgiioc4_init_one,
+};
+
+static int
+sgiioc4_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void
+sgiioc4_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sgiioc4_ide_init);
+module_exit(sgiioc4_ide_exit);
+
+MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)");
+MODULE_DESCRIPTION("PCI driver module for SGI IOC4 Base-IO Card");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Nru a/drivers/ide/pci/sgiioc4.h b/drivers/ide/pci/sgiioc4.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/sgiioc4.h	Wed Aug 27 13:07:27 2003
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#ifndef SGIIOC4_H
+#define SGIIOC4_H
+
+#define IDE_ARCH_ACK_INTR	1
+#include <linux/ide.h>
+
+/* IOC4 Specific Definitions */
+#define IOC4_CMD_OFFSET		0x100
+#define IOC4_CTRL_OFFSET	0x120
+#define IOC4_DMA_OFFSET		0x140
+#define IOC4_INTR_OFFSET	0x0
+
+#define IOC4_TIMING		0x00
+#define IOC4_DMA_PTR_L		0x01
+#define IOC4_DMA_PTR_H		0x02
+#define IOC4_DMA_ADDR_L		0x03
+#define IOC4_DMA_ADDR_H		0x04
+#define IOC4_BC_DEV		0x05
+#define IOC4_BC_MEM		0x06
+#define	IOC4_DMA_CTRL		0x07
+#define	IOC4_DMA_END_ADDR	0x08
+
+/* Bits in the IOC4 Control/Status Register */
+#define	IOC4_S_DMA_START	0x01
+#define	IOC4_S_DMA_STOP		0x02
+#define	IOC4_S_DMA_DIR		0x04
+#define	IOC4_S_DMA_ACTIVE	0x08
+#define	IOC4_S_DMA_ERROR	0x10
+#define	IOC4_ATA_MEMERR		0x02
+
+/* Read/Write Directions */
+#define	IOC4_DMA_WRITE		0x04
+#define	IOC4_DMA_READ		0x00
+
+/* Interrupt Register Offsets */
+#define IOC4_INTR_REG		0x03
+#define	IOC4_INTR_SET		0x05
+#define	IOC4_INTR_CLEAR		0x07
+
+#define IOC4_IDE_CACHELINE_SIZE	128
+#define IOC4_SUPPORTED_FIRMWARE_REV 46
+
+
+/* Weeds out non-IDE interrupts to the IOC4 */
+#define ide_ack_intr(hwif)      ((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1)
+
+#define SGIIOC4_MAX_DEVS	32
+
+#if  defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sgiioc4_proc;
+
+static struct pci_dev *sgiioc4_devs[SGIIOC4_MAX_DEVS];
+static int sgiioc4_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t sgiioc4_procs[] __initdata = {
+	{
+		.name = "sgiioc4",
+		.set = 1,
+		.get_info = sgiioc4_get_info,
+		.parent = NULL,
+	}
+};
+#endif
+
+typedef volatile struct {
+	u32 timing_reg0;
+	u32 timing_reg1;
+	u32 low_mem_ptr;
+	u32 high_mem_ptr;
+	u32 low_mem_addr;
+	u32 high_mem_addr;
+	u32 dev_byte_count;
+	u32 mem_byte_count;
+	u32 status;
+} ioc4_dma_regs_t;
+
+/* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */
+/* IOC4 has only 1 IDE channel */
+#define IOC4_PRD_BYTES       16
+#define IOC4_PRD_ENTRIES     (PAGE_SIZE /IOC4_PRD_BYTES)
+
+typedef enum pciio_endian_e {
+	PCIDMA_ENDIAN_BIG,
+	PCIDMA_ENDIAN_LITTLE
+} pciio_endian_t;
+
+static void sgiioc4_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port, 
+				    ide_ioreg_t ctrl_port, ide_ioreg_t irq_port);
+static void sgiioc4_ide_setup_pci_device(struct pci_dev *dev, const char *name);
+static void sgiioc4_resetproc(ide_drive_t * drive);
+static void sgiioc4_maskproc(ide_drive_t * drive, int mask);
+static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive);
+static void __init ide_init_sgiioc4(ide_hwif_t * hwif);
+static void __init ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base);
+static int sgiioc4_checkirq(ide_hwif_t * hwif);
+static int sgiioc4_clearirq(ide_drive_t * drive);
+static int sgiioc4_get_info(char *buffer, char **addr, off_t offset, int count);
+static int sgiioc4_ide_dma_read(ide_drive_t * drive);
+static int sgiioc4_ide_dma_write(ide_drive_t * drive);
+static int sgiioc4_ide_dma_begin(ide_drive_t * drive);
+static int sgiioc4_ide_dma_end(ide_drive_t * drive);
+static int sgiioc4_ide_dma_check(ide_drive_t * drive);
+static int sgiioc4_ide_dma_on(ide_drive_t * drive);
+static int sgiioc4_ide_dma_off(ide_drive_t * drive);
+static int sgiioc4_ide_dma_off_quietly(ide_drive_t * drive);
+static int sgiioc4_ide_dma_test_irq(ide_drive_t * drive);
+static int sgiioc4_ide_dma_host_on(ide_drive_t * drive);
+static int sgiioc4_ide_dma_host_off(ide_drive_t * drive);
+static int sgiioc4_ide_dma_count(ide_drive_t * drive);
+static int sgiioc4_ide_dma_verbose(ide_drive_t * drive);
+static int sgiioc4_ide_dma_lostirq(ide_drive_t * drive);
+static int sgiioc4_ide_dma_timeout(ide_drive_t * drive);
+static int sgiioc4_ide_build_sglist(ide_hwif_t * hwif, struct request *rq,
+				    int ddir);
+static int sgiioc4_ide_raw_build_sglist(ide_hwif_t * hwif, struct request *rq);
+
+static u8 sgiioc4_INB(unsigned long port);
+static inline void xide_delay(long ticks);
+extern int (*sgiioc4_display_info) (char *, char **, off_t, int);	/* ide-proc.c */
+static unsigned int sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq,
+					    int ddir);
+static unsigned int __init pci_init_sgiioc4(struct pci_dev *dev, const char *name);
+
+static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = {
+	{		
+		/* Channel 0 */
+		.vendor = PCI_VENDOR_ID_SGI,
+		.device = PCI_DEVICE_ID_SGI_IOC4,
+		.name = "SGIIOC4",
+		.init_chipset = pci_init_sgiioc4,
+		.init_iops = NULL,
+		.init_hwif = ide_init_sgiioc4,
+		.init_dma = ide_dma_sgiioc4,
+		.channels = 1,
+		.autodma = AUTODMA,
+		.enablebits = { { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } },
+		.bootable = ON_BOARD,
+		.extra = 0,
+	}
+};
+
+#endif
diff -Nru a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
--- a/drivers/ide/pci/siimage.c	Thu Jul 31 06:17:42 2003
+++ b/drivers/ide/pci/siimage.c	Sat Aug  9 08:07:32 2003
@@ -1113,7 +1113,10 @@
 	hwif->pre_reset = &siimage_pre_reset;
 
 	if(is_sata(hwif))
+	{
 		hwif->busproc   = &siimage_busproc;
+		hwif->sata = 1;
+	}
 
 	if (!hwif->dma_base) {
 		hwif->drives[0].autotune = 1;
diff -Nru a/drivers/ide/raid/hptraid.c b/drivers/ide/raid/hptraid.c
--- a/drivers/ide/raid/hptraid.c	Sun Jun 29 08:10:17 2003
+++ b/drivers/ide/raid/hptraid.c	Fri Aug 15 07:02:20 2003
@@ -584,7 +584,7 @@
 	ide_drive_t *ideinfo;
 	
 	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
+	ideinfo = ide_info_ptr (dev, 0);
 	if (ideinfo==NULL)
 		return 0;
 	
diff -Nru a/drivers/ide/raid/pdcraid.c b/drivers/ide/raid/pdcraid.c
--- a/drivers/ide/raid/pdcraid.c	Mon Mar 24 10:12:03 2003
+++ b/drivers/ide/raid/pdcraid.c	Fri Aug 15 07:02:31 2003
@@ -350,7 +350,7 @@
 	ide_drive_t *ideinfo;
 	
 	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
+	ideinfo = ide_info_ptr (dev, 0);
 	if (ideinfo==NULL)
 		return 0;
 	
diff -Nru a/drivers/ide/raid/silraid.c b/drivers/ide/raid/silraid.c
--- a/drivers/ide/raid/silraid.c	Thu Jan  9 11:43:30 2003
+++ b/drivers/ide/raid/silraid.c	Fri Aug 15 07:02:48 2003
@@ -253,7 +253,7 @@
 	ide_drive_t *ideinfo;
 	
 	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
+	ideinfo = ide_info_ptr (dev, 0);
 	if (ideinfo==NULL)
 		return 0;
 	
diff -Nru a/drivers/md/lvm-fs.c b/drivers/md/lvm-fs.c
--- a/drivers/md/lvm-fs.c	Thu Jul 25 06:46:01 2002
+++ b/drivers/md/lvm-fs.c	Mon Mar 10 06:55:46 2003
@@ -59,9 +59,9 @@
 static int _proc_read_global(char *page, char **start, off_t off,
 			     int count, int *eof, void *data);
 
-static int _vg_info(vg_t *vg_ptr, char *buf);
-static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf);
-static int _pv_info(pv_t *pv_ptr, char *buf);
+static int _vg_info(vg_t * vg_ptr, char *buf);
+static int _lv_info(vg_t * vg_ptr, lv_t * lv_ptr, char *buf);
+static int _pv_info(pv_t * pv_ptr, char *buf);
 
 static void _show_uuid(const char *src, char *b, char *e);
 
@@ -78,65 +78,72 @@
 /* inline functions */
 
 /* public interface */
-void __init lvm_init_fs() {
+void __init lvm_init_fs()
+{
 	struct proc_dir_entry *pde;
 
 /* User-space has already registered this */
 #if 0
-	lvm_devfs_handle = devfs_register(
-		0 , "lvm", 0, LVM_CHAR_MAJOR, 0,
-		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
-		&lvm_chr_fops, NULL);
+	lvm_devfs_handle = devfs_register(0, "lvm", 0, LVM_CHAR_MAJOR, 0,
+					  S_IFCHR | S_IRUSR | S_IWUSR |
+					  S_IRGRP, &lvm_chr_fops, NULL);
 #endif
 	lvm_proc_dir = create_proc_entry(LVM_DIR, S_IFDIR, &proc_root);
 	if (lvm_proc_dir) {
-		lvm_proc_vg_subdir = create_proc_entry(LVM_VG_SUBDIR, S_IFDIR,
-						       lvm_proc_dir);
+		lvm_proc_vg_subdir =
+		    create_proc_entry(LVM_VG_SUBDIR, S_IFDIR,
+				      lvm_proc_dir);
 		pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir);
-		if ( pde != NULL) pde->read_proc = _proc_read_global;
+		if (pde != NULL)
+			pde->read_proc = _proc_read_global;
 	}
 }
 
-void lvm_fin_fs() {
+void lvm_fin_fs()
+{
 #if 0
-	devfs_unregister (lvm_devfs_handle);
+	devfs_unregister(lvm_devfs_handle);
 #endif
 	remove_proc_entry(LVM_GLOBAL, lvm_proc_dir);
 	remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir);
 	remove_proc_entry(LVM_DIR, &proc_root);
 }
 
-void lvm_fs_create_vg(vg_t *vg_ptr) {
+void lvm_fs_create_vg(vg_t * vg_ptr)
+{
 	struct proc_dir_entry *pde;
 
 	if (!vg_ptr)
 		return;
 
 	vg_devfs_handle[vg_ptr->vg_number] =
-		devfs_mk_dir(0, vg_ptr->vg_name, NULL);
+	    devfs_mk_dir(0, vg_ptr->vg_name, NULL);
 
-	ch_devfs_handle[vg_ptr->vg_number] = devfs_register(
-		vg_devfs_handle[vg_ptr->vg_number] , "group",
-		DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number,
-		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
-		&lvm_chr_fops, NULL);
+	ch_devfs_handle[vg_ptr->vg_number] =
+	    devfs_register(vg_devfs_handle[vg_ptr->vg_number], "group",
+			   DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR,
+			   vg_ptr->vg_number,
+			   S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
+			   &lvm_chr_fops, NULL);
 
 	vg_ptr->vg_dir_pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR,
 					       lvm_proc_vg_subdir);
 
-	if((pde = create_proc_entry("group", S_IFREG, vg_ptr->vg_dir_pde))) {
+	if ((pde =
+	     create_proc_entry("group", S_IFREG, vg_ptr->vg_dir_pde))) {
 		pde->read_proc = _proc_read_vg;
 		pde->data = vg_ptr;
 	}
 
 	vg_ptr->lv_subdir_pde =
-		create_proc_entry(LVM_LV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
+	    create_proc_entry(LVM_LV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
 
 	vg_ptr->pv_subdir_pde =
-		create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
+	    create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
 }
 
-void lvm_fs_remove_vg(vg_t *vg_ptr) {
+void lvm_fs_remove_vg(vg_t * vg_ptr)
+{
 	int i;
 
 	if (!vg_ptr)
@@ -146,18 +153,20 @@
 	ch_devfs_handle[vg_ptr->vg_number] = NULL;
 
 	/* remove lv's */
-	for(i = 0; i < vg_ptr->lv_max; i++)
-		if(vg_ptr->lv[i]) lvm_fs_remove_lv(vg_ptr, vg_ptr->lv[i]);
+	for (i = 0; i < vg_ptr->lv_max; i++)
+		if (vg_ptr->lv[i])
+			lvm_fs_remove_lv(vg_ptr, vg_ptr->lv[i]);
 
 	/* must not remove directory before leaf nodes */
 	devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]);
 	vg_devfs_handle[vg_ptr->vg_number] = NULL;
 
 	/* remove pv's */
-	for(i = 0; i < vg_ptr->pv_max; i++)
-		if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]);
+	for (i = 0; i < vg_ptr->pv_max; i++)
+		if (vg_ptr->pv[i])
+			lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]);
 
-	if(vg_ptr->vg_dir_pde) {
+	if (vg_ptr->vg_dir_pde) {
 		remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde);
 		vg_ptr->lv_subdir_pde = NULL;
 
@@ -172,13 +181,15 @@
 }
 
 
-static inline const char *_basename(const char *str) {
+static inline const char *_basename(const char *str)
+{
 	const char *name = strrchr(str, '/');
 	name = name ? name + 1 : str;
 	return name;
 }
 
-devfs_handle_t lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv) {
+devfs_handle_t lvm_fs_create_lv(vg_t * vg_ptr, lv_t * lv)
+{
 	struct proc_dir_entry *pde;
 	const char *name;
 
@@ -187,21 +198,24 @@
 
 	name = _basename(lv->lv_name);
 
-	lv_devfs_handle[MINOR(lv->lv_dev)] = devfs_register(
-		vg_devfs_handle[vg_ptr->vg_number], name,
-		DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, MINOR(lv->lv_dev),
-		S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-		&lvm_blk_dops, NULL);
-
-	if(vg_ptr->lv_subdir_pde &&
-	   (pde = create_proc_entry(name, S_IFREG, vg_ptr->lv_subdir_pde))) {
+	lv_devfs_handle[MINOR(lv->lv_dev)] =
+	    devfs_register(vg_devfs_handle[vg_ptr->vg_number], name,
+			   DEVFS_FL_DEFAULT, LVM_BLK_MAJOR,
+			   MINOR(lv->lv_dev),
+			   S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
+			   &lvm_blk_dops, NULL);
+
+	if (vg_ptr->lv_subdir_pde &&
+	    (pde =
+	     create_proc_entry(name, S_IFREG, vg_ptr->lv_subdir_pde))) {
 		pde->read_proc = _proc_read_lv;
 		pde->data = lv;
 	}
 	return lv_devfs_handle[MINOR(lv->lv_dev)];
 }
 
-void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) {
+void lvm_fs_remove_lv(vg_t * vg_ptr, lv_t * lv)
+{
 
 	if (!vg_ptr || !lv)
 		return;
@@ -209,51 +223,55 @@
 	devfs_unregister(lv_devfs_handle[MINOR(lv->lv_dev)]);
 	lv_devfs_handle[MINOR(lv->lv_dev)] = NULL;
 
-	if(vg_ptr->lv_subdir_pde) {
+	if (vg_ptr->lv_subdir_pde) {
 		const char *name = _basename(lv->lv_name);
 		remove_proc_entry(name, vg_ptr->lv_subdir_pde);
 	}
 }
 
 
-static inline void _make_pv_name(const char *src, char *b, char *e) {
+static inline void _make_pv_name(const char *src, char *b, char *e)
+{
 	int offset = strlen(LVM_DIR_PREFIX);
-	if(strncmp(src, LVM_DIR_PREFIX, offset))
+	if (strncmp(src, LVM_DIR_PREFIX, offset))
 		offset = 0;
 
 	e--;
 	src += offset;
-	while(*src && (b != e)) {
+	while (*src && (b != e)) {
 		*b++ = (*src == '/') ? '_' : *src;
 		src++;
 	}
 	*b = '\0';
 }
 
-void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv) {
+void lvm_fs_create_pv(vg_t * vg_ptr, pv_t * pv)
+{
 	struct proc_dir_entry *pde;
 	char name[NAME_LEN];
 
 	if (!vg_ptr || !pv)
 		return;
 
-	if(!vg_ptr->pv_subdir_pde)
+	if (!vg_ptr->pv_subdir_pde)
 		return;
 
 	_make_pv_name(pv->pv_name, name, name + sizeof(name));
-	if((pde = create_proc_entry(name, S_IFREG, vg_ptr->pv_subdir_pde))) {
+	if ((pde =
+	     create_proc_entry(name, S_IFREG, vg_ptr->pv_subdir_pde))) {
 		pde->read_proc = _proc_read_pv;
 		pde->data = pv;
 	}
 }
 
-void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv) {
+void lvm_fs_remove_pv(vg_t * vg_ptr, pv_t * pv)
+{
 	char name[NAME_LEN];
 
 	if (!vg_ptr || !pv)
 		return;
 
-	if(!vg_ptr->pv_subdir_pde)
+	if (!vg_ptr->pv_subdir_pde)
 		return;
 
 	_make_pv_name(pv->pv_name, name, name + sizeof(name));
@@ -262,7 +280,8 @@
 
 
 static int _proc_read_vg(char *page, char **start, off_t off,
-			  int count, int *eof, void *data) {
+			 int count, int *eof, void *data)
+{
 	int sz = 0;
 	vg_t *vg_ptr = data;
 	char uuid[NAME_LEN];
@@ -279,9 +298,11 @@
 	sz += sprintf(page + sz, "PV max:       %u\n", vg_ptr->pv_max);
 	sz += sprintf(page + sz, "PV current:   %u\n", vg_ptr->pv_cur);
 	sz += sprintf(page + sz, "PV active:    %u\n", vg_ptr->pv_act);
-	sz += sprintf(page + sz, "PE size:      %u\n", vg_ptr->pe_size / 2);
+	sz +=
+	    sprintf(page + sz, "PE size:      %u\n", vg_ptr->pe_size / 2);
 	sz += sprintf(page + sz, "PE total:     %u\n", vg_ptr->pe_total);
-	sz += sprintf(page + sz, "PE allocated: %u\n", vg_ptr->pe_allocated);
+	sz +=
+	    sprintf(page + sz, "PE allocated: %u\n", vg_ptr->pe_allocated);
 
 	_show_uuid(vg_ptr->vg_uuid, uuid, uuid + sizeof(uuid));
 	sz += sprintf(page + sz, "uuid:         %s\n", uuid);
@@ -290,7 +311,8 @@
 }
 
 static int _proc_read_lv(char *page, char **start, off_t off,
-			  int count, int *eof, void *data) {
+			 int count, int *eof, void *data)
+{
 	int sz = 0;
 	lv_t *lv = data;
 
@@ -301,7 +323,7 @@
 	sz += sprintf(page + sz, "number:       %u\n", lv->lv_number);
 	sz += sprintf(page + sz, "open:         %u\n", lv->lv_open);
 	sz += sprintf(page + sz, "allocation:   %u\n", lv->lv_allocation);
-	if(lv->lv_stripes > 1) {
+	if (lv->lv_stripes > 1) {
 		sz += sprintf(page + sz, "stripes:      %u\n",
 			      lv->lv_stripes);
 		sz += sprintf(page + sz, "stripesize:   %u\n",
@@ -314,7 +336,8 @@
 }
 
 static int _proc_read_pv(char *page, char **start, off_t off,
-			 int count, int *eof, void *data) {
+			 int count, int *eof, void *data)
+{
 	int sz = 0;
 	pv_t *pv = data;
 	char uuid[NAME_LEN];
@@ -329,7 +352,7 @@
 	sz += sprintf(page + sz, "PE total:     %u\n", pv->pe_total);
 	sz += sprintf(page + sz, "PE allocated: %u\n", pv->pe_allocated);
 	sz += sprintf(page + sz, "device:       %02u:%02u\n",
-                      MAJOR(pv->pv_dev), MINOR(pv->pv_dev));
+		      MAJOR(pv->pv_dev), MINOR(pv->pv_dev));
 
 	_show_uuid(pv->pv_uuid, uuid, uuid + sizeof(uuid));
 	sz += sprintf(page + sz, "uuid:         %s\n", uuid);
@@ -337,13 +360,15 @@
 	return sz;
 }
 
-static int _proc_read_global(char *page, char **start, off_t pos, int count,
-			     int *eof, void *data) {
+static int _proc_read_global(char *page, char **start, off_t pos,
+			     int count, int *eof, void *data)
+{
 
 #define  LVM_PROC_BUF   ( i == 0 ? dummy_buf : &buf[sz])
 
-	int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter,
-		lv_open_total, pe_t_bytes, hash_table_bytes, lv_block_exception_t_bytes, seconds;
+	int c, i, l, p, v, vg_counter, pv_counter, lv_counter,
+	    lv_open_counter, lv_open_total, pe_t_bytes, hash_table_bytes,
+	    lv_block_exception_t_bytes, seconds;
 	static off_t sz;
 	off_t sz_last;
 	static char *buf = NULL;
@@ -359,12 +384,12 @@
 	       lvm_name, pos, count);
 #endif
 
-	if(pos != 0 && buf != NULL)
+	if (pos != 0 && buf != NULL)
 		goto out;
 
-	sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \
-		lv_open_total = pe_t_bytes = hash_table_bytes = \
-		lv_block_exception_t_bytes = 0;
+	sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter =
+	    lv_open_total = pe_t_bytes = hash_table_bytes =
+	    lv_block_exception_t_bytes = 0;
 
 	/* get some statistics */
 	for (v = 0; v < ABS_MAX_VG; v++) {
@@ -374,14 +399,26 @@
 			lv_counter += vg_ptr->lv_cur;
 			if (vg_ptr->lv_cur > 0) {
 				for (l = 0; l < vg[v]->lv_max; l++) {
-					if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
-						pe_t_bytes += lv_ptr->lv_allocated_le;
-						hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size;
-						if (lv_ptr->lv_block_exception != NULL)
-							lv_block_exception_t_bytes += lv_ptr->lv_remap_end;
+					if ((lv_ptr =
+					     vg_ptr->lv[l]) != NULL) {
+						pe_t_bytes +=
+						    lv_ptr->
+						    lv_allocated_le;
+						hash_table_bytes +=
+						    lv_ptr->
+						    lv_snapshot_hash_table_size;
+						if (lv_ptr->
+						    lv_block_exception !=
+						    NULL)
+							lv_block_exception_t_bytes
+							    +=
+							    lv_ptr->
+							    lv_remap_end;
 						if (lv_ptr->lv_open > 0) {
 							lv_open_counter++;
-							lv_open_total += lv_ptr->lv_open;
+							lv_open_total +=
+							    lv_ptr->
+							    lv_open;
 						}
 					}
 				}
@@ -403,8 +440,7 @@
 	   2nd to fill the malloced buffer */
 	for (i = 0; i < 2; i++) {
 		sz = 0;
-		sz += sprintf(LVM_PROC_BUF,
-			      "LVM "
+		sz += sprintf(LVM_PROC_BUF, "LVM "
 #ifdef MODULE
 			      "module"
 #else
@@ -422,8 +458,7 @@
 			      lv_open_counter == 1 ? "" : "s");
 		if (lv_open_total > 0)
 			sz += sprintf(LVM_PROC_BUF,
-				      " %d times)\n",
-				      lv_open_total);
+				      " %d times)\n", lv_open_total);
 		else
 			sz += sprintf(LVM_PROC_BUF, ")");
 		sz += sprintf(LVM_PROC_BUF,
@@ -431,7 +466,8 @@
 			      vg_counter * sizeof(vg_t) +
 			      pv_counter * sizeof(pv_t) +
 			      lv_counter * sizeof(lv_t) +
-			      pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last,
+			      pe_t_bytes + hash_table_bytes +
+			      lv_block_exception_t_bytes + sz_last,
 			      lvm_iop_version);
 
 		seconds = CURRENT_TIME - loadtime;
@@ -445,46 +481,70 @@
 		}
 		sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n",
 			      (seconds % 86400) / 3600,
-			      (seconds % 3600) / 60,
-			      seconds % 60);
+			      (seconds % 3600) / 60, seconds % 60);
 
 		if (vg_counter > 0) {
 			for (v = 0; v < ABS_MAX_VG; v++) {
 				/* volume group */
 				if ((vg_ptr = vg[v]) != NULL) {
-					sz += _vg_info(vg_ptr, LVM_PROC_BUF);
+					sz +=
+					    _vg_info(vg_ptr, LVM_PROC_BUF);
 
 					/* physical volumes */
 					sz += sprintf(LVM_PROC_BUF,
 						      "\n  PV%s ",
-						      vg_ptr->pv_cur == 1 ? ": " : "s:");
+						      vg_ptr->pv_cur ==
+						      1 ? ": " : "s:");
 					c = 0;
-					for (p = 0; p < vg_ptr->pv_max; p++) {
-						if ((pv_ptr = vg_ptr->pv[p]) != NULL) {
-							sz += _pv_info(pv_ptr, LVM_PROC_BUF);
+					for (p = 0; p < vg_ptr->pv_max;
+					     p++) {
+						if ((pv_ptr =
+						     vg_ptr->pv[p]) !=
+						    NULL) {
+							sz +=
+							    _pv_info
+							    (pv_ptr,
+							     LVM_PROC_BUF);
 
 							c++;
-							if (c < vg_ptr->pv_cur)
-								sz += sprintf(LVM_PROC_BUF,
-									      "\n       ");
+							if (c <
+							    vg_ptr->pv_cur)
+								sz +=
+								    sprintf
+								    (LVM_PROC_BUF,
+								     "\n       ");
 						}
 					}
 
 					/* logical volumes */
 					sz += sprintf(LVM_PROC_BUF,
 						      "\n    LV%s ",
-						      vg_ptr->lv_cur == 1 ? ": " : "s:");
+						      vg_ptr->lv_cur ==
+						      1 ? ": " : "s:");
 					c = 0;
-					for (l = 0; l < vg_ptr->lv_max; l++) {
-						if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
-							sz += _lv_info(vg_ptr, lv_ptr, LVM_PROC_BUF);
+					for (l = 0; l < vg_ptr->lv_max;
+					     l++) {
+						if ((lv_ptr =
+						     vg_ptr->lv[l]) !=
+						    NULL) {
+							sz +=
+							    _lv_info
+							    (vg_ptr,
+							     lv_ptr,
+							     LVM_PROC_BUF);
 							c++;
-							if (c < vg_ptr->lv_cur)
-								sz += sprintf(LVM_PROC_BUF,
-									      "\n         ");
+							if (c <
+							    vg_ptr->lv_cur)
+								sz +=
+								    sprintf
+								    (LVM_PROC_BUF,
+								     "\n         ");
 						}
 					}
-					if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none");
+					if (vg_ptr->lv_cur == 0)
+						sz +=
+						    sprintf(LVM_PROC_BUF,
+							    "none");
 					sz += sprintf(LVM_PROC_BUF, "\n");
 				}
 			}
@@ -495,14 +555,15 @@
 			unlock_kernel();
 			if (buf == NULL) {
 				sz = 0;
-				return sprintf(page, "%s - vmalloc error at line %d\n",
+				return sprintf(page,
+					       "%s - vmalloc error at line %d\n",
 					       lvm_name, __LINE__);
 			}
 		}
 		sz_last = sz;
 	}
 
- out:
+      out:
 	if (pos > sz - 1) {
 		lock_kernel();
 		vfree(buf);
@@ -522,11 +583,13 @@
 /*
  * provide VG info for proc filesystem use (global)
  */
-static int _vg_info(vg_t *vg_ptr, char *buf) {
+static int _vg_info(vg_t * vg_ptr, char *buf)
+{
 	int sz = 0;
 	char inactive_flag = ' ';
 
-	if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I';
+	if (!(vg_ptr->vg_status & VG_ACTIVE))
+		inactive_flag = 'I';
 	sz = sprintf(buf,
 		     "\nVG: %c%s  [%d PV, %d LV/%d open] "
 		     " PE Size: %d KB\n"
@@ -537,13 +600,13 @@
 		     vg_ptr->pv_cur,
 		     vg_ptr->lv_cur,
 		     vg_ptr->lv_open,
-	     	     vg_ptr->pe_size >> 1,
+		     vg_ptr->pe_size >> 1,
 		     vg_ptr->pe_size * vg_ptr->pe_total >> 1,
 		     vg_ptr->pe_total,
 		     vg_ptr->pe_allocated * vg_ptr->pe_size >> 1,
-	     	     vg_ptr->pe_allocated,
+		     vg_ptr->pe_allocated,
 		     (vg_ptr->pe_total - vg_ptr->pe_allocated) *
-	     	     vg_ptr->pe_size >> 1,
+		     vg_ptr->pe_size >> 1,
 		     vg_ptr->pe_total - vg_ptr->pe_allocated);
 	return sz;
 }
@@ -552,10 +615,11 @@
 /*
  * provide LV info for proc filesystem use (global)
  */
-static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) {
+static int _lv_info(vg_t * vg_ptr, lv_t * lv_ptr, char *buf)
+{
 	int sz = 0;
 	char inactive_flag = 'A', allocation_flag = ' ',
-		stripes_flag = ' ', rw_flag = ' ', *basename;
+	    stripes_flag = ' ', rw_flag = ' ', *basename;
 
 	if (!(lv_ptr->lv_status & LV_ACTIVE))
 		inactive_flag = 'I';
@@ -568,35 +632,33 @@
 	stripes_flag = 'L';
 	if (lv_ptr->lv_stripes > 1)
 		stripes_flag = 'S';
-	sz += sprintf(buf+sz,
+	sz += sprintf(buf + sz,
 		      "[%c%c%c%c",
 		      inactive_flag,
-	 rw_flag,
-		      allocation_flag,
-		      stripes_flag);
+		      rw_flag, allocation_flag, stripes_flag);
 	if (lv_ptr->lv_stripes > 1)
-		sz += sprintf(buf+sz, "%-2d",
-			      lv_ptr->lv_stripes);
+		sz += sprintf(buf + sz, "%-2d", lv_ptr->lv_stripes);
 	else
-		sz += sprintf(buf+sz, "  ");
+		sz += sprintf(buf + sz, "  ");
 
 	/* FIXME: use _basename */
 	basename = strrchr(lv_ptr->lv_name, '/');
-	if ( basename == 0) basename = lv_ptr->lv_name;
-	else                basename++;
-	sz += sprintf(buf+sz, "] %-25s", basename);
+	if (basename == 0)
+		basename = lv_ptr->lv_name;
+	else
+		basename++;
+	sz += sprintf(buf + sz, "] %-25s", basename);
 	if (strlen(basename) > 25)
-		sz += sprintf(buf+sz,
+		sz += sprintf(buf + sz,
 			      "\n                              ");
-	sz += sprintf(buf+sz, "%9d /%-6d   ",
+	sz += sprintf(buf + sz, "%9d /%-6d   ",
 		      lv_ptr->lv_size >> 1,
 		      lv_ptr->lv_size / vg_ptr->pe_size);
 
 	if (lv_ptr->lv_open == 0)
-		sz += sprintf(buf+sz, "close");
+		sz += sprintf(buf + sz, "close");
 	else
-		sz += sprintf(buf+sz, "%dx open",
-			      lv_ptr->lv_open);
+		sz += sprintf(buf + sz, "%dx open", lv_ptr->lv_open);
 
 	return sz;
 }
@@ -605,7 +667,8 @@
 /*
  * provide PV info for proc filesystem use (global)
  */
-static int _pv_info(pv_t *pv, char *buf) {
+static int _pv_info(pv_t * pv, char *buf)
+{
 	int sz = 0;
 	char inactive_flag = 'A', allocation_flag = ' ';
 	char *pv_name = NULL;
@@ -615,9 +678,11 @@
 	allocation_flag = 'A';
 	if (!(pv->pv_allocatable & PV_ALLOCATABLE))
 		allocation_flag = 'N';
-	pv_name = strchr(pv->pv_name+1,'/');
-	if ( pv_name == 0) pv_name = pv->pv_name;
-	else               pv_name++;
+	pv_name = strchr(pv->pv_name + 1, '/');
+	if (pv_name == 0)
+		pv_name = pv->pv_name;
+	else
+		pv_name++;
 	sz = sprintf(buf,
 		     "[%c%c] %-21s %8d /%-6d  "
 		     "%8d /%-6d  %8d /%-6d",
@@ -629,17 +694,17 @@
 		     pv->pe_allocated * pv->pe_size >> 1,
 		     pv->pe_allocated,
 		     (pv->pe_total - pv->pe_allocated) *
-		     pv->pe_size >> 1,
-		     pv->pe_total - pv->pe_allocated);
+		     pv->pe_size >> 1, pv->pe_total - pv->pe_allocated);
 	return sz;
 }
 
-static void _show_uuid(const char *src, char *b, char *e) {
+static void _show_uuid(const char *src, char *b, char *e)
+{
 	int i;
 
 	e--;
-	for(i = 0; *src && (b != e); i++) {
-		if(i && !(i & 0x3))
+	for (i = 0; *src && (b != e); i++) {
+		if (i && !(i & 0x3))
 			*b++ = '-';
 		*b++ = *src++;
 	}
diff -Nru a/drivers/md/lvm-internal.h b/drivers/md/lvm-internal.h
--- a/drivers/md/lvm-internal.h	Thu Jul 25 06:46:01 2002
+++ b/drivers/md/lvm-internal.h	Mon Mar 10 06:55:46 2003
@@ -50,7 +50,7 @@
 extern struct file_operations lvm_chr_fops;
 
 #ifndef	uchar
-typedef	unsigned char	uchar;
+typedef unsigned char uchar;
 #endif
 
 extern struct block_device_operations lvm_blk_dops;
@@ -89,24 +89,24 @@
 int lvm_get_blksize(kdev_t);
 int lvm_snapshot_alloc(lv_t *);
 int lvm_snapshot_fill_COW_page(vg_t *, lv_t *);
-int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, vg_t *vg, lv_t *);
+int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, vg_t * vg, lv_t *);
 int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *);
 void lvm_snapshot_release(lv_t *);
 int lvm_write_COW_table_block(vg_t *, lv_t *);
 void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, lv_t *);
 int lvm_snapshot_alloc_hash_table(lv_t *);
-void lvm_drop_snapshot(vg_t *vg, lv_t *, const char *);
+void lvm_drop_snapshot(vg_t * vg, lv_t *, const char *);
 
 
 /* lvm_fs.c */
 void lvm_init_fs(void);
 void lvm_fin_fs(void);
 
-void lvm_fs_create_vg(vg_t *vg_ptr);
-void lvm_fs_remove_vg(vg_t *vg_ptr);
-devfs_handle_t lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv);
-void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv);
-void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv);
-void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv);
+void lvm_fs_create_vg(vg_t * vg_ptr);
+void lvm_fs_remove_vg(vg_t * vg_ptr);
+devfs_handle_t lvm_fs_create_lv(vg_t * vg_ptr, lv_t * lv);
+void lvm_fs_remove_lv(vg_t * vg_ptr, lv_t * lv);
+void lvm_fs_create_pv(vg_t * vg_ptr, pv_t * pv);
+void lvm_fs_remove_pv(vg_t * vg_ptr, pv_t * pv);
 
 #endif
diff -Nru a/drivers/md/lvm-snap.c b/drivers/md/lvm-snap.c
--- a/drivers/md/lvm-snap.c	Mon Aug 12 05:10:59 2002
+++ b/drivers/md/lvm-snap.c	Mon Mar 10 06:55:46 2003
@@ -42,6 +42,8 @@
  *    15/10/2001 - fix snapshot alignment problem [CM]
  *               - fix snapshot full oops (always check lv_block_exception) [CM]
  *    26/06/2002 - support for new list_move macro [patch@luckynet.dynu.com]
+ *    26/07/2002 - removed conditional list_move macro because we will
+ *                 discontinue LVM1 before 2.6 anyway
  *
  */
 
@@ -57,7 +59,8 @@
 
 #include "lvm-internal.h"
 
-static char *lvm_snap_version __attribute__ ((unused)) = "LVM "LVM_RELEASE_NAME" snapshot code ("LVM_RELEASE_DATE")\n";
+static char *lvm_snap_version __attribute__ ((unused)) =
+    "LVM " LVM_RELEASE_NAME " snapshot code (" LVM_RELEASE_DATE ")\n";
 
 
 extern const char *const lvm_name;
@@ -65,19 +68,20 @@
 
 void lvm_snapshot_release(lv_t *);
 
-static int _write_COW_table_block(vg_t *vg, lv_t *lv, int idx,
+static int _write_COW_table_block(vg_t * vg, lv_t * lv, int idx,
 				  const char **reason);
-static void _disable_snapshot(vg_t *vg, lv_t *lv);
+static void _disable_snapshot(vg_t * vg, lv_t * lv);
 
 
 static inline int __brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
 			       kdev_t dev, unsigned long b[], int size,
-			       lv_t *lv) {
+			       lv_t * lv)
+{
 	return brw_kiovec(rw, nr, iovec, dev, b, size);
 }
 
 
-static int _pv_get_number(vg_t * vg, kdev_t rdev, uint *pvn)
+static int _pv_get_number(vg_t * vg, kdev_t rdev, uint * pvn)
 {
 	uint p;
 	for (p = 0; p < vg->pv_max; p++) {
@@ -104,34 +108,32 @@
 #define hashfn(dev,block,mask,chunk_size) \
 	((HASHDEV(dev)^((block)/(chunk_size))) & (mask))
 
-static inline lv_block_exception_t *
-lvm_find_exception_table(kdev_t org_dev, unsigned long org_start, lv_t * lv)
+static inline lv_block_exception_t *lvm_find_exception_table(kdev_t
+							     org_dev,
+							     unsigned long
+							     org_start,
+							     lv_t * lv)
 {
-	struct list_head * hash_table = lv->lv_snapshot_hash_table, * next;
+	struct list_head *hash_table = lv->lv_snapshot_hash_table, *next;
 	unsigned long mask = lv->lv_snapshot_hash_mask;
 	int chunk_size = lv->lv_chunk_size;
-	lv_block_exception_t * ret;
+	lv_block_exception_t *ret;
 	int i = 0;
 
-	hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
+	hash_table =
+	    &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
 	ret = NULL;
-	for (next = hash_table->next; next != hash_table; next = next->next)
-	{
-		lv_block_exception_t * exception;
+	for (next = hash_table->next; next != hash_table;
+	     next = next->next) {
+		lv_block_exception_t *exception;
 
 		exception = list_entry(next, lv_block_exception_t, hash);
 		if (exception->rsector_org == org_start &&
-		    exception->rdev_org == org_dev)
-		{
-			if (i)
-			{
+		    exception->rdev_org == org_dev) {
+			if (i) {
 				/* fun, isn't it? :) */
-#ifdef	list_move
-				list_move(next, hash_table);
-#else
 				list_del(next);
 				list_add(next, hash_table);
-#endif
 			}
 			ret = exception;
 			break;
@@ -145,13 +147,14 @@
 			  kdev_t org_dev, unsigned long org_start,
 			  lv_t * lv)
 {
-	struct list_head * hash_table = lv->lv_snapshot_hash_table;
+	struct list_head *hash_table = lv->lv_snapshot_hash_table;
 	unsigned long mask = lv->lv_snapshot_hash_mask;
 	int chunk_size = lv->lv_chunk_size;
 
 	if (!hash_table)
 		BUG();
-	hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
+	hash_table =
+	    &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
 	list_add(&exception->hash, hash_table);
 }
 
@@ -163,26 +166,25 @@
  *
  * We need to be holding at least a read lock on lv->lv_lock.
  */
-int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector,
+int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long *org_sector,
 			     unsigned long pe_start, lv_t * lv)
 {
 	int ret;
 	unsigned long pe_off, pe_adjustment, __org_start;
 	kdev_t __org_dev;
 	int chunk_size = lv->lv_chunk_size;
-	lv_block_exception_t * exception;
+	lv_block_exception_t *exception;
 
 	if (!lv->lv_block_exception)
 		return -1;
 
 	pe_off = pe_start % chunk_size;
-	pe_adjustment = (*org_sector-pe_off) % chunk_size;
+	pe_adjustment = (*org_sector - pe_off) % chunk_size;
 	__org_start = *org_sector - pe_adjustment;
 	__org_dev = *org_dev;
 	ret = 0;
 	exception = lvm_find_exception_table(__org_dev, __org_start, lv);
-	if (exception)
-	{
+	if (exception) {
 		*org_dev = exception->rdev_new;
 		*org_sector = exception->rsector_new + pe_adjustment;
 		ret = 1;
@@ -190,7 +192,7 @@
 	return ret;
 }
 
-void lvm_drop_snapshot(vg_t *vg, lv_t *lv_snap, const char *reason)
+void lvm_drop_snapshot(vg_t * vg, lv_t * lv_snap, const char *reason)
 {
 	kdev_t last_dev;
 	int i;
@@ -203,7 +205,7 @@
 	_disable_snapshot(vg, lv_snap);
 
 	for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) {
-		if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) {
+		if (lv_snap->lv_block_exception[i].rdev_new != last_dev) {
 			last_dev = lv_snap->lv_block_exception[i].rdev_new;
 			invalidate_buffers(last_dev);
 		}
@@ -214,14 +216,14 @@
 
 	printk(KERN_INFO
 	       "%s -- giving up to snapshot %s on %s: %s\n",
-	       lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name,
-	       reason);
+	       lvm_name, lv_snap->lv_snapshot_org->lv_name,
+	       lv_snap->lv_name, reason);
 }
 
 static inline int lvm_snapshot_prepare_blocks(unsigned long *blocks,
-					       unsigned long start,
-					       int nr_sectors,
-					       int blocksize)
+					      unsigned long start,
+					      int nr_sectors,
+					      int blocksize)
 {
 	int i, sectors_per_block, nr_blocks;
 
@@ -244,8 +246,7 @@
 	int correct_size = BLOCK_SIZE, i, major;
 
 	major = MAJOR(dev);
-	if (blksize_size[major])
-	{
+	if (blksize_size[major]) {
 		i = blksize_size[major][MINOR(dev)];
 		if (i)
 			correct_size = i;
@@ -254,10 +255,10 @@
 }
 
 #ifdef DEBUG_SNAPSHOT
-static inline void invalidate_snap_cache(unsigned long start, unsigned long nr,
-					 kdev_t dev)
+static inline void invalidate_snap_cache(unsigned long start,
+					 unsigned long nr, kdev_t dev)
 {
-	struct buffer_head * bh;
+	struct buffer_head *bh;
 	int sectors_per_block, i, blksize, minor;
 
 	minor = MINOR(dev);
@@ -266,8 +267,7 @@
 	nr /= sectors_per_block;
 	start /= sectors_per_block;
 
-	for (i = 0; i < nr; i++)
-	{
+	for (i = 0; i < nr; i++) {
 		bh = get_hash_table(dev, start++, blksize);
 		if (bh)
 			bforget(bh);
@@ -280,40 +280,44 @@
 {
 	int id = 0, is = lv_snap->lv_remap_ptr;
 	ulong blksize_snap;
-	lv_COW_table_disk_t * lv_COW_table = (lv_COW_table_disk_t *)
-		page_address(lv_snap->lv_COW_table_iobuf->maplist[0]);
+	lv_COW_table_disk_t *lv_COW_table = (lv_COW_table_disk_t *)
+	    page_address(lv_snap->lv_COW_table_iobuf->maplist[0]);
 
 	if (is == 0)
 		return 0;
 
 	is--;
 	blksize_snap =
-		lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new);
+	    lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new);
 	is -= is % (blksize_snap / sizeof(lv_COW_table_disk_t));
 
 	memset(lv_COW_table, 0, blksize_snap);
-	for ( ; is < lv_snap->lv_remap_ptr; is++, id++) {
+	for (; is < lv_snap->lv_remap_ptr; is++, id++) {
 		/* store new COW_table entry */
-		lv_block_exception_t *be = lv_snap->lv_block_exception + is;
+		lv_block_exception_t *be =
+		    lv_snap->lv_block_exception + is;
 		uint pvn;
 
 		if (_pv_get_number(vg, be->rdev_org, &pvn))
 			goto bad;
 
 		lv_COW_table[id].pv_org_number = cpu_to_le64(pvn);
-		lv_COW_table[id].pv_org_rsector = cpu_to_le64(be->rsector_org);
+		lv_COW_table[id].pv_org_rsector =
+		    cpu_to_le64(be->rsector_org);
 
 		if (_pv_get_number(vg, be->rdev_new, &pvn))
 			goto bad;
 
 		lv_COW_table[id].pv_snap_number = cpu_to_le64(pvn);
-		lv_COW_table[id].pv_snap_rsector = cpu_to_le64(be->rsector_new);
+		lv_COW_table[id].pv_snap_rsector =
+		    cpu_to_le64(be->rsector_new);
 	}
 
 	return 0;
 
- bad:
-	printk(KERN_ERR "%s -- lvm_snapshot_fill_COW_page failed", lvm_name);
+      bad:
+	printk(KERN_ERR "%s -- lvm_snapshot_fill_COW_page failed",
+	       lvm_name);
 	return -1;
 }
 
@@ -323,12 +327,12 @@
  *
  * We need to hold a write lock on lv_snap->lv_lock.
  */
-int lvm_write_COW_table_block(vg_t * vg, lv_t *lv_snap)
+int lvm_write_COW_table_block(vg_t * vg, lv_t * lv_snap)
 {
 	int r;
 	const char *err;
-	if((r = _write_COW_table_block(vg, lv_snap,
-				       lv_snap->lv_remap_ptr - 1, &err)))
+	if ((r = _write_COW_table_block(vg, lv_snap,
+					lv_snap->lv_remap_ptr - 1, &err)))
 		lvm_drop_snapshot(vg, lv_snap, err);
 	return r;
 }
@@ -349,13 +353,15 @@
 		     unsigned long org_phys_sector,
 		     unsigned long org_pe_start,
 		     unsigned long org_virt_sector,
-		     vg_t *vg, lv_t* lv_snap)
+		     vg_t * vg, lv_t * lv_snap)
 {
-	const char * reason;
-	unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off;
+	const char *reason;
+	unsigned long org_start, snap_start, snap_phys_dev, virt_start,
+	    pe_off;
 	unsigned long phys_start;
-	int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size;
-	struct kiobuf * iobuf = lv_snap->lv_iobuf;
+	int idx = lv_snap->lv_remap_ptr, chunk_size =
+	    lv_snap->lv_chunk_size;
+	struct kiobuf *iobuf = lv_snap->lv_iobuf;
 	unsigned long *blocks = iobuf->blocks;
 	int blksize_snap, blksize_org, min_blksize, max_blksize;
 	int max_sectors, nr_sectors;
@@ -366,7 +372,8 @@
 
 	/* calculate physical boundaries of source chunk */
 	pe_off = org_pe_start % chunk_size;
-	org_start = org_phys_sector - ((org_phys_sector-pe_off) % chunk_size);
+	org_start =
+	    org_phys_sector - ((org_phys_sector - pe_off) % chunk_size);
 	virt_start = org_virt_sector - (org_phys_sector - org_start);
 
 	/* calculate physical boundaries of destination chunk */
@@ -381,25 +388,22 @@
 	       lvm_name,
 	       kdevname(org_phys_dev), org_phys_sector, org_start,
 	       kdevname(snap_phys_dev), snap_start,
-	       chunk_size,
-	       org_pe_start, pe_off,
-	       org_virt_sector);
+	       chunk_size, org_pe_start, pe_off, org_virt_sector);
 #endif
 
 	blksize_org = lvm_sectsize(org_phys_dev);
 	blksize_snap = lvm_sectsize(snap_phys_dev);
 	max_blksize = max(blksize_org, blksize_snap);
 	min_blksize = min(blksize_org, blksize_snap);
-	max_sectors = KIO_MAX_SECTORS * (min_blksize>>9);
+	max_sectors = KIO_MAX_SECTORS * (min_blksize >> 9);
 
-	if (chunk_size % (max_blksize>>9))
+	if (chunk_size % (max_blksize >> 9))
 		goto fail_blksize;
 
 	/* Don't change org_start, we need it to fill in the exception table */
 	phys_start = org_start;
 
-	while (chunk_size)
-	{
+	while (chunk_size) {
 		nr_sectors = min(chunk_size, max_sectors);
 		chunk_size -= nr_sectors;
 
@@ -410,7 +414,8 @@
 			goto fail_prepare;
 
 		if (__brw_kiovec(READ, 1, &iobuf, org_phys_dev, blocks,
-				 blksize_org, lv_snap) != (nr_sectors<<9))
+				 blksize_org,
+				 lv_snap) != (nr_sectors << 9))
 			goto fail_raw_read;
 
 		if (!lvm_snapshot_prepare_blocks(blocks, snap_start,
@@ -418,7 +423,8 @@
 			goto fail_prepare;
 
 		if (__brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, blocks,
-				 blksize_snap, lv_snap) != (nr_sectors<<9))
+				 blksize_snap,
+				 lv_snap) != (nr_sectors << 9))
 			goto fail_raw_write;
 
 		phys_start += nr_sectors;
@@ -440,53 +446,55 @@
 		      org_phys_dev, org_start, lv_snap);
 	lv_snap->lv_remap_ptr = idx + 1;
 	if (lv_snap->lv_snapshot_use_rate > 0) {
-		if (lv_snap->lv_remap_ptr * 100 / lv_snap->lv_remap_end >= lv_snap->lv_snapshot_use_rate)
+		if (lv_snap->lv_remap_ptr * 100 / lv_snap->lv_remap_end >=
+		    lv_snap->lv_snapshot_use_rate)
 			wake_up_interruptible(&lv_snap->lv_snapshot_wait);
 	}
 	return 0;
 
 	/* slow path */
-out:
+      out:
 	lvm_drop_snapshot(vg, lv_snap, reason);
 	return 1;
 
-fail_out_of_space:
+      fail_out_of_space:
 	reason = "out of space";
 	goto out;
-fail_raw_read:
+      fail_raw_read:
 	reason = "read error";
 	goto out;
-fail_raw_write:
+      fail_raw_write:
 	reason = "write error";
 	goto out;
-fail_blksize:
+      fail_blksize:
 	reason = "blocksize error";
 	goto out;
 
-fail_prepare:
+      fail_prepare:
 	reason = "couldn't prepare kiovec blocks "
-		"(start probably isn't block aligned)";
+	    "(start probably isn't block aligned)";
 	goto out;
 }
 
-int lvm_snapshot_alloc_iobuf_pages(struct kiobuf * iobuf, int sectors)
+int lvm_snapshot_alloc_iobuf_pages(struct kiobuf *iobuf, int sectors)
 {
 	int bytes, nr_pages, err, i;
 
 	bytes = sectors * SECTOR_SIZE;
 	nr_pages = (bytes + ~PAGE_MASK) >> PAGE_SHIFT;
 	err = expand_kiobuf(iobuf, nr_pages);
-	if (err) goto out;
+	if (err)
+		goto out;
 
 	err = -ENOMEM;
 	iobuf->locked = 1;
 	iobuf->nr_pages = 0;
-	for (i = 0; i < nr_pages; i++)
-	{
-		struct page * page;
+	for (i = 0; i < nr_pages; i++) {
+		struct page *page;
 
 		page = alloc_page(GFP_KERNEL);
-		if (!page) goto out;
+		if (!page)
+			goto out;
 
 		iobuf->maplist[i] = page;
 		LockPage(page);
@@ -496,7 +504,7 @@
 
 	err = 0;
 
-out:
+      out:
 	return err;
 }
 
@@ -516,13 +524,13 @@
 {
 	int err;
 	unsigned long buckets, max_buckets, size;
-	struct list_head * hash;
+	struct list_head *hash;
 
 	buckets = lv->lv_remap_end;
 	max_buckets = calc_max_buckets();
 	buckets = min(buckets, max_buckets);
-	while (buckets & (buckets-1))
-		buckets &= (buckets-1);
+	while (buckets & (buckets - 1))
+		buckets &= (buckets - 1);
 
 	size = buckets * sizeof(struct list_head);
 
@@ -534,11 +542,11 @@
 		goto out;
 	lv->lv_snapshot_hash_table_size = size;
 
-	lv->lv_snapshot_hash_mask = buckets-1;
+	lv->lv_snapshot_hash_mask = buckets - 1;
 	while (buckets--)
-		INIT_LIST_HEAD(hash+buckets);
+		INIT_LIST_HEAD(hash + buckets);
 	err = 0;
-out:
+      out:
 	return err;
 }
 
@@ -548,33 +556,39 @@
 
 	/* allocate kiovec to do chunk io */
 	ret = alloc_kiovec(1, &lv_snap->lv_iobuf);
-	if (ret) goto out;
+	if (ret)
+		goto out;
 
-	max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9);
+	max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT - 9);
 
-	ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors);
-	if (ret) goto out_free_kiovec;
+	ret =
+	    lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors);
+	if (ret)
+		goto out_free_kiovec;
 
 	/* allocate kiovec to do exception table io */
 	ret = alloc_kiovec(1, &lv_snap->lv_COW_table_iobuf);
-	if (ret) goto out_free_kiovec;
+	if (ret)
+		goto out_free_kiovec;
 
 	ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_COW_table_iobuf,
-					     PAGE_SIZE/SECTOR_SIZE);
-	if (ret) goto out_free_both_kiovecs;
+					     PAGE_SIZE / SECTOR_SIZE);
+	if (ret)
+		goto out_free_both_kiovecs;
 
 	ret = lvm_snapshot_alloc_hash_table(lv_snap);
-	if (ret) goto out_free_both_kiovecs;
+	if (ret)
+		goto out_free_both_kiovecs;
 
-out:
+      out:
 	return ret;
 
-out_free_both_kiovecs:
+      out_free_both_kiovecs:
 	unmap_kiobuf(lv_snap->lv_COW_table_iobuf);
 	free_kiovec(1, &lv_snap->lv_COW_table_iobuf);
 	lv_snap->lv_COW_table_iobuf = NULL;
 
-out_free_kiovec:
+      out_free_kiovec:
 	unmap_kiobuf(lv_snap->lv_iobuf);
 	free_kiovec(1, &lv_snap->lv_iobuf);
 	lv_snap->lv_iobuf = NULL;
@@ -585,27 +599,23 @@
 
 void lvm_snapshot_release(lv_t * lv)
 {
-	if (lv->lv_block_exception)
-	{
+	if (lv->lv_block_exception) {
 		vfree(lv->lv_block_exception);
 		lv->lv_block_exception = NULL;
 	}
-	if (lv->lv_snapshot_hash_table)
-	{
+	if (lv->lv_snapshot_hash_table) {
 		vfree(lv->lv_snapshot_hash_table);
 		lv->lv_snapshot_hash_table = NULL;
 		lv->lv_snapshot_hash_table_size = 0;
 	}
-	if (lv->lv_iobuf)
-	{
-	        kiobuf_wait_for_io(lv->lv_iobuf);
+	if (lv->lv_iobuf) {
+		kiobuf_wait_for_io(lv->lv_iobuf);
 		unmap_kiobuf(lv->lv_iobuf);
 		free_kiovec(1, &lv->lv_iobuf);
 		lv->lv_iobuf = NULL;
 	}
-	if (lv->lv_COW_table_iobuf)
-	{
-	        kiobuf_wait_for_io(lv->lv_COW_table_iobuf);
+	if (lv->lv_COW_table_iobuf) {
+		kiobuf_wait_for_io(lv->lv_COW_table_iobuf);
 		unmap_kiobuf(lv->lv_COW_table_iobuf);
 		free_kiovec(1, &lv->lv_COW_table_iobuf);
 		lv->lv_COW_table_iobuf = NULL;
@@ -613,55 +623,67 @@
 }
 
 
-static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
-				  int idx, const char **reason) {
+static int _write_COW_table_block(vg_t * vg, lv_t * lv_snap,
+				  int idx, const char **reason)
+{
 	int blksize_snap;
 	int end_of_table;
 	int idx_COW_table;
 	uint pvn;
 	ulong snap_pe_start, COW_table_sector_offset,
-	      COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block;
+	    COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block;
 	ulong blocks[1];
 	kdev_t snap_phys_dev;
 	lv_block_exception_t *be;
 	struct kiobuf *COW_table_iobuf = lv_snap->lv_COW_table_iobuf;
-	lv_COW_table_disk_t * lv_COW_table =
-	   ( lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_iobuf->maplist[0]);
+	lv_COW_table_disk_t *lv_COW_table =
+	    (lv_COW_table_disk_t *) page_address(lv_snap->
+						 lv_COW_table_iobuf->
+						 maplist[0]);
 
 	COW_chunks_per_pe = LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg, lv_snap);
 	COW_entries_per_pe = LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg, lv_snap);
 
 	/* get physical addresse of destination chunk */
 	snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
-	snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size;
+	snap_pe_start =
+	    lv_snap->lv_block_exception[idx -
+					(idx %
+					 COW_entries_per_pe)].rsector_new -
+	    lv_snap->lv_chunk_size;
 
 	blksize_snap = lvm_sectsize(snap_phys_dev);
 
-        COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t);
-        idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block;
+	COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t);
+	idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block;
 
-	if ( idx_COW_table == 0) memset(lv_COW_table, 0, blksize_snap);
+	if (idx_COW_table == 0)
+		memset(lv_COW_table, 0, blksize_snap);
 
 	/* sector offset into the on disk COW table */
-	COW_table_sector_offset = (idx % COW_entries_per_pe) / (SECTOR_SIZE / sizeof(lv_COW_table_disk_t));
-
-        /* COW table block to write next */
-	blocks[0] = (snap_pe_start + COW_table_sector_offset) >> (blksize_snap >> 10);
+	COW_table_sector_offset =
+	    (idx % COW_entries_per_pe) / (SECTOR_SIZE /
+					  sizeof(lv_COW_table_disk_t));
+
+	/* COW table block to write next */
+	blocks[0] =
+	    (snap_pe_start +
+	     COW_table_sector_offset) >> (blksize_snap >> 10);
 
 	/* store new COW_table entry */
 	be = lv_snap->lv_block_exception + idx;
-	if(_pv_get_number(vg, be->rdev_org, &pvn))
+	if (_pv_get_number(vg, be->rdev_org, &pvn))
 		goto fail_pv_get_number;
 
 	lv_COW_table[idx_COW_table].pv_org_number = cpu_to_le64(pvn);
 	lv_COW_table[idx_COW_table].pv_org_rsector =
-		cpu_to_le64(be->rsector_org);
-	if(_pv_get_number(vg, snap_phys_dev, &pvn))
+	    cpu_to_le64(be->rsector_org);
+	if (_pv_get_number(vg, snap_phys_dev, &pvn))
 		goto fail_pv_get_number;
 
 	lv_COW_table[idx_COW_table].pv_snap_number = cpu_to_le64(pvn);
 	lv_COW_table[idx_COW_table].pv_snap_rsector =
-		cpu_to_le64(be->rsector_new);
+	    cpu_to_le64(be->rsector_new);
 
 	COW_table_iobuf->length = blksize_snap;
 	/* COW_table_iobuf->nr_pages = 1; */
@@ -672,36 +694,42 @@
 
 	/* initialization of next COW exception table block with zeroes */
 	end_of_table = idx % COW_entries_per_pe == COW_entries_per_pe - 1;
-	if (idx_COW_table % COW_entries_per_block == COW_entries_per_block - 1 || end_of_table)
-	{
+	if (idx_COW_table % COW_entries_per_block ==
+	    COW_entries_per_block - 1 || end_of_table) {
 		/* don't go beyond the end */
-		if (idx + 1 >= lv_snap->lv_remap_end) goto out;
+		if (idx + 1 >= lv_snap->lv_remap_end)
+			goto out;
 
 		memset(lv_COW_table, 0, blksize_snap);
 
-		if (end_of_table)
-		{
+		if (end_of_table) {
 			idx++;
-			snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
-			snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size;
+			snap_phys_dev =
+			    lv_snap->lv_block_exception[idx].rdev_new;
+			snap_pe_start =
+			    lv_snap->lv_block_exception[idx -
+							(idx %
+							 COW_entries_per_pe)].
+			    rsector_new - lv_snap->lv_chunk_size;
 			blksize_snap = lvm_sectsize(snap_phys_dev);
 			blocks[0] = snap_pe_start >> (blksize_snap >> 10);
-		} else blocks[0]++;
+		} else
+			blocks[0]++;
 
 		if (__brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev,
-                                 blocks, blksize_snap, lv_snap) !=
-                    blksize_snap)
+				 blocks, blksize_snap, lv_snap) !=
+		    blksize_snap)
 			goto fail_raw_write;
 	}
 
-out:
+      out:
 	return 0;
 
-fail_raw_write:
+      fail_raw_write:
 	*reason = "write error";
 	return 1;
 
-fail_pv_get_number:
+      fail_pv_get_number:
 	*reason = "_pv_get_number failed";
 	return 1;
 }
@@ -717,10 +745,12 @@
  * to activate the snapshot and prevent this from happening.
  */
 
-static void _disable_snapshot(vg_t *vg, lv_t *lv) {
+static void _disable_snapshot(vg_t * vg, lv_t * lv)
+{
 	const char *err;
-	lv->lv_block_exception[0].rsector_org = LVM_SNAPSHOT_DROPPED_SECTOR;
-	if(_write_COW_table_block(vg, lv, 0, &err) < 0) {
+	lv->lv_block_exception[0].rsector_org =
+	    LVM_SNAPSHOT_DROPPED_SECTOR;
+	if (_write_COW_table_block(vg, lv, 0, &err) < 0) {
 		printk(KERN_ERR "%s -- couldn't disable snapshot: %s\n",
 		       lvm_name, err);
 	}
diff -Nru a/drivers/md/lvm.c b/drivers/md/lvm.c
--- a/drivers/md/lvm.c	Wed Feb  5 18:53:36 2003
+++ b/drivers/md/lvm.c	Mon Mar 10 06:55:46 2003
@@ -8,7 +8,8 @@
  * January-March,May,July,September,October 1999
  * January,February,July,September-November 2000
  * January-May,June,October 2001
- * May-July 2002
+ * May-August 2002
+ * February 2003
  *
  *
  * LVM driver is free software; you can redistribute it and/or modify
@@ -220,6 +221,12 @@
  *               - support HDIO_GETGEO_BIG ioctl
  *    05/07/2002 - fixed OBO error on vg array access [benh@kernel.crashing.org]
  *    22/07/2002 - streamlined blk_ioctl() call
+ *    14/08/2002 - stored fs handle in lvm_do_lv_rename
+ *                 [kaoru@bsd.tnes.nec.co.jp]
+ *    06/02/2003 - fix persistent snapshot extend/reduce bug in
+ *		   lvm_do_lv_extend_reduce() [dalestephenson@mac.com]
+ *    04/03/2003 - snapshot extend/reduce memory leak
+ *               - VG PE counter wrong [dalestephenson@mac.com]
  *
  */
 
@@ -283,13 +290,14 @@
 /*
  * External function prototypes
  */
-static int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*);
+static int lvm_make_request_fn(request_queue_t *, int,
+			       struct buffer_head *);
 
 static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong);
 static int lvm_blk_open(struct inode *, struct file *);
 
 static int lvm_blk_close(struct inode *, struct file *);
-static int lvm_get_snapshot_use_rate(lv_t *lv_ptr, void *arg);
+static int lvm_get_snapshot_use_rate(lv_t * lv_ptr, void *arg);
 static int lvm_user_bmap(struct inode *, struct lv_bmap *);
 
 static int lvm_chr_open(struct inode *, struct file *);
@@ -319,13 +327,13 @@
 static int lvm_do_lv_extend_reduce(int, char *, lv_t *);
 static int lvm_do_lv_remove(int, char *, int);
 static int lvm_do_lv_rename(vg_t *, lv_req_t *, lv_t *);
-static int lvm_do_lv_status_byname(vg_t *r, void *);
+static int lvm_do_lv_status_byname(vg_t * r, void *);
 static int lvm_do_lv_status_byindex(vg_t *, void *);
 static int lvm_do_lv_status_bydev(vg_t *, void *);
 
-static int lvm_do_pe_lock_unlock(vg_t *r, void *);
+static int lvm_do_pe_lock_unlock(vg_t * r, void *);
 
-static int lvm_do_pv_change(vg_t*, void*);
+static int lvm_do_pv_change(vg_t *, void *);
 static int lvm_do_pv_status(vg_t *, void *);
 static int lvm_do_pv_flush(void *);
 
@@ -335,15 +343,15 @@
 static int lvm_do_vg_rename(vg_t *, void *);
 static int lvm_do_vg_remove(int);
 static void lvm_geninit(struct gendisk *);
-static void __update_hardsectsize(lv_t *lv);
+static void __update_hardsectsize(lv_t * lv);
 
 
 static void _queue_io(struct buffer_head *bh, int rw);
 static struct buffer_head *_dequeue_io(void);
 static void _flush_io(struct buffer_head *bh);
 
-static int _open_pv(pv_t *pv);
-static void _close_pv(pv_t *pv);
+static int _open_pv(pv_t * pv);
+static void _close_pv(pv_t * pv);
 
 static unsigned long _sectors_to_k(unsigned long sect);
 
@@ -354,7 +362,8 @@
 
 
 /* variables */
-char *lvm_version = "LVM version "LVM_RELEASE_NAME"("LVM_RELEASE_DATE")";
+char *lvm_version =
+    "LVM version " LVM_RELEASE_NAME "(" LVM_RELEASE_DATE ")";
 ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION;
 int loadtime = 0;
 const char *const lvm_name = LVM_NAME;
@@ -397,19 +406,18 @@
 
 
 struct file_operations lvm_chr_fops = {
-	owner:		THIS_MODULE,
-	open:		lvm_chr_open,
-	release:	lvm_chr_close,
-	ioctl:		lvm_chr_ioctl,
+	owner:THIS_MODULE,
+	open:lvm_chr_open,
+	release:lvm_chr_close,
+	ioctl:lvm_chr_ioctl,
 };
 
 /* block device operations structure needed for 2.3.38? and above */
-struct block_device_operations lvm_blk_dops =
-{
-	owner:		THIS_MODULE,
-	open:		lvm_blk_open,
-	release:	lvm_blk_close,
-	ioctl:		lvm_blk_ioctl,
+struct block_device_operations lvm_blk_dops = {
+	.owner		= THIS_MODULE,
+	.open		= lvm_blk_open,
+	.release	= lvm_blk_close,
+	.ioctl		= lvm_blk_ioctl,
 };
 
 
@@ -419,15 +427,14 @@
 static int lvm_hardsectsizes[MAX_LV];
 static int lvm_size[MAX_LV];
 
-static struct gendisk lvm_gendisk =
-{
-	major:		MAJOR_NR,
-	major_name:	LVM_NAME,
-	minor_shift:	0,
-	max_p:		1,
-	part:		lvm_hd_struct,
-	sizes:		lvm_size,
-	nr_real:	MAX_LV,
+static struct gendisk lvm_gendisk = {
+	.major		= MAJOR_NR,
+	.major_name	= LVM_NAME,
+	.minor_shift	= 0,
+	.max_p		= 1,
+	.part		= lvm_hd_struct,
+	.sizes		= lvm_size,
+	.nr_real	= MAX_LV,
 };
 
 
@@ -464,7 +471,8 @@
 	lvm_hd_name_ptr = lvm_hd_name;
 #endif
 
-	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn);
+	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR),
+			       lvm_make_request_fn);
 
 
 	/* initialise the pe lock */
@@ -482,7 +490,7 @@
 #endif
 
 	return 0;
-} /* lvm_init() */
+}				/* lvm_init() */
 
 /*
  * cleanup...
@@ -515,11 +523,12 @@
 	lvm_fin_fs();
 
 #ifdef MODULE
-	printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name);
+	printk(KERN_INFO "%s -- Module successfully deactivated\n",
+	       lvm_name);
 #endif
 
 	return;
-}	/* lvm_cleanup() */
+}				/* lvm_cleanup() */
 
 /*
  * support function to initialize lvm variables
@@ -549,7 +558,7 @@
 	}
 
 	return;
-} /* lvm_init_vars() */
+}				/* lvm_init_vars() */
 
 
 /********************************************************************
@@ -572,13 +581,15 @@
 	      minor, VG_CHR(minor), MODE_TO_STR(file->f_mode), lock);
 
 	/* super user validation */
-	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
 
 	/* Group special file open */
-	if (VG_CHR(minor) > MAX_VG) return -ENXIO;
+	if (VG_CHR(minor) > MAX_VG)
+		return -ENXIO;
 
 	spin_lock(&lvm_lock);
-	if(lock == current->pid)
+	if (lock == current->pid)
 		_lock_open_count++;
 	spin_unlock(&lvm_lock);
 
@@ -587,7 +598,7 @@
 	MOD_INC_USE_COUNT;
 
 	return 0;
-} /* lvm_chr_open() */
+}				/* lvm_chr_open() */
 
 
 /*
@@ -604,16 +615,19 @@
 	uint extendable, l, v;
 	void *arg = (void *) a;
 	lv_t lv;
-	vg_t* vg_ptr = vg[VG_CHR(minor)];
+	vg_t *vg_ptr = vg[VG_CHR(minor)];
 
 	/* otherwise cc will complain about unused variables */
 	(void) lvm_lock;
 
-	P_IOCTL("chr MINOR: %d  command: 0x%X  arg: %p  VG#: %d  mode: %s%s\n",
-		minor, command, arg, VG_CHR(minor), MODE_TO_STR(file->f_mode));
+	P_IOCTL
+	    ("chr MINOR: %d  command: 0x%X  arg: %p  VG#: %d  mode: %s%s\n",
+	     minor, command, arg, VG_CHR(minor),
+	     MODE_TO_STR(file->f_mode));
 
 #ifdef LVM_TOTAL_RESET
-	if (lvm_reset_spindown > 0) return -EACCES;
+	if (lvm_reset_spindown > 0)
+		return -EACCES;
 #endif
 
 	/* Main command switch */
@@ -625,7 +639,8 @@
 	case LVM_GET_IOP_VERSION:
 		/* check lvm version to ensure driver/tools+lib
 		   interoperability */
-		if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0)
+		if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) !=
+		    0)
 			return -EFAULT;
 		return 0;
 
@@ -634,7 +649,8 @@
 		/* lock reset function */
 		lvm_reset_spindown = 1;
 		for (v = 0; v < ABS_MAX_VG; v++) {
-			if (vg[v] != NULL) lvm_do_vg_remove(v);
+			if (vg[v] != NULL)
+				lvm_do_vg_remove(v);
 		}
 
 #ifdef MODULE
@@ -642,28 +658,28 @@
 			MOD_INC_USE_COUNT;
 		while (GET_USE_COUNT(&__this_module) > 1)
 			MOD_DEC_USE_COUNT;
-#endif /* MODULE */
+#endif				/* MODULE */
 		lock = 0;	/* release lock */
 		wake_up_interruptible(&lvm_wait);
 		return 0;
-#endif /* LVM_TOTAL_RESET */
+#endif				/* LVM_TOTAL_RESET */
 
 
 	case LE_REMAP:
 		/* remap a logical extent (after moving the physical extent) */
-		return lvm_do_le_remap(vg_ptr,arg);
+		return lvm_do_le_remap(vg_ptr, arg);
 
 	case PE_LOCK_UNLOCK:
 		/* lock/unlock i/o to a physical extent to move it to another
 		   physical volume (move's done in user space's pvmove) */
-		return lvm_do_pe_lock_unlock(vg_ptr,arg);
+		return lvm_do_pe_lock_unlock(vg_ptr, arg);
 
 	case VG_CREATE_OLD:
 		/* create a VGDA */
 		return lvm_do_vg_create(arg, minor);
 
 	case VG_CREATE:
-	        /* create a VGDA, assume VG number is filled in */
+		/* create a VGDA, assume VG number is filled in */
 		return lvm_do_vg_create(arg, -1);
 
 	case VG_EXTEND:
@@ -685,8 +701,10 @@
 
 	case VG_SET_EXTENDABLE:
 		/* set/clear extendability flag of volume group */
-		if (vg_ptr == NULL) return -ENXIO;
-		if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0)
+		if (vg_ptr == NULL)
+			return -ENXIO;
+		if (copy_from_user(&extendable, arg, sizeof(extendable)) !=
+		    0)
 			return -EFAULT;
 
 		if (extendable == VG_EXTENDABLE ||
@@ -695,13 +713,15 @@
 				vg_ptr->vg_status |= VG_EXTENDABLE;
 			else
 				vg_ptr->vg_status &= ~VG_EXTENDABLE;
-		} else return -EINVAL;
+		} else
+			return -EINVAL;
 		return 0;
 
 
 	case VG_STATUS:
 		/* get volume group data (only the vg_t struct) */
-		if (vg_ptr == NULL) return -ENXIO;
+		if (vg_ptr == NULL)
+			return -ENXIO;
 		if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0)
 			return -EFAULT;
 		return 0;
@@ -734,21 +754,26 @@
 	case LV_REMOVE:
 	case LV_RENAME:
 		/* create, extend, reduce, remove or rename a logical volume */
-		if (vg_ptr == NULL) return -ENXIO;
+		if (vg_ptr == NULL)
+			return -ENXIO;
 		if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0)
 			return -EFAULT;
 
 		if (command != LV_REMOVE) {
-			if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0)
+			if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) !=
+			    0)
 				return -EFAULT;
 		}
 		switch (command) {
 		case LV_CREATE:
-			return lvm_do_lv_create(minor, lv_req.lv_name, &lv);
+			return lvm_do_lv_create(minor, lv_req.lv_name,
+						&lv);
 
 		case LV_EXTEND:
 		case LV_REDUCE:
-			return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv);
+			return lvm_do_lv_extend_reduce(minor,
+						       lv_req.lv_name,
+						       &lv);
 		case LV_REMOVE:
 			return lvm_do_lv_remove(minor, lv_req.lv_name, -1);
 
@@ -776,12 +801,12 @@
 
 	case PV_CHANGE:
 		/* change a physical volume */
-		return lvm_do_pv_change(vg_ptr,arg);
+		return lvm_do_pv_change(vg_ptr, arg);
 
 
 	case PV_STATUS:
 		/* get physical volume data (pv_t structure only) */
-		return lvm_do_pv_status(vg_ptr,arg);
+		return lvm_do_pv_status(vg_ptr, arg);
 
 
 	case PV_FLUSH:
@@ -797,7 +822,7 @@
 	}
 
 	return 0;
-} /* lvm_chr_ioctl */
+}				/* lvm_chr_ioctl */
 
 
 /*
@@ -815,12 +840,14 @@
 	}
 #endif
 
-	if (lvm_chr_open_count > 0) lvm_chr_open_count--;
+	if (lvm_chr_open_count > 0)
+		lvm_chr_open_count--;
 
 	spin_lock(&lvm_lock);
-	if(lock == current->pid) {
-		if(!_lock_open_count) {
-			P_DEV("chr_close: unlocking LVM for pid %d\n", lock);
+	if (lock == current->pid) {
+		if (!_lock_open_count) {
+			P_DEV("chr_close: unlocking LVM for pid %d\n",
+			      lock);
 			lock = 0;
 			wake_up_interruptible(&lvm_wait);
 		} else
@@ -831,7 +858,7 @@
 	MOD_DEC_USE_COUNT;
 
 	return 0;
-} /* lvm_chr_close() */
+}				/* lvm_chr_close() */
 
 
 
@@ -851,7 +878,8 @@
 	vg_t *vg_ptr = vg[VG_BLK(minor)];
 
 	P_DEV("blk_open MINOR: %d  VG#: %d  LV#: %d  mode: %s%s\n",
-	      minor, VG_BLK(minor), LV_BLK(minor), MODE_TO_STR(file->f_mode));
+	      minor, VG_BLK(minor), LV_BLK(minor),
+	      MODE_TO_STR(file->f_mode));
 
 #ifdef LVM_TOTAL_RESET
 	if (lvm_reset_spindown > 0)
@@ -861,26 +889,27 @@
 	if (vg_ptr != NULL &&
 	    (vg_ptr->vg_status & VG_ACTIVE) &&
 	    (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL &&
-	    LV_BLK(minor) >= 0 &&
-	    LV_BLK(minor) < vg_ptr->lv_max) {
+	    LV_BLK(minor) >= 0 && LV_BLK(minor) < vg_ptr->lv_max) {
 
 		/* Check parallel LV spindown (LV remove) */
-		if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM;
+		if (lv_ptr->lv_status & LV_SPINDOWN)
+			return -EPERM;
 
 		/* Check inactive LV and open for read/write */
 		/* We need to be able to "read" an inactive LV
 		   to re-activate it again */
 		if ((file->f_mode & FMODE_WRITE) &&
 		    (!(lv_ptr->lv_status & LV_ACTIVE)))
-		    return -EPERM;
+			return -EPERM;
 
 		if (!(lv_ptr->lv_access & LV_WRITE) &&
 		    (file->f_mode & FMODE_WRITE))
 			return -EACCES;
 
 
-                /* be sure to increment VG counter */
-		if (lv_ptr->lv_open == 0) vg_ptr->lv_open++;
+		/* be sure to increment VG counter */
+		if (lv_ptr->lv_open == 0)
+			vg_ptr->lv_open++;
 		lv_ptr->lv_open++;
 
 		MOD_INC_USE_COUNT;
@@ -890,10 +919,10 @@
 		return 0;
 	}
 	return -ENXIO;
-} /* lvm_blk_open() */
+}				/* lvm_blk_open() */
 
 /* Deliver "hard disk geometry" */
-static int _hdio_getgeo(ulong a, lv_t *lv_ptr, int what)
+static int _hdio_getgeo(ulong a, lv_t * lv_ptr, int what)
 {
 	int ret = 0;
 	uchar heads = 128;
@@ -901,34 +930,34 @@
 	ulong start = 0;
 	uint cylinders;
 
-	while ( heads * sectors > lv_ptr->lv_size) {
+	while (heads * sectors > lv_ptr->lv_size) {
 		heads >>= 1;
 		sectors >>= 1;
 	}
 	cylinders = lv_ptr->lv_size / heads / sectors;
 
 	switch (what) {
-		case 0:
+	case 0:
 		{
 			struct hd_geometry *hd = (struct hd_geometry *) a;
 
 			if (put_user(heads, &hd->heads) ||
-	    		    put_user(sectors, &hd->sectors) ||
-	    		    put_user((ushort) cylinders, &hd->cylinders) ||
+			    put_user(sectors, &hd->sectors) ||
+			    put_user((ushort) cylinders, &hd->cylinders) ||
 			    put_user(start, &hd->start))
 				return -EFAULT;
 			break;
 		}
 
 #ifdef HDIO_GETGEO_BIG
-		case 1:
+	case 1:
 		{
 			struct hd_big_geometry *hd =
-				(struct hd_big_geometry *) a;
+			    (struct hd_big_geometry *) a;
 
 			if (put_user(heads, &hd->heads) ||
-	    		    put_user(sectors, &hd->sectors) ||
-	    		    put_user(cylinders, &hd->cylinders) ||
+			    put_user(sectors, &hd->sectors) ||
+			    put_user(cylinders, &hd->cylinders) ||
 			    put_user(start, &hd->start))
 				return -EFAULT;
 			break;
@@ -960,91 +989,92 @@
 		LV_BLK(minor), MODE_TO_STR(file->f_mode));
 
 	switch (cmd) {
-		case BLKRASET:
-			/* set read ahead for block device */
-			ret = blk_ioctl(dev, cmd, a);
-			if (ret)
-				return ret;
-			lv_ptr->lv_read_ahead = (long) a;
-			LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
-			break;
-	
-		case HDIO_GETGEO:
+	case BLKRASET:
+		/* set read ahead for block device */
+		ret = blk_ioctl(dev, cmd, a);
+		if (ret)
+			return ret;
+		lv_ptr->lv_read_ahead = (long) a;
+		LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
+		break;
+
+	case HDIO_GETGEO:
 #ifdef HDIO_GETGEO_BIG
-		case HDIO_GETGEO_BIG:
+	case HDIO_GETGEO_BIG:
 #endif
-			/* get disk geometry */
-			P_IOCTL("%s -- lvm_blk_ioctl -- HDIO_GETGEO\n",
-				lvm_name);
-			if (!a)
-				return -EINVAL;
-
-			switch (cmd) {
-				case HDIO_GETGEO:
-					return _hdio_getgeo(a, lv_ptr, 0);
+		/* get disk geometry */
+		P_IOCTL("%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name);
+		if (!a)
+			return -EINVAL;
+
+		switch (cmd) {
+		case HDIO_GETGEO:
+			return _hdio_getgeo(a, lv_ptr, 0);
 #ifdef HDIO_GETGEO_BIG
-				case HDIO_GETGEO_BIG:
-					return _hdio_getgeo(a, lv_ptr, 1);
+		case HDIO_GETGEO_BIG:
+			return _hdio_getgeo(a, lv_ptr, 1);
 #endif
-			}
-	
-		case LV_BMAP:
-			/* turn logical block into (dev_t, block). non privileged. */
-			/* don't bmap a snapshot, since the mapping can change */
-			if (lv_ptr->lv_access & LV_SNAPSHOT)
-				return -EPERM;
-	
-			return lvm_user_bmap(inode, (struct lv_bmap *) arg);
-	
-		case LV_SET_ACCESS:
-			/* set access flags of a logical volume */
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-	
-			down_write(&lv_ptr->lv_lock);
-			lv_ptr->lv_access = (ulong) arg;
-			up_write(&lv_ptr->lv_lock);
-	
-			if ( lv_ptr->lv_access & LV_WRITE)
-				set_device_ro(lv_ptr->lv_dev, 0);
-			else
-				set_device_ro(lv_ptr->lv_dev, 1);
-			break;
-	
-	
-		case LV_SET_ALLOCATION:
-			/* set allocation flags of a logical volume */
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			down_write(&lv_ptr->lv_lock);
-			lv_ptr->lv_allocation = (ulong) arg;
-			up_write(&lv_ptr->lv_lock);
-			break;
-	
-		case LV_SET_STATUS:
-			/* set status flags of a logical volume */
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1)
-				return -EPERM;
-			down_write(&lv_ptr->lv_lock);
-			lv_ptr->lv_status = (ulong) arg;
-			up_write(&lv_ptr->lv_lock);
-			break;
-	
-		case LV_SNAPSHOT_USE_RATE:
-			return lvm_get_snapshot_use_rate(lv_ptr, arg);
-	
-		default:
-			/* Handle rest here */
-			ret = blk_ioctl(dev, cmd, a);
-			if (ret)
-				printk(KERN_WARNING
-				       "%s -- lvm_blk_ioctl: unknown "
-				       "cmd 0x%x\n",
-				       lvm_name, cmd);
-			return ret;
+		}
+
+	case LV_BMAP:
+		/* turn logical block into (dev_t, block). non privileged. */
+		/* don't bmap a snapshot, since the mapping can change */
+		if (lv_ptr->lv_access & LV_SNAPSHOT)
+			return -EPERM;
+
+		return lvm_user_bmap(inode, (struct lv_bmap *) arg);
+
+	case LV_SET_ACCESS:
+		/* set access flags of a logical volume */
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+
+		down_write(&lv_ptr->lv_lock);
+		lv_ptr->lv_access = (ulong) arg;
+		up_write(&lv_ptr->lv_lock);
+
+		if (lv_ptr->lv_access & LV_WRITE)
+			set_device_ro(lv_ptr->lv_dev, 0);
+		else
+			set_device_ro(lv_ptr->lv_dev, 1);
+		break;
+
+
+	case LV_SET_ALLOCATION:
+		/* set allocation flags of a logical volume */
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		down_write(&lv_ptr->lv_lock);
+		lv_ptr->lv_allocation = (ulong) arg;
+		up_write(&lv_ptr->lv_lock);
+		break;
+
+	case LV_SET_STATUS:
+		/* set status flags of a logical volume */
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1)
+			return -EPERM;
+		down_write(&lv_ptr->lv_lock);
+		lv_ptr->lv_status = (ulong) arg;
+		up_write(&lv_ptr->lv_lock);
+		break;
+
+	case LV_SNAPSHOT_USE_RATE:
+		return lvm_get_snapshot_use_rate(lv_ptr, arg);
+
+	default:
+		/* Handle rest here */
+		ret = blk_ioctl(dev, cmd, a);
+		if (ret)
+			printk(KERN_WARNING
+			       "%s -- lvm_blk_ioctl: unknown "
+			       "cmd 0x%x\n", lvm_name, cmd);
+		return ret;
 	}
 
 	return 0;
-} /* lvm_blk_ioctl() */
+}				/* lvm_blk_ioctl() */
 
 
 /*
@@ -1059,15 +1089,16 @@
 	P_DEV("blk_close MINOR: %d  VG#: %d  LV#: %d\n",
 	      minor, VG_BLK(minor), LV_BLK(minor));
 
-	if (lv_ptr->lv_open == 1) vg_ptr->lv_open--;
+	if (lv_ptr->lv_open == 1)
+		vg_ptr->lv_open--;
 	lv_ptr->lv_open--;
 
 	MOD_DEC_USE_COUNT;
 
 	return 0;
-} /* lvm_blk_close() */
+}				/* lvm_blk_close() */
 
-static int lvm_get_snapshot_use_rate(lv_t *lv, void *arg)
+static int lvm_get_snapshot_use_rate(lv_t * lv, void *arg)
 {
 	lv_snapshot_use_rate_req_t lv_rate_req;
 
@@ -1122,20 +1153,20 @@
 	if (get_user(block, &user_result->lv_block))
 		return -EFAULT;
 
-	memset(&bh,0,sizeof bh);
+	memset(&bh, 0, sizeof bh);
 	bh.b_blocknr = block;
 	bh.b_dev = bh.b_rdev = inode->i_rdev;
 	bh.b_size = lvm_get_blksize(bh.b_dev);
 	bh.b_rsector = block * (bh.b_size >> 9);
 	bh.b_end_io = NULL;
-	if ((err = lvm_map(&bh, READ)) < 0)  {
+	if ((err = lvm_map(&bh, READ)) < 0) {
 		printk("lvm map failed: %d\n", err);
 		return -EINVAL;
 	}
 
 	return put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) ||
-	       put_user(bh.b_rsector/(bh.b_size>>9), &user_result->lv_block) ?
-		-EFAULT : 0;
+	    put_user(bh.b_rsector / (bh.b_size >> 9),
+		     &user_result->lv_block) ? -EFAULT : 0;
 }
 
 
@@ -1144,7 +1175,8 @@
  * (see init_module/lvm_init)
  */
 static void __remap_snapshot(kdev_t rdev, ulong rsector,
-				    ulong pe_start, lv_t *lv, vg_t *vg) {
+			     ulong pe_start, lv_t * lv, vg_t * vg)
+{
 
 	/* copy a chunk from the origin to a snapshot device */
 	down_write(&lv->lv_lock);
@@ -1159,7 +1191,8 @@
 }
 
 static inline void _remap_snapshot(kdev_t rdev, ulong rsector,
-				   ulong pe_start, lv_t *lv, vg_t *vg) {
+				   ulong pe_start, lv_t * lv, vg_t * vg)
+{
 	int r;
 
 	/* check to see if this chunk is already in the snapshot */
@@ -1176,7 +1209,8 @@
 /*
  * extents destined for a pe that is on the move should be deferred
  */
-static inline int _should_defer(kdev_t pv, ulong sector, uint32_t pe_size) {
+static inline int _should_defer(kdev_t pv, ulong sector, uint32_t pe_size)
+{
 	return ((pe_lock_req.lock == LOCK_PE) &&
 		(pv == pe_lock_req.data.pv_dev) &&
 		(sector >= pe_lock_req.data.pv_offset) &&
@@ -1223,34 +1257,32 @@
 		goto bad;
 	}
 
-	if ((rw == WRITE || rw == WRITEA) &&
-	    !(lv->lv_access & LV_WRITE)) {
+	if ((rw == WRITE || rw == WRITEA) && !(lv->lv_access & LV_WRITE)) {
 		printk(KERN_CRIT
 		       "%s - lvm_map: ll_rw_blk write for readonly LV %s\n",
 		       lvm_name, lv->lv_name);
 		goto bad;
 	}
 
-	P_MAP("%s - lvm_map minor: %d  *rdev: %s  *rsector: %lu  size:%lu\n",
-	      lvm_name, minor,
-	      kdevname(bh->b_rdev),
-	      rsector_org, size);
+	P_MAP
+	    ("%s - lvm_map minor: %d  *rdev: %s  *rsector: %lu  size:%lu\n",
+	     lvm_name, minor, kdevname(bh->b_rdev), rsector_org, size);
 
 	if (rsector_org + size > lv->lv_size) {
 		printk(KERN_ALERT
 		       "%s - lvm_map access beyond end of device; *rsector: "
-                       "%lu or size: %lu wrong for minor: %2d\n",
-                       lvm_name, rsector_org, size, minor);
+		       "%lu or size: %lu wrong for minor: %2d\n",
+		       lvm_name, rsector_org, size, minor);
 		goto bad;
 	}
 
 
-	if (lv->lv_stripes < 2) { /* linear mapping */
+	if (lv->lv_stripes < 2) {	/* linear mapping */
 		/* get the index */
 		index = rsector_org / vg_this->pe_size;
 		pe_start = lv->lv_current_pe[index].pe;
 		rsector_map = lv->lv_current_pe[index].pe +
-			(rsector_org % vg_this->pe_size);
+		    (rsector_org % vg_this->pe_size);
 		rdev_map = lv->lv_current_pe[index].dev;
 
 		P_MAP("lv_current_pe[%ld].pe: %d  rdev: %s  rsector:%ld\n",
@@ -1263,22 +1295,23 @@
 
 		stripe_length = vg_this->pe_size * lv->lv_stripes;
 		stripe_index = (rsector_org % stripe_length) /
-			lv->lv_stripesize;
+		    lv->lv_stripesize;
 		index = rsector_org / stripe_length +
-			(stripe_index % lv->lv_stripes) *
-			(lv->lv_allocated_le / lv->lv_stripes);
+		    (stripe_index % lv->lv_stripes) *
+		    (lv->lv_allocated_le / lv->lv_stripes);
 		pe_start = lv->lv_current_pe[index].pe;
 		rsector_map = lv->lv_current_pe[index].pe +
-			(rsector_org % stripe_length) -
-			(stripe_index % lv->lv_stripes) * lv->lv_stripesize -
-			stripe_index / lv->lv_stripes *
-			(lv->lv_stripes - 1) * lv->lv_stripesize;
+		    (rsector_org % stripe_length) -
+		    (stripe_index % lv->lv_stripes) * lv->lv_stripesize -
+		    stripe_index / lv->lv_stripes *
+		    (lv->lv_stripes - 1) * lv->lv_stripesize;
 		rdev_map = lv->lv_current_pe[index].dev;
 
 		P_MAP("lv_current_pe[%ld].pe: %d  rdev: %s  rsector:%ld\n"
 		      "stripe_length: %ld  stripe_index: %ld\n",
-		      index, lv->lv_current_pe[index].pe, kdevname(rdev_map),
-		      rsector_map, stripe_length, stripe_index);
+		      index, lv->lv_current_pe[index].pe,
+		      kdevname(rdev_map), rsector_map, stripe_length,
+		      stripe_index);
 	}
 
 	/*
@@ -1287,8 +1320,8 @@
 	 * we need to queue this request, because this is in the fast path.
 	 */
 	if (rw == WRITE || rw == WRITEA) {
-		if(_defer_extent(bh, rw, rdev_map,
-				 rsector_map, vg_this->pe_size)) {
+		if (_defer_extent(bh, rw, rdev_map,
+				  rsector_map, vg_this->pe_size)) {
 
 			up_read(&lv->lv_lock);
 			return 0;
@@ -1299,15 +1332,15 @@
 		lv->lv_current_pe[index].reads++;	/* statistic */
 
 	/* snapshot volume exception handling on physical device address base */
-	if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)))
+	if (!(lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)))
 		goto out;
 
-	if (lv->lv_access & LV_SNAPSHOT) { /* remap snapshot */
+	if (lv->lv_access & LV_SNAPSHOT) {	/* remap snapshot */
 		if (lvm_snapshot_remap_block(&rdev_map, &rsector_map,
 					     pe_start, lv) < 0)
 			goto bad;
 
-	} else if (rw == WRITE || rw == WRITEA) { /* snapshot origin */
+	} else if (rw == WRITE || rw == WRITEA) {	/* snapshot origin */
 		lv_t *snap;
 
 		/* start with first snapshot and loop through all of
@@ -1321,22 +1354,22 @@
 			/* Serializes the COW with the accesses to the
 			   snapshot device */
 			_remap_snapshot(rdev_map, rsector_map,
-					 pe_start, snap, vg_this);
+					pe_start, snap, vg_this);
 		}
 	}
 
- out:
+      out:
 	bh->b_rdev = rdev_map;
 	bh->b_rsector = rsector_map;
 	up_read(&lv->lv_lock);
 	return 1;
 
- bad:
+      bad:
 	if (bh->b_end_io)
-	buffer_IO_error(bh);
+		buffer_IO_error(bh);
 	up_read(&lv->lv_lock);
 	return -1;
-} /* lvm_map() */
+}				/* lvm_map() */
 
 
 /*
@@ -1368,9 +1401,8 @@
 /*
  * make request function
  */
-static int lvm_make_request_fn(request_queue_t *q,
-			       int rw,
-			       struct buffer_head *bh)
+static int lvm_make_request_fn(request_queue_t * q,
+			       int rw, struct buffer_head *bh)
 {
 	return (lvm_map(bh, rw) <= 0) ? 0 : 1;
 }
@@ -1386,7 +1418,7 @@
  */
 static int lvm_do_lock_lvm(void)
 {
-lock_try_again:
+      lock_try_again:
 	spin_lock(&lvm_lock);
 	if (lock != 0 && lock != current->pid) {
 		P_DEV("lvm_do_lock_lvm: locked by pid %d ...\n", lock);
@@ -1404,19 +1436,20 @@
 	P_DEV("lvm_do_lock_lvm: locking LVM for pid %d\n", lock);
 	spin_unlock(&lvm_lock);
 	return 0;
-} /* lvm_do_lock_lvm */
+}				/* lvm_do_lock_lvm */
 
 
 /*
  * character device support function lock/unlock physical extend
  */
-static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg)
+static int lvm_do_pe_lock_unlock(vg_t * vg_ptr, void *arg)
 {
 	pe_lock_req_t new_lock;
 	struct buffer_head *bh;
 	uint p;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 	if (copy_from_user(&new_lock, arg, sizeof(new_lock)) != 0)
 		return -EFAULT;
 
@@ -1427,7 +1460,8 @@
 			    new_lock.data.pv_dev == vg_ptr->pv[p]->pv_dev)
 				break;
 		}
-		if (p == vg_ptr->pv_max) return -ENXIO;
+		if (p == vg_ptr->pv_max)
+			return -ENXIO;
 
 		/*
 		 * this sync releaves memory pressure to lessen the
@@ -1478,12 +1512,13 @@
 /*
  * character device support function logical extend remap
  */
-static int lvm_do_le_remap(vg_t *vg_ptr, void *arg)
+static int lvm_do_le_remap(vg_t * vg_ptr, void *arg)
 {
 	uint l, le;
 	lv_t *lv_ptr;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 	if (copy_from_user(&le_remap_req, arg,
 			   sizeof(le_remap_req_t)) != 0)
 		return -EFAULT;
@@ -1515,7 +1550,7 @@
 		}
 	}
 	return -ENXIO;
-} /* lvm_do_le_remap() */
+}				/* lvm_do_le_remap() */
 
 
 /*
@@ -1529,7 +1564,7 @@
 	vg_t *vg_ptr;
 	lv_t **snap_lv_ptr;
 
-	if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) {
+	if ((vg_ptr = kmalloc(sizeof(vg_t), GFP_KERNEL)) == NULL) {
 		printk(KERN_CRIT
 		       "%s -- VG_CREATE: kmalloc error VG at line %d\n",
 		       lvm_name, __LINE__);
@@ -1537,8 +1572,9 @@
 	}
 	/* get the volume group structure */
 	if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) {
-		P_IOCTL("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n",
-			arg, sizeof(vg_t));
+		P_IOCTL
+		    ("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n",
+		     arg, sizeof(vg_t));
 		kfree(vg_ptr);
 		return -EFAULT;
 	}
@@ -1572,7 +1608,7 @@
 
 	if (vg_ptr->lv_max > ABS_MAX_LV) {
 		printk(KERN_WARNING
-		"%s -- Can't activate VG: ABS_MAX_LV too small for %u\n",
+		       "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n",
 		       lvm_name, vg_ptr->lv_max);
 		kfree(vg_ptr);
 		return -EPERM;
@@ -1590,7 +1626,7 @@
 		/* user space address */
 		if ((pvp = vg_ptr->pv[p]) != NULL) {
 			ret = lvm_do_pv_create(pvp, vg_ptr, p);
-			if ( ret != 0) {
+			if (ret != 0) {
 				lvm_do_vg_remove(minor);
 				return ret;
 			}
@@ -1598,7 +1634,7 @@
 	}
 
 	size = vg_ptr->lv_max * sizeof(lv_t *);
-	if ((snap_lv_ptr = vmalloc ( size)) == NULL) {
+	if ((snap_lv_ptr = vmalloc(size)) == NULL) {
 		printk(KERN_CRIT
 		       "%s -- VG_CREATE: vmalloc error snapshot LVs at line %d\n",
 		       lvm_name, __LINE__);
@@ -1614,12 +1650,13 @@
 		/* user space address */
 		if ((lvp = vg_ptr->lv[l]) != NULL) {
 			if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
-				P_IOCTL("ERROR: copying LV ptr %p (%d bytes)\n",
-					lvp, sizeof(lv_t));
+				P_IOCTL
+				    ("ERROR: copying LV ptr %p (%d bytes)\n",
+				     lvp, sizeof(lv_t));
 				lvm_do_vg_remove(minor);
 				return -EFAULT;
 			}
-			if ( lv.lv_access & LV_SNAPSHOT) {
+			if (lv.lv_access & LV_SNAPSHOT) {
 				snap_lv_ptr[ls] = lvp;
 				vg_ptr->lv[l] = NULL;
 				ls++;
@@ -1659,24 +1696,26 @@
 	vg_ptr->vg_status |= VG_ACTIVE;
 
 	return 0;
-} /* lvm_do_vg_create() */
+}				/* lvm_do_vg_create() */
 
 
 /*
  * character device support function VGDA extend
  */
-static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg)
+static int lvm_do_vg_extend(vg_t * vg_ptr, void *arg)
 {
 	int ret = 0;
 	uint p;
 	pv_t *pv_ptr;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 	if (vg_ptr->pv_cur < vg_ptr->pv_max) {
 		for (p = 0; p < vg_ptr->pv_max; p++) {
-			if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) {
+			if ((pv_ptr = vg_ptr->pv[p]) == NULL) {
 				ret = lvm_do_pv_create(arg, vg_ptr, p);
-				if ( ret != 0) return ret;
+				if (ret != 0)
+					return ret;
 				pv_ptr = vg_ptr->pv[p];
 				vg_ptr->pe_total += pv_ptr->pe_total;
 				return 0;
@@ -1684,26 +1723,28 @@
 		}
 	}
 	return -EPERM;
-} /* lvm_do_vg_extend() */
+}				/* lvm_do_vg_extend() */
 
 
 /*
  * character device support function VGDA reduce
  */
-static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) {
+static int lvm_do_vg_reduce(vg_t * vg_ptr, void *arg)
+{
 	uint p;
 	pv_t *pv_ptr;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 	if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0)
 		return -EFAULT;
 
 	for (p = 0; p < vg_ptr->pv_max; p++) {
 		pv_ptr = vg_ptr->pv[p];
 		if (pv_ptr != NULL &&
-		    strcmp(pv_ptr->pv_name,
-			       pv_name) == 0) {
-			if (pv_ptr->lv_cur > 0) return -EPERM;
+		    strcmp(pv_ptr->pv_name, pv_name) == 0) {
+			if (pv_ptr->lv_cur > 0)
+				return -EPERM;
 			lvm_do_pv_remove(vg_ptr, p);
 			/* Make PV pointer array contiguous */
 			for (; p < vg_ptr->pv_max - 1; p++)
@@ -1713,55 +1754,56 @@
 		}
 	}
 	return -ENXIO;
-} /* lvm_do_vg_reduce */
+}				/* lvm_do_vg_reduce */
 
 
 /*
  * character device support function VG rename
  */
-static int lvm_do_vg_rename(vg_t *vg_ptr, void *arg)
+static int lvm_do_vg_rename(vg_t * vg_ptr, void *arg)
 {
 	int l = 0, p = 0, len = 0;
-	char vg_name[NAME_LEN] = { 0,};
-	char lv_name[NAME_LEN] = { 0,};
+	char vg_name[NAME_LEN] = { 0, };
+	char lv_name[NAME_LEN] = { 0, };
 	char *ptr = NULL;
 	lv_t *lv_ptr = NULL;
 	pv_t *pv_ptr = NULL;
 
 	/* If the VG doesn't exist in the kernel then just exit */
-	if (!vg_ptr) return 0;
+	if (!vg_ptr)
+		return 0;
 
 	if (copy_from_user(vg_name, arg, sizeof(vg_name)) != 0)
 		return -EFAULT;
 
 	lvm_fs_remove_vg(vg_ptr);
 
-	strncpy ( vg_ptr->vg_name, vg_name, sizeof ( vg_name)-1);
-	for ( l = 0; l < vg_ptr->lv_max; l++)
-	{
-		if ((lv_ptr = vg_ptr->lv[l]) == NULL) continue;
-		memset (lv_ptr->vg_name, 0, sizeof (*vg_name));
-		strncpy(lv_ptr->vg_name, vg_name, sizeof ( vg_name));
+	strncpy(vg_ptr->vg_name, vg_name, sizeof(vg_name) - 1);
+	for (l = 0; l < vg_ptr->lv_max; l++) {
+		if ((lv_ptr = vg_ptr->lv[l]) == NULL)
+			continue;
+		memset(lv_ptr->vg_name, 0, sizeof(*vg_name));
+		strncpy(lv_ptr->vg_name, vg_name, sizeof(vg_name));
 		ptr = strrchr(lv_ptr->lv_name, '/');
 		ptr = ptr ? ptr + 1 : lv_ptr->lv_name;
-		strncpy(lv_name, ptr, sizeof ( lv_name));
+		strncpy(lv_name, ptr, sizeof(lv_name));
 		len = sizeof(LVM_DIR_PREFIX);
 		strcpy(lv_ptr->lv_name, LVM_DIR_PREFIX);
 		strncat(lv_ptr->lv_name, vg_name, NAME_LEN - len);
-		strcat (lv_ptr->lv_name, "/");
+		strcat(lv_ptr->lv_name, "/");
 		len += strlen(vg_name) + 1;
 		strncat(lv_ptr->lv_name, lv_name, NAME_LEN - len);
 	}
-	for ( p = 0; p < vg_ptr->pv_max; p++)
-	{
-		if ( (pv_ptr = vg_ptr->pv[p]) == NULL) continue;
+	for (p = 0; p < vg_ptr->pv_max; p++) {
+		if ((pv_ptr = vg_ptr->pv[p]) == NULL)
+			continue;
 		strncpy(pv_ptr->vg_name, vg_name, NAME_LEN);
 	}
 
 	lvm_fs_create_vg(vg_ptr);
 
 	/* Need to add PV entries */
-	for ( p = 0; p < vg_ptr->pv_act; p++) {
+	for (p = 0; p < vg_ptr->pv_act; p++) {
 		pv_t *pv_ptr = vg_ptr->pv[p];
 
 		if (pv_ptr)
@@ -1769,18 +1811,18 @@
 	}
 
 	/* Need to add LV entries */
-        for ( l = 0; l < vg_ptr->lv_max; l++) {
+	for (l = 0; l < vg_ptr->lv_max; l++) {
 		lv_t *lv_ptr = vg_ptr->lv[l];
 
 		if (!lv_ptr)
 			continue;
 
 		lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de =
-	    		lvm_fs_create_lv(vg_ptr, lv_ptr);
+		    lvm_fs_create_lv(vg_ptr, lv_ptr);
 	}
 
 	return 0;
-} /* lvm_do_vg_rename */
+}				/* lvm_do_vg_rename */
 
 
 /*
@@ -1792,7 +1834,8 @@
 	vg_t *vg_ptr = vg[VG_CHR(minor)];
 	pv_t *pv_ptr;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 
 #ifdef LVM_TOTAL_RESET
 	if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0)
@@ -1843,20 +1886,21 @@
 	MOD_DEC_USE_COUNT;
 
 	return 0;
-} /* lvm_do_vg_remove() */
+}				/* lvm_do_vg_remove() */
 
 
 /*
  * character device support function physical volume create
  */
-static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) {
+static int lvm_do_pv_create(pv_t * pvp, vg_t * vg_ptr, ulong p)
+{
 	pv_t *pv;
 	int err;
 
 	if (!vg_ptr)
 		return -ENXIO;
 
-	pv = kmalloc(sizeof(pv_t),GFP_KERNEL);
+	pv = kmalloc(sizeof(pv_t), GFP_KERNEL);
 	if (pv == NULL) {
 		printk(KERN_CRIT
 		       "%s -- PV_CREATE: kmalloc error PV at line %d\n",
@@ -1867,8 +1911,9 @@
 	memset(pv, 0, sizeof(*pv));
 
 	if (copy_from_user(pv, pvp, sizeof(pv_t)) != 0) {
-		P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n",
-			pvp, sizeof(pv_t));
+		P_IOCTL
+		    ("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n",
+		     pvp, sizeof(pv_t));
 		kfree(pv);
 		return -EFAULT;
 	}
@@ -1889,13 +1934,14 @@
 
 	vg_ptr->pv[p] = pv;
 	return 0;
-} /* lvm_do_pv_create() */
+}				/* lvm_do_pv_create() */
 
 
 /*
  * character device support function physical volume remove
  */
-static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) {
+static int lvm_do_pv_remove(vg_t * vg_ptr, ulong p)
+{
 	pv_t *pv = vg_ptr->pv[p];
 
 	lvm_fs_remove_pv(vg_ptr, pv);
@@ -1913,7 +1959,7 @@
 }
 
 
-static void __update_hardsectsize(lv_t *lv)
+static void __update_hardsectsize(lv_t * lv)
 {
 	int max_hardsectsize = 0, hardsectsize = 0;
 	int p;
@@ -1925,9 +1971,10 @@
 			if (max_hardsectsize == 0)
 				max_hardsectsize = hardsectsize;
 			else if (hardsectsize != max_hardsectsize) {
-				P_DEV("%s PV[%d] (%s) sector size %d, not %d\n",
-				      lv->lv_name, p, kdevname(pv->pv_dev),
-				      hardsectsize, max_hardsectsize);
+				P_DEV
+				    ("%s PV[%d] (%s) sector size %d, not %d\n",
+				     lv->lv_name, p, kdevname(pv->pv_dev),
+				     hardsectsize, max_hardsectsize);
 				break;
 			}
 		}
@@ -1937,12 +1984,14 @@
 	if (hardsectsize != max_hardsectsize) {
 		int le;
 		for (le = 0; le < lv->lv_allocated_le; le++) {
-			hardsectsize = lvm_sectsize(lv->lv_current_pe[le].dev);
+			hardsectsize =
+			    lvm_sectsize(lv->lv_current_pe[le].dev);
 			if (hardsectsize > max_hardsectsize) {
-				P_DEV("%s LE[%d] (%s) blocksize %d not %d\n",
-				      lv->lv_name, le,
-				      kdevname(lv->lv_current_pe[le].dev),
-				      hardsectsize, max_hardsectsize);
+				P_DEV
+				    ("%s LE[%d] (%s) blocksize %d not %d\n",
+				     lv->lv_name, le,
+				     kdevname(lv->lv_current_pe[le].dev),
+				     hardsectsize, max_hardsectsize);
 				max_hardsectsize = hardsectsize;
 			}
 		}
@@ -1952,7 +2001,9 @@
 		    (lv->lv_status & LV_ACTIVE)) {
 			int e;
 			for (e = 0; e < lv->lv_remap_end; e++) {
-				hardsectsize = lvm_sectsize(lv->lv_block_exception[e].rdev_new);
+				hardsectsize =
+				    lvm_sectsize(lv->lv_block_exception[e].
+						 rdev_new);
 				if (hardsectsize > max_hardsectsize)
 					max_hardsectsize = hardsectsize;
 			}
@@ -1969,7 +2020,7 @@
 /*
  * character device support function logical volume create
  */
-static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv)
+static int lvm_do_lv_create(int minor, char *lv_name, lv_t * lv)
 {
 	int e, ret, l, le, l_new, p, size, activate = 1;
 	ulong lv_status_save;
@@ -1997,14 +2048,18 @@
 	else {
 		for (l = 0; l < vg_ptr->lv_max; l++) {
 			if (vg_ptr->lv[l] == NULL)
-				if (l_new == -1) l_new = l;
+				if (l_new == -1)
+					l_new = l;
 		}
 	}
-	if (l_new == -1) return -EPERM;
-	else             l = l_new;
+	if (l_new == -1)
+		return -EPERM;
+	else
+		l = l_new;
 
-	if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {;
-		printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n",
+	if ((lv_ptr = kmalloc(sizeof(lv_t), GFP_KERNEL)) == NULL) {;
+		printk(KERN_CRIT
+		       "%s -- LV_CREATE: kmalloc error LV at line %d\n",
 		       lvm_name, __LINE__);
 		return -ENOMEM;
 	}
@@ -2036,8 +2091,7 @@
 		if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) {
 			printk(KERN_CRIT
 			       "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte "
-			       "at line %d\n",
-			       lvm_name, size, __LINE__);
+			       "at line %d\n", lvm_name, size, __LINE__);
 			P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__);
 			kfree(lv_ptr);
 			vg_ptr->lv[l] = NULL;
@@ -2066,7 +2120,9 @@
 			lv_ptr->lv_snapshot_org =
 			    vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)];
 			if (lv_ptr->lv_snapshot_org != NULL) {
-				size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t);
+				size =
+				    lv_ptr->lv_remap_end *
+				    sizeof(lv_block_exception_t);
 
 				if (!size) {
 					printk(KERN_WARNING
@@ -2076,29 +2132,32 @@
 					return -EINVAL;
 				}
 
-				if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) {
+				if ((lv_ptr->lv_block_exception =
+				     vmalloc(size)) == NULL) {
 					printk(KERN_CRIT
 					       "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION "
 					       "of %d byte at line %d\n",
 					       lvm_name, size, __LINE__);
-					P_KFREE("%s -- kfree %d\n", lvm_name,
-						__LINE__);
+					P_KFREE("%s -- kfree %d\n",
+						lvm_name, __LINE__);
 					kfree(lv_ptr);
 					vg_ptr->lv[l] = NULL;
 					return -ENOMEM;
 				}
-				if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) {
+				if (copy_from_user
+				    (lv_ptr->lv_block_exception, lvbe,
+				     size)) {
 					vfree(lv_ptr->lv_block_exception);
 					kfree(lv_ptr);
 					vg_ptr->lv[l] = NULL;
 					return -EFAULT;
 				}
 
-				if(lv_ptr->lv_block_exception[0].rsector_org ==
-				   LVM_SNAPSHOT_DROPPED_SECTOR)
-				{
+				if (lv_ptr->lv_block_exception[0].
+				    rsector_org ==
+				    LVM_SNAPSHOT_DROPPED_SECTOR) {
 					printk(KERN_WARNING
-   "%s -- lvm_do_lv_create: snapshot has been dropped and will not be activated\n",
+					       "%s -- lvm_do_lv_create: snapshot has been dropped and will not be activated\n",
 					       lvm_name);
 					activate = 0;
 				}
@@ -2112,36 +2171,54 @@
 				   which can be the original logical volume */
 				lv_ptr = vg_ptr->lv[l];
 				/* now lv_ptr points to our new last snapshot logical volume */
-				lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe;
-				lv_ptr->lv_allocated_snapshot_le = lv_ptr->lv_allocated_le;
-				lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;
-				lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le;
-				lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size;
-				lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes;
-				lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize;
+				lv_ptr->lv_current_pe =
+				    lv_ptr->lv_snapshot_org->lv_current_pe;
+				lv_ptr->lv_allocated_snapshot_le =
+				    lv_ptr->lv_allocated_le;
+				lv_ptr->lv_allocated_le =
+				    lv_ptr->lv_snapshot_org->
+				    lv_allocated_le;
+				lv_ptr->lv_current_le =
+				    lv_ptr->lv_snapshot_org->lv_current_le;
+				lv_ptr->lv_size =
+				    lv_ptr->lv_snapshot_org->lv_size;
+				lv_ptr->lv_stripes =
+				    lv_ptr->lv_snapshot_org->lv_stripes;
+				lv_ptr->lv_stripesize =
+				    lv_ptr->lv_snapshot_org->lv_stripesize;
 
 				/* Update the VG PE(s) used by snapshot reserve space. */
-				vg_ptr->pe_allocated += lv_ptr->lv_allocated_snapshot_le;
+				vg_ptr->pe_allocated +=
+				    lv_ptr->lv_allocated_snapshot_le;
 
-				if ((ret = lvm_snapshot_alloc(lv_ptr)) != 0)
-				{
+				if ((ret =
+				     lvm_snapshot_alloc(lv_ptr)) != 0) {
 					vfree(lv_ptr->lv_block_exception);
 					kfree(lv_ptr);
 					vg_ptr->lv[l] = NULL;
 					return ret;
 				}
-				for ( e = 0; e < lv_ptr->lv_remap_ptr; e++)
-					lvm_hash_link (lv_ptr->lv_block_exception + e,
-						       lv_ptr->lv_block_exception[e].rdev_org,
-						       lv_ptr->lv_block_exception[e].rsector_org, lv_ptr);
+				for (e = 0; e < lv_ptr->lv_remap_ptr; e++)
+					lvm_hash_link(lv_ptr->
+						      lv_block_exception +
+						      e,
+						      lv_ptr->
+						      lv_block_exception
+						      [e].rdev_org,
+						      lv_ptr->
+						      lv_block_exception
+						      [e].rsector_org,
+						      lv_ptr);
 				/* need to fill the COW exception table data
 				   into the page for disk i/o */
-				if(lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr)) {
+				if (lvm_snapshot_fill_COW_page
+				    (vg_ptr, lv_ptr)) {
 					kfree(lv_ptr);
 					vg_ptr->lv[l] = NULL;
 					return -EINVAL;
 				}
-				init_waitqueue_head(&lv_ptr->lv_snapshot_wait);
+				init_waitqueue_head(&lv_ptr->
+						    lv_snapshot_wait);
 			} else {
 				kfree(lv_ptr);
 				vg_ptr->lv[l] = NULL;
@@ -2152,7 +2229,7 @@
 			vg_ptr->lv[l] = NULL;
 			return -EINVAL;
 		}
-	} /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */
+	}			/* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */
 
 	lv_ptr = vg_ptr->lv[l];
 	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
@@ -2180,23 +2257,24 @@
 
 		down_write(&org->lv_lock);
 		org->lv_access |= LV_SNAPSHOT_ORG;
-		lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */
+		lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG;	/* this can only hide an userspace bug */
 
 
 		/* Link in the list of snapshot volumes */
-		for (last = org; last->lv_snapshot_next; last = last->lv_snapshot_next);
+		for (last = org; last->lv_snapshot_next;
+		     last = last->lv_snapshot_next);
 		lv_ptr->lv_snapshot_prev = last;
 		last->lv_snapshot_next = lv_ptr;
 		up_write(&org->lv_lock);
 	}
 
 	/* activate the logical volume */
-	if(activate)
+	if (activate)
 		lv_ptr->lv_status |= LV_ACTIVE;
 	else
 		lv_ptr->lv_status &= ~LV_ACTIVE;
 
-	if ( lv_ptr->lv_access & LV_WRITE)
+	if (lv_ptr->lv_access & LV_WRITE)
 		set_device_ro(lv_ptr->lv_dev, 0);
 	else
 		set_device_ro(lv_ptr->lv_dev, 1);
@@ -2210,7 +2288,7 @@
 	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de =
 	    lvm_fs_create_lv(vg_ptr, lv_ptr);
 	return 0;
-} /* lvm_do_lv_create() */
+}				/* lvm_do_lv_create() */
 
 
 /*
@@ -2233,7 +2311,8 @@
 			}
 		}
 	}
-	if (l == vg_ptr->lv_max) return -ENXIO;
+	if (l == vg_ptr->lv_max)
+		return -ENXIO;
 
 	lv_ptr = vg_ptr->lv[l];
 #ifdef LVM_TOTAL_RESET
@@ -2253,14 +2332,15 @@
 
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
 		/*
-		 * Atomically make the snapshot invisible
+		 * Atomically make the the snapshot invisible
 		 * to the original lv before playing with it.
 		 */
-		lv_t * org = lv_ptr->lv_snapshot_org;
+		lv_t *org = lv_ptr->lv_snapshot_org;
 		down_write(&org->lv_lock);
 
 		/* remove this snapshot logical volume from the chain */
-		lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next;
+		lv_ptr->lv_snapshot_prev->lv_snapshot_next =
+		    lv_ptr->lv_snapshot_next;
 		if (lv_ptr->lv_snapshot_next != NULL) {
 			lv_ptr->lv_snapshot_next->lv_snapshot_prev =
 			    lv_ptr->lv_snapshot_prev;
@@ -2299,7 +2379,7 @@
 	vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1;
 
 	/* correct the PE count in PVs if this is not a snapshot
-           logical volume */
+	   logical volume */
 	if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
 		/* only if this is no snapshot logical volume because
 		   we share the lv_current_pe[] structs with the
@@ -2320,13 +2400,15 @@
 	vg_ptr->lv[l] = NULL;
 	vg_ptr->lv_cur--;
 	return 0;
-} /* lvm_do_lv_remove() */
+}				/* lvm_do_lv_remove() */
 
 
 /*
  * logical volume extend / reduce
  */
-static int __extend_reduce_snapshot(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) {
+static int __extend_reduce_snapshot(vg_t * vg_ptr, lv_t * old_lv,
+				    lv_t * new_lv)
+{
 	ulong size;
 	lv_block_exception_t *lvbe;
 
@@ -2357,7 +2439,8 @@
 	return 0;
 }
 
-static int __extend_reduce(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) {
+static int __extend_reduce(vg_t * vg_ptr, lv_t * old_lv, lv_t * new_lv)
+{
 	ulong size, l, p, end;
 	pe_t *pe;
 
@@ -2373,7 +2456,7 @@
 
 	/* get the PE structures from user space */
 	if (copy_from_user(pe, new_lv->lv_current_pe, size)) {
-		if(old_lv->lv_access & LV_SNAPSHOT)
+		if (old_lv->lv_access & LV_SNAPSHOT)
 			vfree(new_lv->lv_snapshot_hash_table);
 		vfree(pe);
 		return -EFAULT;
@@ -2398,7 +2481,7 @@
 		vg_ptr->pe_allocated++;
 		for (p = 0; p < vg_ptr->pv_cur; p++) {
 			if (vg_ptr->pv[p]->pv_dev ==
-                            new_lv->lv_current_pe[l].dev) {
+			    new_lv->lv_current_pe[l].dev) {
 				vg_ptr->pv[p]->pe_allocated++;
 				break;
 			}
@@ -2410,25 +2493,30 @@
 		end = min(old_lv->lv_current_le, new_lv->lv_current_le);
 		for (l = 0; l < end; l++) {
 			new_lv->lv_current_pe[l].reads +=
-				old_lv->lv_current_pe[l].reads;
+			    old_lv->lv_current_pe[l].reads;
 
 			new_lv->lv_current_pe[l].writes +=
-				old_lv->lv_current_pe[l].writes;
+			    old_lv->lv_current_pe[l].writes;
 		}
 
 	} else {		/* striped logical volume */
-		uint i, j, source, dest, end, old_stripe_size, new_stripe_size;
+		uint i, j, source, dest, end, old_stripe_size,
+		    new_stripe_size;
 
-		old_stripe_size = old_lv->lv_allocated_le / old_lv->lv_stripes;
-		new_stripe_size = new_lv->lv_allocated_le / new_lv->lv_stripes;
+		old_stripe_size =
+		    old_lv->lv_allocated_le / old_lv->lv_stripes;
+		new_stripe_size =
+		    new_lv->lv_allocated_le / new_lv->lv_stripes;
 		end = min(old_stripe_size, new_stripe_size);
 
 		for (i = source = dest = 0; i < new_lv->lv_stripes; i++) {
 			for (j = 0; j < end; j++) {
 				new_lv->lv_current_pe[dest + j].reads +=
-				    old_lv->lv_current_pe[source + j].reads;
+				    old_lv->lv_current_pe[source +
+							  j].reads;
 				new_lv->lv_current_pe[dest + j].writes +=
-				    old_lv->lv_current_pe[source + j].writes;
+				    old_lv->lv_current_pe[source +
+							  j].writes;
 			}
 			source += old_stripe_size;
 			dest += new_stripe_size;
@@ -2438,7 +2526,7 @@
 	return 0;
 }
 
-static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *new_lv)
+static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t * new_lv)
 {
 	int r;
 	ulong l, e, size;
@@ -2453,7 +2541,8 @@
 		return -EINVAL;
 
 	for (l = 0; l < vg_ptr->lv_max; l++)
-		if (vg_ptr->lv[l] && !strcmp(vg_ptr->lv[l]->lv_name, lv_name))
+		if (vg_ptr->lv[l]
+		    && !strcmp(vg_ptr->lv[l]->lv_name, lv_name))
 			break;
 
 	if (l == vg_ptr->lv_max)
@@ -2464,43 +2553,48 @@
 	if (old_lv->lv_access & LV_SNAPSHOT) {
 		/* only perform this operation on active snapshots */
 		if (old_lv->lv_status & LV_ACTIVE)
-			r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv);
+			r = __extend_reduce_snapshot(vg_ptr, old_lv,
+						     new_lv);
 		else
 			r = -EPERM;
 
 	} else
 		r = __extend_reduce(vg_ptr, old_lv, new_lv);
 
-	if(r)
+	if (r)
 		return r;
 
-	/* copy relevent fields */
+	/* copy relevant fields */
 	down_write(&old_lv->lv_lock);
 
-	if(new_lv->lv_access & LV_SNAPSHOT) {
+	if (new_lv->lv_access & LV_SNAPSHOT) {
 		size = (new_lv->lv_remap_end > old_lv->lv_remap_end) ?
-			old_lv->lv_remap_ptr : new_lv->lv_remap_end;
+		    old_lv->lv_remap_ptr : new_lv->lv_remap_end;
 		size *= sizeof(lv_block_exception_t);
 		memcpy(new_lv->lv_block_exception,
 		       old_lv->lv_block_exception, size);
+		vfree(old_lv->lv_block_exception);
+		vfree(old_lv->lv_snapshot_hash_table);
 
 		old_lv->lv_remap_end = new_lv->lv_remap_end;
 		old_lv->lv_block_exception = new_lv->lv_block_exception;
 		old_lv->lv_snapshot_hash_table =
-			new_lv->lv_snapshot_hash_table;
+		    new_lv->lv_snapshot_hash_table;
 		old_lv->lv_snapshot_hash_table_size =
-			new_lv->lv_snapshot_hash_table_size;
+		    new_lv->lv_snapshot_hash_table_size;
 		old_lv->lv_snapshot_hash_mask =
-			new_lv->lv_snapshot_hash_mask;
+		    new_lv->lv_snapshot_hash_mask;
 
-		for (e = 0; e < new_lv->lv_remap_ptr; e++)
+		for (e = 0; e < old_lv->lv_remap_ptr; e++)
 			lvm_hash_link(new_lv->lv_block_exception + e,
-				      new_lv->lv_block_exception[e].rdev_org,
-				      new_lv->lv_block_exception[e].rsector_org,
-				      new_lv);
+				      new_lv->lv_block_exception[e].
+				      rdev_org,
+				      new_lv->lv_block_exception[e].
+				      rsector_org, new_lv);
 
+		vg_ptr->pe_allocated -= old_lv->lv_allocated_le;
+		vg_ptr->pe_allocated += new_lv->lv_allocated_le;
 	} else {
-
 		vfree(old_lv->lv_current_pe);
 		vfree(old_lv->lv_snapshot_hash_table);
 
@@ -2509,24 +2603,26 @@
 		old_lv->lv_current_le = new_lv->lv_current_le;
 		old_lv->lv_current_pe = new_lv->lv_current_pe;
 		lvm_gendisk.part[MINOR(old_lv->lv_dev)].nr_sects =
-			old_lv->lv_size;
+		    old_lv->lv_size;
 		lvm_size[MINOR(old_lv->lv_dev)] = old_lv->lv_size >> 1;
 
 		if (old_lv->lv_access & LV_SNAPSHOT_ORG) {
 			lv_t *snap;
-			for(snap = old_lv->lv_snapshot_next; snap;
-			    snap = snap->lv_snapshot_next) {
+			for (snap = old_lv->lv_snapshot_next; snap;
+			     snap = snap->lv_snapshot_next) {
 				down_write(&snap->lv_lock);
-				snap->lv_current_pe = old_lv->lv_current_pe;
+				snap->lv_current_pe =
+				    old_lv->lv_current_pe;
 				snap->lv_allocated_le =
-					old_lv->lv_allocated_le;
-				snap->lv_current_le = old_lv->lv_current_le;
+				    old_lv->lv_allocated_le;
+				snap->lv_current_le =
+				    old_lv->lv_current_le;
 				snap->lv_size = old_lv->lv_size;
 
-				lvm_gendisk.part[MINOR(snap->lv_dev)].nr_sects
-					= old_lv->lv_size;
+				lvm_gendisk.part[MINOR(snap->lv_dev)].
+				    nr_sects = old_lv->lv_size;
 				lvm_size[MINOR(snap->lv_dev)] =
-					old_lv->lv_size >> 1;
+				    old_lv->lv_size >> 1;
 				__update_hardsectsize(snap);
 				up_write(&snap->lv_lock);
 			}
@@ -2537,13 +2633,13 @@
 	up_write(&old_lv->lv_lock);
 
 	return 0;
-} /* lvm_do_lv_extend_reduce() */
+}				/* lvm_do_lv_extend_reduce() */
 
 
 /*
  * character device support function logical volume status by name
  */
-static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg)
+static int lvm_do_lv_status_byname(vg_t * vg_ptr, void *arg)
 {
 	uint l;
 	lv_status_byname_req_t lv_status_byname_req;
@@ -2551,137 +2647,166 @@
 	void *saved_ptr2;
 	lv_t *lv_ptr;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 	if (copy_from_user(&lv_status_byname_req, arg,
 			   sizeof(lv_status_byname_req_t)) != 0)
 		return -EFAULT;
 
-	if (lv_status_byname_req.lv == NULL) return -EINVAL;
+	if (lv_status_byname_req.lv == NULL)
+		return -EINVAL;
 
 	for (l = 0; l < vg_ptr->lv_max; l++) {
 		if ((lv_ptr = vg_ptr->lv[l]) != NULL &&
 		    strcmp(lv_ptr->lv_name,
 			   lv_status_byname_req.lv_name) == 0) {
-		        /* Save usermode pointers */
-		        if (copy_from_user(&saved_ptr1, &lv_status_byname_req.lv->lv_current_pe, sizeof(void*)) != 0)
+			/* Save usermode pointers */
+			if (copy_from_user
+			    (&saved_ptr1,
+			     &lv_status_byname_req.lv->lv_current_pe,
+			     sizeof(void *)) != 0)
+				return -EFAULT;
+			if (copy_from_user
+			    (&saved_ptr2,
+			     &lv_status_byname_req.lv->lv_block_exception,
+			     sizeof(void *)) != 0)
 				return -EFAULT;
-			if (copy_from_user(&saved_ptr2, &lv_status_byname_req.lv->lv_block_exception, sizeof(void*)) != 0)
-			        return -EFAULT;
-		        if (copy_to_user(lv_status_byname_req.lv,
-					 lv_ptr,
-					 sizeof(lv_t)) != 0)
+			if (copy_to_user(lv_status_byname_req.lv,
+					 lv_ptr, sizeof(lv_t)) != 0)
 				return -EFAULT;
 			if (saved_ptr1 != NULL) {
 				if (copy_to_user(saved_ptr1,
 						 lv_ptr->lv_current_pe,
 						 lv_ptr->lv_allocated_le *
-				       		 sizeof(pe_t)) != 0)
+						 sizeof(pe_t)) != 0)
 					return -EFAULT;
 			}
 			/* Restore usermode pointers */
-			if (copy_to_user(&lv_status_byname_req.lv->lv_current_pe, &saved_ptr1, sizeof(void*)) != 0)
-			        return -EFAULT;
+			if (copy_to_user
+			    (&lv_status_byname_req.lv->lv_current_pe,
+			     &saved_ptr1, sizeof(void *)) != 0)
+				return -EFAULT;
 			return 0;
 		}
 	}
 	return -ENXIO;
-} /* lvm_do_lv_status_byname() */
+}				/* lvm_do_lv_status_byname() */
 
 
 /*
  * character device support function logical volume status by index
  */
-static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg)
+static int lvm_do_lv_status_byindex(vg_t * vg_ptr, void *arg)
 {
 	lv_status_byindex_req_t lv_status_byindex_req;
 	void *saved_ptr1;
 	void *saved_ptr2;
 	lv_t *lv_ptr;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 	if (copy_from_user(&lv_status_byindex_req, arg,
 			   sizeof(lv_status_byindex_req)) != 0)
 		return -EFAULT;
 
 	if (lv_status_byindex_req.lv == NULL)
 		return -EINVAL;
-	if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL)
+	if ((lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL)
 		return -ENXIO;
 
 	/* Save usermode pointers */
-	if (copy_from_user(&saved_ptr1, &lv_status_byindex_req.lv->lv_current_pe, sizeof(void*)) != 0)
-	        return -EFAULT;
-	if (copy_from_user(&saved_ptr2, &lv_status_byindex_req.lv->lv_block_exception, sizeof(void*)) != 0)
-	        return -EFAULT;
+	if (copy_from_user
+	    (&saved_ptr1, &lv_status_byindex_req.lv->lv_current_pe,
+	     sizeof(void *)) != 0)
+		return -EFAULT;
+	if (copy_from_user
+	    (&saved_ptr2, &lv_status_byindex_req.lv->lv_block_exception,
+	     sizeof(void *)) != 0)
+		return -EFAULT;
 
-	if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(lv_t)) != 0)
+	if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(lv_t)) !=
+	    0)
 		return -EFAULT;
 	if (saved_ptr1 != NULL) {
 		if (copy_to_user(saved_ptr1,
 				 lv_ptr->lv_current_pe,
 				 lv_ptr->lv_allocated_le *
-		       		 sizeof(pe_t)) != 0)
+				 sizeof(pe_t)) != 0)
 			return -EFAULT;
 	}
 
 	/* Restore usermode pointers */
-	if (copy_to_user(&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0)
-	        return -EFAULT;
+	if (copy_to_user
+	    (&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1,
+	     sizeof(void *)) != 0)
+		return -EFAULT;
 
 	return 0;
-} /* lvm_do_lv_status_byindex() */
+}				/* lvm_do_lv_status_byindex() */
 
 
 /*
  * character device support function logical volume status by device number
  */
-static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void * arg) {
+static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void *arg)
+{
 	int l;
 	lv_status_bydev_req_t lv_status_bydev_req;
 	void *saved_ptr1;
 	void *saved_ptr2;
 	lv_t *lv_ptr;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 	if (copy_from_user(&lv_status_bydev_req, arg,
 			   sizeof(lv_status_bydev_req)) != 0)
 		return -EFAULT;
 
-	for ( l = 0; l < vg_ptr->lv_max; l++) {
-		if ( vg_ptr->lv[l] == NULL) continue;
-		if ( vg_ptr->lv[l]->lv_dev == lv_status_bydev_req.dev) break;
+	for (l = 0; l < vg_ptr->lv_max; l++) {
+		if (vg_ptr->lv[l] == NULL)
+			continue;
+		if (vg_ptr->lv[l]->lv_dev == lv_status_bydev_req.dev)
+			break;
 	}
 
-	if ( l == vg_ptr->lv_max) return -ENXIO;
+	if (l == vg_ptr->lv_max)
+		return -ENXIO;
 	lv_ptr = vg_ptr->lv[l];
 
 	/* Save usermode pointers */
-	if (copy_from_user(&saved_ptr1, &lv_status_bydev_req.lv->lv_current_pe, sizeof(void*)) != 0)
-	        return -EFAULT;
-	if (copy_from_user(&saved_ptr2, &lv_status_bydev_req.lv->lv_block_exception, sizeof(void*)) != 0)
-	        return -EFAULT;
+	if (copy_from_user
+	    (&saved_ptr1, &lv_status_bydev_req.lv->lv_current_pe,
+	     sizeof(void *)) != 0)
+		return -EFAULT;
+	if (copy_from_user
+	    (&saved_ptr2, &lv_status_bydev_req.lv->lv_block_exception,
+	     sizeof(void *)) != 0)
+		return -EFAULT;
 
-	if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) != 0)
+	if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) !=
+	    0)
 		return -EFAULT;
 	if (saved_ptr1 != NULL) {
 		if (copy_to_user(saved_ptr1,
 				 lv_ptr->lv_current_pe,
 				 lv_ptr->lv_allocated_le *
-		       		 sizeof(pe_t)) != 0)
+				 sizeof(pe_t)) != 0)
 			return -EFAULT;
 	}
 	/* Restore usermode pointers */
-	if (copy_to_user(&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0)
-	        return -EFAULT;
+	if (copy_to_user
+	    (&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1,
+	     sizeof(void *)) != 0)
+		return -EFAULT;
 
 	return 0;
-} /* lvm_do_lv_status_bydev() */
+}				/* lvm_do_lv_status_bydev() */
 
 
 /*
  * character device support function rename a logical volume
  */
-static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, lv_t *lv)
+static int lvm_do_lv_rename(vg_t * vg_ptr, lv_req_t * lv_req, lv_t * lv)
 {
 	int l = 0;
 	int ret = 0;
@@ -2690,33 +2815,36 @@
 	if (!vg_ptr)
 		return -ENXIO;
 
-	for (l = 0; l < vg_ptr->lv_max; l++)
-	{
-		if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue;
-		if (lv_ptr->lv_dev == lv->lv_dev)
-		{
+	for (l = 0; l < vg_ptr->lv_max; l++) {
+		if ((lv_ptr = vg_ptr->lv[l]) == NULL)
+			continue;
+		if (lv_ptr->lv_dev == lv->lv_dev) {
 			lvm_fs_remove_lv(vg_ptr, lv_ptr);
-			strncpy(lv_ptr->lv_name, lv_req->lv_name, NAME_LEN);
-			lvm_fs_create_lv(vg_ptr, lv_ptr);
+			strncpy(lv_ptr->lv_name, lv_req->lv_name,
+				NAME_LEN);
+			lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de =
+				lvm_fs_create_lv(vg_ptr, lv_ptr);
 			break;
 		}
 	}
-	if (l == vg_ptr->lv_max) ret = -ENODEV;
+	if (l == vg_ptr->lv_max)
+		ret = -ENODEV;
 
 	return ret;
-} /* lvm_do_lv_rename */
+}				/* lvm_do_lv_rename */
 
 
 /*
  * character device support function physical volume change
  */
-static int lvm_do_pv_change(vg_t *vg_ptr, void *arg)
+static int lvm_do_pv_change(vg_t * vg_ptr, void *arg)
 {
 	uint p;
 	pv_t *pv_ptr;
 	struct block_device *bd;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 	if (copy_from_user(&pv_change_req, arg,
 			   sizeof(pv_change_req)) != 0)
 		return -EFAULT;
@@ -2724,8 +2852,7 @@
 	for (p = 0; p < vg_ptr->pv_max; p++) {
 		pv_ptr = vg_ptr->pv[p];
 		if (pv_ptr != NULL &&
-		    strcmp(pv_ptr->pv_name,
-			       pv_change_req.pv_name) == 0) {
+		    strcmp(pv_ptr->pv_name, pv_change_req.pv_name) == 0) {
 
 			bd = pv_ptr->bd;
 			if (copy_from_user(pv_ptr,
@@ -2741,17 +2868,18 @@
 		}
 	}
 	return -ENXIO;
-} /* lvm_do_pv_change() */
+}				/* lvm_do_pv_change() */
 
 /*
  * character device support function get physical volume status
  */
-static int lvm_do_pv_status(vg_t *vg_ptr, void *arg)
+static int lvm_do_pv_status(vg_t * vg_ptr, void *arg)
 {
 	uint p;
 	pv_t *pv_ptr;
 
-	if (vg_ptr == NULL) return -ENXIO;
+	if (vg_ptr == NULL)
+		return -ENXIO;
 	if (copy_from_user(&pv_status_req, arg,
 			   sizeof(pv_status_req)) != 0)
 		return -EFAULT;
@@ -2759,17 +2887,15 @@
 	for (p = 0; p < vg_ptr->pv_max; p++) {
 		pv_ptr = vg_ptr->pv[p];
 		if (pv_ptr != NULL &&
-		    strcmp(pv_ptr->pv_name,
-			       pv_status_req.pv_name) == 0) {
+		    strcmp(pv_ptr->pv_name, pv_status_req.pv_name) == 0) {
 			if (copy_to_user(pv_status_req.pv,
-					 pv_ptr,
-				         sizeof(pv_t)) != 0)
+					 pv_ptr, sizeof(pv_t)) != 0)
 				return -EFAULT;
 			return 0;
 		}
 	}
 	return -ENXIO;
-} /* lvm_do_pv_status() */
+}				/* lvm_do_pv_status() */
 
 
 /*
@@ -2811,13 +2937,15 @@
 	hardsect_size[MAJOR_NR] = lvm_hardsectsizes;
 
 	return;
-} /* lvm_gen_init() */
+}				/* lvm_gen_init() */
 
 
 
 /* Must have down_write(_pe_lock) when we enqueue buffers */
-static void _queue_io(struct buffer_head *bh, int rw) {
-	if (bh->b_reqnext) BUG();
+static void _queue_io(struct buffer_head *bh, int rw)
+{
+	if (bh->b_reqnext)
+		BUG();
 	bh->b_reqnext = _pe_requests;
 	_pe_requests = bh;
 }
@@ -2855,14 +2983,15 @@
 /*
  * we must open the pv's before we use them
  */
-static int _open_pv(pv_t *pv) {
+static int _open_pv(pv_t * pv)
+{
 	int err;
 	struct block_device *bd;
 
 	if (!(bd = bdget(kdev_t_to_nr(pv->pv_dev))))
 		return -ENOMEM;
 
-	err = blkdev_get(bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE);
+	err = blkdev_get(bd, FMODE_READ | FMODE_WRITE, 0, BDEV_FILE);
 	if (err)
 		return err;
 
@@ -2870,7 +2999,8 @@
 	return 0;
 }
 
-static void _close_pv(pv_t *pv) {
+static void _close_pv(pv_t * pv)
+{
 	if (pv) {
 		struct block_device *bdev = pv->bd;
 		pv->bd = NULL;
@@ -2882,7 +3012,7 @@
 
 static unsigned long _sectors_to_k(unsigned long sect)
 {
-	if(SECTOR_SIZE > 1024) {
+	if (SECTOR_SIZE > 1024) {
 		return sect * (SECTOR_SIZE / 1024);
 	}
 
diff -Nru a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
--- a/drivers/media/video/cpia.c	Wed Feb 19 07:55:06 2003
+++ b/drivers/media/video/cpia.c	Thu Jul 31 06:39:39 2003
@@ -1683,13 +1683,9 @@
 			 * values.             - rich@annexia.org
 			 */
 			if (cam->params.exposure.redComp < 220 ||
-			    cam->params.exposure.redComp > 255 ||
 			    cam->params.exposure.green1Comp < 214 ||
-			    cam->params.exposure.green1Comp > 255 ||
 			    cam->params.exposure.green2Comp < 214 ||
-			    cam->params.exposure.green2Comp > 255 ||
-			    cam->params.exposure.blueComp < 230 ||
-			    cam->params.exposure.blueComp > 255)
+			    cam->params.exposure.blueComp < 230)
 			  {
 			    printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
 				    cam->params.exposure.redComp,
diff -Nru a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
--- a/drivers/media/video/cpia.h	Mon Mar  3 07:41:19 2003
+++ b/drivers/media/video/cpia.h	Sun Aug 17 08:22:20 2003
@@ -393,12 +393,14 @@
 /* ErrorCode */
 #define ERROR_FLICKER_BELOW_MIN_EXP     0x01 /*flicker exposure got below minimum exposure */
 
-#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args)
-#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO __FILE__":"__FUNCTION__"(%d):"fmt,##args)
+#define ALOG(function,lineno,fmt,args...) printk(fmt, function, lineno, ##args)
+#define LOG(fmt,args...) ALOG((__FUNCTION__), (__LINE__), \
+			      KERN_INFO __FILE__":%s(%d):"fmt, ##args)
 
 #ifdef _CPIA_DEBUG_
-#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args)
-#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):"__FUNCTION__"(%d):"fmt,##args)
+#define ADBG(function,lineno,fmt,args...) printk(fmt, jiffies, function, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__FUNCTION__), (__LINE__), \
+			      KERN_DEBUG __FILE__"(%ld):%s(%d):"fmt, ##args)
 #else
 #define DBG(fmn,args...) do {} while(0)
 #endif
diff -Nru a/drivers/media/video/meye.c b/drivers/media/video/meye.c
--- a/drivers/media/video/meye.c	Sun Jun 29 08:10:26 2003
+++ b/drivers/media/video/meye.c	Mon Jul  7 04:48:00 2003
@@ -35,7 +35,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/delay.h>
-#include <linux/wrapper.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
 
@@ -139,7 +138,7 @@
 		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
 	        adr = (unsigned long)mem;
 		while (size > 0) {
-			mem_map_reserve(vmalloc_to_page((void *)adr));
+			SetPageReserved(vmalloc_to_page((void *)adr));
 			adr += PAGE_SIZE;
 			size -= PAGE_SIZE;
 		}
@@ -153,7 +152,7 @@
 	if (mem) {
 	        adr = (unsigned long) mem;
 		while ((long) size > 0) {
-			mem_map_unreserve(vmalloc_to_page((void *)adr));
+			ClearPageReserved(vmalloc_to_page((void *)adr));
 			adr += PAGE_SIZE;
 			size -= PAGE_SIZE;
 		}
diff -Nru a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
--- a/drivers/message/fusion/linux_compat.h	Sun Jul  6 12:59:52 2003
+++ b/drivers/message/fusion/linux_compat.h	Mon Dec  2 18:10:12 2002
@@ -93,7 +93,7 @@
  * Used prior to schedule_timeout calls..
  */
 #define __set_current_state(state_value)	do { current->state = state_value; } while (0)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define set_current_state(state_value)		do { __set_current_state(state_value); mb(); } while (0)
 #else
 #define set_current_state(state_value)		__set_current_state(state_value)
diff -Nru a/drivers/net/3c501.c b/drivers/net/3c501.c
--- a/drivers/net/3c501.c	Mon Mar  3 07:19:48 2003
+++ b/drivers/net/3c501.c	Tue Aug 26 13:18:53 2003
@@ -148,7 +148,7 @@
 static int  el1_close(struct net_device *dev);
 static struct net_device_stats *el1_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
 
 #define EL1_IO_EXTENT	16
 
@@ -388,7 +388,7 @@
 	dev->stop = &el1_close;
 	dev->get_stats = &el1_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
-	dev->do_ioctl = netdev_ioctl;
+	dev->ethtool_ops = &netdev_ethtool_ops;
 
 	/*
 	 *	Setup the generic properties
@@ -939,86 +939,31 @@
 	}
 }
 
-/**
- * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @useraddr: userspace address to which data is to be read and returned
- *
- * Process the various commands of the SIOCETHTOOL interface.
- */
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		debug = edata.data;
-		return 0;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
 }
 
-/**
- * netdev_ioctl: Handle network interface ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @rq: user request data
- * @cmd: command issued by user
- *
- * Process the various out-of-band ioctls passed to this driver.
- */
-
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static u32 netdev_get_msglevel(struct net_device *dev)
 {
-	int rc = 0;
+	return debug;
+}
 
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+	debug = level;
+}
 
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+};
 
-	return rc;
-}
- 
 #ifdef MODULE
 
 static struct net_device dev_3c501 = {
diff -Nru a/drivers/net/3c503.c b/drivers/net/3c503.c
--- a/drivers/net/3c503.c	Mon Jul 29 09:11:46 2002
+++ b/drivers/net/3c503.c	Tue Aug 26 13:28:31 2003
@@ -82,7 +82,7 @@
 			   int ring_offset);
 static void el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 			 int ring_page);
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
 
 
 /* This routine probes for a memory-mapped 3c503 board by looking for
@@ -310,7 +310,7 @@
 
     dev->open = &el2_open;
     dev->stop = &el2_close;
-    dev->do_ioctl = &netdev_ioctl;
+    dev->ethtool_ops = &netdev_ethtool_ops;
 
     if (dev->mem_start)
 	printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
@@ -619,69 +619,18 @@
     return;
 }
 
-/**
- * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @useraddr: userspace address to which data is to be read and returned
- *
- * Process the various commands of the SIOCETHTOOL interface.
- */
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
 }
 
-/**
- * netdev_ioctl: Handle network interface ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @rq: user request data
- * @cmd: command issued by user
- *
- * Process the various out-of-band ioctls passed to this driver.
- */
-
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	int rc = 0;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
-
-	return rc;
-}
- 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
 
 #ifdef MODULE
 #define MAX_EL2_CARDS	4	/* Max number of EL2 cards per module */
diff -Nru a/drivers/net/3c505.c b/drivers/net/3c505.c
--- a/drivers/net/3c505.c	Mon Jan  6 07:38:15 2003
+++ b/drivers/net/3c505.c	Tue Aug 26 13:28:31 2003
@@ -1270,86 +1270,30 @@
 	}
 }
 
-/**
- * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @useraddr: userspace address to which data is to be read and returned
- *
- * Process the various commands of the SIOCETHTOOL interface.
- */
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		debug = edata.data;
-		return 0;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
 }
 
-/**
- * netdev_ioctl: Handle network interface ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @rq: user request data
- * @cmd: command issued by user
- *
- * Process the various out-of-band ioctls passed to this driver.
- */
-
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static u32 netdev_get_msglevel(struct net_device *dev)
 {
-	int rc = 0;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
+	return debug;
+}
 
-	return rc;
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+	debug = level;
 }
- 
+
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+};
 
 /******************************************************
  *
@@ -1371,7 +1315,7 @@
 	dev->tx_timeout = elp_timeout;			/* local */
 	dev->watchdog_timeo = 10*HZ;
 	dev->set_multicast_list = elp_set_mc_list;	/* local */
-	dev->do_ioctl = netdev_ioctl;			/* local */
+	dev->ethtool_ops = &netdev_ethtool_ops;		/* local */
 
 	/* Setup the generic properties */
 	ether_setup(dev);
diff -Nru a/drivers/net/3c507.c b/drivers/net/3c507.c
--- a/drivers/net/3c507.c	Mon Jan  6 07:38:15 2003
+++ b/drivers/net/3c507.c	Tue Aug 26 13:28:31 2003
@@ -305,7 +305,7 @@
 
 static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
 static void init_82586_mem(struct net_device *dev);
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
 
 
 /* Check for a network adaptor of this type, and return '0' iff one exists.
@@ -437,7 +437,7 @@
 	dev->get_stats	= el16_get_stats;
 	dev->tx_timeout = el16_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->do_ioctl = netdev_ioctl;
+	dev->ethtool_ops = &netdev_ethtool_ops;
 
 	ether_setup(dev);	/* Generic ethernet behaviour */
 
@@ -879,86 +879,29 @@
 	lp->rx_tail = rx_tail;
 }
 
-/**
- * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @useraddr: userspace address to which data is to be read and returned
- *
- * Process the various commands of the SIOCETHTOOL interface.
- */
-
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
-{
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		debug = edata.data;
-		return 0;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
 }
 
-/**
- * netdev_ioctl: Handle network interface ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @rq: user request data
- * @cmd: command issued by user
- *
- * Process the various out-of-band ioctls passed to this driver.
- */
-
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static u32 netdev_get_msglevel(struct net_device *dev)
 {
-	int rc = 0;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
+	return debug;
+}
 
-	return rc;
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+	debug = level;
 }
- 
+
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+};
 
 #ifdef MODULE
 static struct net_device dev_3c507;
diff -Nru a/drivers/net/3c515.c b/drivers/net/3c515.c
--- a/drivers/net/3c515.c	Sat Nov 30 15:54:49 2002
+++ b/drivers/net/3c515.c	Tue Aug 26 13:39:47 2003
@@ -406,7 +406,7 @@
 static void update_stats(int addr, struct net_device *dev);
 static struct net_device_stats *corkscrew_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
 
 
 /* 
@@ -736,7 +736,7 @@
 	dev->stop = &corkscrew_close;
 	dev->get_stats = &corkscrew_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = netdev_ioctl;
+	dev->ethtool_ops = &netdev_ethtool_ops;
 
 	return 0;
 }
@@ -1608,86 +1608,30 @@
 	outw(new_mode, ioaddr + EL3_CMD);
 }
 
-/**
- * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @useraddr: userspace address to which data is to be read and returned
- *
- * Process the various commands of the SIOCETHTOOL interface.
- */
-
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = corkscrew_debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		corkscrew_debug = edata.data;
-		return 0;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
 }
 
-/**
- * netdev_ioctl: Handle network interface ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @rq: user request data
- * @cmd: command issued by user
- *
- * Process the various out-of-band ioctls passed to this driver.
- */
-
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static u32 netdev_get_msglevel(struct net_device *dev)
 {
-	int rc = 0;
+	return debug;
+}
 
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+	debug = level;
+}
 
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+};
 
-	return rc;
-}
- 
 
 #ifdef MODULE
 void cleanup_module(void)
diff -Nru a/drivers/net/3c523.c b/drivers/net/3c523.c
--- a/drivers/net/3c523.c	Wed Jan  8 16:47:04 2003
+++ b/drivers/net/3c523.c	Tue Aug 26 13:39:47 2003
@@ -190,7 +190,7 @@
 #ifdef ELMC_MULTICAST
 static void set_multicast_list(struct net_device *dev);
 #endif
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
 
 /* helper-functions */
 static int init586(struct net_device *dev);
@@ -573,7 +573,7 @@
 #else
 	dev->set_multicast_list = NULL;
 #endif
-	dev->do_ioctl = netdev_ioctl;
+	dev->ethtool_ops = &netdev_ethtool_ops;
 	
 	ether_setup(dev);
 
@@ -1228,70 +1228,17 @@
 }
 #endif
 
-/**
- * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @useraddr: userspace address to which data is to be read and returned
- *
- * Process the various commands of the SIOCETHTOOL interface.
- */
-
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "MCA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
 }
 
-/**
- * netdev_ioctl: Handle network interface ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @rq: user request data
- * @cmd: command issued by user
- *
- * Process the various out-of-band ioctls passed to this driver.
- */
-
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	int rc = 0;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
-
-	return rc;
-}
- 
-/*************************************************************************/
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
 
 #ifdef MODULE
 
diff -Nru a/drivers/net/3c527.c b/drivers/net/3c527.c
--- a/drivers/net/3c527.c	Mon Jan  6 07:38:18 2003
+++ b/drivers/net/3c527.c	Sun Aug 31 06:33:37 2003
@@ -220,7 +220,7 @@
 static struct	net_device_stats *mc32_get_stats(struct net_device *dev);
 static void	mc32_set_multicast_list(struct net_device *dev);
 static void	mc32_reset_multicast_list(struct net_device *dev);
-static int	netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
 
 /**
  * mc32_probe 	-	Search for supported boards
@@ -510,7 +510,7 @@
 	dev->set_multicast_list = mc32_set_multicast_list;
 	dev->tx_timeout		= mc32_timeout;
 	dev->watchdog_timeo	= HZ*5;	/* Board does all the work */
-	dev->do_ioctl		= netdev_ioctl;
+	dev->ethtool_ops	= &netdev_ethtool_ops;
 	
 	lp->xceiver_state = HALTED; 
 	
@@ -1083,15 +1083,16 @@
 	/* 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;
-   	   
    	if(skb->len < ETH_ZLEN)
    	{
    		skb = skb_padto(skb, ETH_ZLEN);
    		if(skb == NULL)
    			goto out;
    	}
+
+	/* 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);
@@ -1658,86 +1659,30 @@
 	do_mc32_set_multicast_list(dev,1);
 }
 
-/**
- * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @useraddr: userspace address to which data is to be read and returned
- *
- * Process the various commands of the SIOCETHTOOL interface.
- */
-
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "MCA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = mc32_debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		mc32_debug = edata.data;
-		return 0;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
 }
 
-/**
- * netdev_ioctl: Handle network interface ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @rq: user request data
- * @cmd: command issued by user
- *
- * Process the various out-of-band ioctls passed to this driver.
- */
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+	return mc32_debug;
+}
 
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
 {
-	int rc = 0;
+	mc32_debug = level;
+}
 
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+};
 
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
-
-	return rc;
-}
- 
 #ifdef MODULE
 
 static struct net_device this_device;
diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c	Sun Jun 29 08:47:11 2003
+++ b/drivers/net/3c59x.c	Tue Aug 26 13:12:28 2003
@@ -866,6 +866,7 @@
 static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void vortex_tx_timeout(struct net_device *dev);
 static void acpi_set_WOL(struct net_device *dev);
+static struct ethtool_ops vortex_ethtool_ops;
 
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Option count limit only -- unlimited interfaces are supported. */
@@ -1330,6 +1331,7 @@
 	dev->stop = vortex_close;
 	dev->get_stats = vortex_get_stats;
 	dev->do_ioctl = vortex_ioctl;
+	dev->ethtool_ops = &vortex_ethtool_ops;
 	dev->set_multicast_list = set_rx_mode;
 	dev->tx_timeout = vortex_tx_timeout;
 	dev->watchdog_timeo = (watchdog * HZ) / 1000;
@@ -2690,35 +2692,24 @@
 	return;
 }
 
-
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void vortex_get_drvinfo(struct net_device *dev,
+				struct ethtool_drvinfo *info)
 {
 	struct vortex_private *vp = dev->priv;
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-
-        switch (ethcmd) {
-        case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		if (vp->pdev)
-			strcpy(info.bus_info, vp->pdev->slot_name);
-		else
-			sprintf(info.bus_info, "EISA 0x%lx %d",
-				dev->base_addr, dev->irq);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
 
-        }
-	
-	return -EOPNOTSUPP;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	if (vp->pdev)
+		strcpy(info->bus_info, pci_name(vp->pdev));
+	else
+		sprintf(info->bus_info, "EISA 0x%lx %d",
+			dev->base_addr, dev->irq);
 }
 
+static struct ethtool_ops vortex_ethtool_ops = {
+	.get_drvinfo		= vortex_get_drvinfo,
+};
+
 static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
@@ -2728,9 +2719,6 @@
 	int retval;
 
 	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
 	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = phy;
diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c	Wed Jun  4 20:50:00 2003
+++ b/drivers/net/8139cp.c	Sat Aug 30 23:06:23 2003
@@ -24,15 +24,13 @@
 		PCI suspend/resume  - Felipe Damasio <felipewd@terra.com.br>
 		LinkChg interrupt   - Felipe Damasio <felipewd@terra.com.br>
 			
-	TODO, in rough priority order:
+	TODO:
 	* Test Tx checksumming thoroughly
-	* dev->tx_timeout
-	* Constants (module parms?) for Rx work limit
+	* Implement dev->tx_timeout
+
+	Low priority TODO:
 	* Complete reset on PciErr
 	* Consider Rx interrupt mitigation using TimerIntr
-	* Implement 8139C+ statistics dump; maybe not...
-	  h/w stats can be reset only by software reset
-	* Handle netif_rx return value
 	* Investigate using skb->priority with h/w VLAN priority
 	* Investigate using High Priority Tx Queue with skb->priority
 	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
@@ -41,14 +39,17 @@
 	  Tx descriptor bit
 	* The real minimum of CP_MIN_MTU is 4 bytes.  However,
 	  for this to be supported, one must(?) turn on packet padding.
-	* Support 8169 GMII
-	* Support external MII transceivers
+	* Support external MII transceivers (patch available)
+
+	NOTES:
+	* TX checksumming is considered experimental.  It is off by
+	  default, use ethtool to turn it on.
 
  */
 
 #define DRV_NAME		"8139cp"
-#define DRV_VERSION		"0.3.0"
-#define DRV_RELDATE		"Sep 29, 2002"
+#define DRV_VERSION		"1.1"
+#define DRV_RELDATE		"Aug 30, 2003"
 
 
 #include <linux/config.h>
@@ -71,9 +72,6 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-/* experimental TX checksumming feature enable/disable */
-#undef CP_TX_CHECKSUM
-
 /* VLAN tagging feature enable/disable */
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define CP_VLAN_TAG_USED 1
@@ -86,7 +84,7 @@
 #endif
 
 /* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
+static char version[] =
 KERN_INFO DRV_NAME ": 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
@@ -160,6 +158,7 @@
 	TxConfig	= 0x40, /* Tx configuration */
 	ChipVersion	= 0x43, /* 8-bit chip version, inside TxConfig */
 	RxConfig	= 0x44, /* Rx configuration */
+	RxMissed	= 0x4C,	/* 24 bits valid, write clears */
 	Cfg9346		= 0x50, /* EEPROM select/control; Cfg reg [un]lock */
 	Config1		= 0x52, /* Config1 */
 	Config3		= 0x59, /* Config3 */
@@ -292,12 +291,11 @@
 	UWF             = (1 << 4),  /* Accept Unicast wakeup frame */
 	LANWake         = (1 << 1),  /* Enable LANWake signal */
 	PMEStatus	= (1 << 0),  /* PME status can be reset by PCI RST# */
-};
 
-static const unsigned int cp_intr_mask =
-	PciErr | LinkChg |
-	RxOK | RxErr | RxEmpty | RxFIFOOvr |
-	TxOK | TxErr | TxEmpty;
+	cp_norx_intr_mask = PciErr | LinkChg | TxOK | TxErr | TxEmpty,
+	cp_rx_intr_mask = RxOK | RxErr | RxEmpty | RxFIFOOvr,
+	cp_intr_mask = cp_rx_intr_mask | cp_norx_intr_mask,
+};
 
 static const unsigned int cp_rx_config =
 	  (RX_FIFO_THRESH << RxCfgFIFOShift) |
@@ -364,11 +362,7 @@
 
 	struct pci_dev		*pdev;
 	u32			rx_config;
-
-	struct sk_buff		*frag_skb;
-	unsigned		dropping_frag : 1;
-	unsigned		pci_using_dac : 1;
-	unsigned int		board_type;
+	u16			cpcmd;
 
 	unsigned int		wol_enabled : 1; /* Is Wake-on-LAN enabled? */
 	u32			power_state[16];
@@ -400,28 +394,9 @@
 static void cp_tx (struct cp_private *cp);
 static void cp_clean_rings (struct cp_private *cp);
 
-enum board_type {
-	RTL8139Cp,
-	RTL8169,
-};
-
-static struct cp_board_info {
-	const char *name;
-} cp_board_tbl[] __devinitdata = {
-	/* RTL8139Cp */
-	{ "RTL-8139C+" },
-
-	/* RTL8169 */
-	{ "RTL-8169" },
-};
-
-static struct pci_device_id cp_pci_tbl[] __devinitdata = {
+static struct pci_device_id cp_pci_tbl[] = {
 	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139Cp },
-#if 0
-	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8169,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8169 },
-#endif
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
 	{ },
 };
 MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
@@ -446,6 +421,31 @@
 };
 
 
+#if CP_VLAN_TAG_USED
+static void cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+	struct cp_private *cp = dev->priv;
+
+	spin_lock_irq(&cp->lock);
+	cp->vlgrp = grp;
+	cp->cpcmd |= RxVlanOn;
+	cpw16(CpCmd, cp->cpcmd);
+	spin_unlock_irq(&cp->lock);
+}
+
+static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	struct cp_private *cp = dev->priv;
+
+	spin_lock_irq(&cp->lock);
+	cp->cpcmd &= ~RxVlanOn;
+	cpw16(CpCmd, cp->cpcmd);
+	if (cp->vlgrp)
+		cp->vlgrp->vlan_devices[vid] = NULL;
+	spin_unlock_irq(&cp->lock);
+}
+#endif /* CP_VLAN_TAG_USED */
+
 static inline void cp_set_rxbufsize (struct cp_private *cp)
 {
 	unsigned int mtu = cp->dev->mtu;
@@ -468,10 +468,10 @@
 
 #if CP_VLAN_TAG_USED
 	if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) {
-		vlan_hwaccel_rx(skb, cp->vlgrp, desc->opts2 & 0xffff);
+		vlan_hwaccel_rx(skb, cp->vlgrp, be16_to_cpu(desc->opts2 & 0xffff));
 	} else
 #endif
-		netif_rx(skb);
+		netif_receive_skb(skb);
 }
 
 static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
@@ -486,81 +486,14 @@
 		cp->net_stats.rx_frame_errors++;
 	if (status & RxErrCRC)
 		cp->net_stats.rx_crc_errors++;
-	if (status & RxErrRunt)
+	if ((status & RxErrRunt) || (status & RxErrLong))
 		cp->net_stats.rx_length_errors++;
-	if (status & RxErrLong)
+	if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag))
 		cp->net_stats.rx_length_errors++;
 	if (status & RxErrFIFO)
 		cp->net_stats.rx_fifo_errors++;
 }
 
-static void cp_rx_frag (struct cp_private *cp, unsigned rx_tail,
-			struct sk_buff *skb, u32 status, u32 len)
-{
-	struct sk_buff *copy_skb, *frag_skb = cp->frag_skb;
-	unsigned orig_len = frag_skb ? frag_skb->len : 0;
-	unsigned target_len = orig_len + len;
-	unsigned first_frag = status & FirstFrag;
-	unsigned last_frag = status & LastFrag;
-
-	if (netif_msg_rx_status (cp))
-		printk (KERN_DEBUG "%s: rx %s%sfrag, slot %d status 0x%x len %d\n",
-			cp->dev->name,
-			cp->dropping_frag ? "dropping " : "",
-			first_frag ? "first " :
-			last_frag ? "last " : "",
-			rx_tail, status, len);
-
-	cp->cp_stats.rx_frags++;
-
-	if (!frag_skb && !first_frag)
-		cp->dropping_frag = 1;
-	if (cp->dropping_frag)
-		goto drop_frag;
-
-	copy_skb = dev_alloc_skb (target_len + RX_OFFSET);
-	if (!copy_skb) {
-		printk(KERN_WARNING "%s: rx slot %d alloc failed\n",
-		       cp->dev->name, rx_tail);
-
-		cp->dropping_frag = 1;
-drop_frag:
-		if (frag_skb) {
-			dev_kfree_skb_irq(frag_skb);
-			cp->frag_skb = NULL;
-		}
-		if (last_frag) {
-			cp->net_stats.rx_dropped++;
-			cp->dropping_frag = 0;
-		}
-		return;
-	}
-
-	copy_skb->dev = cp->dev;
-	skb_reserve(copy_skb, RX_OFFSET);
-	skb_put(copy_skb, target_len);
-	if (frag_skb) {
-		memcpy(copy_skb->data, frag_skb->data, orig_len);
-		dev_kfree_skb_irq(frag_skb);
-	}
-	pci_dma_sync_single(cp->pdev, cp->rx_skb[rx_tail].mapping,
-			    len, PCI_DMA_FROMDEVICE);
-	memcpy(copy_skb->data + orig_len, skb->data, len);
-
-	copy_skb->ip_summed = CHECKSUM_NONE;
-
-	if (last_frag) {
-		if (status & (RxError | RxErrFIFO)) {
-			cp_rx_err_acct(cp, rx_tail, status, len);
-			dev_kfree_skb_irq(copy_skb);
-		} else
-			cp_rx_skb(cp, copy_skb, &cp->rx_ring[rx_tail]);
-		cp->frag_skb = NULL;
-	} else {
-		cp->frag_skb = copy_skb;
-	}
-}
-
 static inline unsigned int cp_rx_csum_ok (u32 status)
 {
 	unsigned int protocol = (status >> 16) & 0x3;
@@ -574,12 +507,18 @@
 	return 0;
 }
 
-static void cp_rx (struct cp_private *cp)
+static int cp_rx_poll (struct net_device *dev, int *budget)
 {
+	struct cp_private *cp = dev->priv;
 	unsigned rx_tail = cp->rx_tail;
-	unsigned rx_work = 100;
+	unsigned rx_work = dev->quota;
+	unsigned rx;
+
+rx_status_loop:
+	rx = 0;
+	cpw16(IntrStatus, cp_rx_intr_mask);
 
-	while (rx_work--) {
+	while (1) {
 		u32 status, len;
 		dma_addr_t mapping;
 		struct sk_buff *skb, *new_skb;
@@ -599,7 +538,14 @@
 		mapping = cp->rx_skb[rx_tail].mapping;
 
 		if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) {
-			cp_rx_frag(cp, rx_tail, skb, status, len);
+			/* we don't support incoming fragmented frames.
+			 * instead, we attempt to ensure that the
+			 * pre-allocated RX skbs are properly sized such
+			 * that RX fragments are never encountered
+			 */
+			cp_rx_err_acct(cp, rx_tail, status, len);
+			cp->net_stats.rx_dropped++;
+			cp->cp_stats.rx_frags++;
 			goto rx_next;
 		}
 
@@ -640,6 +586,7 @@
 		cp->rx_skb[rx_tail].skb = new_skb;
 
 		cp_rx_skb(cp, skb, desc);
+		rx++;
 
 rx_next:
 		cp->rx_ring[rx_tail].opts2 = 0;
@@ -650,15 +597,34 @@
 		else
 			desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
 		rx_tail = NEXT_RX(rx_tail);
-	}
 
-	if (!rx_work)
-		printk(KERN_WARNING "%s: rx work limit reached\n", cp->dev->name);
+		if (!rx_work--)
+			break;
+	}
 
 	cp->rx_tail = rx_tail;
+
+	dev->quota -= rx;
+	*budget -= rx;
+
+	/* if we did not reach work limit, then we're done with
+	 * this round of polling
+	 */
+	if (rx_work) {
+		if (cpr16(IntrStatus) & cp_rx_intr_mask)
+			goto rx_status_loop;
+
+		cpw16_f(IntrMask, cp_intr_mask);
+		netif_rx_complete(dev);
+
+		return 0;	/* done */
+	}
+
+	return 1;		/* not done */
 }
 
-static void cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t
+cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_instance;
 	struct cp_private *cp = dev->priv;
@@ -666,18 +632,22 @@
 
 	status = cpr16(IntrStatus);
 	if (!status || (status == 0xFFFF))
-		return;
+		return IRQ_NONE;
 
 	if (netif_msg_intr(cp))
 		printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n",
 		        dev->name, status, cpr8(Cmd), cpr16(CpCmd));
 
-	cpw16_f(IntrStatus, status);
+	cpw16(IntrStatus, status & ~cp_rx_intr_mask);
 
 	spin_lock(&cp->lock);
 
-	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
-		cp_rx(cp);
+	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) {
+		if (netif_rx_schedule_prep(dev)) {
+			cpw16_f(IntrMask, cp_norx_intr_mask);
+			__netif_rx_schedule(dev);
+		}
+	}
 	if (status & (TxOK | TxErr | TxEmpty | SWInt))
 		cp_tx(cp);
 	if (status & LinkChg)
@@ -690,9 +660,12 @@
 		pci_write_config_word(cp->pdev, PCI_STATUS, pci_status);
 		printk(KERN_ERR "%s: PCI bus error, status=%04x, PCI status=%04x\n",
 		       dev->name, status, pci_status);
+
+		/* TODO: reset hardware */
 	}
 
 	spin_unlock(&cp->lock);
+	return IRQ_HANDLED;
 }
 
 static void cp_tx (struct cp_private *cp)
@@ -748,7 +721,7 @@
 
 	cp->tx_tail = tx_tail;
 
-	if (netif_queue_stopped(cp->dev) && (TX_BUFFS_AVAIL(cp) > (MAX_SKB_FRAGS + 1)))
+	if (TX_BUFFS_AVAIL(cp) > (MAX_SKB_FRAGS + 1))
 		netif_wake_queue(cp->dev);
 }
 
@@ -774,7 +747,7 @@
 
 #if CP_VLAN_TAG_USED
 	if (cp->vlgrp && vlan_tx_tag_present(skb))
-		vlan_tag = TxVlanTag | vlan_tx_tag_get(skb);
+		vlan_tag = TxVlanTag | cpu_to_be16(vlan_tx_tag_get(skb));
 #endif
 
 	entry = cp->tx_head;
@@ -790,7 +763,6 @@
 		txd->addr = cpu_to_le64(mapping);
 		wmb();
 
-#ifdef CP_TX_CHECKSUM
 		if (skb->ip_summed == CHECKSUM_HW) {
 			const struct iphdr *ip = skb->nh.iph;
 			if (ip->protocol == IPPROTO_TCP)
@@ -804,7 +776,6 @@
 			else
 				BUG();
 		} else
-#endif
 			txd->opts1 = cpu_to_le32(eor | len | DescOwn |
 						 FirstFrag | LastFrag);
 		wmb();
@@ -818,15 +789,13 @@
 		u32 first_len, first_eor;
 		dma_addr_t first_mapping;
 		int frag, first_entry = entry;
-#ifdef CP_TX_CHECKSUM
 		const struct iphdr *ip = skb->nh.iph;
-#endif
 
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
 		 */
 		first_eor = eor;
-		first_len = skb->len - skb->data_len;
+		first_len = skb_headlen(skb);
 		first_mapping = pci_map_single(cp->pdev, skb->data,
 					       first_len, PCI_DMA_TODEVICE);
 		cp->tx_skb[entry].skb = skb;
@@ -846,7 +815,7 @@
 						  this_frag->page_offset),
 						 len, PCI_DMA_TODEVICE);
 			eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
-#ifdef CP_TX_CHECKSUM
+
 			if (skb->ip_summed == CHECKSUM_HW) {
 				ctrl = eor | len | DescOwn | IPCS;
 				if (ip->protocol == IPPROTO_TCP)
@@ -856,7 +825,6 @@
 				else
 					BUG();
 			} else
-#endif
 				ctrl = eor | len | DescOwn;
 
 			if (frag == skb_shinfo(skb)->nr_frags - 1)
@@ -881,7 +849,6 @@
 		txd->addr = cpu_to_le64(first_mapping);
 		wmb();
 
-#ifdef CP_TX_CHECKSUM
 		if (skb->ip_summed == CHECKSUM_HW) {
 			if (ip->protocol == IPPROTO_TCP)
 				txd->opts1 = cpu_to_le32(first_eor | first_len |
@@ -894,7 +861,6 @@
 			else
 				BUG();
 		} else
-#endif
 			txd->opts1 = cpu_to_le32(first_eor | first_len |
 						 FirstFrag | DescOwn);
 		wmb();
@@ -973,7 +939,9 @@
 
 static void __cp_get_stats(struct cp_private *cp)
 {
-	/* XXX implement */
+	/* only lower 24 bits valid; write any value to clear */
+	cp->net_stats.rx_missed_errors += (cpr32 (RxMissed) & 0xffffff);
+	cpw32 (RxMissed, 0);
 }
 
 static struct net_device_stats *cp_get_stats(struct net_device *dev)
@@ -991,17 +959,22 @@
 
 static void cp_stop_hw (struct cp_private *cp)
 {
-	cpw16(IntrMask, 0);
-	cpr16(IntrMask);
+	struct net_device *dev = cp->dev;
+
+	cpw16(IntrStatus, ~(cpr16(IntrStatus)));
+	cpw16_f(IntrMask, 0);
 	cpw8(Cmd, 0);
-	cpw16(CpCmd, 0);
-	cpr16(CpCmd);
+	cpw16_f(CpCmd, 0);
 	cpw16(IntrStatus, ~(cpr16(IntrStatus)));
 	synchronize_irq();
 	udelay(10);
 
 	cp->rx_tail = 0;
 	cp->tx_head = cp->tx_tail = 0;
+
+	(void) dev; /* avoid compiler warning when synchronize_irq()
+		     * disappears during !CONFIG_SMP
+		     */
 }
 
 static void cp_reset_hw (struct cp_private *cp)
@@ -1023,11 +996,7 @@
 
 static inline void cp_start_hw (struct cp_private *cp)
 {
-	u16 pci_dac = cp->pci_using_dac ? PCIDAC : 0;
-	if (cp->board_type == RTL8169)
-		cpw16(CpCmd, pci_dac | PCIMulRW | RxChkSum);
-	else
-		cpw16(CpCmd, pci_dac | PCIMulRW | RxChkSum | CpRxOn | CpTxOn);
+	cpw16(CpCmd, cp->cpcmd);
 	cpw8(Cmd, RxOn | TxOn);
 }
 
@@ -1051,13 +1020,10 @@
 
 	cpw8(Config1, cpr8(Config1) | DriverLoaded | PMEnable);
 	/* Disable Wake-on-LAN. Can be turned on with ETHTOOL_SWOL */
-	if (cp->board_type == RTL8139Cp) {
-		cpw8(Config3, PARMEnable);
-		cp->wol_enabled = 0;
-	}
+	cpw8(Config3, PARMEnable);
+	cp->wol_enabled = 0;
+
 	cpw8(Config5, cpr8(Config5) & PMEStatus); 
-	if (cp->board_type == RTL8169)
-		cpw16(RxMaxSize, cp->rx_buf_sz);
 
 	cpw32_f(HiTxRingAddr, 0);
 	cpw32_f(HiTxRingAddr + 4, 0);
@@ -1250,8 +1216,6 @@
 
 	dev->mtu = new_mtu;
 	cp_set_rxbufsize(cp);		/* set new rx buf size */
-	if (cp->board_type == RTL8169)
-		cpw16(RxMaxSize, cp->rx_buf_sz);
 
 	rc = cp_init_rings(cp);		/* realloc and restart h/w */
 	cp_start_hw(cp);
@@ -1296,8 +1260,8 @@
 }
 
 /* Set the ethtool Wake-on-LAN settings */
-static void netdev_set_wol (struct cp_private *cp,
-                     const struct ethtool_wolinfo *wol)
+static int netdev_set_wol (struct cp_private *cp,
+			   const struct ethtool_wolinfo *wol)
 {
 	u8 options;
 
@@ -1324,6 +1288,8 @@
 	cpw8 (Config5, options);
 
 	cp->wol_enabled = (wol->wolopts) ? 1 : 0;
+
+	return 0;
 }
 
 /* Get the ethtool Wake-on-LAN settings */
@@ -1349,308 +1315,216 @@
 	if (options & MWF)           wol->wolopts |= WAKE_MCAST;
 }
 
-static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
+static void cp_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
+	struct cp_private *cp = dev->priv;
 
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+	strcpy (info->driver, DRV_NAME);
+	strcpy (info->version, DRV_VERSION);
+	strcpy (info->bus_info, pci_name(cp->pdev));
+}
 
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		strcpy (info.bus_info, cp->pdev->slot_name);
-		info.regdump_len = CP_REGS_SIZE;
-		info.n_stats = CP_NUM_STATS;
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
+static int cp_get_regs_len(struct net_device *dev)
+{
+	return CP_REGS_SIZE;
+}
 
-	/* get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		spin_lock_irq(&cp->lock);
-		mii_ethtool_gset(&cp->mii_if, &ecmd);
-		spin_unlock_irq(&cp->lock);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set settings */
-	case ETHTOOL_SSET: {
-		int r;
-		struct ethtool_cmd ecmd;
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
-		spin_lock_irq(&cp->lock);
-		r = mii_ethtool_sset(&cp->mii_if, &ecmd);
-		spin_unlock_irq(&cp->lock);
-		return r;
-	}
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST: {
-		return mii_nway_restart(&cp->mii_if);
-	}
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		edata.data = mii_link_ok(&cp->mii_if);
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
+static int cp_get_stats_count (struct net_device *dev)
+{
+	return CP_NUM_STATS;
+}
 
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = cp->msg_enable;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		cp->msg_enable = edata.data;
-		return 0;
-	}
+static int cp_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct cp_private *cp = dev->priv;
+	int rc;
 
-	/* NIC register dump */
-	case ETHTOOL_GREGS: {
-                struct ethtool_regs regs;
-                u8 *regbuf = kmalloc(CP_REGS_SIZE, GFP_KERNEL);
-                int rc;
-
-		if (!regbuf)
-			return -ENOMEM;
-		memset(regbuf, 0, CP_REGS_SIZE);
+	spin_lock_irq(&cp->lock);
+	rc = mii_ethtool_gset(&cp->mii_if, cmd);
+	spin_unlock_irq(&cp->lock);
 
-                rc = copy_from_user(&regs, useraddr, sizeof(regs));
-		if (rc) {
-			rc = -EFAULT;
-			goto err_out_gregs;
-		}
-                
-                if (regs.len > CP_REGS_SIZE)
-                        regs.len = CP_REGS_SIZE;
-                if (regs.len < CP_REGS_SIZE) {
-			rc = -EINVAL;
-			goto err_out_gregs;
-		}
+	return rc;
+}
 
-                regs.version = CP_REGS_VER;
-                rc = copy_to_user(useraddr, &regs, sizeof(regs));
-		if (rc) {
-			rc = -EFAULT;
-			goto err_out_gregs;
-		}
+static int cp_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct cp_private *cp = dev->priv;
+	int rc;
 
-                useraddr += offsetof(struct ethtool_regs, data);
+	spin_lock_irq(&cp->lock);
+	rc = mii_ethtool_sset(&cp->mii_if, cmd);
+	spin_unlock_irq(&cp->lock);
 
-                spin_lock_irq(&cp->lock);
-                memcpy_fromio(regbuf, cp->regs, CP_REGS_SIZE);
-                spin_unlock_irq(&cp->lock);
+	return rc;
+}
 
-                if (copy_to_user(useraddr, regbuf, regs.len))
-                        rc = -EFAULT;
+static int cp_nway_reset(struct net_device *dev)
+{
+	struct cp_private *cp = dev->priv;
+	return mii_nway_restart(&cp->mii_if);
+}
 
-err_out_gregs:
-		kfree(regbuf);
-		return rc;
-	}
+static u32 cp_get_msglevel(struct net_device *dev)
+{
+	struct cp_private *cp = dev->priv;
+	return cp->msg_enable;
+}
 
-	/* get/set RX checksumming */
-	case ETHTOOL_GRXCSUM: {
-		struct ethtool_value edata = { ETHTOOL_GRXCSUM };
-		u16 cmd = cpr16(CpCmd) & RxChkSum;
-
-		edata.data = cmd ? 1 : 0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SRXCSUM: {
-		struct ethtool_value edata;
-		u16 cmd = cpr16(CpCmd), newcmd;
+static void cp_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct cp_private *cp = dev->priv;
+	cp->msg_enable = value;
+}
 
-		newcmd = cmd;
+static u32 cp_get_rx_csum(struct net_device *dev)
+{
+	struct cp_private *cp = dev->priv;
+	return (cpr16(CpCmd) & RxChkSum) ? 1 : 0;
+}
 
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
+static int cp_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct cp_private *cp = dev->priv;
+	u16 cmd = cp->cpcmd, newcmd;
 
-		if (edata.data)
-			newcmd |= RxChkSum;
-		else
-			newcmd &= ~RxChkSum;
+	newcmd = cmd;
 
-		if (newcmd == cmd)
-			return 0;
+	if (data)
+		newcmd |= RxChkSum;
+	else
+		newcmd &= ~RxChkSum;
 
+	if (newcmd != cmd) {
 		spin_lock_irq(&cp->lock);
+		cp->cpcmd = newcmd;
 		cpw16_f(CpCmd, newcmd);
 		spin_unlock_irq(&cp->lock);
 	}
 
-	/* get/set TX checksumming */
-	case ETHTOOL_GTXCSUM: {
-		struct ethtool_value edata = { ETHTOOL_GTXCSUM };
-
-		edata.data = (cp->dev->features & NETIF_F_IP_CSUM) != 0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_STXCSUM: {
-		struct ethtool_value edata;
-
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
+	return 0;
+}
 
-		if (edata.data)
-			cp->dev->features |= NETIF_F_IP_CSUM;
-		else
-			cp->dev->features &= ~NETIF_F_IP_CSUM;
+/* move this to net/core/ethtool.c */
+static int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
+{
+	if (data)
+		dev->features |= NETIF_F_IP_CSUM;
+	else
+		dev->features &= ~NETIF_F_IP_CSUM;
 
-		return 0;
-	}
+	return 0;
+}
 
-	/* get/set scatter-gather */
-	case ETHTOOL_GSG: {
-		struct ethtool_value edata = { ETHTOOL_GSG };
-
-		edata.data = (cp->dev->features & NETIF_F_SG) != 0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SSG: {
-		struct ethtool_value edata;
+static void cp_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+		        void *p)
+{
+	struct cp_private *cp = dev->priv;
 
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
+	if (regs->len < CP_REGS_SIZE)
+		return /* -EINVAL */;
 
-		if (edata.data)
-			cp->dev->features |= NETIF_F_SG;
-		else
-			cp->dev->features &= ~NETIF_F_SG;
+	regs->version = CP_REGS_VER;
 
-		return 0;
-	}
+	spin_lock_irq(&cp->lock);
+	memcpy_fromio(p, cp->regs, CP_REGS_SIZE);
+	spin_unlock_irq(&cp->lock);
+}
 
-	/* get string list(s) */
-	case ETHTOOL_GSTRINGS: {
-		struct ethtool_gstrings estr = { ETHTOOL_GSTRINGS };
-
-		if (copy_from_user(&estr, useraddr, sizeof(estr)))
-			return -EFAULT;
-		if (estr.string_set != ETH_SS_STATS)
-			return -EINVAL;
-
-		estr.len = CP_NUM_STATS;
-		if (copy_to_user(useraddr, &estr, sizeof(estr)))
-			return -EFAULT;
-		if (copy_to_user(useraddr + sizeof(estr),
-				 &ethtool_stats_keys,
-				 sizeof(ethtool_stats_keys)))
-			return -EFAULT;
-		return 0;
-	}
+static void cp_get_wol (struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct cp_private *cp = dev->priv;
 
-	/* get NIC-specific statistics */
-	case ETHTOOL_GSTATS: {
-		struct ethtool_stats estats = { ETHTOOL_GSTATS };
-		u64 *tmp_stats;
-		unsigned int work = 100;
-		const unsigned int sz = sizeof(u64) * CP_NUM_STATS;
-		int i;
-
-		/* begin NIC statistics dump */
-		cpw32(StatsAddr + 4, 0); /* FIXME: 64-bit PCI */
-		cpw32(StatsAddr, cp->nic_stats_dma | DumpStats);
-		cpr32(StatsAddr);
-
-		estats.n_stats = CP_NUM_STATS;
-		if (copy_to_user(useraddr, &estats, sizeof(estats)))
-			return -EFAULT;
-
-		while (work-- > 0) {
-			if ((cpr32(StatsAddr) & DumpStats) == 0)
-				break;
-			cpu_relax();
-		}
+	spin_lock_irq (&cp->lock);
+	netdev_get_wol (cp, wol);
+	spin_unlock_irq (&cp->lock);
+}
 
-		if (cpr32(StatsAddr) & DumpStats)
-			return -EIO;
+static int cp_set_wol (struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct cp_private *cp = dev->priv;
+	int rc;
 
-		tmp_stats = kmalloc(sz, GFP_KERNEL);
-		if (!tmp_stats)
-			return -ENOMEM;
-		memset(tmp_stats, 0, sz);
-
-		i = 0;
-		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok);
-		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok);
-		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_err);
-		tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_err);
-		tmp_stats[i++] = le16_to_cpu(cp->nic_stats->rx_fifo);
-		tmp_stats[i++] = le16_to_cpu(cp->nic_stats->frame_align);
-		tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_1col);
-		tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_mcol);
-		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_phys);
-		tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_bcast);
-		tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_ok_mcast);
-		tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_abort);
-		tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_underrun);
-		tmp_stats[i++] = cp->cp_stats.rx_frags;
-		if (i != CP_NUM_STATS)
-			BUG();
+	spin_lock_irq (&cp->lock);
+	rc = netdev_set_wol (cp, wol);
+	spin_unlock_irq (&cp->lock);
 
-		i = copy_to_user(useraddr + sizeof(estats),
-				 tmp_stats, sz);
-		kfree(tmp_stats);
+	return rc;
+}
 
-		if (i)
-			return -EFAULT;
-		return 0;
+static void cp_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
+{
+	switch (stringset) {
+	case ETH_SS_STATS:
+		memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
+		break;
+	default:
+		BUG();
+		break;
 	}
+}
 
-	/* get/set Wake-on-LAN settings */
-	case ETHTOOL_GWOL: {
-		struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
-		
-		spin_lock_irq (&cp->lock);
-		netdev_get_wol (cp, &wol);
-		spin_unlock_irq (&cp->lock);
-		return ((copy_to_user (useraddr, &wol, sizeof (wol)))? -EFAULT : 0);
-	}
-	
-	case ETHTOOL_SWOL: {
-		struct ethtool_wolinfo wol;
+static void cp_get_ethtool_stats (struct net_device *dev,
+				  struct ethtool_stats *estats, u64 *tmp_stats)
+{
+	struct cp_private *cp = dev->priv;
+	unsigned int work = 100;
+	int i;
 
-		if (copy_from_user (&wol, useraddr, sizeof (wol)))
-			return -EFAULT;
-		spin_lock_irq (&cp->lock);
-		netdev_set_wol (cp, &wol);
-		spin_unlock_irq (&cp->lock);
-		return 0;
-	}
+	/* begin NIC statistics dump */
+	cpw32(StatsAddr + 4, 0); /* FIXME: 64-bit PCI */
+	cpw32(StatsAddr, cp->nic_stats_dma | DumpStats);
+	cpr32(StatsAddr);
 
-	default:
-		break;
+	while (work-- > 0) {
+		if ((cpr32(StatsAddr) & DumpStats) == 0)
+			break;
+		cpu_relax();
 	}
 
-	return -EOPNOTSUPP;
+	if (cpr32(StatsAddr) & DumpStats)
+		return /* -EIO */;
+
+	i = 0;
+	tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok);
+	tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok);
+	tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_err);
+	tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_err);
+	tmp_stats[i++] = le16_to_cpu(cp->nic_stats->rx_fifo);
+	tmp_stats[i++] = le16_to_cpu(cp->nic_stats->frame_align);
+	tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_1col);
+	tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_mcol);
+	tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_phys);
+	tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_bcast);
+	tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_ok_mcast);
+	tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_abort);
+	tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_underrun);
+	tmp_stats[i++] = cp->cp_stats.rx_frags;
+	if (i != CP_NUM_STATS)
+		BUG();
 }
 
+static struct ethtool_ops cp_ethtool_ops = {
+	.get_drvinfo		= cp_get_drvinfo,
+	.get_regs_len		= cp_get_regs_len,
+	.get_stats_count	= cp_get_stats_count,
+	.get_settings		= cp_get_settings,
+	.set_settings		= cp_set_settings,
+	.nway_reset		= cp_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_msglevel		= cp_get_msglevel,
+	.set_msglevel		= cp_set_msglevel,
+	.get_rx_csum		= cp_get_rx_csum,
+	.set_rx_csum		= cp_set_rx_csum,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= ethtool_op_set_tx_csum, /* local! */
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+	.get_regs		= cp_get_regs,
+	.get_wol		= cp_get_wol,
+	.set_wol		= cp_set_wol,
+	.get_strings		= cp_get_strings,
+	.get_ethtool_stats	= cp_get_ethtool_stats,
+};
 
 static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -1661,38 +1535,12 @@
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	if (cmd == SIOCETHTOOL)
-		return cp_ethtool_ioctl(cp, (void *) rq->ifr_data);
-
 	spin_lock_irq(&cp->lock);
 	rc = generic_mii_ioctl(&cp->mii_if, mii, cmd, NULL);
 	spin_unlock_irq(&cp->lock);
 	return rc;
 }
 
-#if CP_VLAN_TAG_USED
-static void cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
-{
-	struct cp_private *cp = dev->priv;
-
-	spin_lock_irq(&cp->lock);
-	cp->vlgrp = grp;
-	cpw16(CpCmd, cpr16(CpCmd) | RxVlanOn);
-	spin_unlock_irq(&cp->lock);
-}
-
-static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
-{
-	struct cp_private *cp = dev->priv;
-
-	spin_lock_irq(&cp->lock);
-	cpw16(CpCmd, cpr16(CpCmd) & ~RxVlanOn);
-	if (cp->vlgrp)
-		cp->vlgrp->vlan_devices[vid] = NULL;
-	spin_unlock_irq(&cp->lock);
-}
-#endif
-
 /* Serial EEPROM section. */
 
 /*  EEPROM_Ctrl bits. */
@@ -1715,7 +1563,7 @@
 #define EE_READ_CMD		(6)
 #define EE_ERASE_CMD	(7)
 
-static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
+static int read_eeprom (void *ioaddr, int location, int addr_len)
 {
 	int i;
 	unsigned retval = 0;
@@ -1761,17 +1609,15 @@
 	pci_set_power_state (cp->pdev, 3);
 }
 
-static int __devinit cp_init_one (struct pci_dev *pdev,
-				  const struct pci_device_id *ent)
+static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct net_device *dev;
 	struct cp_private *cp;
 	int rc;
 	void *regs;
 	long pciaddr;
-	unsigned int addr_len, i;
+	unsigned int addr_len, i, pci_using_dac;
 	u8 pci_rev, cache_size;
-	unsigned int board_type = (unsigned int) ent->driver_data;
 
 #ifndef MODULE
 	static int version_printed;
@@ -1784,7 +1630,7 @@
 	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
 	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) {
 		printk(KERN_ERR PFX "pci dev %s (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
-		       pdev->slot_name, pdev->vendor, pdev->device, pci_rev);
+		       pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
 		printk(KERN_ERR PFX "Try the \"8139too\" driver instead.\n");
 		return -ENODEV;
 	}
@@ -1795,7 +1641,6 @@
 	SET_MODULE_OWNER(dev);
 	cp = dev->priv;
 	cp->pdev = pdev;
-	cp->board_type = board_type;
 	cp->dev = dev;
 	cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug);
 	spin_lock_init (&cp->lock);
@@ -1818,41 +1663,45 @@
 	if (pdev->irq < 2) {
 		rc = -EIO;
 		printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n",
-		       pdev->irq, pdev->slot_name);
+		       pdev->irq, pci_name(pdev));
 		goto err_out_res;
 	}
 	pciaddr = pci_resource_start(pdev, 1);
 	if (!pciaddr) {
 		rc = -EIO;
 		printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
-		       pdev->slot_name);
+		       pci_name(pdev));
 		goto err_out_res;
 	}
 	if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
 		rc = -EIO;
 		printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
-		       pci_resource_len(pdev, 1), pdev->slot_name);
+		       pci_resource_len(pdev, 1), pci_name(pdev));
 		goto err_out_res;
 	}
 
 	/* Configure DMA attributes. */
-	if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) {
-		cp->pci_using_dac = 1;
+	if ((sizeof(dma_addr_t) > 32) &&
+	    !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
+		pci_using_dac = 1;
 	} else {
-		rc = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+		rc = pci_set_dma_mask(pdev, 0xffffffffULL);
 		if (rc) {
 			printk(KERN_ERR PFX "No usable DMA configuration, "
 			       "aborting.\n");
 			goto err_out_res;
 		}
-		cp->pci_using_dac = 0;
+		pci_using_dac = 0;
 	}
 
+	cp->cpcmd = (pci_using_dac ? PCIDAC : 0) |
+		    PCIMulRW | RxChkSum | CpRxOn | CpTxOn;
+
 	regs = ioremap_nocache(pciaddr, CP_REGS_SIZE);
 	if (!regs) {
 		rc = -EIO;
 		printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
-		       pci_resource_len(pdev, 1), pciaddr, pdev->slot_name);
+		       pci_resource_len(pdev, 1), pciaddr, pci_name(pdev));
 		goto err_out_res;
 	}
 	dev->base_addr = (unsigned long) regs;
@@ -1872,16 +1721,17 @@
 	dev->hard_start_xmit = cp_start_xmit;
 	dev->get_stats = cp_get_stats;
 	dev->do_ioctl = cp_ioctl;
+	dev->poll = cp_rx_poll;
+	dev->weight = 16;	/* arbitrary? from NAPI_HOWTO.txt. */
 #ifdef BROKEN
 	dev->change_mtu = cp_change_mtu;
 #endif
+	dev->ethtool_ops = &cp_ethtool_ops;
 #if 0
 	dev->tx_timeout = cp_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 #endif
-#ifdef CP_TX_CHECKSUM
-	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
-#endif
+
 #if CP_VLAN_TAG_USED
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 	dev->vlan_rx_register = cp_vlan_rx_register;
@@ -1894,11 +1744,10 @@
 	if (rc)
 		goto err_out_iomap;
 
-	printk (KERN_INFO "%s: %s at 0x%lx, "
+	printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, "
 		"%02x:%02x:%02x:%02x:%02x:%02x, "
 		"IRQ %d\n",
 		dev->name,
-		cp_board_tbl[board_type].name,
 		dev->base_addr,
 		dev->dev_addr[0], dev->dev_addr[1],
 		dev->dev_addr[2], dev->dev_addr[3],
@@ -1946,7 +1795,7 @@
 	return rc;
 }
 
-static void __devexit cp_remove_one (struct pci_dev *pdev)
+static void cp_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct cp_private *cp = dev->priv;
@@ -2019,7 +1868,7 @@
 	.name         = DRV_NAME,
 	.id_table     = cp_pci_tbl,
 	.probe        =	cp_init_one,
-	.remove       = __devexit_p(cp_remove_one),
+	.remove       = cp_remove_one,
 #ifdef CONFIG_PM
 	.resume       = cp_resume,
 	.suspend      = cp_suspend,
diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c
--- a/drivers/net/8139too.c	Sat Jul  5 12:10:09 2003
+++ b/drivers/net/8139too.c	Sun Aug 31 05:48:06 2003
@@ -122,6 +122,11 @@
 #define USE_IO_OPS 1
 #endif
 
+/* use a 16K rx ring buffer instead of the default 32K */
+#ifdef CONFIG_SH_DREAMCAST
+#define USE_BUF16K 1
+#endif
+
 /* define to 1 to enable copious debugging info */
 #undef RTL8139_DEBUG
 
@@ -164,7 +169,11 @@
 static int debug = -1;
 
 /* Size of the in-memory receive ring. */
+#ifdef USE_BUF16K
+#define RX_BUF_LEN_IDX	1	/* 0==8K, 1==16K, 2==32K, 3==64K */
+#else
 #define RX_BUF_LEN_IDX	2	/* 0==8K, 1==16K, 2==32K, 3==64K */
+#endif
 #define RX_BUF_LEN	(8192 << RX_BUF_LEN_IDX)
 #define RX_BUF_PAD	16
 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
@@ -211,18 +220,7 @@
 
 typedef enum {
 	RTL8139 = 0,
-	RTL8139_CB,
-	SMC1211TX,
-	/*MPX5030,*/
-	DELTA8139,
-	ADDTRON8139,
-	DFE538TX,
-	DFE690TXD,
-	FE2000VX,
-	ALLIED8139,
 	RTL8129,
-	FNW3603TX,
-	FNW3800TX,
 } board_t;
 
 
@@ -231,36 +229,29 @@
 	const char *name;
 	u32 hw_flags;
 } board_info[] __devinitdata = {
-	{ "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 },
-	{ "D-Link DFE-690TXD (RealTek RTL8139)", RTL8139_CAPS },
-	{ "AboCom FE2000VX (RealTek RTL8139)", RTL8139_CAPS },
-	{ "Allied Telesyn 8139 CardBus", RTL8139_CAPS },
+	{ "RealTek RTL8139", RTL8139_CAPS },
 	{ "RealTek RTL8129", RTL8129_CAPS },
-	{ "Planex FNW-3603-TX 10/100 CardBus", RTL8139_CAPS },
-	{ "Planex FNW-3800-TX 10/100 CardBus", RTL8139_CAPS },
 };
 
 
-static struct pci_device_id rtl8139_pci_tbl[] __devinitdata = {
+static struct pci_device_id rtl8139_pci_tbl[] = {
 	{0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
-	{0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139_CB },
-	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
-/*	{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 },
-	{0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE690TXD },
-	{0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FE2000VX },
-	{0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALLIED8139 },
-	{0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3603TX },
-	{0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3800TX },
-
+	{0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+
+#ifdef CONFIG_SH_SECUREEDGE5410
+	/* Bogus 8139 silicon reports 8129 without external PROM :-( */
+	{0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+#endif
 #ifdef CONFIG_8139TOO_8129
 	{0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
 #endif
@@ -270,8 +261,8 @@
 	 * so we simply don't match on the main vendor id.
 	 */
 	{PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
-	{PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, DFE538TX },
-	{PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, FE2000VX },
+	{PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, RTL8139 },
+	{PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, RTL8139 },
 
 	{0,}
 };
@@ -301,7 +292,6 @@
 	IntrMask = 0x3C,
 	IntrStatus = 0x3E,
 	TxConfig = 0x40,
-	ChipVersion = 0x43,
 	RxConfig = 0x44,
 	Timer = 0x48,		/* A general-purpose counter. */
 	RxMissed = 0x4C,	/* 24 bits valid, write clears. */
@@ -498,9 +488,13 @@
 	CH_8139 = 0,
 	CH_8139_K,
 	CH_8139A,
+	CH_8139A_G,
 	CH_8139B,
 	CH_8130,
 	CH_8139C,
+	CH_8100,
+	CH_8100B_8139D,
+	CH_8101,
 } chip_t;
 
 enum chip_flags {
@@ -508,50 +502,65 @@
 	HasLWake = (1 << 1),
 };
 
+#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
+	(b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
+#define HW_REVID_MASK	HW_REVID(1, 1, 1, 1, 1, 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 version; /* from RTL8139C/RTL8139D docs */
 	u32 flags;
 } rtl_chip_info[] = {
 	{ "RTL-8139",
-	  0x40,
-	  0xf0fe0040, /* XXX copied from RTL8139A, verify */
+	  HW_REVID(1, 0, 0, 0, 0, 0, 0),
 	  HasHltClk,
 	},
 
 	{ "RTL-8139 rev K",
-	  0x60,
-	  0xf0fe0040,
+	  HW_REVID(1, 1, 0, 0, 0, 0, 0),
 	  HasHltClk,
 	},
 
 	{ "RTL-8139A",
-	  0x70,
-	  0xf0fe0040,
+	  HW_REVID(1, 1, 1, 0, 0, 0, 0),
+	  HasHltClk, /* XXX undocumented? */
+	},
+
+	{ "RTL-8139A rev G",
+	  HW_REVID(1, 1, 1, 0, 0, 1, 0),
 	  HasHltClk, /* XXX undocumented? */
 	},
 
 	{ "RTL-8139B",
-	  0x78,
-	  0xf0fc0040,
+	  HW_REVID(1, 1, 1, 1, 0, 0, 0),
 	  HasLWake,
 	},
 
 	{ "RTL-8130",
-	  0x7C,
-	  0xf0fe0040, /* XXX copied from RTL8139A, verify */
+	  HW_REVID(1, 1, 1, 1, 1, 0, 0),
 	  HasLWake,
 	},
 
 	{ "RTL-8139C",
-	  0x74,
-	  0xf0fc0040, /* XXX copied from RTL8139B, verify */
+	  HW_REVID(1, 1, 1, 0, 1, 0, 0),
+	  HasLWake,
+	},
+
+	{ "RTL-8100",
+	  HW_REVID(1, 1, 1, 1, 0, 1, 0),
+ 	  HasLWake,
+ 	},
+
+	{ "RTL-8100B/8139D",
+	  HW_REVID(1, 1, 1, 0, 1, 0, 1),
 	  HasLWake,
 	},
 
+	{ "RTL-8101",
+	  HW_REVID(1, 1, 1, 0, 1, 1, 1),
+	  HasLWake,
+	},
 };
 
 struct rtl_extra_stats {
@@ -565,6 +574,7 @@
 	void *mmio_addr;
 	int drv_flags;
 	struct pci_dev *pci_dev;
+	u32 pci_state[16];
 	struct net_device_stats stats;
 	unsigned char *rx_ring;
 	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
@@ -615,7 +625,7 @@
 static void rtl8139_init_ring (struct net_device *dev);
 static int rtl8139_start_xmit (struct sk_buff *skb,
 			       struct net_device *dev);
-static void rtl8139_interrupt (int irq, void *dev_instance,
+static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
 			       struct pt_regs *regs);
 static int rtl8139_close (struct net_device *dev);
 static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
@@ -623,6 +633,7 @@
 static void rtl8139_set_rx_mode (struct net_device *dev);
 static void __set_rx_mode (struct net_device *dev);
 static void rtl8139_hw_start (struct net_device *dev);
+static struct ethtool_ops rtl8139_ethtool_ops;
 
 #ifdef USE_IO_OPS
 
@@ -686,10 +697,17 @@
 	PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
 	TxErr | TxOK | RxErr | RxOK;
 
+#ifdef USE_BUF16K 
+static const unsigned int rtl8139_rx_config =
+	RxCfgRcv16K | RxNoWrap |
+	(RX_FIFO_THRESH << RxCfgFIFOShift) |
+	(RX_DMA_BURST << RxCfgDMAShift);
+#else
 static const unsigned int rtl8139_rx_config =
 	RxCfgRcv32K | RxNoWrap |
 	(RX_FIFO_THRESH << RxCfgFIFOShift) |
 	(RX_DMA_BURST << RxCfgDMAShift);
+#endif
 
 static const unsigned int rtl8139_tx_config =
 	(TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
@@ -755,7 +773,7 @@
 	unsigned int i;
 	u32 pio_start, pio_end, pio_flags, pio_len;
 	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
-	u32 tmp;
+	u32 version;
 
 	assert (pdev != NULL);
 
@@ -764,10 +782,11 @@
 	/* dev and dev->priv zeroed in alloc_etherdev */
 	dev = alloc_etherdev (sizeof (*tp));
 	if (dev == NULL) {
-		printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pdev->slot_name);
+		printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
+
 	tp = dev->priv;
 	tp->pci_dev = pdev;
 
@@ -794,25 +813,25 @@
 #ifdef USE_IO_OPS
 	/* make sure PCI base addr 0 is PIO */
 	if (!(pio_flags & IORESOURCE_IO)) {
-		printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pdev->slot_name);
+		printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
 		rc = -ENODEV;
 		goto err_out;
 	}
 	/* check for weird/broken PCI region reporting */
 	if (pio_len < RTL_MIN_IO_SIZE) {
-		printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pdev->slot_name);
+		printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
 		rc = -ENODEV;
 		goto err_out;
 	}
 #else
 	/* make sure PCI base addr 1 is MMIO */
 	if (!(mmio_flags & IORESOURCE_MEM)) {
-		printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pdev->slot_name);
+		printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
 		rc = -ENODEV;
 		goto err_out;
 	}
 	if (mmio_len < RTL_MIN_IO_SIZE) {
-		printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pdev->slot_name);
+		printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
 		rc = -ENODEV;
 		goto err_out;
 	}
@@ -834,7 +853,7 @@
 	/* ioremap MMIO region */
 	ioaddr = ioremap (mmio_start, mmio_len);
 	if (ioaddr == NULL) {
-		printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pdev->slot_name);
+		printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
 		rc = -EIO;
 		goto err_out;
 	}
@@ -849,23 +868,23 @@
 	/* check for missing/broken hardware */
 	if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
 		printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
-			pdev->slot_name);
+			pci_name(pdev));
 		rc = -EIO;
 		goto err_out;
 	}
 
 	/* identify chip attached to board */
-	tmp = RTL_R8 (ChipVersion);
+	version = RTL_R32 (TxConfig) & HW_REVID_MASK;
 	for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++)
-		if (tmp == rtl_chip_info[i].version) {
+		if (version == rtl_chip_info[i].version) {
 			tp->chipset = i;
 			goto match;
 		}
 
 	/* if unknown chip, assume array element #0, original RTL-8139 in this case */
 	printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
-		pdev->slot_name);
-	printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pdev->slot_name, RTL_R32 (TxConfig));
+		pci_name(pdev));
+	printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
 	tp->chipset = 0;
 
 match:
@@ -888,8 +907,11 @@
 		}
 		if (rtl_chip_info[tp->chipset].flags & HasLWake) {
 			tmp8 = RTL_R8 (Config4);
-			if (tmp8 & LWPTN)
+			if (tmp8 & LWPTN) {
+				RTL_W8 (Cfg9346, Cfg9346_Unlock);
 				RTL_W8 (Config4, tmp8 & ~LWPTN);
+				RTL_W8 (Cfg9346, Cfg9346_Lock);
+			}
 		}
 	} else {
 		DPRINTK("Old chip wakeup\n");
@@ -940,7 +962,7 @@
 	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
 	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
 		printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
-		       pdev->slot_name, pdev->vendor, pdev->device, pci_rev);
+		       pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
 		printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
 	}
 
@@ -967,6 +989,7 @@
 	dev->get_stats = rtl8139_get_stats;
 	dev->set_multicast_list = rtl8139_set_rx_mode;
 	dev->do_ioctl = netdev_ioctl;
+	dev->ethtool_ops = &rtl8139_ethtool_ops;
 	dev->tx_timeout = rtl8139_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
@@ -1335,23 +1358,12 @@
 }
 
 
-static void rtl_check_media (struct net_device *dev)
+static void rtl_check_media (struct net_device *dev, unsigned int init_media)
 {
 	struct rtl8139_private *tp = dev->priv;
 
 	if (tp->phys[0] >= 0) {
-		u16 mii_lpa = mdio_read(dev, tp->phys[0], MII_LPA);
-		if (mii_lpa == 0xffff)
-			;					/* Not there */
-		else if ((mii_lpa & LPA_100FULL) == LPA_100FULL
-				 || (mii_lpa & 0x00C0) == LPA_10FULL)
-			tp->mii.full_duplex = 1;
-
-		printk (KERN_INFO"%s: Setting %s%s-duplex based on"
-				" auto-negotiated partner ability %4.4x.\n",
-		        dev->name, mii_lpa == 0 ? "" :
-				(mii_lpa & 0x0180) ? "100mbps " : "10mbps ",
-			tp->mii.full_duplex ? "full" : "half", mii_lpa);
+		mii_check_media(&tp->mii, 1, init_media);
 	}
 }
 
@@ -1386,7 +1398,7 @@
 
 	tp->cur_rx = 0;
 
-	rtl_check_media (dev);
+	rtl_check_media (dev, 1);
 
 	if (tp->chipset >= CH_8139B) {
 		/* Disable magic packet scanning, which is enabled
@@ -2001,18 +2013,7 @@
 
 	if ((status & RxUnderrun) && link_changed &&
 	    (tp->drv_flags & HAS_LNK_CHNG)) {
-		/* Really link-change on new chips. */
-		int lpar = RTL_R16 (NWayLPAR);
-		int duplex = (lpar & LPA_100FULL) || (lpar & 0x01C0) == 0x0040
-				|| tp->mii.force_media;
-		if (tp->mii.full_duplex != duplex) {
-			tp->mii.full_duplex = duplex;
-#if 0
-			RTL_W8 (Cfg9346, Cfg9346_Unlock);
-			RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
-			RTL_W8 (Cfg9346, Cfg9346_Lock);
-#endif
-		}
+		rtl_check_media(dev, 0);
 		status &= ~RxUnderrun;
 	}
 
@@ -2038,7 +2039,7 @@
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
-static void rtl8139_interrupt (int irq, void *dev_instance,
+static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
 			       struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
@@ -2047,6 +2048,7 @@
 	void *ioaddr = tp->mmio_addr;
 	int ackstat, status;
 	int link_changed = 0; /* avoid bogus "uninit" warning */
+	int handled = 0;
 
 	spin_lock (&tp->lock);
 
@@ -2062,6 +2064,8 @@
 		      RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
 			break;
 
+		handled = 1;
+
 		/* Acknowledge all of the current interrupt sources ASAP, but
 		   an first get an additional status bit from CSCR. */
 		if (status & RxUnderrun)
@@ -2106,6 +2110,7 @@
 
 	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
 		 dev->name, RTL_R16 (IntrStatus));
+	return IRQ_RETVAL(handled);
 }
 
 
@@ -2171,11 +2176,12 @@
 /* Get the ethtool Wake-on-LAN settings.  Assumes that wol points to
    kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and
    other threads or interrupts aren't messing with the 8139.  */
-static void netdev_get_wol (struct net_device *dev, struct ethtool_wolinfo *wol)
+static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct rtl8139_private *np = dev->priv;
 	void *ioaddr = np->mmio_addr;
 
+	spin_lock_irq(&np->lock);
 	if (rtl_chip_info[np->chipset].flags & HasLWake) {
 		u8 cfg3 = RTL_R8 (Config3);
 		u8 cfg5 = RTL_R8 (Config5);
@@ -2197,14 +2203,14 @@
 		if (cfg5 & Cfg5_BWF)
 			wol->wolopts |= WAKE_BCAST;
 	}
+	spin_unlock_irq(&np->lock);
 }
 
 
 /* Set the ethtool Wake-on-LAN settings.  Return 0 or -errno.  Assumes
    that wol points to kernel memory and other threads or interrupts
    aren't messing with the 8139.  */
-static int netdev_set_wol (struct net_device *dev,
-			   const struct ethtool_wolinfo *wol)
+static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct rtl8139_private *np = dev->priv;
 	void *ioaddr = np->mmio_addr;
@@ -2218,6 +2224,7 @@
 	if (wol->wolopts & ~support)
 		return -EINVAL;
 
+	spin_lock_irq(&np->lock);
 	cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic);
 	if (wol->wolopts & WAKE_PHY)
 		cfg3 |= Cfg3_LinkUp;
@@ -2238,213 +2245,120 @@
 	if (wol->wolopts & WAKE_BCAST)
 		cfg5 |= Cfg5_BWF;
 	RTL_W8 (Config5, cfg5);	/* need not unlock via Cfg9346 */
+	spin_unlock_irq(&np->lock);
 
 	return 0;
 }
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct rtl8139_private *np = dev->priv;
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(np->pci_dev));
+	info->regdump_len = np->regs_len;
+}
 
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
+static int rtl8139_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8139_private *np = dev->priv;
+	spin_lock_irq(&np->lock);
+	mii_ethtool_gset(&np->mii, cmd);
+	spin_unlock_irq(&np->lock);
+	return 0;
+}
 
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		strcpy (info.bus_info, np->pci_dev->slot_name);
-		info.regdump_len = np->regs_len;
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
+static int rtl8139_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8139_private *np = dev->priv;
+	int rc;
+	spin_lock_irq(&np->lock);
+	rc = mii_ethtool_sset(&np->mii, cmd);
+	spin_unlock_irq(&np->lock);
+	return rc;
+}
 
-	/* get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		spin_lock_irq(&np->lock);
-		mii_ethtool_gset(&np->mii, &ecmd);
-		spin_unlock_irq(&np->lock);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set settings */
-	case ETHTOOL_SSET: {
-		int r;
-		struct ethtool_cmd ecmd;
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
-		spin_lock_irq(&np->lock);
-		r = mii_ethtool_sset(&np->mii, &ecmd);
-		spin_unlock_irq(&np->lock);
-		return r;
-	}
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST: {
-		return mii_nway_restart(&np->mii);
-	}
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		edata.data = mii_link_ok(&np->mii);
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
+static int rtl8139_nway_reset(struct net_device *dev)
+{
+	struct rtl8139_private *np = dev->priv;
+	return mii_nway_restart(&np->mii);
+}
 
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		debug = edata.data;
-		return 0;
-	}
+static u32 rtl8139_get_link(struct net_device *dev)
+{
+	struct rtl8139_private *np = dev->priv;
+	return mii_link_ok(&np->mii);
+}
 
-	case ETHTOOL_GWOL:
-		{
-			struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
-			spin_lock_irq (&np->lock);
-			netdev_get_wol (dev, &wol);
-			spin_unlock_irq (&np->lock);
-			if (copy_to_user (useraddr, &wol, sizeof (wol)))
-				return -EFAULT;
-			return 0;
-		}
+static u32 rtl8139_get_msglevel(struct net_device *dev)
+{
+	return debug;
+}
 
-	case ETHTOOL_SWOL:
-		{
-			struct ethtool_wolinfo wol;
-			int rc;
-			if (copy_from_user (&wol, useraddr, sizeof (wol)))
-				return -EFAULT;
-			spin_lock_irq (&np->lock);
-			rc = netdev_set_wol (dev, &wol);
-			spin_unlock_irq (&np->lock);
-			return rc;
-		}
+static void rtl8139_set_msglevel(struct net_device *dev, u32 datum)
+{
+	debug = datum;
+}
 
 /* TODO: we are too slack to do reg dumping for pio, for now */
-#ifndef CONFIG_8139TOO_PIO
-	/* NIC register dump */
-	case ETHTOOL_GREGS: {
-                struct ethtool_regs regs;
-		unsigned int regs_len = np->regs_len;
-                u8 *regbuf = kmalloc(regs_len, GFP_KERNEL);
-                int rc;
-
-		if (!regbuf)
-			return -ENOMEM;
-		memset(regbuf, 0, regs_len);
-
-                rc = copy_from_user(&regs, useraddr, sizeof(regs));
-		if (rc) {
-			rc = -EFAULT;
-			goto err_out_gregs;
-		}
-                
-                if (regs.len > regs_len)
-                        regs.len = regs_len;
-                if (regs.len < regs_len) {
-			rc = -EINVAL;
-			goto err_out_gregs;
-		}
-
-                regs.version = RTL_REGS_VER;
-                rc = copy_to_user(useraddr, &regs, sizeof(regs));
-		if (rc) {
-			rc = -EFAULT;
-			goto err_out_gregs;
-		}
-
-                useraddr += offsetof(struct ethtool_regs, data);
-
-                spin_lock_irq(&np->lock);
-                memcpy_fromio(regbuf, np->mmio_addr, regs_len);
-                spin_unlock_irq(&np->lock);
-
-                if (copy_to_user(useraddr, regbuf, regs_len))
-                        rc = -EFAULT;
-
-err_out_gregs:
-		kfree(regbuf);
-		return rc;
-	}
-#endif /* CONFIG_8139TOO_PIO */
-
-	/* get string list(s) */
-	case ETHTOOL_GSTRINGS: {
-		struct ethtool_gstrings estr = { ETHTOOL_GSTRINGS };
-
-		if (copy_from_user(&estr, useraddr, sizeof(estr)))
-			return -EFAULT;
-		if (estr.string_set != ETH_SS_STATS)
-			return -EINVAL;
-
-		estr.len = RTL_NUM_STATS;
-		if (copy_to_user(useraddr, &estr, sizeof(estr)))
-			return -EFAULT;
-		if (copy_to_user(useraddr + sizeof(estr),
-				 &ethtool_stats_keys,
-				 sizeof(ethtool_stats_keys)))
-			return -EFAULT;
-		return 0;
-	}
+#ifdef CONFIG_8139TOO_PIO
+#define rtl8139_get_regs_len	NULL
+#define rtl8139_get_regs	NULL
+#else
+static int rtl8139_get_regs_len(struct net_device *dev)
+{
+	struct rtl8139_private *np = dev->priv;
+	return np->regs_len;
+}
 
-	/* get NIC-specific statistics */
-	case ETHTOOL_GSTATS: {
-		struct ethtool_stats estats = { ETHTOOL_GSTATS };
-		u64 *tmp_stats;
-		const unsigned int sz = sizeof(u64) * RTL_NUM_STATS;
-		int i;
-
-		estats.n_stats = RTL_NUM_STATS;
-		if (copy_to_user(useraddr, &estats, sizeof(estats)))
-			return -EFAULT;
-
-		tmp_stats = kmalloc(sz, GFP_KERNEL);
-		if (!tmp_stats)
-			return -ENOMEM;
-		memset(tmp_stats, 0, sz);
-
-		i = 0;
-		tmp_stats[i++] = np->xstats.early_rx;
-		tmp_stats[i++] = np->xstats.tx_buf_mapped;
-		tmp_stats[i++] = np->xstats.tx_timeouts;
-		tmp_stats[i++] = np->xstats.rx_lost_in_ring;
-		if (i != RTL_NUM_STATS)
-			BUG();
+static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+{
+	struct rtl8139_private *np = dev->priv;
 
-		i = copy_to_user(useraddr + sizeof(estats), tmp_stats, sz);
-		kfree(tmp_stats);
+	regs->version = RTL_REGS_VER;
 
-		if (i)
-			return -EFAULT;
-		return 0;
-	}
-	default:
-		break;
-	}
+	spin_lock_irq(&np->lock);
+	memcpy_fromio(regbuf, np->mmio_addr, regs->len);
+	spin_unlock_irq(&np->lock);
+}
+#endif /* CONFIG_8139TOO_MMIO */
 
-	return -EOPNOTSUPP;
+static int rtl8139_get_stats_count(struct net_device *dev)
+{
+	return RTL_NUM_STATS;
 }
 
+static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+	struct rtl8139_private *np = dev->priv;
+
+	data[0] = np->xstats.early_rx;
+	data[1] = np->xstats.tx_buf_mapped;
+	data[2] = np->xstats.tx_timeouts;
+	data[3] = np->xstats.rx_lost_in_ring;
+}
+
+static void rtl8139_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static struct ethtool_ops rtl8139_ethtool_ops = {
+	.get_drvinfo		= rtl8139_get_drvinfo,
+	.get_settings		= rtl8139_get_settings,
+	.set_settings		= rtl8139_set_settings,
+	.get_regs_len		= rtl8139_get_regs_len,
+	.get_regs		= rtl8139_get_regs,
+	.nway_reset		= rtl8139_nway_reset,
+	.get_link		= rtl8139_get_link,
+	.get_msglevel		= rtl8139_get_msglevel,
+	.set_msglevel		= rtl8139_set_msglevel,
+	.get_wol		= rtl8139_get_wol,
+	.set_wol		= rtl8139_set_wol,
+	.get_strings		= rtl8139_get_strings,
+	.get_stats_count	= rtl8139_get_stats_count,
+	.get_ethtool_stats	= rtl8139_get_ethtool_stats,
+};
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -2455,14 +2369,9 @@
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	if (cmd == SIOCETHTOOL)
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	else {
-		spin_lock_irq(&np->lock);
-		rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
-		spin_unlock_irq(&np->lock);
-	}
+	spin_lock_irq(&np->lock);
+	rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
+	spin_unlock_irq(&np->lock);
 
 	return rc;
 }
@@ -2569,6 +2478,9 @@
 	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
 	RTL_W32 (RxMissed, 0);
 
+	pci_set_power_state (pdev, 3);
+	pci_save_state (pdev, tp->pci_state);
+
 	spin_unlock_irqrestore (&tp->lock, flags);
 	return 0;
 }
@@ -2577,11 +2489,15 @@
 static int rtl8139_resume (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
+	struct rtl8139_private *tp = dev->priv;
 
 	if (!netif_running (dev))
 		return 0;
-	netif_device_attach (dev);
+	pci_restore_state (pdev, tp->pci_state);
+	pci_set_power_state (pdev, 0);
+	rtl8139_init_ring (dev);
 	rtl8139_hw_start (dev);
+	netif_device_attach (dev);
 	return 0;
 }
 
diff -Nru a/drivers/net/8390.h b/drivers/net/8390.h
--- a/drivers/net/8390.h	Thu Feb 13 20:44:10 2003
+++ b/drivers/net/8390.h	Sat Jun 28 12:59:05 2003
@@ -116,7 +116,7 @@
  */
  
 #if defined(CONFIG_MAC) ||  \
-    defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \
+    defined(CONFIG_ZORRO8390) || defined(CONFIG_ZORRO8390_MODULE) || \
     defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE)
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
 #undef inb
diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in
--- a/drivers/net/Config.in	Sun Aug 24 14:30:49 2003
+++ b/drivers/net/Config.in	Sat Jun 28 12:43:24 2003
@@ -49,9 +49,9 @@
    fi
    if [ "$CONFIG_ZORRO" = "y" ]; then
       tristate '  Ariadne support' CONFIG_ARIADNE
-      tristate '  Ariadne II and X-Surf support' CONFIG_NE2K_ZORRO
       tristate '  A2065 support' CONFIG_A2065
       tristate '  Hydra support' CONFIG_HYDRA
+      tristate '  Zorro NS8390-based Ethernet support' CONFIG_ZORRO8390
    fi
    if [ "$CONFIG_PARISC" = "y" ]; then
       dep_tristate '  Lasi ethernet' CONFIG_LASI_82596 $CONFIG_GSC_LASI
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Tue Jul 29 08:59:54 2003
+++ b/drivers/net/Makefile	Sat Jun 28 12:41:40 2003
@@ -212,7 +212,7 @@
 obj-$(CONFIG_LP486E) += lp486e.o
 
 obj-$(CONFIG_ETH16I) += eth16i.o
-obj-$(CONFIG_ARIADNE2) += ariadne2.o 8390.o
+obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_EQUALIZER) += eql.o
diff -Nru a/drivers/net/ariadne2.c b/drivers/net/ariadne2.c
--- a/drivers/net/ariadne2.c	Thu Nov  8 05:15:27 2001
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,427 +0,0 @@
-/*
- *  Amiga Linux/m68k and Linux/PPC Ariadne II and X-Surf Ethernet Driver
- *
- *  (C) Copyright 1998-2000 by some Elitist 680x0 Users(TM)
- *
- *  ---------------------------------------------------------------------------
- *
- *  This program is based on all the other NE2000 drivers for Linux
- *
- *  ---------------------------------------------------------------------------
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of the Linux
- *  distribution for more details.
- *
- *  ---------------------------------------------------------------------------
- *
- *  The Ariadne II and X-Surf are Zorro-II boards containing Realtek RTL8019AS
- *  Ethernet Controllers.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/zorro.h>
-
-#include <asm/system.h>
-
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-
-#include "8390.h"
-
-
-#define NE_BASE		(dev->base_addr)
-#define NE_CMD		(0x00*2)
-#define NE_DATAPORT	(0x10*2)	/* NatSemi-defined port window offset. */
-#define NE_RESET	(0x1f*2)	/* Issue a read to reset, a write to clear. */
-#define NE_IO_EXTENT	(0x20*2)
-
-#define NE_EN0_ISR	(0x07*2)
-#define NE_EN0_DCFG	(0x0e*2)
-
-#define NE_EN0_RSARLO	(0x08*2)
-#define NE_EN0_RSARHI	(0x09*2)
-#define NE_EN0_RCNTLO	(0x0a*2)
-#define NE_EN0_RXCR	(0x0c*2)
-#define NE_EN0_TXCR	(0x0d*2)
-#define NE_EN0_RCNTHI	(0x0b*2)
-#define NE_EN0_IMR	(0x0f*2)
-
-#define NESM_START_PG	0x40	/* First page of TX buffer */
-#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
-
-
-#define WORDSWAP(a)	((((a)>>8)&0xff) | ((a)<<8))
-
-#ifdef MODULE
-static struct net_device *root_ariadne2_dev;
-#endif
-
-static const struct card_info {
-    zorro_id id;
-    const char *name;
-    unsigned int offset;
-} cards[] __initdata = {
-    { ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2, "Ariadne II", 0x0600 },
-    { ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, "X-Surf", 0x8600 },
-};
-
-static int __init ariadne2_probe(void);
-static int __init ariadne2_init(struct net_device *dev, unsigned long board,
-				const char *name, unsigned long ioaddr);
-static int ariadne2_open(struct net_device *dev);
-static int ariadne2_close(struct net_device *dev);
-static void ariadne2_reset_8390(struct net_device *dev);
-static void ariadne2_get_8390_hdr(struct net_device *dev,
-				  struct e8390_pkt_hdr *hdr, int ring_page);
-static void ariadne2_block_input(struct net_device *dev, int count,
-				 struct sk_buff *skb, int ring_offset);
-static void ariadne2_block_output(struct net_device *dev, const int count,
-				  const unsigned char *buf,
-				  const int start_page);
-static void __exit ariadne2_cleanup(void);
-
-static int __init ariadne2_probe(void)
-{
-    struct net_device *dev;
-    struct zorro_dev *z = NULL;
-    unsigned long board, ioaddr;
-    int err = -ENODEV;
-    int i;
-
-    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-	for (i = ARRAY_SIZE(cards)-1; i >= 0; i--)
-	    if (z->id == cards[i].id)
-		break;
-	if (i < 0)
-	    continue;
-	board = z->resource.start;
-	ioaddr = board+cards[i].offset;
-	dev = init_etherdev(0, 0);
-	SET_MODULE_OWNER(dev);
-	if (!dev)
-	    return -ENOMEM;
-	if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name)) {
-	    kfree(dev);
-	    continue;
-	}
-	if ((err = ariadne2_init(dev, board, cards[i].name,
-				 ZTWO_VADDR(ioaddr)))) {
-	    release_mem_region(ioaddr, NE_IO_EXTENT*2);
-	    kfree(dev);
-	    return err;
-	}
-	err = 0;
-    }
-
-    if (err == -ENODEV)
-	printk("No Ariadne II or X-Surf ethernet card found.\n");
-    return err;
-}
-
-static int __init ariadne2_init(struct net_device *dev, unsigned long board,
-				const char *name, unsigned long ioaddr)
-{
-    int i;
-    unsigned char SA_prom[32];
-    int start_page, stop_page;
-    static u32 ariadne2_offsets[16] = {
-	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
-	0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
-    };
-
-    /* Reset card. Who knows what dain-bramaged state it was left in. */
-    {
-	unsigned long reset_start_time = jiffies;
-
-	z_writeb(z_readb(ioaddr + NE_RESET), ioaddr + NE_RESET);
-
-	while ((z_readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
-	    if (jiffies - reset_start_time > 2*HZ/100) {
-		printk(" not found (no reset ack).\n");
-		return -ENODEV;
-	    }
-
-	z_writeb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
-    }
-
-    /* Read the 16 bytes of station address PROM.
-       We must first initialize registers, similar to NS8390_init(eifdev, 0).
-       We can't reliably read the SAPROM address without this.
-       (I learned the hard way!). */
-    {
-	struct {
-	    u32 value;
-	    u32 offset;
-	} program_seq[] = {
-	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
-	    {0x48,	NE_EN0_DCFG},	/* Set byte-wide (0x48) access. */
-	    {0x00,	NE_EN0_RCNTLO},	/* Clear the count regs. */
-	    {0x00,	NE_EN0_RCNTHI},
-	    {0x00,	NE_EN0_IMR},	/* Mask completion irq. */
-	    {0xFF,	NE_EN0_ISR},
-	    {E8390_RXOFF, NE_EN0_RXCR},	/* 0x20  Set to monitor */
-	    {E8390_TXOFF, NE_EN0_TXCR},	/* 0x02  and loopback mode. */
-	    {32,	NE_EN0_RCNTLO},
-	    {0x00,	NE_EN0_RCNTHI},
-	    {0x00,	NE_EN0_RSARLO},	/* DMA starting at 0x0000. */
-	    {0x00,	NE_EN0_RSARHI},
-	    {E8390_RREAD+E8390_START, NE_CMD},
-	};
-	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
-	    z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
-	}
-    }
-    for (i = 0; i < 16; i++) {
-	SA_prom[i] = z_readb(ioaddr + NE_DATAPORT);
-	(void)z_readb(ioaddr + NE_DATAPORT);
-    }
-
-    /* We must set the 8390 for word mode. */
-    z_writeb(0x49, ioaddr + NE_EN0_DCFG);
-    start_page = NESM_START_PG;
-    stop_page = NESM_STOP_PG;
-
-    dev->base_addr = ioaddr;
-    dev->irq = IRQ_AMIGA_PORTS;
-
-    /* Install the Interrupt handler */
-    i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, dev->name, dev);
-    if (i) return i;
-
-    /* Allocate dev->priv and fill in 8390 specific dev fields. */
-    if (ethdev_init(dev)) {
-	printk("Unable to get memory for dev->priv.\n");
-	return -ENOMEM;
-    }
-
-    for(i = 0; i < ETHER_ADDR_LEN; i++) {
-#ifdef DEBUG
-	printk(" %2.2x", SA_prom[i]);
-#endif
-	dev->dev_addr[i] = SA_prom[i];
-    }
-
-    printk("%s: %s at 0x%08lx, Ethernet Address "
-	   "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, name, board,
-	   dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-
-    ei_status.name = name;
-    ei_status.tx_start_page = start_page;
-    ei_status.stop_page = stop_page;
-    ei_status.word16 = 1;
-
-    ei_status.rx_start_page = start_page + TX_PAGES;
-
-    ei_status.reset_8390 = &ariadne2_reset_8390;
-    ei_status.block_input = &ariadne2_block_input;
-    ei_status.block_output = &ariadne2_block_output;
-    ei_status.get_8390_hdr = &ariadne2_get_8390_hdr;
-    ei_status.reg_offset = ariadne2_offsets;
-    dev->open = &ariadne2_open;
-    dev->stop = &ariadne2_close;
-#ifdef MODULE
-    ei_status.priv = (unsigned long)root_ariadne2_dev;
-    root_ariadne2_dev = dev;
-#endif
-    NS8390_init(dev, 0);
-    return 0;
-}
-
-static int ariadne2_open(struct net_device *dev)
-{
-    ei_open(dev);
-    return 0;
-}
-
-static int ariadne2_close(struct net_device *dev)
-{
-    if (ei_debug > 1)
-	printk("%s: Shutting down ethercard.\n", dev->name);
-    ei_close(dev);
-    return 0;
-}
-
-/* Hard reset the card.  This used to pause for the same period that a
-   8390 reset command required, but that shouldn't be necessary. */
-static void ariadne2_reset_8390(struct net_device *dev)
-{
-    unsigned long reset_start_time = jiffies;
-
-    if (ei_debug > 1)
-	printk("resetting the 8390 t=%ld...", jiffies);
-
-    z_writeb(z_readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
-
-    ei_status.txing = 0;
-    ei_status.dmaing = 0;
-
-    /* This check _should_not_ be necessary, omit eventually. */
-    while ((z_readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
-	if (jiffies - reset_start_time > 2*HZ/100) {
-	    printk("%s: ne_reset_8390() did not complete.\n", dev->name);
-	    break;
-	}
-    z_writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-static void ariadne2_get_8390_hdr(struct net_device *dev,
-				  struct e8390_pkt_hdr *hdr, int ring_page)
-{
-    int nic_base = dev->base_addr;
-    int cnt;
-    short *ptrs;
-
-    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
-    if (ei_status.dmaing) {
-	printk("%s: DMAing conflict in ne_get_8390_hdr "
-	   "[DMAstat:%d][irqlock:%d].\n", dev->name, ei_status.dmaing,
-	   ei_status.irqlock);
-	return;
-    }
-
-    ei_status.dmaing |= 0x01;
-    z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
-    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
-    z_writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
-    z_writeb(0, nic_base + NE_EN0_RCNTHI);
-    z_writeb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
-    z_writeb(ring_page, nic_base + NE_EN0_RSARHI);
-    z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
-
-    ptrs = (short*)hdr;
-    for (cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
-	*ptrs++ = z_readw(NE_BASE + NE_DATAPORT);
-
-    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
-
-    hdr->count = WORDSWAP(hdr->count);
-
-    ei_status.dmaing &= ~0x01;
-}
-
-/* Block input and output, similar to the Crynwr packet driver.  If you
-   are porting to a new ethercard, look at the packet driver source for hints.
-   The NEx000 doesn't share the on-board packet memory -- you have to put
-   the packet out through the "remote DMA" dataport using z_writeb. */
-
-static void ariadne2_block_input(struct net_device *dev, int count,
-				 struct sk_buff *skb, int ring_offset)
-{
-    int nic_base = dev->base_addr;
-    char *buf = skb->data;
-    short *ptrs;
-    int cnt;
-
-    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
-    if (ei_status.dmaing) {
-	printk("%s: DMAing conflict in ne_block_input "
-	   "[DMAstat:%d][irqlock:%d].\n",
-	   dev->name, ei_status.dmaing, ei_status.irqlock);
-	return;
-    }
-    ei_status.dmaing |= 0x01;
-    z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
-    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
-    z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
-    z_writeb(count >> 8, nic_base + NE_EN0_RCNTHI);
-    z_writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
-    z_writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
-    z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
-    ptrs = (short*)buf;
-    for (cnt = 0; cnt < (count>>1); cnt++)
-	*ptrs++ = z_readw(NE_BASE + NE_DATAPORT);
-    if (count & 0x01)
-	buf[count-1] = z_readb(NE_BASE + NE_DATAPORT);
-
-    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
-    ei_status.dmaing &= ~0x01;
-}
-
-static void ariadne2_block_output(struct net_device *dev, int count,
-				  const unsigned char *buf,
-				  const int start_page)
-{
-    int nic_base = NE_BASE;
-    unsigned long dma_start;
-    short *ptrs;
-    int cnt;
-
-    /* Round the count up for word writes.  Do we need to do this?
-       What effect will an odd byte count have on the 8390?
-       I should check someday. */
-    if (count & 0x01)
-	count++;
-
-    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
-    if (ei_status.dmaing) {
-	printk("%s: DMAing conflict in ne_block_output."
-	   "[DMAstat:%d][irqlock:%d]\n", dev->name, ei_status.dmaing,
-	   ei_status.irqlock);
-	return;
-    }
-    ei_status.dmaing |= 0x01;
-    /* We should already be in page 0, but to be safe... */
-    z_writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
-
-    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
-
-   /* Now the normal output. */
-    z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
-    z_writeb(count >> 8,   nic_base + NE_EN0_RCNTHI);
-    z_writeb(0x00, nic_base + NE_EN0_RSARLO);
-    z_writeb(start_page, nic_base + NE_EN0_RSARHI);
-
-    z_writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
-    ptrs = (short*)buf;
-    for (cnt = 0; cnt < count>>1; cnt++)
-	z_writew(*ptrs++, NE_BASE+NE_DATAPORT);
-
-    dma_start = jiffies;
-
-    while ((z_readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
-	if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
-		printk("%s: timeout waiting for Tx RDC.\n", dev->name);
-		ariadne2_reset_8390(dev);
-		NS8390_init(dev,1);
-		break;
-	}
-
-    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
-    ei_status.dmaing &= ~0x01;
-    return;
-}
-
-static void __exit ariadne2_cleanup(void)
-{
-#ifdef MODULE
-    struct net_device *dev, *next;
-
-    while ((dev = root_ariadne2_dev)) {
-	next = (struct net_device *)(ei_status.priv);
-	unregister_netdev(dev);
-	free_irq(IRQ_AMIGA_PORTS, dev);
-	release_mem_region(ZTWO_PADDR(dev->base_addr), NE_IO_EXTENT*2);
-	kfree(dev);
-	root_ariadne2_dev = next;
-    }
-#endif
-}
-
-module_init(ariadne2_probe);
-module_exit(ariadne2_cleanup);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
--- a/drivers/net/bonding/bond_alb.c	Wed Jun 25 09:33:20 2003
+++ b/drivers/net/bonding/bond_alb.c	Wed Aug 27 14:41:54 2003
@@ -24,10 +24,15 @@
  * 2003/06/25 - Shmulik Hen <shmulik.hen at intel dot com>
  *	- Fixed signed/unsigned calculation errors that caused load sharing
  *	  to collapse to one slave under very heavy UDP Tx stress.
+ *
+ * 2003/08/06 - Amir Noam <amir.noam at intel dot com>
+ *	- Add support for setting bond's MAC address with special
+ *	  handling required for ALB/TLB.
  */
 
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/pkt_sched.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -943,10 +948,11 @@
 }
 
 /* hw is a boolean parameter that determines whether we should try and
- * set the hw address of the hw as well as the hw address of the net_device
+ * set the hw address of the device as well as the hw address of the
+ * net_device
  */
 static int
-alb_set_mac_addr(struct slave *slave, u8 addr[], int hw)
+alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw)
 {
 	struct net_device *dev = NULL;
 	struct sockaddr s_addr;
@@ -954,16 +960,16 @@
 	dev = slave->dev;
 
 	if (!hw) {
-		memcpy(dev->dev_addr, addr, ETH_ALEN);
+		memcpy(dev->dev_addr, addr, dev->addr_len);
 		return 0;
 	}
 
 	/* for rlb each slave must have a unique hw mac addresses so that */
 	/* each slave will receive packets destined to a different mac */
-	memcpy(s_addr.sa_data, addr, ETH_ALEN);
+	memcpy(s_addr.sa_data, addr, dev->addr_len);
 	s_addr.sa_family = dev->type;
 	if (dev->set_mac_address(dev, &s_addr)) {
-		printk(KERN_DEBUG "bonding: Error: alb_set_mac_addr:"
+		printk(KERN_DEBUG "bonding: Error: alb_set_slave_mac_addr:"
 				  " dev->set_mac_address of dev %s failed!"
 				  " ALB mode requires that the base driver"
 				  " support setting the hw address also when"
@@ -987,8 +993,8 @@
 	slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));
 
 	memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN);
-	alb_set_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled);
-	alb_set_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled);
+	alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled);
+	alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled);
 
 	/* fasten the change in the switch */
 	if (SLAVE_IS_OK(slave1)) {
@@ -1153,8 +1159,8 @@
 	}
 
 	if (tmp_slave1) {
-		alb_set_mac_addr(slave, tmp_slave1->perm_hwaddr,
-				 bond->alb_info.rlb_enabled);
+		alb_set_slave_mac_addr(slave, tmp_slave1->perm_hwaddr,
+				       bond->alb_info.rlb_enabled);
 
 		printk(KERN_WARNING "bonding: Warning: the hw address "
 		       "of slave %s is in use by the bond; "
@@ -1172,6 +1178,67 @@
 	return 0;
 }
 
+/**
+ * alb_set_mac_address
+ * @bond:
+ * @addr:
+ *
+ * In TLB mode all slaves are configured to the bond's hw address, but set
+ * their dev_addr field to different addresses (based on their permanent hw
+ * addresses).
+ *
+ * For each slave, this function sets the interface to the new address and then
+ * changes its dev_addr field to its previous value.
+ * 
+ * Unwinding assumes bond's mac address has not yet changed.
+ */
+static inline int
+alb_set_mac_address(struct bonding *bond, void *addr)
+{
+	struct sockaddr sa;
+	struct slave *slave;
+	char tmp_addr[ETH_ALEN];
+	int error;
+
+	if (bond->alb_info.rlb_enabled) {
+		return 0;
+	}
+
+	slave = bond_get_first_slave(bond);
+	for (; slave; slave = bond_get_next_slave(bond, slave)) {
+		if (slave->dev->set_mac_address == NULL) {
+			error = -EOPNOTSUPP;
+			goto unwind;
+		}
+
+		/* save net_device's current hw address */
+		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
+
+		error = slave->dev->set_mac_address(slave->dev, addr);
+
+		/* restore net_device's hw address */
+		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
+
+		if (error) {
+			goto unwind;
+		}
+	}
+
+	return 0;
+
+unwind:
+	memcpy(sa.sa_data, bond->device->dev_addr, bond->device->addr_len);
+	sa.sa_family = bond->device->type;
+	slave = bond_get_first_slave(bond);
+	for (; slave; slave = bond_get_next_slave(bond, slave)) {
+		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
+		slave->dev->set_mac_address(slave->dev, &sa);
+		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
+	}
+
+	return error;
+}
+
 /************************ exported alb funcions ************************/
 
 int
@@ -1442,8 +1509,8 @@
 {
 	int err = 0;
 
-	err = alb_set_mac_addr(slave, slave->perm_hwaddr,
-				bond->alb_info.rlb_enabled);
+	err = alb_set_slave_mac_addr(slave, slave->perm_hwaddr,
+				     bond->alb_info.rlb_enabled);
 	if (err) {
 		return err;
 	}
@@ -1567,10 +1634,61 @@
 		alb_swap_mac_addr(bond, swap_slave, new_slave);
 	} else {
 		/* set the new_slave to the bond mac address */
-		alb_set_mac_addr(new_slave, bond->device->dev_addr,
-				 bond->alb_info.rlb_enabled);
+		alb_set_slave_mac_addr(new_slave, bond->device->dev_addr,
+				       bond->alb_info.rlb_enabled);
 		/* fasten bond mac on new current slave */
 		alb_send_learning_packets(new_slave, bond->device->dev_addr);
 	}
+}
+
+int
+bond_alb_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct bonding *bond = dev->priv;
+	struct sockaddr *sa = addr;
+	struct slave *swap_slave = NULL;
+	int error = 0;
+
+	if (!is_valid_ether_addr(sa->sa_data)) {
+		return -EADDRNOTAVAIL;
+	}
+
+	error = alb_set_mac_address(bond, addr);
+	if (error) {
+		return error;
+	}
+
+	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+	/* If there is no current_slave there is nothing else to do.
+	 * Otherwise we'll need to pass the new address to it and handle
+	 * duplications.
+	 */
+	if (bond->current_slave == NULL) {
+		return 0;
+	}
+
+	swap_slave = bond_get_first_slave(bond);
+	while (swap_slave) {
+		if (!memcmp(swap_slave->dev->dev_addr, dev->dev_addr, ETH_ALEN)) {
+			break;
+		}
+		swap_slave = bond_get_next_slave(bond, swap_slave);
+	}
+
+	if (swap_slave) {
+		alb_swap_mac_addr(bond, swap_slave, bond->current_slave);
+	} else {
+		alb_set_slave_mac_addr(bond->current_slave, dev->dev_addr,
+				       bond->alb_info.rlb_enabled);
+
+		alb_send_learning_packets(bond->current_slave, dev->dev_addr);
+		if (bond->alb_info.rlb_enabled) {
+			/* inform clients mac address has changed */
+			rlb_req_update_slave_clients(bond, bond->current_slave);
+		}
+	}
+
+	return 0;
 }
 
diff -Nru a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
--- a/drivers/net/bonding/bond_alb.h	Fri May 23 11:20:53 2003
+++ b/drivers/net/bonding/bond_alb.h	Wed Aug 27 14:41:54 2003
@@ -17,6 +17,13 @@
  *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
+ *
+ *
+ * Changes:
+ *
+ * 2003/08/06 - Amir Noam <amir.noam at intel dot com>
+ *	- Add support for setting bond's MAC address with special
+ *	  handling required for ALB/TLB.
  */
 
 #ifndef __BOND_ALB_H__
@@ -122,6 +129,7 @@
 void bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave);
 int bond_alb_xmit(struct sk_buff *skb, struct net_device *dev);
 void bond_alb_monitor(struct bonding *bond);
+int bond_alb_set_mac_address(struct net_device *dev, void *addr);
 
 #endif /* __BOND_ALB_H__ */
 
diff -Nru a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
--- a/drivers/net/bonding/bond_main.c	Wed Aug 20 07:19:11 2003
+++ b/drivers/net/bonding/bond_main.c	Wed Aug 27 14:43:00 2003
@@ -278,7 +278,7 @@
  *	  bonding round-robin mode ignoring links after failover/recovery
  *
  * 2003/03/17 - Jay Vosburgh <fubar at us dot ibm dot com>
- *	- kmalloc fix (GPF_KERNEL to GPF_ATOMIC) reported by
+ *	- kmalloc fix (GFP_KERNEL to GFP_ATOMIC) reported by
  *	  Shmulik dot Hen at intel.com.
  *	- Based on discussion on mailing list, changed use of
  *	  update_slave_cnt(), created wrapper functions for adding/removing
@@ -323,22 +323,22 @@
  * 2003/03/18 - Amir Noam <amir.noam at intel dot com>,
  *		Tsippy Mendelson <tsippy.mendelson at intel dot com> and
  *		Shmulik Hen <shmulik.hen at intel dot com>
- *    - Added support for IEEE 802.3ad Dynamic link aggregation mode.
+ *	- Added support for IEEE 802.3ad Dynamic link aggregation mode.
  *
  * 2003/05/01 - Amir Noam <amir.noam at intel dot com>
- *    - Added ABI version control to restore compatibility between
- *      new/old ifenslave and new/old bonding.
+ *	- Added ABI version control to restore compatibility between
+ *	  new/old ifenslave and new/old bonding.
  *
  * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
- *    - Fixed bug in bond_release_all(): save old value of current_slave
- *      before setting it to NULL.
- *    - Changed driver versioning scheme to include version number instead
- *      of release date (that is already in another field). There are 3
- *      fields X.Y.Z where:
- *            X - Major version - big behavior changes
- *            Y - Minor version - addition of features
- *            Z - Extra version - minor changes and bug fixes
- *      The current version is 1.0.0 as a base line.
+ *	- Fixed bug in bond_release_all(): save old value of current_slave
+ *	  before setting it to NULL.
+ *	- Changed driver versioning scheme to include version number instead
+ *	  of release date (that is already in another field). There are 3
+ *	  fields X.Y.Z where:
+ *		X - Major version - big behavior changes
+ *		Y - Minor version - addition of features
+ *		Z - Extra version - minor changes and bug fixes
+ *	  The current version is 1.0.0 as a base line.
  *
  * 2003/05/01 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
  *		Amir Noam <amir.noam at intel dot com>
@@ -382,12 +382,44 @@
  *	  ABI version if receiving unsupported ioctl commands.
  *
  * 2003/05/22 - Jay Vosburgh <fubar at us dot ibm dot com>
+ *	- Fix ifenslave -c causing bond to loose existing routes;
+ *	  added bond_set_mac_address() that doesn't require the
+ *	  bond to be down.
  *	- In conjunction with fix for ifenslave -c, in
  *	  bond_change_active(), changing to the already active slave
  *	  is no longer an error (it successfully does nothing).
  *
  * 2003/06/30 - Amir Noam <amir.noam at intel dot com>
  * 	- Fixed bond_change_active() for ALB/TLB modes.
+ *	  Version to 2.2.14.
+ *
+ * 2003/07/29 - Amir Noam <amir.noam at intel dot com>
+ * 	- Fixed ARP monitoring bug.
+ *	  Version to 2.2.15.
+ *
+ * 2003/07/31 - Willy Tarreau <willy at ods dot org>
+ * 	- Fixed kernel panic when using ARP monitoring without
+ *	  setting bond's IP address.
+ *	  Version to 2.2.16.
+ *
+ * 2003/08/06 - Amir Noam <amir.noam at intel dot com>
+ * 	- Back port from 2.6: use alloc_netdev(); fix /proc handling;
+ *	  made stats a part of bond struct so no need to allocate
+ *	  and free it separately; use standard list operations instead
+ *	  of pre-allocated array of bonds.
+ *	  Version to 2.3.0.
+ *
+ * 2003/08/07 - Jay Vosburgh <fubar at us dot ibm dot com>,
+ *	       Amir Noam <amir.noam at intel dot com> and
+ *	       Shmulik Hen <shmulik.hen at intel dot com>
+ *	- Propagating master's settings: Distinguish between modes that
+ *	  use a primary slave from those that don't, and propagate settings
+ *	  accordingly; Consolidate change_active opeartions and add
+ *	  reselect_active and find_best opeartions; Decouple promiscuous
+ *	  handling from the multicast mode setting; Add support for changing
+ *	  HW address and MTU with proper unwind; Consolidate procfs code,
+ *	  add CHANGENAME handler; Enhance netdev notification handling.
+ *	  Version to 2.4.0.
  */
 
 #include <linux/config.h>
@@ -432,10 +464,10 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION		"2.2.14"
-#define DRV_RELDATE		"June 30, 2003"
-#define DRV_NAME		"bonding"
-#define DRV_DESCRIPTION		"Ethernet Channel Bonding Driver"
+#define DRV_VERSION	"2.4.0"
+#define DRV_RELDATE	"August 7, 2003"
+#define DRV_NAME	"bonding"
+#define DRV_DESCRIPTION	"Ethernet Channel Bonding Driver"
 
 static const char *version =
 DRV_NAME ".c:v" DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -453,6 +485,11 @@
 #define MAX_ARP_IP_TARGETS 16
 #endif
 
+#define USES_PRIMARY(mode) \
+		(((mode) == BOND_MODE_ACTIVEBACKUP) || \
+		 ((mode) == BOND_MODE_TLB) || \
+		 ((mode) == BOND_MODE_ALB))
+
 struct bond_parm_tbl {
 	char *modename;
 	int mode;
@@ -515,9 +552,7 @@
 {	NULL,		-1},
 };
 
-static int first_pass	= 1;
-static struct bonding *these_bonds =  NULL;
-static struct net_device *dev_bonds = NULL;
+static LIST_HEAD(bond_dev_list);
 
 MODULE_PARM(max_bonds, "i");
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
@@ -549,7 +584,6 @@
 static void bond_mii_monitor(struct net_device *dev);
 static void loadbalance_arp_monitor(struct net_device *dev);
 static void activebackup_arp_monitor(struct net_device *dev);
-static int bond_event(struct notifier_block *this, unsigned long event, void *ptr);
 static void bond_mc_list_destroy(struct bonding *bond);
 static void bond_mc_add(bonding_t *bond, void *addr, int alen);
 static void bond_mc_delete(bonding_t *bond, void *addr, int alen);
@@ -563,30 +597,17 @@
 static int bond_release(struct net_device *master, struct net_device *slave);
 static int bond_release_all(struct net_device *master);
 static int bond_sethwaddr(struct net_device *master, struct net_device *slave);
+static void change_active_interface(struct bonding *bond, struct slave *new);
+static void reselect_active_interface(struct bonding *bond);
+static struct slave *find_best_interface(struct bonding *bond);
 
-/*
- * bond_get_info is the interface into the /proc filesystem.  This is
- * a different interface than the BOND_INFO_QUERY ioctl.  That is done
- * through the generic networking ioctl interface, and bond_info_query
- * is the internal function which provides that information.
- */
-static int bond_get_info(char *buf, char **start, off_t offset, int length);
-
-/* Caller must hold bond->ptrlock for write */
-static inline struct slave*
-bond_assign_current_slave(struct bonding *bond,struct slave *newslave)
-{
-	if ((bond_mode == BOND_MODE_TLB) ||
-	    (bond_mode == BOND_MODE_ALB)) {
-		bond_alb_assign_current_slave(bond, newslave);
-	} else {
-		bond->current_slave = newslave;
-	}
-
-	return bond->current_slave;
-}
 
 /* #define BONDING_DEBUG 1 */
+#ifdef BONDING_DEBUG
+#define dprintk(x...) printk(x...)
+#else /* BONDING_DEBUG */
+#define dprintk(x...) do {} while (0)
+#endif /* BONDING_DEBUG */
 
 /* several macros */
 
@@ -675,26 +696,13 @@
 		BUG();
 }
 
-/*
- * Set MAC.  Differs from eth_mac_addr in that we allow changes while
- * netif_running().
- */
-static int
-bond_set_mac_address(struct net_device *dev, void *p)
-{
-	struct sockaddr *addr = p;
-
-	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-	return 0;
-}
-
 /* 
  * This function detaches the slave <slave> from the list <bond>.
  * WARNING: no check is made to verify if the slave effectively
  * belongs to <bond>. It returns <slave> in case it's needed.
  * Nothing is freed on return, structures are just unchained.
  * If the bond->current_slave pointer was pointing to <slave>,
- * it's replaced with bond->next, or NULL if not applicable.
+ * it should be changed by the calling function.
  *
  * bond->lock held for writing by caller.
  */
@@ -728,17 +736,6 @@
 
 	update_slave_cnt(bond, -1);
 
-	/* no need to hold ptrlock since bond lock is
-	 * already held for writing
-	 */
-	if (slave == bond->current_slave) {
-		if ( bond->next != (slave_t *)bond) {  /* found one slave */
-			bond_assign_current_slave(bond, bond->next);
-		} else {
-			bond_assign_current_slave(bond, NULL);
-		}
-	}
-
 	return slave;
 }
 
@@ -1173,23 +1170,22 @@
 } 
 
 /*
- * Push the promiscuity flag down to all slaves
+ * Push the promiscuity flag down to appropriate slaves
  */
 static void bond_set_promiscuity(bonding_t *bond, int inc)
 { 
 	slave_t *slave; 
-	switch (multicast_mode) {
-	case BOND_MULTICAST_ACTIVE :
-		/* write lock already acquired */
-		if (bond->current_slave != NULL)
+
+	if (USES_PRIMARY(bond_mode)) {
+		if (bond->current_slave) {
 			dev_set_promiscuity(bond->current_slave->dev, inc);
-		break;
-	case BOND_MULTICAST_ALL :
-		for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
+		}
+
+	} else { 
+		for (slave = bond->prev; slave != (slave_t*)bond;
+		     slave = slave->prev) {
 			dev_set_promiscuity(slave->dev, inc);
-		break;
-	case BOND_MULTICAST_DISABLED :
-		break;
+		}
 	}
 } 
 
@@ -1235,20 +1231,23 @@
 	bonding_t *bond = master->priv;
 	struct dev_mc_list *dmi;
 
-	if (multicast_mode == BOND_MULTICAST_DISABLED)
-		return;
-	/*
-	 * Lock the private data for the master
-	 */
 	write_lock_bh(&bond->lock);
 
-	/* set promiscuity flag to slaves */
+	/*
+	 * Do promisc before checking multicast_mode
+	 */
 	if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) )
 		bond_set_promiscuity(bond, 1); 
 
 	if ( !(master->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC) ) 
 		bond_set_promiscuity(bond, -1); 
 
+	if (multicast_mode == BOND_MULTICAST_DISABLED) {
+		bond->flags = master->flags;
+		write_unlock_bh(&bond->lock);
+		return;
+	}
+
 	/* set allmulti flag to slaves */ 
 	if ( (master->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI) ) 
 		bond_set_allmulti(bond, 1); 
@@ -1280,32 +1279,40 @@
 
 /*
  * Update the mc list and multicast-related flags for the new and 
- * old active slaves (if any) according to the multicast mode
+ * old active slaves (if any) according to the multicast mode, and
+ * promiscuous flags unconditionally.
  */
 static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old)
 {
 	struct dev_mc_list *dmi;
 
-	switch(multicast_mode) {
-	case BOND_MULTICAST_ACTIVE :		
+	if (USES_PRIMARY(bond_mode)) {
 		if (bond->device->flags & IFF_PROMISC) {
-			if (old != NULL && new != old)
+			if (old)
 				dev_set_promiscuity(old->dev, -1);
-			dev_set_promiscuity(new->dev, 1);
+			if (new)
+				dev_set_promiscuity(new->dev, 1);
 		}
+	}
+
+	switch(multicast_mode) {
+	case BOND_MULTICAST_ACTIVE :		
 		if (bond->device->flags & IFF_ALLMULTI) {
-			if (old != NULL && new != old)
+			if (old)
 				dev_set_allmulti(old->dev, -1);
-			dev_set_allmulti(new->dev, 1);
+			if (new)
+				dev_set_allmulti(new->dev, 1);
 		}
 		/* first remove all mc addresses from old slave if any,
 		   and _then_ add them to new active slave */
-		if (old != NULL && new != old) {
+		if (old) {
 			for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next)
 				dev_mc_delete(old->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
 		}
-		for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next)
-			dev_mc_add(new->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+		if (new) {
+			for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next)
+				dev_mc_add(new->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+		}
 		break;
 	case BOND_MULTICAST_ALL :
 		/* nothing to do: mc list is already up-to-date on all slaves */
@@ -1421,7 +1428,7 @@
 			 * The application already set the master's
 			 * mac address to that of the first slave
 			 */
-			memcpy(addr.sa_data, master_dev->dev_addr, ETH_ALEN);
+			memcpy(addr.sa_data, master_dev->dev_addr, master_dev->addr_len);
 			addr.sa_family = slave_dev->type;
 			err = slave_dev->set_mac_address(slave_dev, &addr);
 			if (err) {
@@ -1467,11 +1474,19 @@
 		}
 	}
 
-	if (multicast_mode == BOND_MULTICAST_ALL) {
-		/* set promiscuity level to new slave */ 
-		if (master_dev->flags & IFF_PROMISC)
+	/* set promiscuity level to new slave */ 
+	if (master_dev->flags & IFF_PROMISC) {
+		/* If the mode USES_PRIMARY, then the new slave gets the
+		 * master's promisc (and mc) settings only if it becomes the
+		 * current_slave, and that is taken care of later when calling
+		 * bond_change_active()
+		 */
+		if (!USES_PRIMARY(bond_mode)) {
 			dev_set_promiscuity(slave_dev, 1); 
+		}
+	}
  
+	if (multicast_mode == BOND_MULTICAST_ALL) {
 		/* set allmulti level to new slave */
 		if (master_dev->flags & IFF_ALLMULTI) 
 			dev_set_allmulti(slave_dev, 1); 
@@ -1584,9 +1599,7 @@
 #endif
 			/* first slave or no active slave yet, and this link
 			   is OK, so make this interface the active one */
-			bond_assign_current_slave(bond, new_slave);
-			bond_set_slave_active_flags(new_slave);
-			bond_mc_update(bond, new_slave, NULL);
+			change_active_interface(bond, new_slave);
 		}
 		else {
 #ifdef BONDING_DEBUG
@@ -1636,7 +1649,7 @@
 			/* first slave or no active slave yet, and this link
 			 * is OK, so make this interface the active one
 			 */
-			bond_assign_current_slave(bond, new_slave);
+			change_active_interface(bond, new_slave);
 		}
 
 		/* if there is a primary slave, remember it */
@@ -1651,8 +1664,13 @@
 #endif
 		/* always active in trunk mode */
 		new_slave->state = BOND_STATE_ACTIVE;
+
+		/* In trunking mode there is little meaning to current_slave
+		 * anyway (it holds no special properties of the bond device),
+		 * so we can change it without calling change_active_interface()
+		 */
 		if (bond->current_slave == NULL) 
-			bond_assign_current_slave(bond, new_slave);
+			bond->current_slave = new_slave;
 	}
 
 	write_unlock_bh(&bond->lock);
@@ -1743,6 +1761,13 @@
 		return -ENODEV;
 	}
 
+	/* Verify that master_dev is indeed the master of slave_dev */
+	if (!(slave_dev->flags & IFF_SLAVE) ||
+	    (slave_dev->master != master_dev)) {
+
+		return -EINVAL;
+	}
+
 	bond = (struct bonding *) master_dev->priv;
 	write_lock_bh(&bond->lock);
 	slave = (slave_t *)bond;
@@ -1767,16 +1792,7 @@
 	    (oldactive != NULL)&&
 	    (newactive->link == BOND_LINK_UP)&&
 	    IS_UP(newactive->dev)) {
-		if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
-			bond_set_slave_inactive_flags(oldactive);
-			bond_set_slave_active_flags(newactive);
-		}
-
-		bond_mc_update(bond, newactive, oldactive);
-		bond_assign_current_slave(bond, newactive);
-		printk("%s : activate %s(old : %s)\n",
-			master_dev->name, newactive->dev->name, 
-			oldactive->dev->name);
+		change_active_interface(bond, newactive);
 	} else {
 		ret = -EINVAL;
 	}
@@ -1784,47 +1800,26 @@
 	return ret;
 }
 
-/* Choose a new valid interface from the pool, set it active
- * and make it the current slave. If no valid interface is
- * found, the oldest slave in BACK state is choosen and
- * activated. If none is found, it's considered as no
- * interfaces left so the current slave is set to NULL.
- * The result is a pointer to the current slave.
- *
- * Since this function sends messages tails through printk, the caller
- * must have started something like `printk(KERN_INFO "xxxx ");'.
+/**
+ * find_best_interface - select the best available slave to be the active one
+ * @bond: our bonding struct
  *
  * Warning: Caller must hold ptrlock for writing.
  */
-slave_t *change_active_interface(bonding_t *bond)
+static struct slave *find_best_interface(struct bonding *bond)
 {
-	slave_t *newslave, *oldslave;
-	slave_t *bestslave = NULL;
+	struct slave *newslave, *oldslave;
+	struct slave *bestslave = NULL;
 	int mintime;
 
 	newslave = oldslave = bond->current_slave;
 
 	if (newslave == NULL) { /* there were no active slaves left */
 		if (bond->next != (slave_t *)bond) {  /* found one slave */
-			newslave = bond_assign_current_slave(bond, bond->next);
+			newslave = bond->next;
 		} else {
-
-			printk (" but could not find any %s interface.\n",
-				(bond_mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
-			bond_assign_current_slave(bond, NULL);
 			return NULL; /* still no slave, return NULL */
 		}
-	} else if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
-		/* make sure oldslave doesn't send arps - this could
-		 * cause a ping-pong effect between interfaces since they
-		 * would be able to tx arps - in active backup only one
-		 * slave should be able to tx arps, and that should be
-		 * the current_slave; the only exception is when all
-		 * slaves have gone down, then only one non-current slave can
-		 * send arps at a time; clearing oldslaves' mc list is handled
-		 * later in this function.
-		 */
-		bond_set_slave_inactive_flags(oldslave);
 	}
 
 	mintime = updelay;
@@ -1839,22 +1834,12 @@
 			newslave = bond->primary_slave;
 	}
 
+	/* remember where to stop iterating over the slaves */
+	oldslave = newslave;
+
 	do {
 		if (IS_UP(newslave->dev)) {
 			if (newslave->link == BOND_LINK_UP) {
-				/* this one is immediately usable */
-				if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
-					bond_set_slave_active_flags(newslave);
-					bond_mc_update(bond, newslave, oldslave);
-					printk (" and making interface %s the active one.\n",
-						newslave->dev->name);
-				}
-				else {
-					printk (" and setting pointer to interface %s.\n",
-						newslave->dev->name);
-				}
-
-				bond_assign_current_slave(bond, newslave);
 				return newslave;
 			}
 			else if (newslave->link == BOND_LINK_BACK) {
@@ -1867,46 +1852,105 @@
 		}
 	} while ((newslave = newslave->next) != oldslave);
 
-	/* no usable backup found, we'll see if we at least got a link that was
-	   coming back for a long time, and could possibly already be usable.
-	*/
-
-	if (bestslave != NULL) {
-		/* early take-over. */
-		printk (" and making interface %s the active one %d ms earlier.\n",
-			bestslave->dev->name,
-			(updelay - bestslave->delay)*miimon);
-
-		bestslave->delay = 0;
-		bestslave->link = BOND_LINK_UP;
-		bestslave->jiffies = jiffies;
-		bond_set_slave_active_flags(bestslave);
-		bond_mc_update(bond, bestslave, oldslave);
-		bond_assign_current_slave(bond, bestslave);
-		return bestslave;
-	}
-
-	if ((bond_mode == BOND_MODE_ACTIVEBACKUP) &&
-	    (multicast_mode == BOND_MULTICAST_ACTIVE) &&
-	    (oldslave != NULL)) {
-		/* flush bonds (master's) mc_list from oldslave since it wasn't
-		 * updated (and deleted) above
-		 */ 
-		bond_mc_list_flush(oldslave->dev, bond->device); 
-		if (bond->device->flags & IFF_PROMISC) {
-			dev_set_promiscuity(oldslave->dev, -1);
+	return bestslave;
+}
+
+/**
+ * change_active_interface - change the active slave into the specified one
+ * @bond: our bonding struct
+ * @new: the new slave to make the active one
+ * 
+ * Set the new slave to the bond's settings and unset them on the old
+ * current_slave.
+ * Setting include flags, mc-list, promiscuity, allmulti, etc.
+ *
+ * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP,
+ * because it is apparently the best available slave we have, even though its
+ * updelay hasn't timed out yet.
+ *
+ * Warning: Caller must hold ptrlock for writing.
+ */
+static void change_active_interface(struct bonding *bond, struct slave *new)
+{
+	struct slave *old = bond->current_slave;
+
+	if (old == new) {
+		return;
+	}
+
+	if (new) {
+		if (new->link == BOND_LINK_BACK) {
+			if (USES_PRIMARY(bond_mode)) {
+				printk (KERN_INFO
+					"%s: making interface %s the new "
+					"active one %d ms earlier.\n",
+					bond->device->name, new->dev->name,
+					(updelay - new->delay) * miimon);
+			}
+
+			new->delay = 0;
+			new->link = BOND_LINK_UP;
+			new->jiffies = jiffies;
+
+			if (bond_mode == BOND_MODE_8023AD) {
+				bond_3ad_handle_link_change(new, BOND_LINK_UP);
+			}
+
+			if ((bond_mode == BOND_MODE_TLB) ||
+			    (bond_mode == BOND_MODE_ALB)) {
+				bond_alb_handle_link_change(bond, new, BOND_LINK_UP);
+			}
+		} else {
+			if (USES_PRIMARY(bond_mode)) {
+				printk (KERN_INFO
+					"%s: making interface %s the new active one.\n",
+					bond->device->name, new->dev->name);
+			}
 		}
-		if (bond->device->flags & IFF_ALLMULTI) {
-			dev_set_allmulti(oldslave->dev, -1);
+	}
+
+	if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
+		if (old) {
+			bond_set_slave_inactive_flags(old);
+		}
+
+		if (new) {
+			bond_set_slave_active_flags(new);
 		}
 	}
 
-	printk (" but could not find any %s interface.\n",
-		(bond_mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
-	
-	/* absolutely nothing found. let's return NULL */
-	bond_assign_current_slave(bond, NULL);
-	return NULL;
+	if (USES_PRIMARY(bond_mode)) {
+		bond_mc_update(bond, new, old);
+	}
+
+	if ((bond_mode == BOND_MODE_TLB) ||
+	    (bond_mode == BOND_MODE_ALB)) {
+		bond_alb_assign_current_slave(bond, new);
+	} else {
+		bond->current_slave = new;
+	}
+}
+
+/**
+ * reselect_active_interface - select a new active slave, if needed
+ * @bond: our bonding struct
+ *
+ * This functions shoud be called when one of the following occurs:
+ * - The old current_slave has been released or lost its link.
+ * - The primary_slave has got its link back.
+ * - A slave has got its link back and there's no old current_slave.
+ *
+ * Warning: Caller must hold ptrlock for writing.
+ */
+static void reselect_active_interface(struct bonding *bond)
+{
+	struct slave *best_slave;
+
+	best_slave = find_best_interface(bond);
+
+	if (best_slave != bond->current_slave) {
+		change_active_interface(bond, best_slave);
+	}
 }
 
 /*
@@ -1955,12 +1999,12 @@
 				"of %s to a different address "
 				"to avoid conflicts.\n",
 				       slave->name,
-				       slave->dev_addr[0],
-				       slave->dev_addr[1],
-				       slave->dev_addr[2],
-				       slave->dev_addr[3],
-				       slave->dev_addr[4],
-				       slave->dev_addr[5],
+				       our_slave->perm_hwaddr[0],
+				       our_slave->perm_hwaddr[1],
+				       our_slave->perm_hwaddr[2],
+				       our_slave->perm_hwaddr[3],
+				       our_slave->perm_hwaddr[4],
+				       our_slave->perm_hwaddr[5],
 				       bond->device->name,
 				       slave->name);
 			}
@@ -1973,6 +2017,11 @@
 				bond_3ad_unbind_slave(our_slave);
 			}
 
+			printk (KERN_INFO "%s: releasing %s interface %s\n",
+				master->name,
+				(our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup",
+				slave->name);
+
 			/* release the slave from its bond */
 			bond_detach_slave(bond, our_slave);
 
@@ -1980,18 +2029,11 @@
 				bond->primary_slave = NULL;
 			}
 
-			printk (KERN_INFO "%s: releasing %s interface %s",
-				master->name,
-				(our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup",
-				slave->name);
-
-			if (our_slave == old_current) {
-				/* find a new interface and be verbose */
-				change_active_interface(bond); 
-			} else {
-				printk(".\n");
+			if (bond->current_slave == our_slave) {
+				change_active_interface(bond, NULL);
+				reselect_active_interface(bond);
 			}
-			
+
 			if (bond->current_slave == NULL) {
 				printk(KERN_INFO
 					"%s: now running without any active interface !\n",
@@ -2019,16 +2061,22 @@
 		return -EINVAL;
 	}
 
+	/* unset promiscuity level from slave */
+	if (master->flags & IFF_PROMISC) {
+		/* If the mode USES_PRIMARY, then we should only remove its
+		 * promisc settings if it was the current_slave, but that was
+		 * already taken care of above when we detached the slave
+		 */
+		if (!USES_PRIMARY(bond_mode)) {
+			dev_set_promiscuity(slave, -1); 
+		}
+	}
+
 	/* undo settings and restore original values */
-	
 	if (multicast_mode == BOND_MULTICAST_ALL) {
 		/* flush master's mc_list from slave */ 
 		bond_mc_list_flush (slave, master); 
 
-		/* unset promiscuity level from slave */
-		if (master->flags & IFF_PROMISC) 
-			dev_set_promiscuity(slave, -1); 
-
 		/* unset allmulti level from slave */ 
 		if (master->flags & IFF_ALLMULTI)
 			dev_set_allmulti(slave, -1); 
@@ -2095,7 +2143,7 @@
 	}
 
 	old_current = bond->current_slave;
-	bond_assign_current_slave(bond, NULL);
+	change_active_interface(bond, NULL);
 	bond->current_arp_slave = NULL;
 	bond->primary_slave = NULL;
 
@@ -2124,17 +2172,17 @@
 		 */
 		write_unlock_bh(&bond->lock);
 
-		if (multicast_mode == BOND_MULTICAST_ALL 
-		    || (multicast_mode == BOND_MULTICAST_ACTIVE 
-			&& old_current == our_slave)) {
+		/* unset promiscuity level from slave */
+		if (master->flags & IFF_PROMISC) {
+			if (!USES_PRIMARY(bond_mode)) {
+				dev_set_promiscuity(slave_dev, -1); 
+			}
+		}
 
+		if (multicast_mode == BOND_MULTICAST_ALL) {
 			/* flush master's mc_list from slave */ 
 			bond_mc_list_flush (slave_dev, master); 
 
-			/* unset promiscuity level from slave */
-			if (master->flags & IFF_PROMISC) 
-				dev_set_promiscuity(slave_dev, -1); 
-
 			/* unset allmulti level from slave */ 
 			if (master->flags & IFF_ALLMULTI)
 				dev_set_allmulti(slave_dev, -1); 
@@ -2183,8 +2231,9 @@
 static void bond_mii_monitor(struct net_device *master)
 {
 	bonding_t *bond = (struct bonding *) master->priv;
-	slave_t *slave, *bestslave, *oldcurrent;
+	slave_t *slave, *oldcurrent;
 	int slave_died = 0;
+	int do_failover = 0;
 
 	read_lock(&bond->lock);
 
@@ -2194,7 +2243,6 @@
 	 * program could monitor the link itself if needed.
 	 */
 
-	bestslave = NULL;
 	slave = (slave_t *)bond;
 
 	read_lock(&bond->ptrlock);
@@ -2202,8 +2250,6 @@
 	read_unlock(&bond->ptrlock);
 
 	while ((slave = slave->prev) != (slave_t *)bond) {
-		/* use updelay+1 to match an UP slave even when updelay is 0 */
-		int mindelay = updelay + 1;
 		struct net_device *dev = slave->dev;
 		int link_state;
 		u16 old_speed = slave->speed;
@@ -2214,14 +2260,7 @@
 		switch (slave->link) {
 		case BOND_LINK_UP:	/* the link was up */
 			if (link_state == BMSR_LSTATUS) {
-				/* link stays up, tell that this one
-				   is immediately available */
-				if (IS_UP(dev) && (mindelay > -2)) {
-					/* -2 is the best case :
-					   this slave was already up */
-					mindelay = -2;
-					bestslave = slave;
-				}
+				/* link stays up, nothing more to do */
 				break;
 			}
 			else { /* link going down */
@@ -2261,6 +2300,7 @@
 					    (bond_mode == BOND_MODE_8023AD)) {
 						bond_set_slave_inactive_flags(slave);
 					}
+
 					printk(KERN_INFO
 						"%s: link status definitely down "
 						"for interface %s, disabling it",
@@ -2277,14 +2317,10 @@
 						bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN);
 					}
 
-					write_lock(&bond->ptrlock);
-					if (slave == bond->current_slave) {
-						/* find a new interface and be verbose */
-						change_active_interface(bond);
-					} else {
-						printk(".\n");
+					if (slave == oldcurrent) {
+						do_failover = 1;
 					}
-					write_unlock(&bond->ptrlock);
+
 					slave_died = 1;
 				} else {
 					slave->delay--;
@@ -2299,13 +2335,6 @@
 					master->name,
 					(downdelay - slave->delay) * miimon,
 					dev->name);
-
-				if (IS_UP(dev) && (mindelay > -1)) {
-					/* -1 is a good case : this slave went
-					   down only for a short time */
-					mindelay = -1;
-					bestslave = slave;
-				}
 			}
 			break;
 		case BOND_LINK_DOWN:	/* the link was down */
@@ -2375,26 +2404,12 @@
 						bond_alb_handle_link_change(bond, slave, BOND_LINK_UP);
 					}
 
-					write_lock(&bond->ptrlock);
-					if ( (bond->primary_slave != NULL)
-					  && (slave == bond->primary_slave) )
-						change_active_interface(bond); 
-					write_unlock(&bond->ptrlock);
-				}
-				else
+					if ((oldcurrent == NULL) ||
+					    (slave == bond->primary_slave)) {
+						do_failover = 1;
+					}
+				} else {
 					slave->delay--;
-
-				/* we'll also look for the mostly eligible slave */
-				if (bond->primary_slave == NULL)  {
-				    if (IS_UP(dev) && (slave->delay < mindelay)) {
-					mindelay = slave->delay;
-					bestslave = slave;
-				    } 
-				} else if ( (IS_UP(bond->primary_slave->dev))  || 
-				          ( (!IS_UP(bond->primary_slave->dev))  && 
-				          (IS_UP(dev) && (slave->delay < mindelay)) ) ) {
-					mindelay = slave->delay;
-					bestslave = slave;
 				}
 			}
 			break;
@@ -2413,58 +2428,17 @@
 
 	} /* end of while */
 
-	/* 
-	 * if there's no active interface and we discovered that one
-	 * of the slaves could be activated earlier, so we do it.
-	 */
-	read_lock(&bond->ptrlock);
-	oldcurrent = bond->current_slave;
-	read_unlock(&bond->ptrlock);
-
-	/* no active interface at the moment or need to bring up the primary */
-	if (oldcurrent == NULL)  { /* no active interface at the moment */
-		if (bestslave != NULL) { /* last chance to find one ? */
-			if (bestslave->link == BOND_LINK_UP) {
-				printk (KERN_INFO
-					"%s: making interface %s the new active one.\n",
-					master->name, bestslave->dev->name);
-			} else {
-				printk (KERN_INFO
-					"%s: making interface %s the new "
-					"active one %d ms earlier.\n",
-					master->name, bestslave->dev->name,
-					(updelay - bestslave->delay) * miimon);
-
-				bestslave->delay = 0;
-				bestslave->link  = BOND_LINK_UP;
-				bestslave->jiffies = jiffies;
-
-				/* notify ad that the link status has changed */
-				if (bond_mode == BOND_MODE_8023AD) {
-					bond_3ad_handle_link_change(bestslave, BOND_LINK_UP);
-				}
-
-				if ((bond_mode == BOND_MODE_TLB) ||
-				    (bond_mode == BOND_MODE_ALB)) {
-					bond_alb_handle_link_change(bond, bestslave, BOND_LINK_UP);
-				}
-			}
+	if (do_failover) {
+		write_lock(&bond->ptrlock);
 
-			if (bond_mode == BOND_MODE_ACTIVEBACKUP) {
-				bond_set_slave_active_flags(bestslave);
-				bond_mc_update(bond, bestslave, NULL);
-			} else if (bond_mode != BOND_MODE_8023AD) {
-				bestslave->state = BOND_STATE_ACTIVE;
-			}
-			write_lock(&bond->ptrlock);
-			bond_assign_current_slave(bond, bestslave);
-			write_unlock(&bond->ptrlock);
-		} else if (slave_died) {
-			/* print this message only once a slave has just died */
+		reselect_active_interface(bond);
+		if (oldcurrent && !bond->current_slave) {
 			printk(KERN_INFO
 				"%s: now running without any active interface !\n",
 				master->name);
 		}
+
+		write_unlock(&bond->ptrlock);
 	}
 
 	read_unlock(&bond->lock);
@@ -2482,9 +2456,10 @@
 static void loadbalance_arp_monitor(struct net_device *master)
 {
 	bonding_t *bond;
-	slave_t *slave;
+	slave_t *slave, *oldcurrent;
 	int the_delta_in_ticks =  arp_interval * HZ / 1000;
 	int next_timer = jiffies + (arp_interval * HZ / 1000);
+	int do_failover = 0;
 
 	bond = (struct bonding *) master->priv; 
 	if (master->priv == NULL) {
@@ -2508,6 +2483,10 @@
 
 	read_lock(&bond->lock);
 
+	read_lock(&bond->ptrlock);
+	oldcurrent = bond->current_slave;
+	read_unlock(&bond->ptrlock);
+
 	/* see if any of the previous devices are up now (i.e. they have
 	 * xmt and rcv traffic). the current_slave does not come into
 	 * the picture unless it is null. also, slave->jiffies is not needed
@@ -2534,21 +2513,19 @@
 				 * current_slave being null after enslaving
 				 * is closed.
 				 */
-				write_lock(&bond->ptrlock);
-				if (bond->current_slave == NULL) {
+				if (oldcurrent == NULL) {
 					printk(KERN_INFO
 						"%s: link status definitely up "
 						"for interface %s, ",
 						master->name,
 						slave->dev->name);
-					change_active_interface(bond); 
+					do_failover = 1;
 				} else {
 					printk(KERN_INFO
 						"%s: interface %s is now up\n",
 						master->name,
 						slave->dev->name);
 				}
-				write_unlock(&bond->ptrlock);
 			} 
 		} else {
 			/* slave->link == BOND_LINK_UP */
@@ -2571,11 +2548,9 @@
 				       master->name,
 				       slave->dev->name);
 
-				write_lock(&bond->ptrlock);
-				if (slave == bond->current_slave) {
-					change_active_interface(bond);
+				if (slave == oldcurrent) {
+					do_failover = 1;
 				}
-				write_unlock(&bond->ptrlock);
 			}
 		} 
 
@@ -2591,6 +2566,19 @@
 		}
 	}
 
+	if (do_failover) {
+		write_lock(&bond->ptrlock);
+
+		reselect_active_interface(bond);
+		if (oldcurrent && !bond->current_slave) {
+			printk(KERN_INFO
+				"%s: now running without any active interface !\n",
+				master->name);
+		}
+
+		write_unlock(&bond->ptrlock);
+	}
+
 	read_unlock(&bond->lock);
 	rtnl_exunlock();
 	rtnl_shunlock();
@@ -2651,9 +2639,7 @@
 				if ((bond->current_slave == NULL) &&
 				    ((jiffies - slave->dev->trans_start) <=
 				     the_delta_in_ticks)) {
-					bond_assign_current_slave(bond, slave);
-					bond_set_slave_active_flags(slave);
-			                bond_mc_update(bond, slave, NULL);
+					change_active_interface(bond, slave);
 					bond->current_arp_slave = NULL;
 				} else if (bond->current_slave != slave) {
 					/* this slave has just come up but we 
@@ -2743,7 +2729,8 @@
 			       master->name,
 			       slave->dev->name);
 			write_lock(&bond->ptrlock);
-			slave = change_active_interface(bond);
+			reselect_active_interface(bond);
+			slave = bond->current_slave;
 			write_unlock(&bond->ptrlock);
 			bond->current_arp_slave = slave;
 			if (slave != NULL) {
@@ -2762,13 +2749,10 @@
 			       bond->primary_slave->dev->name);
 			       
 			/* primary is up so switch to it */
-			bond_set_slave_inactive_flags(slave);
-			bond_mc_update(bond, bond->primary_slave, slave);
 			write_lock(&bond->ptrlock);
-			bond_assign_current_slave(bond, bond->primary_slave);
+			change_active_interface(bond, bond->primary_slave);
 			write_unlock(&bond->ptrlock);
 			slave = bond->primary_slave;
-			bond_set_slave_active_flags(slave);
 			slave->jiffies = jiffies;
 		} else {
 			bond->current_arp_slave = NULL;
@@ -2811,7 +2795,7 @@
 				/* if the link state is up at this point, we 
 				 * mark it down - this can happen if we have 
 				 * simultaneous link failures and 
-				 * change_active_interface doesn't make this 
+				 * reselect_active_interface doesn't make this 
 				 * one the current slave so it is still marked 
 				 * up when it is actually down
 				 */
@@ -3056,15 +3040,9 @@
 		case SIOCBONDRELEASE:	
 			ret = bond_release(master_dev, slave_dev); 
 			break;
-		case BOND_SETHWADDR_OLD:
-		case SIOCBONDSETHWADDR:	
-			ret = bond_sethwaddr(master_dev, slave_dev);
-			break;
 		case BOND_CHANGE_ACTIVE_OLD:
 		case SIOCBONDCHANGEACTIVE:
-			if ((bond_mode == BOND_MODE_ACTIVEBACKUP) ||
-			    (bond_mode == BOND_MODE_TLB) ||
-			    (bond_mode == BOND_MODE_ALB)) {
+			if (USES_PRIMARY(bond_mode)) {
 				ret = bond_change_active(master_dev, slave_dev);
 			}
 			else {
@@ -3186,7 +3164,7 @@
 			dev_queue_xmit(skb);
 
 			write_lock(&bond->ptrlock);
-			bond_assign_current_slave(bond, slave->next);
+			bond->current_slave = slave->next;
 			write_unlock(&bond->ptrlock);
 
 			read_unlock(&bond->lock);
@@ -3330,10 +3308,10 @@
 static struct net_device_stats *bond_get_stats(struct net_device *dev)
 {
 	bonding_t *bond = dev->priv;
-	struct net_device_stats *stats = bond->stats, *sstats;
+	struct net_device_stats *stats = &(bond->stats), *sstats;
 	slave_t *slave;
 
-	memset(bond->stats, 0, sizeof(struct net_device_stats));
+	memset(stats, 0, sizeof(struct net_device_stats));
 
 	read_lock_bh(&bond->lock);
 
@@ -3372,215 +3350,479 @@
 	return stats;
 }
 
-static int bond_get_info(char *buf, char **start, off_t offset, int length)
+#ifdef CONFIG_PROC_FS
+static int bond_read_proc(char *buf, char **start, off_t off, int count, int *eof, void *data)
 {
-	bonding_t *bond = these_bonds;
+	struct bonding *bond = (struct bonding *) data;
 	int len = 0;
-	off_t begin = 0;
 	u16 link;
 	slave_t *slave = NULL;
 
+	/* make sure the bond won't be taken away */
+	read_lock(&dev_base_lock);
+
 	len += sprintf(buf + len, "%s\n", version);
 
-	while (bond != NULL) {
-		/*
-		 * This function locks the mutex, so we can't lock it until 
-		 * afterwards
-		 */
-		link = bond_check_mii_link(bond);
+	/*
+	 * This function locks the mutex, so we can't lock it until
+	 * afterwards
+	 */
+	link = bond_check_mii_link(bond);
 
-		len += sprintf(buf + len, "Bonding Mode: %s\n",
-			       bond_mode_name());
+	len += sprintf(buf + len, "Bonding Mode: %s\n",
+		       bond_mode_name());
 
-		if ((bond_mode == BOND_MODE_ACTIVEBACKUP) ||
-		    (bond_mode == BOND_MODE_TLB) ||
-		    (bond_mode == BOND_MODE_ALB)) {
-			read_lock_bh(&bond->lock);
-			read_lock(&bond->ptrlock);
-			if (bond->current_slave != NULL) {
-				len += sprintf(buf + len, 
-					"Currently Active Slave: %s\n", 
-					bond->current_slave->dev->name);
-			}
-			read_unlock(&bond->ptrlock);
-			read_unlock_bh(&bond->lock);
+	if (USES_PRIMARY(bond_mode)) {
+		read_lock_bh(&bond->lock);
+		read_lock(&bond->ptrlock);
+		if (bond->current_slave != NULL) {
+			len += sprintf(buf + len,
+				"Currently Active Slave: %s\n",
+				bond->current_slave->dev->name);
 		}
+		read_unlock(&bond->ptrlock);
+		read_unlock_bh(&bond->lock);
+	}
+
+	len += sprintf(buf + len, "MII Status: ");
+	len += sprintf(buf + len,
+			link == BMSR_LSTATUS ? "up\n" : "down\n");
+	len += sprintf(buf + len, "MII Polling Interval (ms): %d\n",
+			miimon);
+	len += sprintf(buf + len, "Up Delay (ms): %d\n",
+			updelay * miimon);
+	len += sprintf(buf + len, "Down Delay (ms): %d\n",
+			downdelay * miimon);
+	len += sprintf(buf + len, "Multicast Mode: %s\n",
+		       multicast_mode_name());
+
+	read_lock_bh(&bond->lock);
+
+	if (bond_mode == BOND_MODE_8023AD) {
+		struct ad_info ad_info;
+
+		len += sprintf(buf + len, "\n802.3ad info\n");
+
+		if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
+			len += sprintf(buf + len, "bond %s has no active aggregator\n", bond->device->name);
+		} else {
+			len += sprintf(buf + len, "Active Aggregator Info:\n");
+
+			len += sprintf(buf + len, "\tAggregator ID: %d\n", ad_info.aggregator_id);
+			len += sprintf(buf + len, "\tNumber of ports: %d\n", ad_info.ports);
+			len += sprintf(buf + len, "\tActor Key: %d\n", ad_info.actor_key);
+			len += sprintf(buf + len, "\tPartner Key: %d\n", ad_info.partner_key);
+			len += sprintf(buf + len, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+				       ad_info.partner_system[0],
+				       ad_info.partner_system[1],
+				       ad_info.partner_system[2],
+				       ad_info.partner_system[3],
+				       ad_info.partner_system[4],
+				       ad_info.partner_system[5]);
+		}
+	}
+
+	for (slave = bond->prev; slave != (slave_t *)bond;
+	     slave = slave->prev) {
+		len += sprintf(buf + len, "\nSlave Interface: %s\n", slave->dev->name);
 
 		len += sprintf(buf + len, "MII Status: ");
-		len += sprintf(buf + len, 
-				link == BMSR_LSTATUS ? "up\n" : "down\n");
-		len += sprintf(buf + len, "MII Polling Interval (ms): %d\n", 
-				miimon);
-		len += sprintf(buf + len, "Up Delay (ms): %d\n", 
-				updelay * miimon);
-		len += sprintf(buf + len, "Down Delay (ms): %d\n", 
-				downdelay * miimon);
-		len += sprintf(buf + len, "Multicast Mode: %s\n",
-			       multicast_mode_name());
 
-		read_lock_bh(&bond->lock);
+		len += sprintf(buf + len,
+			slave->link == BOND_LINK_UP ?
+			"up\n" : "down\n");
+		len += sprintf(buf + len, "Link Failure Count: %d\n",
+			slave->link_failure_count);
 
-		if (bond_mode == BOND_MODE_8023AD) {
-			struct ad_info ad_info;
+		if (app_abi_ver >= 1) {
+			len += sprintf(buf + len,
+				       "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+				       slave->perm_hwaddr[0],
+				       slave->perm_hwaddr[1],
+				       slave->perm_hwaddr[2],
+				       slave->perm_hwaddr[3],
+				       slave->perm_hwaddr[4],
+				       slave->perm_hwaddr[5]);
+		}
 
-			len += sprintf(buf + len, "\n802.3ad info\n");
+		if (bond_mode == BOND_MODE_8023AD) {
+			struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
 
-			if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
-				len += sprintf(buf + len, "bond %s has no active aggregator\n", bond->device->name);
+			if (agg) {
+				len += sprintf(buf + len, "Aggregator ID: %d\n",
+					       agg->aggregator_identifier);
 			} else {
-				len += sprintf(buf + len, "Active Aggregator Info:\n");
-
-				len += sprintf(buf + len, "\tAggregator ID: %d\n", ad_info.aggregator_id);
-				len += sprintf(buf + len, "\tNumber of ports: %d\n", ad_info.ports);
-				len += sprintf(buf + len, "\tActor Key: %d\n", ad_info.actor_key);
-				len += sprintf(buf + len, "\tPartner Key: %d\n", ad_info.partner_key);
-				len += sprintf(buf + len, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-					       ad_info.partner_system[0],
-					       ad_info.partner_system[1],
-					       ad_info.partner_system[2],
-					       ad_info.partner_system[3],
-					       ad_info.partner_system[4],
-					       ad_info.partner_system[5]);
+				len += sprintf(buf + len, "Aggregator ID: N/A\n");
 			}
 		}
+	}
+	read_unlock_bh(&bond->lock);
 
-		for (slave = bond->prev; slave != (slave_t *)bond; 
-		     slave = slave->prev) {
-			len += sprintf(buf + len, "\nSlave Interface: %s\n", slave->dev->name);
+	/*
+	 * Figure out the calcs for the /proc/net interface
+	 */
+	if (len <= off + count) {
+		*eof = 1;
+	}
+	*start = buf + off;
+	len -= off;
+	if (len > count) {
+		len = count;
+	}
+	if (len < 0) {
+		len = 0;
+	}
 
-			len += sprintf(buf + len, "MII Status: ");
+	read_unlock(&dev_base_lock);
 
-			len += sprintf(buf + len, 
-				slave->link == BOND_LINK_UP ? 
-				"up\n" : "down\n");
-			len += sprintf(buf + len, "Link Failure Count: %d\n", 
-				slave->link_failure_count);
-
-			if (app_abi_ver >= 1) {
-				len += sprintf(buf + len,
-					       "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
-					       slave->perm_hwaddr[0],
-					       slave->perm_hwaddr[1],
-					       slave->perm_hwaddr[2],
-					       slave->perm_hwaddr[3],
-					       slave->perm_hwaddr[4],
-					       slave->perm_hwaddr[5]);
-			}
+	return len;
+}
+#endif /* CONFIG_PROC_FS */
 
-			if (bond_mode == BOND_MODE_8023AD) {
-				struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
+static int bond_create_proc_info(struct bonding *bond)
+{
+#ifdef CONFIG_PROC_FS
+	struct net_device *dev = bond->device;
 
-				if (agg) {
-					len += sprintf(buf + len, "Aggregator ID: %d\n",
-						       agg->aggregator_identifier);
-				} else {
-					len += sprintf(buf + len, "Aggregator ID: N/A\n");
-				}
-			}
+	bond->bond_proc_dir = proc_mkdir(dev->name, proc_net);
+	if (bond->bond_proc_dir == NULL) {
+		printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n",
+			dev->name, dev->name);
+		return -ENOMEM;
+	}
+	bond->bond_proc_dir->owner = THIS_MODULE;
+
+	bond->bond_proc_info_file =
+		create_proc_read_entry("info", 0, bond->bond_proc_dir,
+					bond_read_proc, bond);
+	if (bond->bond_proc_info_file == NULL) {
+		printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n",
+			dev->name, dev->name);
+		remove_proc_entry(dev->name, proc_net);
+		return -ENOMEM;
+	}
+	bond->bond_proc_info_file->owner = THIS_MODULE;
+
+	memcpy(bond->procdir_name, dev->name, IFNAMSIZ);
+#endif /* CONFIG_PROC_FS */
+	return 0;
+}
+
+static void bond_destroy_proc_info(struct bonding *bond)
+{
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("info", bond->bond_proc_dir);
+	remove_proc_entry(bond->procdir_name, proc_net);
+	memset(bond->procdir_name, 0, IFNAMSIZ);
+	bond->bond_proc_dir = NULL;
+#endif /* CONFIG_PROC_FS */
+}
+
+/*
+ * Change HW address
+ *
+ * Note that many devices must be down to change the HW address, and
+ * downing the master releases all slaves.  We can make bonds full of
+ * bonding devices to test this, however.
+ */
+static inline int
+bond_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct bonding *bond = dev->priv;
+	struct sockaddr *sa = addr, tmp_sa;
+	struct slave *slave;
+	int error;
+
+	dprintk(KERN_INFO "bond_set_mac_address %p %s\n", dev,
+	       dev->name);
+
+	if (!is_valid_ether_addr(sa->sa_data)) {
+		return -EADDRNOTAVAIL;
+	}
+
+	for (slave = bond->prev; slave != (struct slave *)bond;
+	     slave = slave->prev) {
+		dprintk(KERN_INFO "bond_set_mac: slave %p %s\n", slave,
+			slave->dev->name);
+		if (slave->dev->set_mac_address == NULL) {
+			error = -EOPNOTSUPP;
+			dprintk(KERN_INFO "bond_set_mac EOPNOTSUPP %s\n",
+				slave->dev->name);
+			goto unwind;
+		}
+
+		error = slave->dev->set_mac_address(slave->dev, addr);
+		if (error) {
+			/* TODO: consider downing the slave 
+			 * and retry ?
+			 * User should expect communications
+			 * breakage anyway until ARP finish
+			 * updating, so...
+			 */
+			dprintk(KERN_INFO "bond_set_mac err %d %s\n",
+				error, slave->dev->name);
+			goto unwind;
 		}
-		read_unlock_bh(&bond->lock);
+	}
 
-		/*
-		 * Figure out the calcs for the /proc/net interface
-		 */
-		*start = buf + (offset - begin);
-		len -= (offset - begin);
-		if (len > length) {
-			len = length;
+	/* success */
+	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+	return 0;
+
+unwind:
+	memcpy(tmp_sa.sa_data, dev->dev_addr, dev->addr_len);
+	tmp_sa.sa_family = dev->type;
+
+	for (slave = slave->next; slave != bond->next;
+	     slave = slave->next) {
+		int tmp_error;
+
+		tmp_error = slave->dev->set_mac_address(slave->dev, &tmp_sa);
+		if (tmp_error) {
+			dprintk(KERN_INFO "bond_set_mac_address: "
+				"unwind err %d dev %s\n",
+				tmp_error, slave->dev->name);
 		}
-		if (len < 0) {
-			len = 0;
+	}
+
+	return error;
+}
+
+/*
+ * Change the MTU of all of a master's slaves to match the master
+ */
+static inline int
+bond_change_mtu(struct net_device *dev, int newmtu)
+{
+	bonding_t *bond = dev->priv;
+	slave_t *slave;
+	int error;
+
+	dprintk(KERN_INFO "CM: b %p nm %d\n", bond, newmtu);
+	for (slave = bond->prev; slave != (slave_t *)bond;
+	     slave = slave->prev) {
+		dprintk(KERN_INFO "CM: s %p s->p %p c_m %p\n", slave,
+			slave->prev, slave->dev->change_mtu);
+		if (slave->dev->change_mtu) {
+			error = slave->dev->change_mtu(slave->dev, newmtu);
+		} else {
+			slave->dev->mtu = newmtu;
+			error = 0;
+		}
+
+		if (error) {
+			/* If we failed to set the slave's mtu to the new value
+			 * we must abort the operation even in ACTIVE_BACKUP
+			 * mode, because if we allow the backup slaves to have
+			 * different mtu values than the active slave we'll
+			 * need to change their mtu when doing a failover. That
+			 * means changing their mtu from timer context, which
+			 * is probably not a good idea.
+			 */
+			dprintk(KERN_INFO "bond_change_mtu err %d %s\n",
+			       error, slave->dev->name);
+			goto unwind;
 		}
+	}
+
+	dev->mtu = newmtu;
+	return 0;
+
 
+unwind:
+	for (slave = slave->next; slave != bond->next;
+	     slave = slave->next) {
 
-		bond = bond->next_bond;
+		if (slave->dev->change_mtu) {
+			slave->dev->change_mtu(slave->dev, dev->mtu);
+		} else {
+			slave->dev->mtu = dev->mtu;
+		}
 	}
-	return len;
+
+	return error;
 }
 
-static int bond_event(struct notifier_block *this, unsigned long event, 
-			void *ptr)
+/*
+ * Change device name
+ */
+static inline int bond_event_changename(struct bonding *bond)
 {
-	struct bonding *this_bond = (struct bonding *)these_bonds;
-	struct bonding *last_bond;
-	struct net_device *event_dev = (struct net_device *)ptr;
+	int error;
 
-	/* while there are bonds configured */
-	while (this_bond != NULL) {
-		if (this_bond == event_dev->priv ) {
-			switch (event) {
-			case NETDEV_UNREGISTER:
-				/* 
-				 * remove this bond from a linked list of 
-				 * bonds 
-				 */
-				if (this_bond == these_bonds) {
-					these_bonds = this_bond->next_bond;
-				} else {
-					for (last_bond = these_bonds; 
-					     last_bond != NULL; 
-					     last_bond = last_bond->next_bond) {
-						if (last_bond->next_bond == 
-						    this_bond) {
-							last_bond->next_bond = 
-							this_bond->next_bond;
-						}
-					}
-				}
-				return NOTIFY_DONE;
+	bond_destroy_proc_info(bond);
+	error = bond_create_proc_info(bond);
+	if (error) {
+		return NOTIFY_BAD;
+	}
+	return NOTIFY_DONE;
+}
 
-			default:
-				return NOTIFY_DONE;
-			}
-		} else if (this_bond->device == event_dev->master) {
-			switch (event) {
-			case NETDEV_UNREGISTER:
-				bond_release(this_bond->device, event_dev);
-				break;
-			}
-			return NOTIFY_DONE;
+static int bond_master_netdev_event(unsigned long event, struct net_device *event_dev)
+{
+	struct bonding *bond, *event_bond = NULL;
+
+	list_for_each_entry(bond, &bond_dev_list, bond_list) {
+		if (bond == event_dev->priv) {
+			event_bond = bond;
+			break;
+		}
+	}
+
+	if (event_bond == NULL) {
+		return NOTIFY_DONE;
+	}
+
+	switch (event) {
+	case NETDEV_CHANGENAME:
+		return bond_event_changename(event_bond);
+	case NETDEV_UNREGISTER:
+		/*
+		 * TODO: remove a bond from the list?
+		 */
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int bond_slave_netdev_event(unsigned long event, struct net_device *event_dev)
+{
+	struct net_device *master = event_dev->master;
+
+	switch (event) {
+	case NETDEV_UNREGISTER:
+		if (master != NULL) {
+			bond_release(master, event_dev);
 		}
-		this_bond = this_bond->next_bond;
+		break;
+	case NETDEV_CHANGE:
+		/*
+		 * TODO: is this what we get if somebody
+		 * sets up a hierarchical bond, then rmmod's
+		 * one of the slave bonding devices?
+		 */
+		break;
+	case NETDEV_DOWN:
+		/*
+		 * ... Or is it this?
+		 */
+		break;
+	case NETDEV_CHANGEMTU:
+		/*
+		 * TODO: Should slaves be allowed to
+		 * independently alter their MTU?  For
+		 * an active-backup bond, slaves need
+		 * not be the same type of device, so
+		 * MTUs may vary.  For other modes,
+		 * slaves arguably should have the
+		 * same MTUs. To do this, we'd need to
+		 * take over the slave's change_mtu
+		 * function for the duration of their
+		 * servitude.
+		 */
+		break;
+	case NETDEV_CHANGENAME:
+		/*
+		 * TODO: handle changing the primary's name
+		 */
+		break;
+	default:
+		break;
 	}
+
 	return NOTIFY_DONE;
 }
 
+/*
+ * bond_netdev_event: handle netdev notifier chain events.
+ *
+ * This function receives events for the netdev chain.  The caller (an
+ * ioctl handler calling notifier_call_chain) holds the necessary
+ * locks for us to safely manipulate the slave devices (RTNL lock,
+ * dev_probe_lock).
+ */
+static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct net_device *event_dev = (struct net_device *)ptr;
+	unsigned short flags;
+	int res = NOTIFY_DONE;
+
+	dprintk(KERN_INFO "bond_netdev_event n_b %p ev %lx ptr %p\n",
+		this, event, ptr);
+
+	flags = event_dev->flags & (IFF_MASTER | IFF_SLAVE);
+	switch (flags) {
+	case IFF_MASTER:
+		res = bond_master_netdev_event(event, event_dev);
+		break;
+	case IFF_SLAVE:
+		res = bond_slave_netdev_event(event, event_dev);
+		break;
+	default:
+		/* A master that is also a slave ? */
+		break;
+	}
+
+	return res;
+}
+
 static struct notifier_block bond_netdev_notifier = {
-	notifier_call: bond_event,
+	notifier_call: bond_netdev_event,
 };
 
+static void bond_deinit(struct net_device *dev)
+{
+	struct bonding *bond = dev->priv;
+
+	list_del(&bond->bond_list);
+
+	bond_destroy_proc_info(bond);
+}
+
+static void bond_free_all(void)
+{
+	struct bonding *bond, *nxt;
+
+	list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
+		struct net_device *dev = bond->device;
+
+		unregister_netdev(dev);
+		bond_deinit(dev);
+		kfree(dev);
+	}
+}
+
+/*
+ * Does not allocate but creates a /proc entry.
+ * Allowed to fail.
+ */
 static int __init bond_init(struct net_device *dev)
 {
-	bonding_t *bond, *this_bond, *last_bond;
+	struct bonding *bond;
 	int count;
+	int err = 0;
 
 #ifdef BONDING_DEBUG
 	printk (KERN_INFO "Begin bond_init for %s\n", dev->name);
 #endif
-	bond = kmalloc(sizeof(struct bonding), GFP_KERNEL);
-	if (bond == NULL) {
-		return -ENOMEM;
-	}
-	memset(bond, 0, sizeof(struct bonding));
+	bond = dev->priv;
 
 	/* initialize rwlocks */
 	rwlock_init(&bond->lock);
 	rwlock_init(&bond->ptrlock);
-	
-	bond->stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
-	if (bond->stats == NULL) {
-		kfree(bond);
-		return -ENOMEM;
-	}
-	memset(bond->stats, 0, sizeof(struct net_device_stats));
 
+	/* Initialize pointers */
 	bond->next = bond->prev = (slave_t *)bond;
 	bond->current_slave = NULL;
 	bond->current_arp_slave = NULL;
 	bond->device = dev;
-	dev->priv = bond;
 
 	/* Initialize the device structure. */
+	dev->set_mac_address = bond_set_mac_address;
+
 	switch (bond_mode) {
 	case BOND_MODE_ACTIVEBACKUP:
 		dev->hard_start_xmit = bond_xmit_activebackup;
@@ -3600,11 +3842,10 @@
 	case BOND_MODE_TLB:
 	case BOND_MODE_ALB:
 		dev->hard_start_xmit = bond_alb_xmit;
+		dev->set_mac_address = bond_alb_set_mac_address;
 		break;
 	default:
 		printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode);
-		kfree(bond->stats);
-		kfree(bond);
 		return -EINVAL;
 	}
 
@@ -3613,15 +3854,7 @@
 	dev->stop = bond_close;
 	dev->set_multicast_list = set_multicast_list;
 	dev->do_ioctl = bond_ioctl;
-
-	/* 
-	 * Fill in the fields of the device structure with ethernet-generic 
-	 * values. 
-	 */
-
-	ether_setup(dev);
-
-	dev->set_mac_address = bond_set_mac_address;
+	dev->change_mtu = bond_change_mtu;
 	dev->tx_queue_len = 0;
 	dev->flags |= IFF_MASTER|IFF_MULTICAST;
 #ifdef CONFIG_NET_FASTROUTE
@@ -3649,43 +3882,26 @@
 		printk("out ARP monitoring\n");
 	}
 
-#ifdef CONFIG_PROC_FS
-	bond->bond_proc_dir = proc_mkdir(dev->name, proc_net);
-	if (bond->bond_proc_dir == NULL) {
-		printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n", 
-			dev->name, dev->name);
-		kfree(bond->stats);
-		kfree(bond);
-		return -ENOMEM;
-	}
-	bond->bond_proc_info_file = 
-		create_proc_info_entry("info", 0, bond->bond_proc_dir, 
-					bond_get_info);
-	if (bond->bond_proc_info_file == NULL) {
-		printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n", 
-			dev->name, dev->name);
-		remove_proc_entry(dev->name, proc_net);
-		kfree(bond->stats);
-		kfree(bond);
-		return -ENOMEM;
+	err = bond_create_proc_info(bond);
+	if (err) {
+		printk(KERN_ERR "%s: Failed to create proc entry\n",
+			dev->name);
+		return err;
 	}
-#endif /* CONFIG_PROC_FS */
 
-	if (first_pass == 1) {
-		these_bonds = bond;
-		register_netdevice_notifier(&bond_netdev_notifier);
-		first_pass = 0;
-	} else {
-		last_bond = these_bonds;
-		this_bond = these_bonds->next_bond;
-		while (this_bond != NULL) {
-			last_bond = this_bond;
-			this_bond = this_bond->next_bond;
-		}
-		last_bond->next_bond = bond;
-	} 
+	/* Future:
+	 * If anything fails beyond this point
+	 * make sure to destroy the proc entry
+	 */
+
+	list_add_tail(&bond->bond_list, &bond_dev_list);
 
 	return 0;
+/*
+err_out:
+	bond_destroy_proc_info(bond);
+	return err;
+*/
 }
 
 /*
@@ -3723,9 +3939,6 @@
 	int no;
 	int err;
 
-	/* Find a name for this unit */
-	static struct net_device *dev_bond = NULL;
-
 	printk(KERN_INFO "%s", version);
 
 	/*
@@ -3741,6 +3954,12 @@
 		}
 	}
 
+	if (USES_PRIMARY(bond_mode)) {
+		multicast_mode = BOND_MULTICAST_ACTIVE;
+	} else {
+		multicast_mode = BOND_MULTICAST_ALL;
+	}
+
 	if (multicast) {
 		multicast_mode = bond_parse_parm(multicast, bond_mc_tbl);
 		if (multicast_mode == -1) {
@@ -3776,12 +3995,6 @@
 		       max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS);
 		max_bonds = BOND_DEFAULT_MAX_BONDS;
 	}
-	dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), 
-					GFP_KERNEL);
-	if (dev_bond == NULL) {
-		return -ENOMEM;
-	}
-	memset(dev_bonds, 0, max_bonds*sizeof(struct net_device));
 
 	if (miimon < 0) {
 		printk(KERN_WARNING 
@@ -3959,9 +4172,7 @@
 		       "link failures! see bonding.txt for details.\n");
 	}
 
-	if ((primary != NULL) && (bond_mode != BOND_MODE_ACTIVEBACKUP) &&
-	    (bond_mode != BOND_MODE_TLB) &&
-	    (bond_mode != BOND_MODE_ALB)){
+	if ((primary != NULL) && !USES_PRIMARY(bond_mode)) {
 		/* currently, using a primary only makes sense
 		 * in active backup, TLB or ALB modes
 		 */
@@ -3972,48 +4183,62 @@
 		primary = NULL;
 	}
 
+	rtnl_lock();
 
+	err = 0;
 	for (no = 0; no < max_bonds; no++) {
-		dev_bond->init = bond_init;
-	
-		err = dev_alloc_name(dev_bond,"bond%d");
+		struct net_device *dev;
+
+		dev = alloc_netdev(sizeof(struct bonding), "", ether_setup);
+		if (!dev) {
+			err = -ENOMEM;
+			goto out_err;
+		}
+
+		err = dev_alloc_name(dev, "bond%d");
+		if (err < 0) {
+			kfree(dev);
+			goto out_err;
+		}
+
+		/* bond_init() must be called after dev_alloc_name() (for the
+		 * /proc files), but before register_netdevice(), because we
+		 * need to set function pointers.
+		 */
+		err = bond_init(dev);
+		if (err < 0) {
+			kfree(dev);
+			goto out_err;
+		}
+
+		SET_MODULE_OWNER(dev);
+
+		err = register_netdevice(dev);
 		if (err < 0) {
-			kfree(dev_bonds);
-			return err;
+			bond_deinit(dev);
+			kfree(dev);
+			goto out_err;
 		}
-		SET_MODULE_OWNER(dev_bond);
-		if (register_netdev(dev_bond) != 0) {
-			kfree(dev_bonds);
-			return -EIO;
-		}	
-		dev_bond++;
 	}
+
+	rtnl_unlock();
+	register_netdevice_notifier(&bond_netdev_notifier);
+
 	return 0;
+
+out_err:
+	rtnl_unlock();
+
+	/* free and unregister all bonds that were successfully added */
+	bond_free_all();
+
+	return err;
 }
 
 static void __exit bonding_exit(void)
 {
-	struct net_device *dev_bond = dev_bonds;
-	struct bonding *bond;
-	int no;
-
 	unregister_netdevice_notifier(&bond_netdev_notifier);
-		 
-	for (no = 0; no < max_bonds; no++) {
-
-#ifdef CONFIG_PROC_FS
-		bond = (struct bonding *) dev_bond->priv;
-		remove_proc_entry("info", bond->bond_proc_dir);
-		remove_proc_entry(dev_bond->name, proc_net);
-#endif
-		unregister_netdev(dev_bond);
-		kfree(bond->stats);
-		kfree(dev_bond->priv);
-		
-		dev_bond->priv = NULL;
-		dev_bond++;
-	}
-	kfree(dev_bonds);
+	bond_free_all();
 }
 
 module_init(bonding_init);
diff -Nru a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
--- a/drivers/net/bonding/bonding.h	Fri May 23 11:19:49 2003
+++ b/drivers/net/bonding/bonding.h	Wed Aug 27 14:42:25 2003
@@ -99,12 +99,13 @@
 	rwlock_t ptrlock;
 	struct timer_list mii_timer;
 	struct timer_list arp_timer;
-	struct net_device_stats *stats;
+	struct net_device_stats stats;
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *bond_proc_dir;
 	struct proc_dir_entry *bond_proc_info_file;
+	char procdir_name[IFNAMSIZ];
 #endif /* CONFIG_PROC_FS */
-	struct bonding *next_bond;
+	struct list_head bond_list;
 	struct net_device *device;
 	struct dev_mc_list *mc_list;
 	unsigned short flags;
diff -Nru a/drivers/net/dmfe.c b/drivers/net/dmfe.c
--- a/drivers/net/dmfe.c	Thu Mar  6 07:48:18 2003
+++ b/drivers/net/dmfe.c	Tue Aug 26 13:39:47 2003
@@ -299,7 +299,7 @@
 static int dmfe_stop(struct DEVICE *);
 static struct net_device_stats * dmfe_get_stats(struct DEVICE *);
 static void dmfe_set_filter_mode(struct DEVICE *);
-static int dmfe_do_ioctl(struct DEVICE *, struct ifreq *, int);
+static struct ethtool_ops netdev_ethtool_ops;
 static u16 read_srom_word(long ,int);
 static void dmfe_interrupt(int , void *, struct pt_regs *);
 static void dmfe_descriptor_init(struct dmfe_board_info *, unsigned long);
@@ -419,7 +419,7 @@
 	dev->stop = &dmfe_stop;
 	dev->get_stats = &dmfe_get_stats;
 	dev->set_multicast_list = &dmfe_set_filter_mode;
-	dev->do_ioctl = &dmfe_do_ioctl;
+	dev->ethtool_ops = &netdev_ethtool_ops;
 	spin_lock_init(&db->lock);
 
 	pci_read_config_dword(pdev, 0x50, &pci_pmr);
@@ -1002,54 +1002,23 @@
 }
 
 
-/*
- *	Process the ethtool ioctl command
- */
-
-static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr)
-{
-	struct dmfe_board_info *db = dev->priv;
-	struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-	u32 ethcmd;
-
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-
-        switch (ethcmd) {
-        case ETHTOOL_GDRVINFO:
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		if (db->pdev)
-			strcpy(info.bus_info, db->pdev->slot_name);
-		else
-			sprintf(info.bus_info, "EISA 0x%lx %d",
-				dev->base_addr, dev->irq);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-        }
-
-	return -EOPNOTSUPP;
-}
-
-
-/*
- *	Process the upper socket ioctl command
- */
-
-static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	int retval = -EOPNOTSUPP;
-	DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
-
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return dmfe_ethtool_ioctl(dev, (void*)ifr->ifr_data);
-	}
+	struct dmfe_board_info *np = dev->priv;
 
-	return retval;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	if (np->pdev)
+		strcpy(info->bus_info, pci_name(np->pdev));
+	else
+		sprintf(info->bus_info, "EISA 0x%lx %d",
+			dev->base_addr, dev->irq);
 }
 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
 
 /*
  *	A periodic timer routine
diff -Nru a/drivers/net/dummy.c b/drivers/net/dummy.c
--- a/drivers/net/dummy.c	Mon Feb  4 23:49:26 2002
+++ b/drivers/net/dummy.c	Sun Aug 24 04:55:17 2003
@@ -28,8 +28,6 @@
 			Alan Cox, 30th May 1994
 */
 
-/* To have statistics (just packets sent) define this */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
diff -Nru a/drivers/net/eth16i.c b/drivers/net/eth16i.c
--- a/drivers/net/eth16i.c	Mon Jan  6 07:38:15 2003
+++ b/drivers/net/eth16i.c	Sun Aug 31 06:33:37 2003
@@ -1057,7 +1057,7 @@
 	int ioaddr = dev->base_addr;
 	int status = 0;
 	ushort length = skb->len;
-	unsigned char *buf = skb->data;
+	unsigned char *buf;
 	unsigned long flags;
 
 	if(length < ETH_ZLEN)
@@ -1067,6 +1067,7 @@
 			return 0;
 		length = ETH_ZLEN;
 	}
+	buf = skb->data;
 
 	netif_stop_queue(dev);
 		
diff -Nru a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c
--- a/drivers/net/fmv18x.c	Mon Jan  6 07:38:15 2003
+++ b/drivers/net/fmv18x.c	Sun Aug 31 06:33:37 2003
@@ -370,7 +370,7 @@
 	struct net_local *lp = dev->priv;
 	int ioaddr = dev->base_addr;
 	short length = skb->len;
-	unsigned char *buf = skb->data;
+	unsigned char *buf;
 	unsigned long flags;
 
 	/* Block a transmit from overlapping.  */
@@ -389,6 +389,7 @@
 			return 0;
 		length = ETH_ZLEN;
 	}
+	buf = skb->data;
 	
 	if (net_debug > 4)
 		printk("%s: Transmitting a packet of length %lu.\n", dev->name,
diff -Nru a/drivers/net/net_init.c b/drivers/net/net_init.c
--- a/drivers/net/net_init.c	Mon Feb  4 23:44:55 2002
+++ b/drivers/net/net_init.c	Thu Aug  7 17:12:46 2003
@@ -71,7 +71,7 @@
 */
 
 
-static struct net_device *alloc_netdev(int sizeof_priv, const char *mask,
+struct net_device *alloc_netdev(int sizeof_priv, const char *mask,
 				       void (*setup)(struct net_device *))
 {
 	struct net_device *dev;
@@ -97,6 +97,7 @@
 
 	return dev;
 }
+EXPORT_SYMBOL(alloc_netdev);
 
 static struct net_device *init_alloc_dev(int sizeof_priv)
 {
diff -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
--- a/drivers/net/pcmcia/3c574_cs.c	Mon Jul 14 09:46:47 2003
+++ b/drivers/net/pcmcia/3c574_cs.c	Sun Aug 31 05:17:33 2003
@@ -253,6 +253,7 @@
 static int el3_close(struct net_device *dev);
 static void el3_tx_timeout(struct net_device *dev);
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
 static void set_rx_mode(struct net_device *dev);
 
 static dev_info_t dev_info = "3c574_cs";
@@ -328,6 +329,7 @@
 	dev->hard_start_xmit = &el3_start_xmit;
 	dev->get_stats = &el3_get_stats;
 	dev->do_ioctl = &el3_ioctl;
+	SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 	dev->set_multicast_list = &set_rx_mode;
 	ether_setup(dev);
 	dev->open = &el3_open;
@@ -1191,26 +1193,16 @@
 	return worklimit;
 }
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-	
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, "3c574_cs", sizeof(info.driver)-1);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-	
-	return -EOPNOTSUPP;
+	strcpy(info->driver, "3c574_cs");
 }
 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
+
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -1224,11 +1216,11 @@
 		  data[0], data[1], data[2], data[3]);
 
     switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *)rq->ifr_data);
-	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+	case SIOCGMIIPHY:		/* Get the address of the PHY in use. */
+	case SIOCDEVPRIVATE:
 		data[0] = phy;
-	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+	case SIOCGMIIREG:		/* Read the specified MII register. */
+	case SIOCDEVPRIVATE+1:
 		{
 			int saved_window;
 			unsigned long flags;
@@ -1242,7 +1234,8 @@
 			restore_flags(flags);
 			return 0;
 		}
-	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+	case SIOCSMIIREG:		/* Write the specified MII register */
+	case SIOCDEVPRIVATE+2:
 		{
 			int saved_window;
 			unsigned long flags;
diff -Nru a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
--- a/drivers/net/pcmcia/3c589_cs.c	Tue Feb  5 06:10:16 2002
+++ b/drivers/net/pcmcia/3c589_cs.c	Tue Aug 26 14:26:12 2003
@@ -165,7 +165,7 @@
 static int el3_close(struct net_device *dev);
 static void el3_tx_timeout(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
 
 static dev_info_t dev_info = "3c589_cs";
 
@@ -256,7 +256,7 @@
     dev->tx_timeout = el3_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
-    dev->do_ioctl = netdev_ioctl;
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     /* Register with Card Services */
     link->next = dev_list;
@@ -648,70 +648,33 @@
 	 | AdapterFailure, ioaddr + EL3_CMD);
 }
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+}
 
 #ifdef PCMCIA_DEBUG
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = pc_debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		pc_debug = edata.data;
-		return 0;
-	}
-#endif
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+	return pc_debug;
 }
 
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
 {
-	int rc;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
-
-	return rc;
+	pc_debug = level;
 }
+#endif /* PCMCIA_DEBUG */
+
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+#ifdef PCMCIA_DEBUG
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+#endif /* PCMCIA_DEBUG */
+};
 
 static int el3_config(struct net_device *dev, struct ifmap *map)
 {
diff -Nru a/drivers/net/pcmcia/aironet4500_cs.c b/drivers/net/pcmcia/aironet4500_cs.c
--- a/drivers/net/pcmcia/aironet4500_cs.c	Sun Jun 29 08:09:55 2003
+++ b/drivers/net/pcmcia/aironet4500_cs.c	Tue Aug 26 14:26:12 2003
@@ -165,65 +165,33 @@
 	return ret;
 }
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+}
 
 #ifdef PCMCIA_DEBUG
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = pc_debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		pc_debug = edata.data;
-		return 0;
-	}
-#endif
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+	return pc_debug;
 }
 
-static int awc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
 {
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	default:
-		return -EOPNOTSUPP;
-	}
-	return 0;
+	pc_debug = level;
 }
+#endif /* PCMCIA_DEBUG */
+
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+#ifdef PCMCIA_DEBUG
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+#endif /* PCMCIA_DEBUG */
+};
 
 /*
 	awc_attach() creates an "instance" of the driver, allocating
@@ -296,7 +264,7 @@
 //	dev->set_config = 		&awc_config_misiganes,aga mitte awc_config;
 	dev->get_stats = 		&awc_get_stats;
 //	dev->set_multicast_list = 	&awc_set_multicast_list;
-	dev->do_ioctl =			&awc_ioctl;
+	SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 	
 	strcpy(dev->name, ((struct awc_private *)dev->priv)->node.dev_name);
 
diff -Nru a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
--- a/drivers/net/pcmcia/axnet_cs.c	Mon Jul 14 09:46:47 2003
+++ b/drivers/net/pcmcia/axnet_cs.c	Sun Aug 31 05:17:33 2003
@@ -99,6 +99,8 @@
 static int axnet_open(struct net_device *dev);
 static int axnet_close(struct net_device *dev);
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
+
 static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
 static void ei_watchdog(u_long arg);
 static void axnet_reset_8390(struct net_device *dev);
@@ -221,6 +223,7 @@
     dev->open = &axnet_open;
     dev->stop = &axnet_close;
     dev->do_ioctl = &axnet_ioctl;
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     /* Register with Card Services */
     link->next = dev_list;
@@ -822,26 +825,16 @@
     add_timer(&info->watchdog);
 }
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-	
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, "axnet_cs", sizeof(info.driver)-1);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-	
-	return -EOPNOTSUPP;
+	strcpy(info->driver, "axnet_cs");
 }
 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
+
 /*====================================================================*/
 
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -850,13 +843,14 @@
     u16 *data = (u16 *)&rq->ifr_data;
     ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
     switch (cmd) {
-    case SIOCETHTOOL:
-        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+    case SIOCGMIIPHY:
     case SIOCDEVPRIVATE:
 	data[0] = info->phy_id;
+    case SIOCGMIIREG:		/* Read MII PHY register. */
     case SIOCDEVPRIVATE+1:
 	data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f);
 	return 0;
+    case SIOCSMIIREG:		/* Write MII PHY register. */
     case SIOCDEVPRIVATE+2:
 	if (!capable(CAP_NET_ADMIN))
 	    return -EPERM;
diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
--- a/drivers/net/pcmcia/fmvj18x_cs.c	Mon Jan  6 07:38:19 2003
+++ b/drivers/net/pcmcia/fmvj18x_cs.c	Tue Aug 26 14:41:16 2003
@@ -115,7 +115,7 @@
 static struct net_device_stats *fjn_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static void fjn_tx_timeout(struct net_device *dev);
-static int fjn_ioctl(struct net_device *, struct ifreq *, int);
+static struct ethtool_ops netdev_ethtool_ops;
 
 static dev_info_t dev_info = "fmvj18x_cs";
 static dev_link_t *dev_list;
@@ -326,7 +326,7 @@
     dev->tx_timeout = fjn_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
-    dev->do_ioctl = fjn_ioctl;
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
     
     /* Register with Card Services */
     link->next = dev_list;
@@ -1205,64 +1205,33 @@
 
 /*====================================================================*/
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+}
 
 #ifdef PCMCIA_DEBUG
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = pc_debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		pc_debug = edata.data;
-		return 0;
-	}
-#endif
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+	return pc_debug;
 }
 
-static int fjn_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
 {
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	default:
-		return -EOPNOTSUPP;
-	}
+	pc_debug = level;
 }
+#endif /* PCMCIA_DEBUG */
+
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+#ifdef PCMCIA_DEBUG
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+#endif /* PCMCIA_DEBUG */
+};
 
 static int fjn_config(struct net_device *dev, struct ifmap *map){
     return 0;
diff -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
--- a/drivers/net/pcmcia/ibmtr_cs.c	Mon Jul 14 09:46:47 2003
+++ b/drivers/net/pcmcia/ibmtr_cs.c	Tue Aug 26 14:41:16 2003
@@ -166,36 +166,15 @@
     CardServices(ReportError, handle, &err);
 }
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-	
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, "ibmtr_cs", sizeof(info.driver)-1);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-	
-	return -EOPNOTSUPP;
+	strcpy(info->driver, "ibmtr_cs");
 }
 
-static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-
-       switch(cmd) {
-       case SIOCETHTOOL:
-	       return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-	default:
-	    return -EOPNOTSUPP;
-	}
-}
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
 
 /*======================================================================
 
@@ -249,7 +228,7 @@
     link->irq.Instance = info->dev = dev;
     
     dev->init = &ibmtr_probe;
-    dev->do_ioctl = &private_ioctl;
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     /* Register with Card Services */
     link->next = dev_list;
diff -Nru a/drivers/net/pcmcia/netwave_cs.c b/drivers/net/pcmcia/netwave_cs.c
--- a/drivers/net/pcmcia/netwave_cs.c	Tue Feb  5 06:10:16 2002
+++ b/drivers/net/pcmcia/netwave_cs.c	Tue Aug 26 14:41:16 2003
@@ -247,6 +247,8 @@
 #endif
 static int netwave_ioctl(struct net_device *, struct ifreq *, int);
 
+static struct ethtool_ops netdev_ethtool_ops;
+
 static void set_multicast_list(struct net_device *dev);
 
 /*
@@ -493,6 +495,7 @@
     dev->get_wireless_stats = &netwave_get_wireless_stats;
 #endif
     dev->do_ioctl = &netwave_ioctl;
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     dev->tx_timeout = &netwave_watchdog;
     dev->watchdog_timeo = TX_TIMEOUT;
@@ -603,53 +606,34 @@
     }
 } /* netwave_flush_stale_links */
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+}
 
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+#ifdef PCMCIA_DEBUG
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+	return pc_debug;
+}
 
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
+{
+	pc_debug = level;
+}
+#endif /* PCMCIA_DEBUG */
 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
 #ifdef PCMCIA_DEBUG
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = pc_debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		pc_debug = edata.data;
-		return 0;
-	}
-#endif
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+#endif /* PCMCIA_DEBUG */
+};
 
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
-}
 /*
  * Function netwave_ioctl (dev, rq, cmd)
  *
@@ -672,9 +656,6 @@
 	
     DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd);
 	
-    if (cmd == SIOCETHTOOL)
-    	return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
     /* Disable interrupts & save flags */
     save_flags(flags);
     cli();
diff -Nru a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
--- a/drivers/net/pcmcia/nmclan_cs.c	Fri Oct 18 17:38:56 2002
+++ b/drivers/net/pcmcia/nmclan_cs.c	Tue Aug 26 14:41:16 2003
@@ -438,7 +438,8 @@
 static int mace_rx(struct net_device *dev, unsigned char RxCnt);
 static void restore_multicast_list(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
-static int mace_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
+
 
 static dev_link_t *nmclan_attach(void);
 static void nmclan_detach(dev_link_t *);
@@ -520,7 +521,7 @@
     dev->set_config = &mace_config;
     dev->get_stats = &mace_get_stats;
     dev->set_multicast_list = &set_multicast_list;
-    dev->do_ioctl = &mace_ioctl;
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
     ether_setup(dev);
     dev->open = &mace_open;
     dev->stop = &mace_close;
@@ -1010,65 +1011,33 @@
   return 0;
 } /* mace_close */
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+}
 
 #ifdef PCMCIA_DEBUG
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = pc_debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		pc_debug = edata.data;
-		return 0;
-	}
-#endif
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+	return pc_debug;
 }
 
-static int mace_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static void netdev_set_msglevel(struct net_device *dev, u32 level)
 {
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	default:
-		return -EOPNOTSUPP;
-	}
-	return 0;
+	pc_debug = level;
 }
+#endif /* PCMCIA_DEBUG */
+
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+#ifdef PCMCIA_DEBUG
+	.get_msglevel		= netdev_get_msglevel,
+	.set_msglevel		= netdev_set_msglevel,
+#endif /* PCMCIA_DEBUG */
+};
 
 /* ----------------------------------------------------------------------------
 mace_start_xmit
diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
--- a/drivers/net/pcmcia/pcnet_cs.c	Mon Jul 14 09:46:47 2003
+++ b/drivers/net/pcmcia/pcnet_cs.c	Sun Aug 31 05:17:33 2003
@@ -117,7 +117,9 @@
 static int pcnet_open(struct net_device *dev);
 static int pcnet_close(struct net_device *dev);
 static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int do_ioctl_light(struct net_device *dev, struct ifreq *rq, int cmd);
+
+static struct ethtool_ops netdev_ethtool_ops;
+
 static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
 static void ei_watchdog(u_long arg);
 static void pcnet_reset_8390(struct net_device *dev);
@@ -765,6 +767,7 @@
 
     strcpy(info->node.dev_name, dev->name);
     link->dev = &info->node;
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     if (info->flags & (IS_DL10019|IS_DL10022)) {
 	u_char id = inb(dev->base_addr + 0x1a);
@@ -778,7 +781,6 @@
 	    printk("PNA, ");
     } else {
 	printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name);
- 	dev->do_ioctl = &do_ioctl_light;	
     }
     printk("io %#3lx, irq %d,", dev->base_addr, dev->irq);
     if (info->flags & USE_SHMEM)
@@ -1215,26 +1217,16 @@
 
 /*====================================================================*/
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-	
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-	
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, "pcnet_cs", sizeof(info.driver)-1);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-	
-	return -EOPNOTSUPP;
+	strcpy(info->driver, "pcnet_cs");
 }
 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
+
 /*====================================================================*/
 
 
@@ -1244,13 +1236,14 @@
     u16 *data = (u16 *)&rq->ifr_data;
     ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO;
     switch (cmd) {
-    case SIOCETHTOOL:
-        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+    case SIOCGMIIPHY:
     case SIOCDEVPRIVATE:
 	data[0] = info->phy_id;
+    case SIOCGMIIREG:		/* Read MII PHY register. */
     case SIOCDEVPRIVATE+1:
 	data[3] = mdio_read(mii_addr, data[0], data[1] & 0x1f);
 	return 0;
+    case SIOCSMIIREG:		/* Write MII PHY register. */
     case SIOCDEVPRIVATE+2:
 	if (!capable(CAP_NET_ADMIN))
 	    return -EPERM;
@@ -1258,17 +1251,6 @@
 	return 0;
     }
     return -EOPNOTSUPP;
-}
-
-/*====================================================================*/
-
-static int do_ioctl_light(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-    switch (cmd) {
-        case SIOCETHTOOL:
-            return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-    }	    
-    return -EOPNOTSUPP;    
 }
 
 /*====================================================================*/
diff -Nru a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c
--- a/drivers/net/pcmcia/ray_cs.c	Mon Jul 14 09:46:47 2003
+++ b/drivers/net/pcmcia/ray_cs.c	Tue Aug 26 14:41:16 2003
@@ -105,6 +105,9 @@
 static struct net_device_stats *ray_get_stats(struct net_device *dev);
 static int ray_dev_init(struct net_device *dev);
 static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+static struct ethtool_ops netdev_ethtool_ops;
+
 static int ray_open(struct net_device *dev);
 static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
@@ -417,6 +420,7 @@
     dev->set_config = &ray_dev_config;
     dev->get_stats  = &ray_get_stats;
     dev->do_ioctl = &ray_dev_ioctl;
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 #if WIRELESS_EXT > 7	/* If wireless extension exist in the kernel */
     dev->get_wireless_stats = ray_get_wireless_stats;
 #endif
@@ -1236,26 +1240,16 @@
 
 /*===========================================================================*/
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-	
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, "ray_cs", sizeof(info.driver)-1);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-	
-	return -EOPNOTSUPP;
+	strcpy(info->driver, "ray_cs");
 }
 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
+
 /*====================================================================*/
 
 static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -1275,10 +1269,6 @@
     /* Validate the command */
     switch (cmd)
     {
-    case SIOCETHTOOL:
-      err = netdev_ethtool_ioctl(dev, (void *) ifr->ifr_data);
-      break;
-
 #if WIRELESS_EXT > 7
       /* --------------- WIRELESS EXTENSIONS --------------- */
       /* Get name */
diff -Nru a/drivers/net/pcmcia/wavelan_cs.c b/drivers/net/pcmcia/wavelan_cs.c
--- a/drivers/net/pcmcia/wavelan_cs.c	Mon Jul 14 09:46:47 2003
+++ b/drivers/net/pcmcia/wavelan_cs.c	Tue Aug 26 14:41:16 2003
@@ -1890,27 +1890,17 @@
 }
 #endif	/* HISTOGRAM */
 
-static inline int
-wl_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-	
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, "wavelan_cs", sizeof(info.driver)-1);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-	
-	return -EOPNOTSUPP;
+	strcpy(info->driver, "wavelan_cs");
 }
 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
+
 /*------------------------------------------------------------------*/
 /*
  * Perform ioctl : config & info stuff
@@ -1933,9 +1923,6 @@
   printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
 #endif
 
-  if (cmd == SIOCETHTOOL)
-    return wl_netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
   /* Disable interrupts & save flags */
   wv_splhi(lp, &flags);
 
@@ -4568,6 +4555,7 @@
   dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
+  SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
   /* Other specific data */
   dev->mtu = WAVELAN_MTU;
diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
--- a/drivers/net/pcmcia/xirc2ps_cs.c	Mon Jul 14 09:46:47 2003
+++ b/drivers/net/pcmcia/xirc2ps_cs.c	Sun Aug 31 05:17:33 2003
@@ -386,6 +386,7 @@
 static int do_config(struct net_device *dev, struct ifmap *map);
 static int do_open(struct net_device *dev);
 static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops netdev_ethtool_ops;
 static void hardreset(struct net_device *dev);
 static void do_reset(struct net_device *dev, int full);
 static int init_mii(struct net_device *dev);
@@ -650,6 +651,7 @@
     dev->set_config = &do_config;
     dev->get_stats = &do_get_stats;
     dev->do_ioctl = &do_ioctl;
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
     dev->set_multicast_list = &set_multicast_list;
     ether_setup(dev);
     dev->open = &do_open;
@@ -1722,26 +1724,16 @@
     return 0;
 }
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-	
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, "xirc2ps_cs", sizeof(info.driver)-1);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-	
-	return -EOPNOTSUPP;
+	strcpy(info->driver, "xirc2ps_cs");
 }
 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
+
 static int
 do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -1757,15 +1749,16 @@
 	return -EOPNOTSUPP;
 
     switch(cmd) {
-      case SIOCETHTOOL:
-        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-      case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
+      case SIOCGMIIPHY:		/* Get the address of the PHY in use. */
+      case SIOCDEVPRIVATE:
 	data[0] = 0;		/* we have only this address */
 	/* fall trough */
-      case SIOCDEVPRIVATE+1:	/* Read the specified MII register. */
+      case SIOCGMIIREG:		/* Read the specified MII register. */
+      case SIOCDEVPRIVATE+1:
 	data[3] = mii_rd(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
 	break;
-      case SIOCDEVPRIVATE+2:	/* Write the specified MII register */
+      case SIOCSMIIREG:		/* Write the specified MII register */
+      case SIOCDEVPRIVATE+2:
 	if (!capable(CAP_NET_ADMIN))
 	    return -EPERM;
 	mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16);
diff -Nru a/drivers/net/pcmcia/xircom_cb.c b/drivers/net/pcmcia/xircom_cb.c
--- a/drivers/net/pcmcia/xircom_cb.c	Mon Oct 28 07:18:57 2002
+++ b/drivers/net/pcmcia/xircom_cb.c	Tue Aug 26 14:41:16 2003
@@ -176,37 +176,19 @@
 }
 #endif
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-	
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, "xircom_cb", sizeof(info.driver)-1);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-	
-	return -EOPNOTSUPP;
-}
+	struct xircom_private *private = dev->priv;
 
-static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-
-       switch(cmd) {
-       case SIOCETHTOOL:
-	       return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-	default:
-		return -EOPNOTSUPP;
-	}
+	strcpy(info->driver, "xircom_cb");
+	strcpy(info->bus_info, pci_name(private->pdev));
 }
 
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+};
+
 /* xircom_probe is the code that gets called on device insertion.
    it sets up the hardware and registers the device to the networklayer.
    
@@ -295,7 +277,7 @@
 	dev->stop = &xircom_close;
 	dev->get_stats = &xircom_get_stats;
 	dev->priv = private;
-	dev->do_ioctl = &private_ioctl;
+	SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 	pci_set_drvdata(pdev, dev);
 
 	/* start the transmitter to get a heartbeat */
diff -Nru a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
--- a/drivers/net/seeq8005.c	Mon Jan  6 07:38:15 2003
+++ b/drivers/net/seeq8005.c	Sun Aug 31 06:33:37 2003
@@ -379,7 +379,7 @@
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short length = skb->len;
-	unsigned char *buf = skb->data;
+	unsigned char *buf;
 
 	if(length < ETH_ZLEN)
 	{
@@ -388,6 +388,8 @@
 			return 0;
 		length = ETH_ZLEN;
 	}
+	buf = skb->data;
+
 	/* Block a timer-based transmit from overlapping */
 	netif_stop_queue(dev);
 	
diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c
--- a/drivers/net/sis900.c	Thu Jun 19 19:54:40 2003
+++ b/drivers/net/sis900.c	Tue Aug 26 16:37:38 2003
@@ -98,7 +98,7 @@
 	"SiS 900 PCI Fast Ethernet",
 	"SiS 7016 PCI Fast Ethernet"
 };
-static struct pci_device_id sis900_pci_tbl [] __devinitdata = {
+static struct pci_device_id sis900_pci_tbl [] = {
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900},
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
@@ -170,6 +170,7 @@
 	dma_addr_t rx_ring_dma;
 
 	unsigned int tx_full;			/* The Tx queue is full.    */
+	u8 host_bridge_rev;
 };
 
 MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>, Ollie Lho <ollie@sis.com.tw>");
@@ -197,7 +198,7 @@
 static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
 static int sis900_rx(struct net_device *net_dev);
 static void sis900_finish_xmit (struct net_device *net_dev);
-static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int sis900_close(struct net_device *net_dev);
 static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);
 static struct net_device_stats *sis900_get_stats(struct net_device *net_dev);
@@ -211,6 +212,7 @@
 static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr);
 static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr);
 static void sis900_set_mode (long ioaddr, int speed, int duplex);
+static struct ethtool_ops sis900_ethtool_ops;
 
 /**
  *	sis900_get_mac_addr - Get MAC address for stand alone SiS900 model
@@ -368,6 +370,7 @@
 {
 	struct sis900_private *sis_priv;
 	struct net_device *net_dev;
+	struct pci_dev *dev;
 	dma_addr_t ring_dma;
 	void *ring_space;
 	long ioaddr;
@@ -440,6 +443,7 @@
 	net_dev->do_ioctl = &mii_ioctl;
 	net_dev->tx_timeout = sis900_tx_timeout;
 	net_dev->watchdog_timeo = TX_TIMEOUT;
+	net_dev->ethtool_ops = &sis900_ethtool_ops;
 	
 	ret = register_netdev(net_dev);
 	if (ret)
@@ -473,6 +477,11 @@
 		goto err_out_unregister;
 	}
 
+	/* save our host bridge revision */
+	dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, NULL);
+	if (dev)
+		pci_read_config_byte(dev, PCI_CLASS_REVISION, &sis_priv->host_bridge_rev);
+
 	/* print some information about our NIC */
 	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name,
 	       card_name, ioaddr, net_dev->irq);
@@ -1108,18 +1117,12 @@
 {
 	struct sis900_private *sis_priv = net_dev->priv;
 	u16 reg14h, eq_value=0, max_value=0, min_value=0;
-	u8 host_bridge_rev;
 	int i, maxcount=10;
-	struct pci_dev *dev=NULL;
 
 	if ( !(revision == SIS630E_900_REV || revision == SIS630EA1_900_REV ||
 	       revision == SIS630A_900_REV || revision ==  SIS630ET_900_REV) )
 		return;
 
-	dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, dev);
-	if (dev)
-		pci_read_config_byte(dev, PCI_CLASS_REVISION, &host_bridge_rev);
-
 	if (netif_carrier_ok(net_dev)) {
 		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
 		mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (0x2200 | reg14h) & 0xBFFF);
@@ -1142,7 +1145,8 @@
 		}
 		/* 630B0&B1 rule to determine the equalizer value */
 		if (revision == SIS630A_900_REV && 
-		    (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) {
+		    (sis_priv->host_bridge_rev == SIS630B0 || 
+		     sis_priv->host_bridge_rev == SIS630B1)) {
 			if (max_value == 0)
 				eq_value=3;
 			else
@@ -1157,7 +1161,8 @@
 	else {
 		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
 		if (revision == SIS630A_900_REV && 
-		    (host_bridge_rev == SIS630B0 || host_bridge_rev == SIS630B1)) 
+		    (sis_priv->host_bridge_rev == SIS630B0 || 
+		     sis_priv->host_bridge_rev == SIS630B1)) 
 			mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2200) & 0xBFFF);
 		else
 			mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF);
@@ -1536,13 +1541,14 @@
  *	and cleans up after the Tx thread
  */
 
-static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	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;
+	unsigned int handled = 0;
 
 	spin_lock (&sis_priv->lock);
 
@@ -1552,6 +1558,7 @@
 		if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
 			/* nothing intresting happened */
 			break;
+		handled = 1;
 
 		/* why dow't we break after Tx/Rx case ?? keyword: full-duplex */
 		if (status & (RxORN | RxERR | RxOK))
@@ -1582,7 +1589,7 @@
 		       net_dev->name, inl(ioaddr + isr));
 	
 	spin_unlock (&sis_priv->lock);
-	return;
+	return IRQ_RETVAL(handled);
 }
 
 /**
@@ -1851,39 +1858,27 @@
 }
 
 /**
- *	netdev_ethtool_ioctl - For the basic support of ethtool
- *	@net_dev: the net device to command for
- *	@useraddr: start address of interface request
+ *	sis900_get_drvinfo - Return information about driver
+ *	@net_dev: the net device to probe
+ *	@info: container for info returned
  *
  *	Process ethtool command such as "ehtool -i" to show information
  */
-
-static int netdev_ethtool_ioctl (struct net_device *net_dev, void *useraddr)
+ 
+static void sis900_get_drvinfo(struct net_device *net_dev,
+			       struct ethtool_drvinfo *info)
 {
  	struct sis900_private *sis_priv = net_dev->priv;
- 	u32 ethcmd;
 
-	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
-		return -EFAULT;
-	
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO:
-		{
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strcpy (info.driver, SIS900_MODULE_NAME);
-			strcpy (info.version, SIS900_DRV_VERSION);
-			strcpy (info.bus_info, sis_priv->pci_dev->slot_name);
-			if (copy_to_user (useraddr, &info, sizeof (info)))
-				return -EFAULT;
-			return 0;
-		}
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+	strcpy (info->driver, SIS900_MODULE_NAME);
+	strcpy (info->version, SIS900_DRV_VERSION);
+	strcpy (info->bus_info, pci_name(sis_priv->pci_dev));
 }
 
+static struct ethtool_ops sis900_ethtool_ops = {
+	.get_drvinfo =		sis900_get_drvinfo,
+};
+
 /**
  *	mii_ioctl - process MII i/o control command 
  *	@net_dev: the net device to command for
@@ -1899,9 +1894,6 @@
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
 
 	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(net_dev, (void *) rq->ifr_data);
-
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
 	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = sis_priv->mii->phy_addr;
diff -Nru a/drivers/net/sonic.c b/drivers/net/sonic.c
--- a/drivers/net/sonic.c	Sun Jun 29 08:09:54 2003
+++ b/drivers/net/sonic.c	Mon Jun 30 09:21:50 2003
@@ -223,7 +223,7 @@
 
 			/* We must free the original skb */
 			if (lp->tx_skb[entry]) {
-				dev_kfree_skb(lp->tx_skb[entry]);
+				dev_kfree_skb_irq(lp->tx_skb[entry]);
 				lp->tx_skb[entry] = 0;
 			}
 			/* and the VDMA address */
diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c
--- a/drivers/net/sungem.c	Thu Jun 19 23:03:16 2003
+++ b/drivers/net/sungem.c	Wed Jul 30 16:48:16 2003
@@ -2330,17 +2330,14 @@
 		gp->hw_running = 1;
 	}
 
-	spin_lock_irq(&gp->lock);
-
 	/* We can now request the interrupt as we know it's masked
 	 * on the controller
 	 */
 	if (request_irq(gp->pdev->irq, gem_interrupt,
 			SA_SHIRQ, dev->name, (void *)dev)) {
-		spin_unlock_irq(&gp->lock);
-
 		printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
 
+		spin_lock_irq(&gp->lock);
 #ifdef CONFIG_ALL_PPC
 		if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
 			gem_apple_powerdown(gp);
@@ -2349,9 +2346,12 @@
 		gp->pm_timer.expires = jiffies + 10*HZ;
 		add_timer(&gp->pm_timer);
 		up(&gp->pm_sem);
+		spin_unlock_irq(&gp->lock);
 
 		return -EAGAIN;
 	}
+
+       	spin_lock_irq(&gp->lock);
 
 	/* Allocate & setup ring buffers */
 	gem_init_rings(gp);
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Mon Jun 23 16:21:28 2003
+++ b/drivers/net/tg3.c	Sun Aug 31 01:20:31 2003
@@ -1,8 +1,8 @@
 /*
  * tg3.c: Broadcom Tigon3 ethernet driver.
  *
- * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
- * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@pobox.com)
+ * Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
  */
 
 #include <linux/config.h>
@@ -23,12 +23,22 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+
+#include <net/checksum.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_SPARC64
+#include <asm/idprom.h>
+#include <asm/oplib.h>
+#include <asm/pbm.h>
+#endif
+
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define TG3_VLAN_TAG_USED 1
 #else
@@ -36,18 +46,17 @@
 #endif
 
 #ifdef NETIF_F_TSO
-/* XXX some bug in tso firmware hangs tx cpu, disabled until fixed */
-#define TG3_DO_TSO	0
+#define TG3_TSO_SUPPORT	1
 #else
-#define TG3_DO_TSO	0
+#define TG3_TSO_SUPPORT	0
 #endif
 
 #include "tg3.h"
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.6"
-#define DRV_MODULE_RELDATE	"June 11, 2003"
+#define DRV_MODULE_VERSION	"2.2"
+#define DRV_MODULE_RELDATE	"August 24, 2003"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -69,7 +78,8 @@
 
 /* hardware minimum and maximum for a single frame's data payload */
 #define TG3_MIN_MTU			60
-#define TG3_MAX_MTU			9000
+#define TG3_MAX_MTU(tp)	\
+	(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 ? 9000 : 1500)
 
 /* These numbers seem to be hard coded in the NIC firmware somehow.
  * You can't change the ring sizes, but you can change where you place
@@ -79,7 +89,17 @@
 #define TG3_DEF_RX_RING_PENDING		200
 #define TG3_RX_JUMBO_RING_SIZE		256
 #define TG3_DEF_RX_JUMBO_RING_PENDING	100
-#define TG3_RX_RCB_RING_SIZE		1024
+
+/* Do not place this n-ring entries value into the tp struct itself,
+ * we really want to expose these constants to GCC so that modulo et
+ * al.  operations are done with shifts and masks instead of with
+ * hw multiply/modulo instructions.  Another solution would be to
+ * replace things like '% foo' with '& (foo - 1)'.
+ */
+#define TG3_RX_RCB_RING_SIZE(tp)	\
+	(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ? \
+	 512 : 1024)
+
 #define TG3_TX_RING_SIZE		512
 #define TG3_DEF_TX_RING_PENDING		(TG3_TX_RING_SIZE - 1)
 
@@ -87,8 +107,8 @@
 				 TG3_RX_RING_SIZE)
 #define TG3_RX_JUMBO_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
 			         TG3_RX_JUMBO_RING_SIZE)
-#define TG3_RX_RCB_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
-			         TG3_RX_RCB_RING_SIZE)
+#define TG3_RX_RCB_RING_BYTES(tp) (sizeof(struct tg3_rx_buffer_desc) * \
+			           TG3_RX_RCB_RING_SIZE(tp))
 #define TG3_TX_RING_BYTES	(sizeof(struct tg3_tx_buffer_desc) * \
 				 TG3_TX_RING_SIZE)
 #define TX_RING_GAP(TP)	\
@@ -116,7 +136,7 @@
 
 static int tg3_debug = -1;	/* -1 == use TG3_DEF_MSG_ENABLE as value */
 
-static struct pci_device_id tg3_pci_tbl[] __devinitdata = {
+static struct pci_device_id tg3_pci_tbl[] = {
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701,
@@ -129,6 +149,14 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X,
@@ -139,10 +167,24 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
-	{ PCI_VENDOR_ID_SYSKONNECT, 0x4400,
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ 0, }
@@ -245,6 +287,7 @@
 {
 	if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) BUG();
 	list_del(&dev->poll_list);
+	smp_mb__before_clear_bit();
 	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
 }
 
@@ -274,17 +317,28 @@
 
 static void tg3_switch_clocks(struct tg3 *tp)
 {
-	if (tr32(TG3PCI_CLOCK_CTRL) & CLOCK_CTRL_44MHZ_CORE) {
+	u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
+	u32 orig_clock_ctrl;
+
+	orig_clock_ctrl = clock_ctrl;
+	clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN |
+		       CLOCK_CTRL_CLKRUN_OENABLE |
+		       0x1f);
+	tp->pci_clock_ctrl = clock_ctrl;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
+	    (orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) {
 		tw32(TG3PCI_CLOCK_CTRL,
+		     clock_ctrl |
 		     (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));
 		tr32(TG3PCI_CLOCK_CTRL);
 		udelay(40);
 		tw32(TG3PCI_CLOCK_CTRL,
-		     (CLOCK_CTRL_ALTCLK));
+		     clock_ctrl | (CLOCK_CTRL_ALTCLK));
 		tr32(TG3PCI_CLOCK_CTRL);
 		udelay(40);
 	}
-	tw32(TG3PCI_CLOCK_CTRL, 0);
+	tw32(TG3PCI_CLOCK_CTRL, clock_ctrl);
 	tr32(TG3PCI_CLOCK_CTRL);
 	udelay(40);
 }
@@ -387,24 +441,22 @@
 	return ret;
 }
 
-/* This will reset the tigon3 PHY if there is no valid
- * link unless the FORCE argument is non-zero.
- */
-static int tg3_phy_reset(struct tg3 *tp, int force)
+static void tg3_phy_set_wirespeed(struct tg3 *tp)
 {
-	u32 phy_status, phy_control;
-	int err, limit;
+	u32 val;
 
-	err  = tg3_readphy(tp, MII_BMSR, &phy_status);
-	err |= tg3_readphy(tp, MII_BMSR, &phy_status);
-	if (err != 0)
-		return -EBUSY;
+	if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
+		return;
 
-	/* If we have link, and not forcing a reset, then nothing
-	 * to do.
-	 */
-	if ((phy_status & BMSR_LSTATUS) != 0 && (force == 0))
-		return 0;
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
+	tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
+}
+
+static int tg3_bmcr_reset(struct tg3 *tp)
+{
+	u32 phy_control;
+	int limit, err;
 
 	/* OK, reset it, and poll the BMCR_RESET bit until it
 	 * clears or we time out.
@@ -422,12 +474,303 @@
 
 		if ((phy_control & BMCR_RESET) == 0) {
 			udelay(40);
-			return 0;
+			break;
 		}
 		udelay(10);
 	}
+	if (limit <= 0)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int tg3_wait_macro_done(struct tg3 *tp)
+{
+	int limit = 100;
+
+	while (limit--) {
+		u32 tmp32;
+
+		tg3_readphy(tp, 0x16, &tmp32);
+		if ((tmp32 & 0x1000) == 0)
+			break;
+	}
+	if (limit <= 0)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp)
+{
+	static const u32 test_pat[4][6] = {
+	{ 0x00005555, 0x00000005, 0x00002aaa, 0x0000000a, 0x00003456, 0x00000003 },
+	{ 0x00002aaa, 0x0000000a, 0x00003333, 0x00000003, 0x0000789a, 0x00000005 },
+	{ 0x00005a5a, 0x00000005, 0x00002a6a, 0x0000000a, 0x00001bcd, 0x00000003 },
+	{ 0x00002a5a, 0x0000000a, 0x000033c3, 0x00000003, 0x00002ef1, 0x00000005 }
+	};
+	int chan;
+
+	for (chan = 0; chan < 4; chan++) {
+		int i;
+
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+			     (chan * 0x2000) | 0x0200);
+		tg3_writephy(tp, 0x16, 0x0002);
+
+		for (i = 0; i < 6; i++)
+			tg3_writephy(tp, MII_TG3_DSP_RW_PORT,
+				     test_pat[chan][i]);
+
+		tg3_writephy(tp, 0x16, 0x0202);
+		if (tg3_wait_macro_done(tp)) {
+			*resetp = 1;
+			return -EBUSY;
+		}
+
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+			     (chan * 0x2000) | 0x0200);
+		tg3_writephy(tp, 0x16, 0x0082);
+		if (tg3_wait_macro_done(tp)) {
+			*resetp = 1;
+			return -EBUSY;
+		}
+
+		tg3_writephy(tp, 0x16, 0x0802);
+		if (tg3_wait_macro_done(tp)) {
+			*resetp = 1;
+			return -EBUSY;
+		}
+
+		for (i = 0; i < 6; i += 2) {
+			u32 low, high;
+
+			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low);
+			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high);
+			if (tg3_wait_macro_done(tp)) {
+				*resetp = 1;
+				return -EBUSY;
+			}
+			low &= 0x7fff;
+			high &= 0x000f;
+			if (low != test_pat[chan][i] ||
+			    high != test_pat[chan][i+1]) {
+				tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000b);
+				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4001);
+				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4005);
+
+				return -EBUSY;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int tg3_phy_reset_chanpat(struct tg3 *tp)
+{
+	int chan;
+
+	for (chan = 0; chan < 4; chan++) {
+		int i;
+
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+			     (chan * 0x2000) | 0x0200);
+		tg3_writephy(tp, 0x16, 0x0002);
+		for (i = 0; i < 6; i++)
+			tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
+		tg3_writephy(tp, 0x16, 0x0202);
+		if (tg3_wait_macro_done(tp))
+			return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
+{
+	u32 reg32, phy9_orig;
+	int retries, do_phy_reset, err;
+
+	retries = 10;
+	do_phy_reset = 1;
+	do {
+		if (do_phy_reset) {
+			err = tg3_bmcr_reset(tp);
+			if (err)
+				return err;
+			do_phy_reset = 0;
+		}
+
+		/* Disable transmitter and interrupt.  */
+		tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
+		reg32 |= 0x3000;
+		tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+
+		/* Set full-duplex, 1000 mbps.  */
+		tg3_writephy(tp, MII_BMCR,
+			     BMCR_FULLDPLX | TG3_BMCR_SPEED1000);
+
+		/* Set to master mode.  */
+		tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig);
+		tg3_writephy(tp, MII_TG3_CTRL,
+			     (MII_TG3_CTRL_AS_MASTER |
+			      MII_TG3_CTRL_ENABLE_AS_MASTER));
+
+		/* Enable SM_DSP_CLOCK and 6dB.  */
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+
+		/* Block the PHY control access.  */
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
+		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0800);
+
+		err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset);
+		if (!err)
+			break;
+	} while (--retries);
+
+	err = tg3_phy_reset_chanpat(tp);
+	if (err)
+		return err;
+
+	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
+	tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0000);
+
+	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
+	tg3_writephy(tp, 0x16, 0x0000);
+
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
+
+	tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
+
+	tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
+	reg32 &= ~0x3000;
+	tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+
+	return err;
+}
+
+/* This will reset the tigon3 PHY if there is no valid
+ * link unless the FORCE argument is non-zero.
+ */
+static int tg3_phy_reset(struct tg3 *tp, int force)
+{
+	u32 phy_status;
+	int err;
+
+	err  = tg3_readphy(tp, MII_BMSR, &phy_status);
+	err |= tg3_readphy(tp, MII_BMSR, &phy_status);
+	if (err != 0)
+		return -EBUSY;
+
+	/* If we have link, and not forcing a reset, then nothing
+	 * to do.
+	 */
+	if ((phy_status & BMSR_LSTATUS) != 0 && (force == 0))
+		return 0;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		err = tg3_phy_reset_5703_4_5(tp);
+		if (err)
+			return err;
+		goto out;
+	}
+
+	err = tg3_bmcr_reset(tp);
+	if (err)
+		return err;
+
+out:
+	tg3_phy_set_wirespeed(tp);
+	return 0;
+}
+
+static void tg3_frob_aux_power(struct tg3 *tp)
+{
+	struct tg3 *tp_peer = tp;
+
+	if ((tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) != 0)
+		return;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		tp_peer = pci_get_drvdata(tp->pdev_peer);
+		if (!tp_peer)
+			BUG();
+	}
+
+
+	if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 ||
+	    (tp_peer->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0) {
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+			tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT0 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+		} else {
+			if (tp_peer != tp &&
+			    (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0)
+				return;
+
+			tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1 |
+			      GRC_LCLCTRL_GPIO_OUTPUT2));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+
+			tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT0 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1 |
+			      GRC_LCLCTRL_GPIO_OUTPUT2));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+
+			tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT0 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+		}
+	} else {
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
+			if (tp_peer != tp &&
+			    (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0)
+				return;
+
+			tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+			     (GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+
+			tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+			     (GRC_LCLCTRL_GPIO_OE1));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
 
-	return -EBUSY;
+			tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+			     (GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+		}
+	}
 }
 
 static int tg3_setup_phy(struct tg3 *);
@@ -533,89 +876,65 @@
 		udelay(10);
 	}
 
-	if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) {
+	if (!(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) &&
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
 		u32 base_val;
 
-		base_val = 0;
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
-			base_val |= (CLOCK_CTRL_RXCLK_DISABLE |
-				     CLOCK_CTRL_TXCLK_DISABLE);
-
-		tw32(TG3PCI_CLOCK_CTRL, base_val |
-		     CLOCK_CTRL_ALTCLK);
-		tr32(TG3PCI_CLOCK_CTRL);
-		udelay(40);
+		base_val = tp->pci_clock_ctrl;
+		base_val |= (CLOCK_CTRL_RXCLK_DISABLE |
+			     CLOCK_CTRL_TXCLK_DISABLE);
 
 		tw32(TG3PCI_CLOCK_CTRL, base_val |
 		     CLOCK_CTRL_ALTCLK |
-		     CLOCK_CTRL_44MHZ_CORE);
-		tr32(TG3PCI_CLOCK_CTRL);
-		udelay(40);
-
-		tw32(TG3PCI_CLOCK_CTRL, base_val |
-		     CLOCK_CTRL_44MHZ_CORE);
+		     CLOCK_CTRL_PWRDOWN_PLL133);
 		tr32(TG3PCI_CLOCK_CTRL);
 		udelay(40);
 	} else {
-		u32 base_val;
+		u32 newbits1, newbits2;
 
-		base_val = 0;
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
-			base_val |= (CLOCK_CTRL_RXCLK_DISABLE |
-				     CLOCK_CTRL_TXCLK_DISABLE);
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+			newbits1 = (CLOCK_CTRL_RXCLK_DISABLE |
+				    CLOCK_CTRL_TXCLK_DISABLE |
+				    CLOCK_CTRL_ALTCLK);
+			newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
+		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+			newbits1 = CLOCK_CTRL_625_CORE;
+			newbits2 = newbits1 | CLOCK_CTRL_ALTCLK;
+		} else {
+			newbits1 = CLOCK_CTRL_ALTCLK;
+			newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
+		}
 
-		tw32(TG3PCI_CLOCK_CTRL, base_val |
-		     CLOCK_CTRL_ALTCLK |
-		     CLOCK_CTRL_PWRDOWN_PLL133);
+		tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits1);
 		tr32(TG3PCI_CLOCK_CTRL);
 		udelay(40);
-	}
 
-	if (!(tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) &&
-	    (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
-			tw32(GRC_LOCAL_CTRL,
-			     (GRC_LCLCTRL_GPIO_OE0 |
-			      GRC_LCLCTRL_GPIO_OE1 |
-			      GRC_LCLCTRL_GPIO_OE2 |
-			      GRC_LCLCTRL_GPIO_OUTPUT0 |
-			      GRC_LCLCTRL_GPIO_OUTPUT1));
-			tr32(GRC_LOCAL_CTRL);
-			udelay(100);
-		} else {
-			tw32(GRC_LOCAL_CTRL,
-			     (GRC_LCLCTRL_GPIO_OE0 |
-			      GRC_LCLCTRL_GPIO_OE1 |
-			      GRC_LCLCTRL_GPIO_OE2 |
-			      GRC_LCLCTRL_GPIO_OUTPUT1 |
-			      GRC_LCLCTRL_GPIO_OUTPUT2));
-			tr32(GRC_LOCAL_CTRL);
-			udelay(100);
+		tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2);
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
 
-			tw32(GRC_LOCAL_CTRL,
-			     (GRC_LCLCTRL_GPIO_OE0 |
-			      GRC_LCLCTRL_GPIO_OE1 |
-			      GRC_LCLCTRL_GPIO_OE2 |
-			      GRC_LCLCTRL_GPIO_OUTPUT0 |
-			      GRC_LCLCTRL_GPIO_OUTPUT1 |
-			      GRC_LCLCTRL_GPIO_OUTPUT2));
-			tr32(GRC_LOCAL_CTRL);
-			udelay(100);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+			u32 newbits3;
 
-			tw32(GRC_LOCAL_CTRL,
-			     (GRC_LCLCTRL_GPIO_OE0 |
-			      GRC_LCLCTRL_GPIO_OE1 |
-			      GRC_LCLCTRL_GPIO_OE2 |
-			      GRC_LCLCTRL_GPIO_OUTPUT0 |
-			      GRC_LCLCTRL_GPIO_OUTPUT1));
-			tr32(GRC_LOCAL_CTRL);
-			udelay(100);
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+				newbits3 = (CLOCK_CTRL_RXCLK_DISABLE |
+					    CLOCK_CTRL_TXCLK_DISABLE |
+					    CLOCK_CTRL_44MHZ_CORE);
+			} else {
+				newbits3 = CLOCK_CTRL_44MHZ_CORE;
+			}
+
+			tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits3);
+			tr32(TG3PCI_CLOCK_CTRL);
+			udelay(40);
 		}
 	}
 
+	tg3_frob_aux_power(tp);
+
 	/* Finally, set the new power state. */
 	pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
 
@@ -934,11 +1253,10 @@
 
 	/* Some third-party PHYs need to be reset on link going
 	 * down.
-	 *
-	 * XXX 5705 note: This workaround also applies to 5705_a0
 	 */
 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
-	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
+	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+	     tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) &&
 	    netif_carrier_ok(tp->dev)) {
 		tg3_readphy(tp, MII_BMSR, &bmsr);
 		tg3_readphy(tp, MII_BMSR, &bmsr);
@@ -1742,7 +2060,7 @@
 
 		pci_unmap_single(tp->pdev,
 				 pci_unmap_addr(ri, mapping),
-				 (skb->len - skb->data_len),
+				 skb_headlen(skb),
 				 PCI_DMA_TODEVICE);
 
 		ri->skb = NULL;
@@ -1913,7 +2231,7 @@
  * Each TG3_BDINFO specifies a MAXLEN field and the first TG3_BDINFO
  * which is within the range of the new packet's length is chosen.
  *
- * The "seperate ring for rx status" scheme may sound queer, but it makes
+ * The "separate ring for rx status" scheme may sound queer, but it makes
  * sense from a cache coherency perspective.  If only the host writes
  * to the buffer post rings, and only the chip writes to the rx status
  * rings, then cache lines never move beyond shared-modified state.
@@ -1928,7 +2246,7 @@
 	int received;
 
 	hw_idx = tp->hw_status->idx[0].rx_producer;
-	sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE;
+	sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp);
 	work_mask = 0;
 	received = 0;
 	while (sw_idx != hw_idx && budget > 0) {
@@ -2029,13 +2347,13 @@
 		(*post_ptr)++;
 next_pkt_nopost:
 		rx_rcb_ptr++;
-		sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE;
+		sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp);
 	}
 
 	/* ACK the status ring. */
 	tp->rx_rcb_ptr = rx_rcb_ptr;
 	tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW,
-		     (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE));
+		     (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp)));
 	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
 		tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW);
 
@@ -2139,12 +2457,13 @@
 	return work_exists;
 }
 
-static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
 	struct tg3 *tp = dev->priv;
 	struct tg3_hw_status *sblk = tp->hw_status;
 	unsigned long flags;
+	unsigned int handled = 1;
 
 	spin_lock_irqsave(&tp->lock, flags);
 
@@ -2175,12 +2494,15 @@
 			     	0x00000000);
 			tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 		}
+	} else {	/* shared interrupt */
+		handled = 0;
 	}
 
 	spin_unlock_irqrestore(&tp->lock, flags);
+
+	return IRQ_RETVAL(handled);
 }
 
-static void tg3_init_rings(struct tg3 *);
 static int tg3_init_hw(struct tg3 *);
 static int tg3_halt(struct tg3 *);
 
@@ -2198,7 +2520,6 @@
 	tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
 
 	tg3_halt(tp);
-	tg3_init_rings(tp);
 	tg3_init_hw(tp);
 
 	spin_unlock(&tp->tx_lock);
@@ -2236,7 +2557,7 @@
 		return -1;
 	}
 
-	/* New SKB is guarenteed to be linear. */
+	/* New SKB is guaranteed to be linear. */
 	entry = *start;
 	new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
 				  PCI_DMA_TODEVICE);
@@ -2251,7 +2572,7 @@
 		int len;
 
 		if (i == 0)
-			len = skb->len - skb->data_len;
+			len = skb_headlen(skb);
 		else
 			len = skb_shinfo(skb)->frags[i-1].size;
 		pci_unmap_single(tp->pdev,
@@ -2335,7 +2656,7 @@
 	int would_hit_hwbug;
 	unsigned long flags;
 
-	len = (skb->len - skb->data_len);
+	len = skb_headlen(skb);
 
 	/* No BH disabling for tx_lock here.  We are running in BH disabled
 	 * context and TX reclaim runs via tp->poll inside of a software
@@ -2371,10 +2692,36 @@
 	base_flags = 0;
 	if (skb->ip_summed == CHECKSUM_HW)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#if TG3_DO_TSO != 0
-	if ((mss = skb_shinfo(skb)->tso_size) != 0)
+#if TG3_TSO_SUPPORT != 0
+	mss = 0;
+	if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
+	    (mss = skb_shinfo(skb)->tso_size) != 0) {
+		int tcp_opt_len, ip_tcp_len;
+
+		tcp_opt_len = ((skb->h.th->doff - 5) * 4);
+		ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
+
 		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
 			       TXD_FLAG_CPU_POST_DMA);
+
+		skb->nh.iph->check = 0;
+		skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len);
+		skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+						      skb->nh.iph->daddr,
+						      0, IPPROTO_TCP, 0);
+
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+			if (tcp_opt_len || skb->nh.iph->ihl > 5) {
+				int tsflags;
+
+				tsflags = ((skb->nh.iph->ihl - 5) +
+					   (tcp_opt_len >> 2));
+				mss |= (tsflags << 11);
+			}
+		} else {
+			mss += tcp_opt_len;
+		}
+	}
 #else
 	mss = 0;
 #endif
@@ -2425,7 +2772,7 @@
 			}
 
 			tg3_set_txd(tp, entry, mapping, len,
-				    base_flags, (i == last) | (mss << 1));
+				    base_flags, (i == last));
 
 			entry = NEXT_TX(entry);
 		}
@@ -2443,7 +2790,7 @@
 		i = 0;
 		while (entry != last_plus_one) {
 			if (i == 0)
-				len = skb->len - skb->data_len;
+				len = skb_headlen(skb);
 			else
 				len = skb_shinfo(skb)->frags[i-1].size;
 
@@ -2516,7 +2863,7 @@
 	u32 len, entry, base_flags, mss;
 	unsigned long flags;
 
-	len = (skb->len - skb->data_len);
+	len = skb_headlen(skb);
 
 	/* No BH disabling for tx_lock here.  We are running in BH disabled
 	 * context and TX reclaim runs via tp->poll inside of a software
@@ -2552,10 +2899,36 @@
 	base_flags = 0;
 	if (skb->ip_summed == CHECKSUM_HW)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#if TG3_DO_TSO != 0
-	if ((mss = skb_shinfo(skb)->tso_size) != 0)
+#if TG3_TSO_SUPPORT != 0
+	mss = 0;
+	if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
+	    (mss = skb_shinfo(skb)->tso_size) != 0) {
+		int tcp_opt_len, ip_tcp_len;
+
+		tcp_opt_len = ((skb->h.th->doff - 5) * 4);
+		ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
+
 		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
 			       TXD_FLAG_CPU_POST_DMA);
+
+		skb->nh.iph->check = 0;
+		skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len);
+		skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+						      skb->nh.iph->daddr,
+						      0, IPPROTO_TCP, 0);
+
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+			if (tcp_opt_len || skb->nh.iph->ihl > 5) {
+				int tsflags;
+
+				tsflags = ((skb->nh.iph->ihl - 5) +
+					   (tcp_opt_len >> 2));
+				mss |= (tsflags << 11);
+			}
+		} else {
+			mss += tcp_opt_len;
+		}
+	}
 #else
 	mss = 0;
 #endif
@@ -2595,7 +2968,7 @@
 			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			tg3_set_txd(tp, entry, mapping, len,
-				    base_flags, (i == last) | (mss << 1));
+				    base_flags, (i == last));
 
 			entry = NEXT_TX(entry);
 		}
@@ -2655,7 +3028,7 @@
 {
 	struct tg3 *tp = dev->priv;
 
-	if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU)
+	if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
 		return -EINVAL;
 
 	if (!netif_running(dev)) {
@@ -2674,7 +3047,6 @@
 
 	tg3_set_mtu(dev, tp, new_mtu);
 
-	tg3_init_rings(tp);
 	tg3_init_hw(tp);
 
 	spin_unlock(&tp->tx_lock);
@@ -2737,7 +3109,7 @@
 
 		pci_unmap_single(tp->pdev,
 				 pci_unmap_addr(txp, mapping),
-				 (skb->len - skb->data_len),
+				 skb_headlen(skb),
 				 PCI_DMA_TODEVICE);
 		txp->skb = NULL;
 
@@ -2760,8 +3132,8 @@
  *
  * The chip has been shut down and the driver detached from
  * the networking, so no interrupts or new tx packets will
- * end up in the driver.  tp->{tx,}lock is not held and we are not
- * in an interrupt context and thus may sleep.
+ * end up in the driver.  tp->{tx,}lock are held and thus
+ * we may not sleep.
  */
 static void tg3_init_rings(struct tg3 *tp)
 {
@@ -2774,7 +3146,7 @@
 	/* Zero out all descriptors. */
 	memset(tp->rx_std, 0, TG3_RX_RING_BYTES);
 	memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES);
-	memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES);
+	memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
 
 	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
 		memset(tp->tx_ring, 0, TG3_TX_RING_BYTES);
@@ -2857,7 +3229,7 @@
 		tp->rx_jumbo = NULL;
 	}
 	if (tp->rx_rcb) {
-		pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES,
+		pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp),
 				    tp->rx_rcb, tp->rx_rcb_mapping);
 		tp->rx_rcb = NULL;
 	}
@@ -2915,7 +3287,7 @@
 	if (!tp->rx_jumbo)
 		goto err_out;
 
-	tp->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES,
+	tp->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES(tp),
 					  &tp->rx_rcb_mapping);
 	if (!tp->rx_rcb)
 		goto err_out;
@@ -2962,6 +3334,23 @@
 	unsigned int i;
 	u32 val;
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		switch (ofs) {
+		case RCVLSC_MODE:
+		case DMAC_MODE:
+		case MBFREE_MODE:
+		case BUFMGR_MODE:
+		case MEMARB_MODE:
+			/* We can't enable/disable these bits of the
+			 * 5705, just say success.
+			 */
+			return 0;
+
+		default:
+			break;
+		};
+	}
+
 	val = tr32(ofs);
 	val &= ~enable_bit;
 	tw32(ofs, val);
@@ -3058,18 +3447,20 @@
 	u32 val;
 	u32 flags_save;
 
-	/* Force NVRAM to settle.
-	 * This deals with a chip bug which can result in EEPROM
-	 * corruption.
-	 */
-	if (tp->tg3_flags & TG3_FLAG_NVRAM) {
-		int i;
+	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
+		/* Force NVRAM to settle.
+		 * This deals with a chip bug which can result in EEPROM
+		 * corruption.
+		 */
+		if (tp->tg3_flags & TG3_FLAG_NVRAM) {
+			int i;
 
-		tw32(NVRAM_SWARB, SWARB_REQ_SET1);
-		for (i = 0; i < 100000; i++) {
-			if (tr32(NVRAM_SWARB) & SWARB_GNT1)
-				break;
-			udelay(10);
+			tw32(NVRAM_SWARB, SWARB_REQ_SET1);
+			for (i = 0; i < 100000; i++) {
+				if (tr32(NVRAM_SWARB) & SWARB_GNT1)
+					break;
+				udelay(10);
+			}
 		}
 	}
 
@@ -3083,7 +3474,10 @@
 	tp->tg3_flags &= ~TG3_FLAG_5701_REG_WRITE_BUG;
 
 	/* do the reset */
-	tw32(GRC_MISC_CFG, GRC_MISC_CFG_CORECLK_RESET);
+	val = GRC_MISC_CFG_CORECLK_RESET;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+		val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
+	tw32(GRC_MISC_CFG, val);
 
 	/* restore 5701 hardware bug workaround flag */
 	tp->tg3_flags = flags_save;
@@ -3119,6 +3513,13 @@
 
 	tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
 
+	if ((tp->nic_sram_data_cfg & NIC_SRAM_DATA_CFG_MINI_PCI) != 0 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		tp->pci_clock_ctrl |=
+			(CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE);
+		tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+	}
+
 	tw32(TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
 }
 
@@ -3162,7 +3563,8 @@
 		udelay(10);
 	}
 
-	if (i >= 100000) {
+	if (i >= 100000 &&
+	    !(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
 		printk(KERN_ERR PFX "tg3_halt timed out for %s, "
 		       "firmware will not restart magic=%08x\n",
 		       tp->dev->name, val);
@@ -3300,7 +3702,7 @@
 	0x00000000
 };
 
-#if 0 /* All zeros, dont eat up space with it. */
+#if 0 /* All zeros, don't eat up space with it. */
 u32 tg3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = {
 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
 	0x00000000, 0x00000000, 0x00000000, 0x00000000
@@ -3313,28 +3715,32 @@
 #define TX_CPU_SCRATCH_SIZE	0x04000
 
 /* tp->lock is held. */
-static int tg3_reset_cpu(struct tg3 *tp, u32 offset)
+static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
 {
 	int i;
 
-	tw32(offset + CPU_STATE, 0xffffffff);
-	tw32(offset + CPU_MODE,  CPU_MODE_RESET);
+	if (offset == TX_CPU_BASE &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+		BUG();
+
 	if (offset == RX_CPU_BASE) {
-		for (i = 0; i < 10000; i++)
-			if (!(tr32(offset + CPU_MODE) & CPU_MODE_RESET))
+		for (i = 0; i < 10000; i++) {
+			tw32(offset + CPU_STATE, 0xffffffff);
+			tw32(offset + CPU_MODE,  CPU_MODE_HALT);
+			if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
 				break;
+		}
+
 		tw32(offset + CPU_STATE, 0xffffffff);
-		tw32(offset + CPU_MODE,  CPU_MODE_RESET);
+		tw32(offset + CPU_MODE,  CPU_MODE_HALT);
 		tr32(offset + CPU_MODE);
 		udelay(10);
 	} else {
 		for (i = 0; i < 10000; i++) {
-			if (!(tr32(offset + CPU_MODE) & CPU_MODE_RESET))
-				break;
 			tw32(offset + CPU_STATE, 0xffffffff);
-			tw32(offset + CPU_MODE,  CPU_MODE_RESET);
-			tr32(offset + CPU_MODE);
-			udelay(10);
+			tw32(offset + CPU_MODE,  CPU_MODE_HALT);
+			if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
+				break;
 		}
 	}
 
@@ -3366,38 +3772,52 @@
 {
 	int err, i;
 	u32 orig_tg3_flags = tp->tg3_flags;
+	void (*write_op)(struct tg3 *, u32, u32);
+
+	if (cpu_base == TX_CPU_BASE &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		printk(KERN_ERR PFX "tg3_load_firmware_cpu: Trying to load "
+		       "TX cpu firmware on %s which is 5705.\n",
+		       tp->dev->name);
+		return -EINVAL;
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+		write_op = tg3_write_mem;
+	else
+		write_op = tg3_write_indirect_reg32;
 
 	/* Force use of PCI config space for indirect register
 	 * write calls.
 	 */
 	tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
 
-	err = tg3_reset_cpu(tp, cpu_base);
+	err = tg3_halt_cpu(tp, cpu_base);
 	if (err)
 		goto out;
 
 	for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
-		tg3_write_indirect_reg32(tp, cpu_scratch_base + i, 0);
+		write_op(tp, cpu_scratch_base + i, 0);
 	tw32(cpu_base + CPU_STATE, 0xffffffff);
 	tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
 	for (i = 0; i < (info->text_len / sizeof(u32)); i++)
-		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
-					      (info->text_base & 0xffff) +
-					      (i * sizeof(u32))),
-					 (info->text_data ?
-					  info->text_data[i] : 0));
+		write_op(tp, (cpu_scratch_base +
+			      (info->text_base & 0xffff) +
+			      (i * sizeof(u32))),
+			 (info->text_data ?
+			  info->text_data[i] : 0));
 	for (i = 0; i < (info->rodata_len / sizeof(u32)); i++)
-		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
-					      (info->rodata_base & 0xffff) +
-					      (i * sizeof(u32))),
-					 (info->rodata_data ?
-					  info->rodata_data[i] : 0));
+		write_op(tp, (cpu_scratch_base +
+			      (info->rodata_base & 0xffff) +
+			      (i * sizeof(u32))),
+			 (info->rodata_data ?
+			  info->rodata_data[i] : 0));
 	for (i = 0; i < (info->data_len / sizeof(u32)); i++)
-		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
-					      (info->data_base & 0xffff) +
-					      (i * sizeof(u32))),
-					 (info->data_data ?
-					  info->data_data[i] : 0));
+		write_op(tp, (cpu_scratch_base +
+			      (info->data_base & 0xffff) +
+			      (i * sizeof(u32))),
+			 (info->data_data ?
+			  info->data_data[i] : 0));
 
 	err = 0;
 
@@ -3468,335 +3888,595 @@
 	return 0;
 }
 
-#if TG3_DO_TSO != 0
+#if TG3_TSO_SUPPORT != 0
 
 #define TG3_TSO_FW_RELEASE_MAJOR	0x1
-#define TG3_TSO_FW_RELASE_MINOR		0x8
+#define TG3_TSO_FW_RELASE_MINOR		0x3
 #define TG3_TSO_FW_RELEASE_FIX		0x0
 #define TG3_TSO_FW_START_ADDR		0x08000000
 #define TG3_TSO_FW_TEXT_ADDR		0x08000000
-#define TG3_TSO_FW_TEXT_LEN		0x1650
+#define TG3_TSO_FW_TEXT_LEN		0x1ac0
 #define TG3_TSO_FW_RODATA_ADDR		0x08001650
-#define TG3_TSO_FW_RODATA_LEN		0x30
+#define TG3_TSO_FW_RODATA_LEN		0x60
 #define TG3_TSO_FW_DATA_ADDR		0x080016a0
 #define TG3_TSO_FW_DATA_LEN		0x20
 #define TG3_TSO_FW_SBSS_ADDR		0x080016c0
-#define TG3_TSO_FW_SBSS_LEN		0x14
+#define TG3_TSO_FW_SBSS_LEN		0x2c
 #define TG3_TSO_FW_BSS_ADDR		0x080016e0
-#define TG3_TSO_FW_BSS_LEN		0x8fc
+#define TG3_TSO_FW_BSS_LEN		0x890
 
 static u32 tg3TsoFwText[] = {
 	0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800,
 	0x37bd4000, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000010, 0x00000000,
-	0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0x3c1bc000,
-	0xafbf0018, 0x0e000058, 0xaf60680c, 0x3c040800, 0x24841650, 0x03602821,
-	0x24060001, 0x24070004, 0xafa00010, 0x0e00006c, 0xafa00014, 0x8f625c50,
-	0x34420001, 0xaf625c50, 0x8f625c90, 0x34420001, 0xaf625c90, 0x2402ffff,
-	0x0e000098, 0xaf625404, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x00000000,
-	0x00000000, 0x00000000, 0x24030b60, 0x24050fff, 0xac000b50, 0x00002021,
-	0xac640000, 0x24630004, 0x0065102b, 0x1440fffc, 0x24840001, 0x24030b60,
-	0x0065102b, 0x10400011, 0x00002021, 0x24090b54, 0x3c06dead, 0x34c6beef,
-	0x24080b58, 0x24070b5c, 0x8c620000, 0x50440006, 0x24630004, 0xad260000,
-	0x8c620000, 0xace40000, 0xad020000, 0x24630004, 0x0065102b, 0x1440fff6,
-	0x24840001, 0x03e00008, 0x00000000, 0x27bdfff8, 0x18800009, 0x00002821,
-	0x8f63680c, 0x8f62680c, 0x1043fffe, 0x00000000, 0x24a50001, 0x00a4102a,
-	0x1440fff9, 0x00000000, 0x03e00008, 0x27bd0008, 0x3c020800, 0x34423000,
-	0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac2216c4,
-	0x24020040, 0x3c010800, 0xac2216c8, 0x3c010800, 0xac2016c0, 0xac600000,
-	0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000,
-	0x00804821, 0x8faa0010, 0x3c020800, 0x8c4216c0, 0x3c040800, 0x8c8416c8,
-	0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac2316c0, 0x14400003,
-	0x00004021, 0x3c010800, 0xac2016c0, 0x3c020800, 0x8c4216c0, 0x3c030800,
-	0x8c6316c4, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001,
-	0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c4216c0,
-	0x3c030800, 0x8c6316c4, 0x8f64680c, 0x00021140, 0x00431021, 0xac440008,
-	0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c,
-	0x00000000, 0x00000000, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0x0e0000b6,
-	0xafb00010, 0x24110001, 0x8f706820, 0x32020100, 0x10400003, 0x00000000,
-	0x0e000127, 0x00000000, 0x8f706820, 0x32022000, 0x10400004, 0x32020001,
-	0x0e00025a, 0x24040001, 0x32020001, 0x10400003, 0x00000000, 0x0e0000e6,
-	0x00000000, 0x0a00009e, 0xaf715028, 0x8fbf0018, 0x8fb10014, 0x8fb00010,
-	0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x24841660, 0x00002821,
-	0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00006c, 0xafa00014,
-	0x3c010800, 0xa4201fb8, 0x3c010800, 0xa02016f8, 0x3c010800, 0xac2016fc,
-	0x3c010800, 0xac201700, 0x3c010800, 0xac201704, 0x3c010800, 0xac20170c,
-	0x3c010800, 0xac201718, 0x3c010800, 0xac20171c, 0x8f624434, 0x3c010800,
-	0xac2216e8, 0x8f624438, 0x3c010800, 0xac2216ec, 0x8f624410, 0x3c010800,
-	0xac2016e0, 0x3c010800, 0xac2016e4, 0x3c010800, 0xac201fc0, 0x3c010800,
-	0xac201f68, 0x3c010800, 0xac201f6c, 0x3c010800, 0xac2216f0, 0x8fbf0018,
-	0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x2484166c, 0x00002821,
-	0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00006c, 0xafa00014,
-	0x3c040800, 0x24841660, 0x00002821, 0x00003021, 0x00003821, 0xafa00010,
-	0x0e00006c, 0xafa00014, 0x3c010800, 0xa4201fb8, 0x3c010800, 0xa02016f8,
-	0x3c010800, 0xac2016fc, 0x3c010800, 0xac201700, 0x3c010800, 0xac201704,
-	0x3c010800, 0xac20170c, 0x3c010800, 0xac201718, 0x3c010800, 0xac20171c,
-	0x8f624434, 0x3c010800, 0xac2216e8, 0x8f624438, 0x3c010800, 0xac2216ec,
-	0x8f624410, 0x3c010800, 0xac2016e0, 0x3c010800, 0xac2016e4, 0x3c010800,
-	0xac201fc0, 0x3c010800, 0xac201f68, 0x3c010800, 0xac201f6c, 0x3c010800,
-	0xac2216f0, 0x0e000120, 0x00002021, 0x8fbf0018, 0x03e00008, 0x27bd0020,
-	0x24020001, 0x8f636820, 0x00821004, 0x00021027, 0x00621824, 0x03e00008,
-	0xaf636820, 0x27bdffd0, 0x3c0300ff, 0xafbf002c, 0xafb60028, 0xafb50024,
-	0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x8f665c5c,
-	0x3c040800, 0x2484171c, 0x8c820000, 0x3463fff8, 0x14460005, 0x00c38824,
-	0x3c020800, 0x904216f8, 0x14400115, 0x00000000, 0x00111902, 0x306300ff,
-	0x30c20003, 0x000211c0, 0x00623825, 0x00e02821, 0x00061602, 0xac860000,
-	0x3c030800, 0x906316f8, 0x3044000f, 0x1460002b, 0x00804021, 0x24020001,
-	0x3c010800, 0xa02216f8, 0x00071100, 0x00821025, 0x3c010800, 0xac2016fc,
-	0x3c010800, 0xac201700, 0x3c010800, 0xac201704, 0x3c010800, 0xac20170c,
-	0x3c010800, 0xac201718, 0x3c010800, 0xac201710, 0x3c010800, 0xac201714,
-	0x3c010800, 0xa4221fb8, 0x9623000c, 0x30628000, 0x10400008, 0x30627fff,
-	0x2442003e, 0x3c010800, 0xa42216f6, 0x24020001, 0x3c010800, 0x0a00016e,
-	0xac221fd4, 0x24620036, 0x3c010800, 0xa42216f6, 0x3c010800, 0xac201fd4,
-	0x3c010800, 0xac201fd0, 0x3c010800, 0x0a000176, 0xac201fd8, 0x9622000c,
-	0x3c010800, 0xa4221fcc, 0x3c040800, 0x248416fc, 0x8c820000, 0x00021100,
-	0x3c010800, 0x00220821, 0xac311728, 0x8c820000, 0x00021100, 0x3c010800,
-	0x00220821, 0xac26172c, 0x8c820000, 0x24a30001, 0x306701ff, 0x00021100,
-	0x3c010800, 0x00220821, 0xac271730, 0x8c820000, 0x00021100, 0x3c010800,
-	0x00220821, 0xac281734, 0x96230008, 0x3c020800, 0x8c42170c, 0x00432821,
-	0x3c010800, 0xac25170c, 0x9622000a, 0x30420004, 0x14400019, 0x00071100,
-	0x3c02c000, 0x00c21825, 0xaf635c5c, 0x8f625c50, 0x30420002, 0x1440fffc,
-	0x00000000, 0x8f630c14, 0x3063000f, 0x2c620002, 0x1440001e, 0x00000000,
-	0x8f630c14, 0x3c020800, 0x8c4216b4, 0x3063000f, 0x24420001, 0x3c010800,
-	0xac2216b4, 0x2c620002, 0x1040fff7, 0x00000000, 0x0a0001c1, 0x00000000,
-	0x3c030800, 0x8c6316e0, 0x3c040800, 0x948416f4, 0x01021025, 0x3c010800,
-	0xa4221fba, 0x24020001, 0x3c010800, 0xac221718, 0x24630001, 0x0085202a,
-	0x3c010800, 0x10800003, 0xac2316e0, 0x3c010800, 0xa42516f4, 0x3c030800,
-	0x246316fc, 0x8c620000, 0x24420001, 0xac620000, 0x28420080, 0x14400005,
-	0x24020001, 0x0e0002df, 0x24040002, 0x0a000250, 0x00000000, 0x3c030800,
-	0x906316f8, 0x1462007c, 0x24020003, 0x3c160800, 0x96d616f6, 0x3c050800,
-	0x8ca5170c, 0x32c4ffff, 0x00a4102a, 0x14400078, 0x00000000, 0x3c020800,
-	0x8c421718, 0x10400005, 0x32c2ffff, 0x14a40003, 0x00000000, 0x3c010800,
-	0xac231fd0, 0x10400062, 0x00009021, 0x0040a021, 0x3c150800, 0x26b51700,
-	0x26b30010, 0x8ea20000, 0x00028100, 0x3c110800, 0x02308821, 0x0e0002e1,
-	0x8e311728, 0x00403021, 0x10c00059, 0x00000000, 0x9628000a, 0x31020040,
-	0x10400004, 0x2407180c, 0x8e22000c, 0x2407188c, 0xacc20018, 0x31021000,
-	0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, 0x3c030800,
-	0x00701821, 0x8c631730, 0x3c020800, 0x00501021, 0x8c421734, 0x00031d00,
-	0x00021400, 0x00621825, 0xacc30014, 0x8ea30004, 0x96220008, 0x00432023,
-	0x3242ffff, 0x3083ffff, 0x00431021, 0x0282102a, 0x14400002, 0x02d22823,
-	0x00802821, 0x8e620000, 0x30a4ffff, 0x00441021, 0xae620000, 0x8e220000,
-	0xacc20000, 0x8e220004, 0x8e63fff4, 0x00431021, 0xacc20004, 0xa4c5000e,
-	0x8e62fff4, 0x00441021, 0xae62fff4, 0x96230008, 0x0043102a, 0x14400005,
-	0x02459021, 0x8e62fff0, 0xae60fff4, 0x24420001, 0xae62fff0, 0xacc00008,
-	0x3242ffff, 0x14540008, 0x24020305, 0x31020080, 0x54400001, 0x34e70010,
-	0x24020905, 0xa4c2000c, 0x0a000233, 0x34e70020, 0xa4c2000c, 0x30e2ffff,
-	0xacc20010, 0x3c020800, 0x8c421fd0, 0x10400003, 0x3c024b65, 0x0a00023d,
-	0x34427654, 0x3c02b49a, 0x344289ab, 0xacc2001c, 0x0e000560, 0x00c02021,
-	0x3242ffff, 0x0054102b, 0x1440ffa4, 0x00000000, 0x24020002, 0x3c010800,
-	0x0a000250, 0xa02216f8, 0x8ea208bc, 0x24420001, 0x0a000250, 0xaea208bc,
-	0x14620003, 0x00000000, 0x0e000450, 0x00000000, 0x8fbf002c, 0x8fb60028,
-	0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
-	0x03e00008, 0x27bd0030, 0x27bdffd8, 0xafb3001c, 0x00809821, 0xafbf0020,
-	0xafb20018, 0xafb10014, 0xafb00010, 0x8f725c9c, 0x3c0200ff, 0x3442fff8,
-	0x3c040800, 0x24841714, 0x02428824, 0x9623000e, 0x8c820000, 0x00431021,
-	0xac820000, 0x8e220010, 0x30420020, 0x14400011, 0x00000000, 0x0e0002f7,
+	0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0x3c04fefe,
+	0xafbf0018, 0x0e0005e0, 0x34840002, 0x0e000670, 0x00000000, 0x3c030800,
+	0x90631b78, 0x24020002, 0x3c040800, 0x24841acc, 0x14620003, 0x24050001,
+	0x3c040800, 0x24841ac0, 0x24060002, 0x00003821, 0xafa00010, 0x0e000684,
+	0xafa00014, 0x8f625c50, 0x34420001, 0xaf625c50, 0x8f625c90, 0x34420001,
+	0xaf625c90, 0x2402ffff, 0x0e000034, 0xaf625404, 0x8fbf0018, 0x03e00008,
+	0x27bd0020, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0xafbf0018,
+	0xafb10014, 0x0e000052, 0xafb00010, 0x24110001, 0x8f706820, 0x32020100,
+	0x10400003, 0x00000000, 0x0e0000b2, 0x00000000, 0x8f706820, 0x32022000,
+	0x10400004, 0x32020001, 0x0e0001e3, 0x24040001, 0x32020001, 0x10400003,
+	0x00000000, 0x0e00009a, 0x00000000, 0x0a00003a, 0xaf715028, 0x8fbf0018,
+	0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800,
+	0x24841ae0, 0x00002821, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010,
+	0x0e000684, 0xafa00014, 0x3c040800, 0x248423e8, 0xa4800000, 0x3c010800,
+	0xa0201ba8, 0x3c010800, 0xac201bac, 0x3c010800, 0xac201bb0, 0x3c010800,
+	0xac201bb4, 0x3c010800, 0xac201bbc, 0x3c010800, 0xac201bc8, 0x3c010800,
+	0xac201bcc, 0x8f624434, 0x3c010800, 0xac221b98, 0x8f624438, 0x3c010800,
+	0xac221b9c, 0x8f624410, 0xac80f7a8, 0x3c010800, 0xac201b94, 0x3c010800,
+	0xac2023f0, 0x3c010800, 0xac2023d8, 0x3c010800, 0xac2023dc, 0x3c010800,
+	0xac202410, 0x3c010800, 0xac221ba0, 0x8f620068, 0x24030007, 0x00021702,
+	0x10430005, 0x00000000, 0x8f620068, 0x00021702, 0x14400004, 0x24020001,
+	0x3c010800, 0x0a00008e, 0xac20241c, 0xac820034, 0x3c040800, 0x24841aec,
+	0x3c050800, 0x8ca5241c, 0x00003021, 0x00003821, 0xafa00010, 0x0e000684,
+	0xafa00014, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800,
+	0x24841af8, 0x00002821, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010,
+	0x0e000684, 0xafa00014, 0x0e000052, 0x00000000, 0x0e0000ab, 0x00002021,
+	0x8fbf0018, 0x03e00008, 0x27bd0020, 0x24020001, 0x8f636820, 0x00821004,
+	0x00021027, 0x00621824, 0x03e00008, 0xaf636820, 0x27bdffd0, 0xafbf002c,
+	0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014,
+	0xafb00010, 0x8f665c5c, 0x3c030800, 0x24631bcc, 0x8c620000, 0x14460005,
+	0x3c0200ff, 0x3c020800, 0x90421ba8, 0x14400115, 0x3c0200ff, 0x3442fff8,
+	0x00c28824, 0xac660000, 0x00111902, 0x306300ff, 0x30c20003, 0x000211c0,
+	0x00623825, 0x00e02821, 0x00061602, 0x3c030800, 0x90631ba8, 0x3044000f,
+	0x1460002b, 0x00804021, 0x24020001, 0x3c010800, 0xa0221ba8, 0x00071100,
+	0x00821025, 0x3c010800, 0xac201bac, 0x3c010800, 0xac201bb0, 0x3c010800,
+	0xac201bb4, 0x3c010800, 0xac201bbc, 0x3c010800, 0xac201bc8, 0x3c010800,
+	0xac201bc0, 0x3c010800, 0xac201bc4, 0x3c010800, 0xa42223e8, 0x9623000c,
+	0x30628000, 0x10400008, 0x30627fff, 0x2442003e, 0x3c010800, 0xa4221ba6,
+	0x24020001, 0x3c010800, 0x0a0000f9, 0xac222404, 0x24620036, 0x3c010800,
+	0xa4221ba6, 0x3c010800, 0xac202404, 0x3c010800, 0xac202400, 0x3c010800,
+	0x0a000101, 0xac202408, 0x9622000c, 0x3c010800, 0xa42223fc, 0x3c040800,
+	0x24841bac, 0x8c820000, 0x00021100, 0x3c010800, 0x00220821, 0xac311bd8,
+	0x8c820000, 0x00021100, 0x3c010800, 0x00220821, 0xac261bdc, 0x8c820000,
+	0x24a30001, 0x306701ff, 0x00021100, 0x3c010800, 0x00220821, 0xac271be0,
+	0x8c820000, 0x00021100, 0x3c010800, 0x00220821, 0xac281be4, 0x96230008,
+	0x3c020800, 0x8c421bbc, 0x00432821, 0x3c010800, 0xac251bbc, 0x9622000a,
+	0x30420004, 0x14400018, 0x00071100, 0x8f630c14, 0x3063000f, 0x2c620002,
+	0x1440000b, 0x3c02c000, 0x8f630c14, 0x3c020800, 0x8c421b50, 0x3063000f,
+	0x24420001, 0x3c010800, 0xac221b50, 0x2c620002, 0x1040fff7, 0x3c02c000,
+	0x00c21825, 0xaf635c5c, 0x8f625c50, 0x30420002, 0x10400014, 0x00000000,
+	0x0a000133, 0x00000000, 0x3c030800, 0x8c631b90, 0x3c040800, 0x94841ba4,
+	0x01021025, 0x3c010800, 0xa42223ea, 0x24020001, 0x3c010800, 0xac221bc8,
+	0x24630001, 0x0085202a, 0x3c010800, 0x10800003, 0xac231b90, 0x3c010800,
+	0xa4251ba4, 0x3c060800, 0x24c61bac, 0x8cc20000, 0x24420001, 0xacc20000,
+	0x28420080, 0x14400005, 0x00000000, 0x0e00065e, 0x24040002, 0x0a0001d9,
+	0x00000000, 0x3c020800, 0x8c421bc8, 0x1040007f, 0x24020001, 0x3c040800,
+	0x90841ba8, 0x14820077, 0x24020003, 0x3c150800, 0x96b51ba6, 0x3c050800,
+	0x8ca51bbc, 0x32a3ffff, 0x00a3102a, 0x14400073, 0x00000000, 0x14a30003,
+	0x00000000, 0x3c010800, 0xac242400, 0x10600061, 0x00009021, 0x24d60004,
+	0x0060a021, 0x24d30014, 0x8ec20000, 0x00028100, 0x3c110800, 0x02308821,
+	0x0e00062d, 0x8e311bd8, 0x00403021, 0x10c00059, 0x00000000, 0x9628000a,
+	0x31020040, 0x10400004, 0x2407180c, 0x8e22000c, 0x2407188c, 0xacc20018,
+	0x31021000, 0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825,
+	0x3c030800, 0x00701821, 0x8c631be0, 0x3c020800, 0x00501021, 0x8c421be4,
+	0x00031d00, 0x00021400, 0x00621825, 0xacc30014, 0x8ec30004, 0x96220008,
+	0x00432023, 0x3242ffff, 0x3083ffff, 0x00431021, 0x0282102a, 0x14400002,
+	0x02b22823, 0x00802821, 0x8e620000, 0x30a4ffff, 0x00441021, 0xae620000,
+	0x8e220000, 0xacc20000, 0x8e220004, 0x8e63fff4, 0x00431021, 0xacc20004,
+	0xa4c5000e, 0x8e62fff4, 0x00441021, 0xae62fff4, 0x96230008, 0x0043102a,
+	0x14400005, 0x02459021, 0x8e62fff0, 0xae60fff4, 0x24420001, 0xae62fff0,
+	0xacc00008, 0x3242ffff, 0x14540008, 0x24020305, 0x31020080, 0x54400001,
+	0x34e70010, 0x24020905, 0xa4c2000c, 0x0a0001bc, 0x34e70020, 0xa4c2000c,
+	0x3c020800, 0x8c422400, 0x10400003, 0x3c024b65, 0x0a0001c4, 0x34427654,
+	0x3c02b49a, 0x344289ab, 0xacc2001c, 0x30e2ffff, 0xacc20010, 0x0e0005aa,
+	0x00c02021, 0x3242ffff, 0x0054102b, 0x1440ffa4, 0x00000000, 0x24020002,
+	0x3c010800, 0x0a0001d9, 0xa0221ba8, 0x8ec2083c, 0x24420001, 0x0a0001d9,
+	0xaec2083c, 0x14820003, 0x00000000, 0x0e0004b9, 0x00000000, 0x8fbf002c,
+	0x8fb60028, 0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+	0x8fb00010, 0x03e00008, 0x27bd0030, 0x27bdffd0, 0xafbf0028, 0xafb30024,
+	0xafb20020, 0xafb1001c, 0xafb00018, 0x8f725c9c, 0x3c0200ff, 0x3442fff8,
+	0x3c060800, 0x24c61bc4, 0x02428824, 0x9623000e, 0x8cc20000, 0x00431021,
+	0xacc20000, 0x8e220010, 0x30420020, 0x14400011, 0x00809821, 0x0e000643,
 	0x02202021, 0x3c02c000, 0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002,
-	0x10400061, 0x00000000, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x1040005c,
-	0x00000000, 0x0a000278, 0x00000000, 0x8e220008, 0x00021c02, 0x000321c0,
-	0x3042ffff, 0x3c030800, 0x906316f8, 0x000229c0, 0x24020002, 0x14620003,
-	0x3c034b65, 0x0a000290, 0x00008021, 0x8e22001c, 0x34637654, 0x10430002,
-	0x24100002, 0x24100001, 0x0e000300, 0x02003021, 0x24020003, 0x3c010800,
-	0xa02216f8, 0x24020002, 0x1202000a, 0x24020001, 0x3c030800, 0x8c631fd0,
-	0x10620006, 0x00000000, 0x3c020800, 0x94421fb8, 0x00021400, 0x0a0002cd,
-	0xae220014, 0x3c040800, 0x24841fba, 0x94820000, 0x00021400, 0xae220014,
-	0x3c020800, 0x8c42171c, 0x3c03c000, 0x3c010800, 0xa02016f8, 0x00431025,
-	0xaf625c5c, 0x8f625c50, 0x30420002, 0x10400009, 0x00000000, 0x2484f762,
+	0x10400121, 0x00000000, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x1040011c,
+	0x00000000, 0x0a000200, 0x00000000, 0x8e240008, 0x8e230014, 0x00041402,
+	0x000241c0, 0x00031502, 0x304201ff, 0x2442ffff, 0x3042007f, 0x00031942,
+	0x30637800, 0x00021100, 0x24424000, 0x00625021, 0x9542000a, 0x3084ffff,
+	0x30420008, 0x104000b3, 0x000429c0, 0x3c020800, 0x8c422410, 0x1440002d,
+	0x25050008, 0x95020014, 0x3c010800, 0xa42223e0, 0x8d070010, 0x00071402,
+	0x3c010800, 0xa42223e2, 0x3c010800, 0xa42723e4, 0x9502000e, 0x30e3ffff,
+	0x00431023, 0x3c010800, 0xac222418, 0x8f626800, 0x3c030010, 0x00431024,
+	0x10400005, 0x00000000, 0x9503001a, 0x9502001c, 0x0a000235, 0x00431021,
+	0x9502001a, 0x3c010800, 0xac22240c, 0x3c02c000, 0x02421825, 0x3c010800,
+	0xac282410, 0x3c010800, 0xac322414, 0xaf635c9c, 0x8f625c90, 0x30420002,
+	0x104000df, 0x00000000, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x104000da,
+	0x00000000, 0x0a000242, 0x00000000, 0x9502000e, 0x3c030800, 0x946323e4,
+	0x00434823, 0x3123ffff, 0x2c620008, 0x1040001c, 0x00000000, 0x95020014,
+	0x24420028, 0x00a22821, 0x00031042, 0x1840000b, 0x00002021, 0x24c60848,
+	0x00403821, 0x94a30000, 0x8cc20000, 0x24840001, 0x00431021, 0xacc20000,
+	0x0087102a, 0x1440fff9, 0x24a50002, 0x31220001, 0x1040001f, 0x3c024000,
+	0x3c040800, 0x2484240c, 0xa0a00001, 0x94a30000, 0x8c820000, 0x00431021,
+	0x0a000281, 0xac820000, 0x8f626800, 0x3c030010, 0x00431024, 0x10400009,
+	0x00000000, 0x9502001a, 0x3c030800, 0x8c63240c, 0x00431021, 0x3c010800,
+	0xac22240c, 0x0a000282, 0x3c024000, 0x9502001a, 0x9504001c, 0x3c030800,
+	0x8c63240c, 0x00441023, 0x00621821, 0x3c010800, 0xac23240c, 0x3c024000,
+	0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x1440fffc, 0x00000000,
+	0x9542000a, 0x30420010, 0x10400095, 0x00000000, 0x3c060800, 0x24c62410,
+	0x3c020800, 0x944223e4, 0x8cc50000, 0x3c040800, 0x8c842418, 0x24420030,
+	0x00a22821, 0x94a20004, 0x3c030800, 0x8c63240c, 0x00441023, 0x00621821,
+	0x00603821, 0x00032402, 0x30e2ffff, 0x00823821, 0x00071402, 0x00e23821,
+	0x00071027, 0x3c010800, 0xac23240c, 0xa4a20006, 0x3c030800, 0x8c632414,
+	0x3c0200ff, 0x3442fff8, 0x00628824, 0x96220008, 0x24040001, 0x24034000,
+	0x000241c0, 0x00e01021, 0xa502001a, 0xa500001c, 0xacc00000, 0x3c010800,
+	0xac241b70, 0xaf635cb8, 0x8f625cb0, 0x30420002, 0x10400003, 0x00000000,
+	0x3c010800, 0xac201b70, 0x8e220008, 0xaf625cb8, 0x8f625cb0, 0x30420002,
+	0x10400003, 0x00000000, 0x3c010800, 0xac201b70, 0x3c020800, 0x8c421b70,
+	0x1040ffec, 0x00000000, 0x3c040800, 0x0e000643, 0x8c842414, 0x0a000320,
+	0x00000000, 0x3c030800, 0x90631ba8, 0x24020002, 0x14620003, 0x3c034b65,
+	0x0a0002d7, 0x00008021, 0x8e22001c, 0x34637654, 0x10430002, 0x24100002,
+	0x24100001, 0x01002021, 0x0e000346, 0x02003021, 0x24020003, 0x3c010800,
+	0xa0221ba8, 0x24020002, 0x1202000a, 0x24020001, 0x3c030800, 0x8c632400,
+	0x10620006, 0x00000000, 0x3c020800, 0x944223e8, 0x00021400, 0x0a000315,
+	0xae220014, 0x3c040800, 0x248423ea, 0x94820000, 0x00021400, 0xae220014,
+	0x3c020800, 0x8c421bcc, 0x3c03c000, 0x3c010800, 0xa0201ba8, 0x00431025,
+	0xaf625c5c, 0x8f625c50, 0x30420002, 0x10400009, 0x00000000, 0x2484f7e2,
 	0x8c820000, 0x00431025, 0xaf625c5c, 0x8f625c50, 0x30420002, 0x1440fffa,
-	0x00000000, 0x3c020800, 0x244216e4, 0x8c430000, 0x24630001, 0xac430000,
-	0x8f630c14, 0x3063000f, 0x2c620002, 0x1440000b, 0x00009821, 0x8f630c14,
-	0x3c020800, 0x8c4216b4, 0x3063000f, 0x24420001, 0x3c010800, 0xac2216b4,
-	0x2c620002, 0x1040fff7, 0x00009821, 0x3c024000, 0x02421825, 0xaf635c9c,
+	0x00000000, 0x3c020800, 0x24421b94, 0x8c430000, 0x24630001, 0xac430000,
+	0x8f630c14, 0x3063000f, 0x2c620002, 0x1440000c, 0x3c024000, 0x8f630c14,
+	0x3c020800, 0x8c421b50, 0x3063000f, 0x24420001, 0x3c010800, 0xac221b50,
+	0x2c620002, 0x1040fff7, 0x00000000, 0x3c024000, 0x02421825, 0xaf635c9c,
 	0x8f625c90, 0x30420002, 0x1440fffc, 0x00000000, 0x12600003, 0x00000000,
-	0x0e000450, 0x00000000, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
-	0x8fb00010, 0x03e00008, 0x27bd0028, 0x0a0002df, 0x00000000, 0x8f634450,
-	0x3c040800, 0x248416e8, 0x8c820000, 0x00031c02, 0x0043102b, 0x14400007,
-	0x3c038000, 0x8c840004, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc,
-	0x3c038000, 0xaf634444, 0x8f624444, 0x00431024, 0x1440fffd, 0x00000000,
-	0x8f624448, 0x03e00008, 0x3042ffff, 0x3c024000, 0x00822025, 0xaf645c38,
-	0x8f625c30, 0x30420002, 0x1440fffc, 0x00000000, 0x03e00008, 0x00000000,
-	0x27bdffe0, 0x00805021, 0x14c00017, 0x254c0008, 0x3c020800, 0x8c421fd4,
-	0x1040000a, 0x2402003e, 0x3c010800, 0xa4221fb0, 0x24020016, 0x3c010800,
-	0xa4221fb2, 0x2402002a, 0x3c010800, 0x0a00031a, 0xa4221fb4, 0x95420014,
-	0x3c010800, 0xa4221fb0, 0x8d430010, 0x00031402, 0x3c010800, 0xa4221fb2,
-	0x3c010800, 0xa4231fb4, 0x3c040800, 0x94841fb4, 0x3c030800, 0x94631fb2,
-	0x958d0006, 0x3c020800, 0x94421fb0, 0x00832023, 0x01a27023, 0x3065ffff,
-	0x24a20028, 0x01824021, 0x3082ffff, 0x14c0001a, 0x01025821, 0x9562000c,
-	0x3042003f, 0x3c010800, 0xa4221fb6, 0x95620004, 0x95630006, 0x3c010800,
-	0xac201fc4, 0x3c010800, 0xac201fc8, 0x00021400, 0x00431025, 0x3c010800,
-	0xac221720, 0x95020004, 0x3c010800, 0xa4221724, 0x95030002, 0x01a51023,
-	0x0043102a, 0x10400010, 0x24020001, 0x3c010800, 0x0a00034e, 0xac221fd8,
-	0x3c030800, 0x8c631fc8, 0x3c020800, 0x94421724, 0x00431021, 0xa5020004,
-	0x3c020800, 0x94421720, 0xa5620004, 0x3c020800, 0x8c421720, 0xa5620006,
-	0x3c020800, 0x8c421fd0, 0x3c070800, 0x8ce71fc4, 0x3c050800, 0x144000c7,
-	0x8ca51fc8, 0x3c020800, 0x94421724, 0x00451821, 0x3063ffff, 0x0062182b,
-	0x24020002, 0x10c2000d, 0x00a32823, 0x3c020800, 0x94421fb6, 0x30420009,
-	0x10400008, 0x00000000, 0x9562000c, 0x3042fff6, 0xa562000c, 0x3c020800,
-	0x94421fb6, 0x30420009, 0x00e23823, 0x3c020800, 0x8c421fd8, 0x1040004b,
-	0x24020002, 0x01003021, 0x3c020800, 0x94421fb2, 0x00003821, 0xa500000a,
-	0x01a21023, 0xa5020002, 0x3082ffff, 0x00021042, 0x18400008, 0x00002821,
-	0x00401821, 0x94c20000, 0x24e70001, 0x00a22821, 0x00e3102a, 0x1440fffb,
-	0x24c60002, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821,
-	0x00a04821, 0x00051027, 0xa502000a, 0x00002821, 0x2506000c, 0x00003821,
-	0x94c20000, 0x24e70001, 0x00a22821, 0x2ce20004, 0x1440fffb, 0x24c60002,
-	0x95020002, 0x00003821, 0x91030009, 0x00442023, 0x01603021, 0x3082ffff,
-	0xa4c00010, 0x00621821, 0x00021042, 0x18400010, 0x00a32821, 0x00404021,
-	0x94c20000, 0x24c60002, 0x00a22821, 0x30c2007f, 0x14400006, 0x24e70001,
-	0x8d430000, 0x3c02007f, 0x3442ff80, 0x00625024, 0x25460008, 0x00e8102a,
-	0x1440fff3, 0x00000000, 0x30820001, 0x10400005, 0x00051c02, 0xa0c00001,
-	0x94c20000, 0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402,
-	0x00a22821, 0x0a000415, 0x30a5ffff, 0x14c20063, 0x00000000, 0x3c090800,
-	0x95291fb2, 0x95030002, 0x01a91023, 0x1062005d, 0x01003021, 0x00003821,
-	0x00002821, 0x01a91023, 0xa5020002, 0x3082ffff, 0x00021042, 0x18400008,
-	0xa500000a, 0x00401821, 0x94c20000, 0x24e70001, 0x00a22821, 0x00e3102a,
-	0x1440fffb, 0x24c60002, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402,
-	0x00a22821, 0x00a04821, 0x00051027, 0xa502000a, 0x00002821, 0x2506000c,
-	0x00003821, 0x94c20000, 0x24e70001, 0x00a22821, 0x2ce20004, 0x1440fffb,
-	0x24c60002, 0x95020002, 0x00003821, 0x91030009, 0x00442023, 0x01603021,
-	0x3082ffff, 0xa4c00010, 0x3c040800, 0x94841fb4, 0x00621821, 0x00a32821,
-	0x00051c02, 0x30a2ffff, 0x00622821, 0x00051c02, 0x3c020800, 0x94421fb0,
-	0x00a34021, 0x00441023, 0x00021fc2, 0x00431021, 0x00021043, 0x18400010,
-	0x00002821, 0x00402021, 0x94c20000, 0x24c60002, 0x00a22821, 0x30c2007f,
-	0x14400006, 0x24e70001, 0x8d430000, 0x3c02007f, 0x3442ff80, 0x00625024,
-	0x25460008, 0x00e4102a, 0x1440fff3, 0x00000000, 0x3c020800, 0x94421fcc,
-	0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821,
-	0x3102ffff, 0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402,
-	0x00a22821, 0x00a02021, 0x00051027, 0xa5620010, 0xad800014, 0x0a000435,
-	0xad800000, 0x8d830010, 0x00602021, 0x10a00007, 0x00034c02, 0x01252821,
-	0x00051402, 0x30a3ffff, 0x00432821, 0x00051402, 0x00a24821, 0x00091027,
-	0xa502000a, 0x3c030800, 0x94631fb4, 0x3082ffff, 0x01a21021, 0x00432823,
-	0x00a72821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821,
-	0x00a02021, 0x00051027, 0xa5620010, 0x3082ffff, 0x00091c00, 0x00431025,
-	0xad820010, 0x3c020800, 0x8c421fd4, 0x10400002, 0x25a2fff2, 0xa5820034,
-	0x3c020800, 0x8c421fc8, 0x3c030800, 0x8c631720, 0x24420001, 0x3c010800,
-	0xac221fc8, 0x3c020800, 0x8c421fc4, 0x31c4ffff, 0x00641821, 0x3c010800,
-	0xac231720, 0x00441021, 0x3c010800, 0xac221fc4, 0x03e00008, 0x27bd0020,
-	0x27bdffc8, 0x3c040800, 0x248416f8, 0xafbf0034, 0xafbe0030, 0xafb7002c,
-	0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014,
-	0xafb00010, 0x90830000, 0x24020003, 0x146200f4, 0x00000000, 0x3c020800,
-	0x8c421710, 0x3c030800, 0x8c63170c, 0x3c1e0800, 0x97de16f6, 0x0043102a,
-	0x104000eb, 0x3c168000, 0x249708c4, 0x33d5ffff, 0x24920018, 0x3c020800,
-	0x8c421718, 0x104000e4, 0x00000000, 0x3c140800, 0x96941fb0, 0x3282ffff,
-	0x104000d6, 0x00008021, 0x00409821, 0x00008821, 0x8f634450, 0x3c020800,
-	0x8c4216e8, 0x00031c02, 0x0043102b, 0x14400008, 0x00000000, 0x3c040800,
-	0x8c8416ec, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc, 0x00000000,
-	0xaf764444, 0x8f624444, 0x00561024, 0x10400006, 0x00000000, 0x3c038000,
-	0x8f624444, 0x00431024, 0x1440fffd, 0x00000000, 0x8f624448, 0x3046ffff,
-	0x10c0005f, 0x00000000, 0x3c090800, 0x01314821, 0x8d291728, 0x9528000a,
-	0x31020040, 0x10400004, 0x2407180c, 0x8d22000c, 0x2407188c, 0xacc20018,
-	0x31021000, 0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825,
-	0x31020080, 0x54400001, 0x34e70010, 0x3c020800, 0x00511021, 0x8c421730,
-	0x3c030800, 0x00711821, 0x8c631734, 0x00021500, 0x00031c00, 0x00431025,
-	0xacc20014, 0x95240008, 0x3202ffff, 0x00821021, 0x0262102a, 0x14400002,
-	0x02902823, 0x00802821, 0x8d220000, 0x02058021, 0xacc20000, 0x8d220004,
-	0x00c02021, 0x26310010, 0xac820004, 0x30e2ffff, 0xac800008, 0xa485000e,
-	0xac820010, 0x24020305, 0x0e000560, 0xa482000c, 0x3202ffff, 0x0053102b,
-	0x1440ffaf, 0x3202ffff, 0x0a00054c, 0x00000000, 0x8e420000, 0x8e43fffc,
-	0x0043102a, 0x10400084, 0x00000000, 0x8e45fff0, 0x8f644450, 0x3c030800,
-	0x8c6316e8, 0x00051100, 0x3c090800, 0x01224821, 0x8d291728, 0x00041402,
-	0x0062182b, 0x14600008, 0x00000000, 0x3c030800, 0x8c6316ec, 0x8f624450,
-	0x00021402, 0x0062102b, 0x1040fffc, 0x00000000, 0xaf764444, 0x8f624444,
-	0x00561024, 0x10400006, 0x00000000, 0x3c038000, 0x8f624444, 0x00431024,
-	0x1440fffd, 0x00000000, 0x8f624448, 0x3046ffff, 0x14c00005, 0x00000000,
-	0x8ee20000, 0x24420001, 0x0a000554, 0xaee20000, 0x9528000a, 0x31020040,
-	0x10400004, 0x2407180c, 0x8d22000c, 0x2407188c, 0xacc20018, 0x31021000,
-	0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, 0x00051900,
-	0x3c020800, 0x00431021, 0x8c421730, 0x3c010800, 0x00230821, 0x8c231734,
-	0x00021500, 0x00031c00, 0x00431025, 0xacc20014, 0x3c030800, 0x8c631704,
-	0x95220008, 0x00432023, 0x3202ffff, 0x3083ffff, 0x00431021, 0x02a2102a,
-	0x14400002, 0x03d02823, 0x00802821, 0x8e420000, 0x30a4ffff, 0x00441021,
-	0xae420000, 0xa4c5000e, 0x8d220000, 0xacc20000, 0x8d220004, 0x8e43fff4,
-	0x00431021, 0xacc20004, 0x8e43fff4, 0x95220008, 0x00641821, 0x0062102a,
-	0x14400006, 0x02058021, 0x8e42fff0, 0xae40fff4, 0x24420001, 0x0a000530,
-	0xae42fff0, 0xae43fff4, 0xacc00008, 0x3202ffff, 0x10550003, 0x31020004,
-	0x10400006, 0x24020305, 0x31020080, 0x54400001, 0x34e70010, 0x34e70020,
-	0x24020905, 0xa4c2000c, 0x30e2ffff, 0xacc20010, 0x3c030800, 0x8c63170c,
-	0x3c020800, 0x8c421710, 0x54620004, 0x3c02b49a, 0x3c024b65, 0x0a000548,
-	0x34427654, 0x344289ab, 0xacc2001c, 0x0e000560, 0x00c02021, 0x3202ffff,
-	0x0055102b, 0x1440ff7e, 0x00000000, 0x8e420000, 0x8e43fffc, 0x0043102a,
-	0x1440ff1a, 0x00000000, 0x8fbf0034, 0x8fbe0030, 0x8fb7002c, 0x8fb60028,
-	0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
-	0x03e00008, 0x27bd0038, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f624450,
-	0x8f634410, 0x0a00056f, 0x00808021, 0x8f626820, 0x30422000, 0x10400003,
-	0x00000000, 0x0e00025a, 0x00002021, 0x8f624450, 0x8f634410, 0x3042ffff,
-	0x0043102b, 0x1440fff5, 0x00000000, 0x8f630c14, 0x3063000f, 0x2c620002,
-	0x1440000b, 0x00000000, 0x8f630c14, 0x3c020800, 0x8c4216b4, 0x3063000f,
-	0x24420001, 0x3c010800, 0xac2216b4, 0x2c620002, 0x1040fff7, 0x00000000,
-	0xaf705c18, 0x8f625c10, 0x30420002, 0x10400009, 0x00000000, 0x8f626820,
-	0x30422000, 0x1040fff8, 0x00000000, 0x0e00025a, 0x00002021, 0x0a000582,
-	0x00000000, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x00000000,
-	0x00000000
+	0x0e0004b9, 0x00000000, 0x8fbf0028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+	0x8fb00018, 0x03e00008, 0x27bd0030, 0x8f634450, 0x3c040800, 0x24841b98,
+	0x8c820000, 0x00031c02, 0x0043102b, 0x14400007, 0x3c038000, 0x8c840004,
+	0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc, 0x3c038000, 0xaf634444,
+	0x8f624444, 0x00431024, 0x1440fffd, 0x00000000, 0x8f624448, 0x03e00008,
+	0x3042ffff, 0x3c024000, 0x00822025, 0xaf645c38, 0x8f625c30, 0x30420002,
+	0x1440fffc, 0x00000000, 0x03e00008, 0x00000000, 0x27bdffe0, 0x00805821,
+	0x14c00017, 0x256e0008, 0x3c020800, 0x8c422404, 0x1040000a, 0x2402003e,
+	0x3c010800, 0xa42223e0, 0x24020016, 0x3c010800, 0xa42223e2, 0x2402002a,
+	0x3c010800, 0x0a000360, 0xa42223e4, 0x95620014, 0x3c010800, 0xa42223e0,
+	0x8d670010, 0x00071402, 0x3c010800, 0xa42223e2, 0x3c010800, 0xa42723e4,
+	0x3c040800, 0x948423e4, 0x3c030800, 0x946323e2, 0x95cf0006, 0x3c020800,
+	0x944223e0, 0x00832023, 0x01e2c023, 0x3065ffff, 0x24a20028, 0x01c24821,
+	0x3082ffff, 0x14c0001a, 0x01226021, 0x9582000c, 0x3042003f, 0x3c010800,
+	0xa42223e6, 0x95820004, 0x95830006, 0x3c010800, 0xac2023f4, 0x3c010800,
+	0xac2023f8, 0x00021400, 0x00431025, 0x3c010800, 0xac221bd0, 0x95220004,
+	0x3c010800, 0xa4221bd4, 0x95230002, 0x01e51023, 0x0043102a, 0x10400010,
+	0x24020001, 0x3c010800, 0x0a000394, 0xac222408, 0x3c030800, 0x8c6323f8,
+	0x3c020800, 0x94421bd4, 0x00431021, 0xa5220004, 0x3c020800, 0x94421bd0,
+	0xa5820004, 0x3c020800, 0x8c421bd0, 0xa5820006, 0x3c020800, 0x8c422400,
+	0x3c0d0800, 0x8dad23f4, 0x3c0a0800, 0x144000e5, 0x8d4a23f8, 0x3c020800,
+	0x94421bd4, 0x004a1821, 0x3063ffff, 0x0062182b, 0x24020002, 0x10c2000d,
+	0x01435023, 0x3c020800, 0x944223e6, 0x30420009, 0x10400008, 0x00000000,
+	0x9582000c, 0x3042fff6, 0xa582000c, 0x3c020800, 0x944223e6, 0x30420009,
+	0x01a26823, 0x3c020800, 0x8c422408, 0x1040004a, 0x01203821, 0x3c020800,
+	0x944223e2, 0x00004021, 0xa520000a, 0x01e21023, 0xa5220002, 0x3082ffff,
+	0x00021042, 0x18400008, 0x00003021, 0x00401821, 0x94e20000, 0x25080001,
+	0x00c23021, 0x0103102a, 0x1440fffb, 0x24e70002, 0x00061c02, 0x30c2ffff,
+	0x00623021, 0x00061402, 0x00c23021, 0x00c02821, 0x00061027, 0xa522000a,
+	0x00003021, 0x2527000c, 0x00004021, 0x94e20000, 0x25080001, 0x00c23021,
+	0x2d020004, 0x1440fffb, 0x24e70002, 0x95220002, 0x00004021, 0x91230009,
+	0x00442023, 0x01803821, 0x3082ffff, 0xa4e00010, 0x00621821, 0x00021042,
+	0x18400010, 0x00c33021, 0x00404821, 0x94e20000, 0x24e70002, 0x00c23021,
+	0x30e2007f, 0x14400006, 0x25080001, 0x8d630000, 0x3c02007f, 0x3442ff80,
+	0x00625824, 0x25670008, 0x0109102a, 0x1440fff3, 0x00000000, 0x30820001,
+	0x10400005, 0x00061c02, 0xa0e00001, 0x94e20000, 0x00c23021, 0x00061c02,
+	0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x0a000479, 0x30c6ffff,
+	0x24020002, 0x14c20081, 0x00000000, 0x3c020800, 0x8c42241c, 0x14400007,
+	0x00000000, 0x3c020800, 0x944223e2, 0x95230002, 0x01e21023, 0x10620077,
+	0x00000000, 0x3c020800, 0x944223e2, 0x01e21023, 0xa5220002, 0x3c020800,
+	0x8c42241c, 0x1040001a, 0x31e3ffff, 0x8dc70010, 0x3c020800, 0x94421ba6,
+	0x00e04021, 0x00072c02, 0x00aa2021, 0x00431023, 0x00823823, 0x00072402,
+	0x30e2ffff, 0x00823821, 0x00071027, 0xa522000a, 0x3102ffff, 0x3c040800,
+	0x948423e4, 0x00453023, 0x00e02821, 0x00641823, 0x006d1821, 0x00c33021,
+	0x00061c02, 0x30c2ffff, 0x0a000479, 0x00623021, 0x01203821, 0x00004021,
+	0x3082ffff, 0x00021042, 0x18400008, 0x00003021, 0x00401821, 0x94e20000,
+	0x25080001, 0x00c23021, 0x0103102a, 0x1440fffb, 0x24e70002, 0x00061c02,
+	0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x00c02821, 0x00061027,
+	0xa522000a, 0x00003021, 0x2527000c, 0x00004021, 0x94e20000, 0x25080001,
+	0x00c23021, 0x2d020004, 0x1440fffb, 0x24e70002, 0x95220002, 0x00004021,
+	0x91230009, 0x00442023, 0x01803821, 0x3082ffff, 0xa4e00010, 0x3c040800,
+	0x948423e4, 0x00621821, 0x00c33021, 0x00061c02, 0x30c2ffff, 0x00623021,
+	0x00061c02, 0x3c020800, 0x944223e0, 0x00c34821, 0x00441023, 0x00021fc2,
+	0x00431021, 0x00021043, 0x18400010, 0x00003021, 0x00402021, 0x94e20000,
+	0x24e70002, 0x00c23021, 0x30e2007f, 0x14400006, 0x25080001, 0x8d630000,
+	0x3c02007f, 0x3442ff80, 0x00625824, 0x25670008, 0x0104102a, 0x1440fff3,
+	0x00000000, 0x3c020800, 0x944223fc, 0x00c23021, 0x3122ffff, 0x00c23021,
+	0x00061c02, 0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x00c04021,
+	0x00061027, 0xa5820010, 0xadc00014, 0x0a000499, 0xadc00000, 0x8dc70010,
+	0x00e04021, 0x11400007, 0x00072c02, 0x00aa3021, 0x00061402, 0x30c3ffff,
+	0x00433021, 0x00061402, 0x00c22821, 0x00051027, 0xa522000a, 0x3c030800,
+	0x946323e4, 0x3102ffff, 0x01e21021, 0x00433023, 0x00cd3021, 0x00061c02,
+	0x30c2ffff, 0x00623021, 0x00061402, 0x00c23021, 0x00c04021, 0x00061027,
+	0xa5820010, 0x3102ffff, 0x00051c00, 0x00431025, 0xadc20010, 0x3c020800,
+	0x8c422404, 0x10400002, 0x25e2fff2, 0xa5c20034, 0x3c020800, 0x8c4223f8,
+	0x3c040800, 0x8c8423f4, 0x24420001, 0x3c010800, 0xac2223f8, 0x3c020800,
+	0x8c421bd0, 0x3303ffff, 0x00832021, 0x3c010800, 0xac2423f4, 0x00431821,
+	0x0062102b, 0x10400003, 0x2482ffff, 0x3c010800, 0xac2223f4, 0x3c010800,
+	0xac231bd0, 0x03e00008, 0x27bd0020, 0x27bdffb8, 0x3c050800, 0x24a51ba8,
+	0xafbf0044, 0xafbe0040, 0xafb7003c, 0xafb60038, 0xafb50034, 0xafb40030,
+	0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, 0x90a30000, 0x24020003,
+	0x146200d5, 0x00000000, 0x3c090800, 0x95291ba6, 0x3c020800, 0x944223e0,
+	0x3c030800, 0x8c631bc0, 0x3c040800, 0x8c841bbc, 0x01221023, 0x0064182a,
+	0xa7a9001e, 0x106000c8, 0xa7a20016, 0x24be0020, 0x97b6001e, 0x24b30018,
+	0x24b70014, 0x8fc20000, 0x14400008, 0x00000000, 0x8fc2fff8, 0x97a30016,
+	0x8fc4fff4, 0x00431021, 0x0082202a, 0x148000ba, 0x00000000, 0x97d50818,
+	0x32a2ffff, 0x104000ad, 0x00009021, 0x0040a021, 0x00008821, 0x0e00062d,
+	0x00000000, 0x00403021, 0x14c00007, 0x00000000, 0x3c020800, 0x8c4223ec,
+	0x24420001, 0x3c010800, 0x0a00059e, 0xac2223ec, 0x3c100800, 0x02118021,
+	0x8e101bd8, 0x9608000a, 0x31020040, 0x10400004, 0x2407180c, 0x8e02000c,
+	0x2407188c, 0xacc20018, 0x31021000, 0x10400004, 0x34e32000, 0x00081040,
+	0x3042c000, 0x00623825, 0x31020080, 0x54400001, 0x34e70010, 0x3c020800,
+	0x00511021, 0x8c421be0, 0x3c030800, 0x00711821, 0x8c631be4, 0x00021500,
+	0x00031c00, 0x00431025, 0xacc20014, 0x96040008, 0x3242ffff, 0x00821021,
+	0x0282102a, 0x14400002, 0x02b22823, 0x00802821, 0x8e020000, 0x02459021,
+	0xacc20000, 0x8e020004, 0x00c02021, 0x26310010, 0xac820004, 0x30e2ffff,
+	0xac800008, 0xa485000e, 0xac820010, 0x24020305, 0x0e0005aa, 0xa482000c,
+	0x3242ffff, 0x0054102b, 0x1440ffc0, 0x3242ffff, 0x0a000596, 0x00000000,
+	0x8e620000, 0x8e63fffc, 0x0043102a, 0x1040006c, 0x00000000, 0x8e62fff0,
+	0x00028900, 0x3c100800, 0x02118021, 0x0e00062d, 0x8e101bd8, 0x00403021,
+	0x14c00005, 0x00000000, 0x8e62082c, 0x24420001, 0x0a00059e, 0xae62082c,
+	0x9608000a, 0x31020040, 0x10400004, 0x2407180c, 0x8e02000c, 0x2407188c,
+	0xacc20018, 0x31021000, 0x10400004, 0x34e32000, 0x00081040, 0x3042c000,
+	0x00623825, 0x3c020800, 0x00511021, 0x8c421be0, 0x3c030800, 0x00711821,
+	0x8c631be4, 0x00021500, 0x00031c00, 0x00431025, 0xacc20014, 0x8e63fff4,
+	0x96020008, 0x00432023, 0x3242ffff, 0x3083ffff, 0x00431021, 0x02c2102a,
+	0x10400003, 0x00802821, 0x97a9001e, 0x01322823, 0x8e620000, 0x30a4ffff,
+	0x00441021, 0xae620000, 0xa4c5000e, 0x8e020000, 0xacc20000, 0x8e020004,
+	0x8e63fff4, 0x00431021, 0xacc20004, 0x8e63fff4, 0x96020008, 0x00641821,
+	0x0062102a, 0x14400006, 0x02459021, 0x8e62fff0, 0xae60fff4, 0x24420001,
+	0x0a000579, 0xae62fff0, 0xae63fff4, 0xacc00008, 0x3242ffff, 0x10560003,
+	0x31020004, 0x10400006, 0x24020305, 0x31020080, 0x54400001, 0x34e70010,
+	0x34e70020, 0x24020905, 0xa4c2000c, 0x8ee30000, 0x8ee20004, 0x14620007,
+	0x3c02b49a, 0x8ee20860, 0x54400001, 0x34e70400, 0x3c024b65, 0x0a000590,
+	0x34427654, 0x344289ab, 0xacc2001c, 0x30e2ffff, 0xacc20010, 0x0e0005aa,
+	0x00c02021, 0x3242ffff, 0x0056102b, 0x1440ff96, 0x00000000, 0x8e620000,
+	0x8e63fffc, 0x0043102a, 0x1440ff3e, 0x00000000, 0x8fbf0044, 0x8fbe0040,
+	0x8fb7003c, 0x8fb60038, 0x8fb50034, 0x8fb40030, 0x8fb3002c, 0x8fb20028,
+	0x8fb10024, 0x8fb00020, 0x03e00008, 0x27bd0048, 0x27bdffe8, 0xafbf0014,
+	0xafb00010, 0x8f624450, 0x8f634410, 0x0a0005b9, 0x00808021, 0x8f626820,
+	0x30422000, 0x10400003, 0x00000000, 0x0e0001e3, 0x00002021, 0x8f624450,
+	0x8f634410, 0x3042ffff, 0x0043102b, 0x1440fff5, 0x00000000, 0x8f630c14,
+	0x3063000f, 0x2c620002, 0x1440000b, 0x00000000, 0x8f630c14, 0x3c020800,
+	0x8c421b50, 0x3063000f, 0x24420001, 0x3c010800, 0xac221b50, 0x2c620002,
+	0x1040fff7, 0x00000000, 0xaf705c18, 0x8f625c10, 0x30420002, 0x10400009,
+	0x00000000, 0x8f626820, 0x30422000, 0x1040fff8, 0x00000000, 0x0e0001e3,
+	0x00002021, 0x0a0005cc, 0x00000000, 0x8fbf0014, 0x8fb00010, 0x03e00008,
+	0x27bd0018, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe8, 0x3c1bc000,
+	0xafbf0014, 0xafb00010, 0xaf60680c, 0x8f626804, 0x34420082, 0xaf626804,
+	0x8f634000, 0x24020b50, 0x3c010800, 0xac221b64, 0x24020b78, 0x3c010800,
+	0xac221b74, 0x34630002, 0xaf634000, 0x0e00060d, 0x00808021, 0x3c010800,
+	0xa0221b78, 0x304200ff, 0x24030002, 0x14430005, 0x00000000, 0x3c020800,
+	0x8c421b64, 0x0a000600, 0xac5000c0, 0x3c020800, 0x8c421b64, 0xac5000bc,
+	0x8f624434, 0x8f634438, 0x8f644410, 0x3c010800, 0xac221b6c, 0x3c010800,
+	0xac231b7c, 0x3c010800, 0xac241b68, 0x8fbf0014, 0x8fb00010, 0x03e00008,
+	0x27bd0018, 0x3c040800, 0x8c870000, 0x3c03aa55, 0x3463aa55, 0x3c06c003,
+	0xac830000, 0x8cc20000, 0x14430007, 0x24050002, 0x3c0355aa, 0x346355aa,
+	0xac830000, 0x8cc20000, 0x50430001, 0x24050001, 0x3c020800, 0xac470000,
+	0x03e00008, 0x00a01021, 0x27bdfff8, 0x18800009, 0x00002821, 0x8f63680c,
+	0x8f62680c, 0x1043fffe, 0x00000000, 0x24a50001, 0x00a4102a, 0x1440fff9,
+	0x00000000, 0x03e00008, 0x27bd0008, 0x8f634450, 0x3c020800, 0x8c421b6c,
+	0x00031c02, 0x0043102b, 0x14400008, 0x3c038000, 0x3c040800, 0x8c841b7c,
+	0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc, 0x3c038000, 0xaf634444,
+	0x8f624444, 0x00431024, 0x1440fffd, 0x00000000, 0x8f624448, 0x03e00008,
+	0x3042ffff, 0x3082ffff, 0x2442e000, 0x2c422001, 0x14400003, 0x3c024000,
+	0x0a000650, 0x2402ffff, 0x00822025, 0xaf645c38, 0x8f625c30, 0x30420002,
+	0x1440fffc, 0x00001021, 0x03e00008, 0x00000000, 0x8f624450, 0x3c030800,
+	0x8c631b68, 0x0a000659, 0x3042ffff, 0x8f624450, 0x3042ffff, 0x0043102b,
+	0x1440fffc, 0x00000000, 0x03e00008, 0x00000000, 0x27bdffe0, 0x00802821,
+	0x3c040800, 0x24841b10, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010,
+	0x0e000684, 0xafa00014, 0x0a000668, 0x00000000, 0x8fbf0018, 0x03e00008,
+	0x27bd0020, 0x00000000, 0x00000000, 0x00000000, 0x3c020800, 0x34423000,
+	0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac221b84,
+	0x24020040, 0x3c010800, 0xac221b88, 0x3c010800, 0xac201b80, 0xac600000,
+	0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000,
+	0x00804821, 0x8faa0010, 0x3c020800, 0x8c421b80, 0x3c040800, 0x8c841b88,
+	0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac231b80, 0x14400003,
+	0x00004021, 0x3c010800, 0xac201b80, 0x3c020800, 0x8c421b80, 0x3c030800,
+	0x8c631b84, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001,
+	0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c421b80,
+	0x3c030800, 0x8c631b84, 0x8f64680c, 0x00021140, 0x00431021, 0xac440008,
+	0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c,
+	0x00000000, 0x00000000,
 };
 
 u32 tg3TsoFwRodata[] = {
-	0x4d61696e, 0x43707542, 0x00000000, 0x00000000, 0x74637073, 0x6567496e,
-	0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000
+	0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541,
+	0x00000000, 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64,
+	0x496e0000, 0x73746b6f, 0x66662a2a, 0x00000000, 0x53774576,
+	0x656e7430, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x66617461, 0x6c457272, 0x00000000, 0x00000000, 0x00000000
 };
 
-#if 0 /* All zeros, dont eat up space with it. */
+#if 0 /* All zeros, don't eat up space with it. */
 u32 tg3TsoFwData[] = {
 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
 	0x00000000, 0x00000000, 0x00000000
 };
 #endif
 
+/* 5705 needs a special version of the TSO firmware.  */
+#define TG3_TSO5_FW_RELEASE_MAJOR	0x1
+#define TG3_TSO5_FW_RELASE_MINOR	0x1
+#define TG3_TSO5_FW_RELEASE_FIX		0x0
+#define TG3_TSO5_FW_START_ADDR		0x00010000
+#define TG3_TSO5_FW_TEXT_ADDR		0x00010000
+#define TG3_TSO5_FW_TEXT_LEN		0xeb0
+#define TG3_TSO5_FW_RODATA_ADDR		0x00010eb0
+#define TG3_TSO5_FW_RODATA_LEN		0x50
+#define TG3_TSO5_FW_DATA_ADDR		0x00010f20
+#define TG3_TSO5_FW_DATA_LEN		0x20
+#define TG3_TSO5_FW_SBSS_ADDR		0x00010f40
+#define TG3_TSO5_FW_SBSS_LEN		0x28
+#define TG3_TSO5_FW_BSS_ADDR		0x00010f70
+#define TG3_TSO5_FW_BSS_LEN		0x88
+
+static u32 tg3Tso5FwText[] = {
+	0x0c004003, 0x00000000, 0x00010f30, 0x00000000, 0x10000003, 0x00000000,
+	0x0000000d, 0x0000000d, 0x3c1d0001, 0x37bde000, 0x03a0f021, 0x3c100001,
+	0x26100000, 0x0c004010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe,
+	0xafbf0018, 0x0c0042f0, 0x34840002, 0x0c00436c, 0x00000000, 0x3c030001,
+	0x90630f54, 0x24020002, 0x3c040001, 0x24840ebc, 0x14620003, 0x24050001,
+	0x3c040001, 0x24840eb0, 0x24060001, 0x00003821, 0xafa00010, 0x0c004380,
+	0xafa00014, 0x0c00402c, 0x00000000, 0x8fbf0018, 0x03e00008, 0x27bd0020,
+	0x00000000, 0x00000000, 0x27bdffe0, 0xafbf001c, 0xafb20018, 0xafb10014,
+	0x0c0042d3, 0xafb00010, 0x3c128000, 0x24110001, 0x8f706810, 0x32020400,
+	0x10400007, 0x00000000, 0x8f641008, 0x00921024, 0x14400003, 0x00000000,
+	0x0c004064, 0x00000000, 0x3c020001, 0x90420f76, 0x10510003, 0x32020200,
+	0x1040fff1, 0x00000000, 0x0c0041b4, 0x00000000, 0x08004034, 0x00000000,
+	0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020,
+	0x27bdffe0, 0x3c040001, 0x24840ed0, 0x00002821, 0x00003021, 0x00003821,
+	0xafbf0018, 0xafa00010, 0x0c004380, 0xafa00014, 0x0000d021, 0x24020130,
+	0xaf625000, 0x3c010001, 0xa4200f70, 0x3c010001, 0xa0200f77, 0x8fbf0018,
+	0x03e00008, 0x27bd0020, 0x00000000, 0x00000000, 0x3c030001, 0x24630f80,
+	0x90620000, 0x27bdfff0, 0x14400003, 0x0080c021, 0x08004073, 0x00004821,
+	0x3c022000, 0x03021024, 0x10400003, 0x24090002, 0x08004073, 0xa0600000,
+	0x24090001, 0x00181040, 0x30431f80, 0x346f8008, 0x1520004b, 0x25eb0028,
+	0x3c040001, 0x00832021, 0x8c848010, 0x3c050001, 0x24a50f9a, 0x00041402,
+	0xa0a20000, 0x3c010001, 0xa0240f9b, 0x3c020001, 0x00431021, 0x94428014,
+	0x3c010001, 0xa0220f9c, 0x3c0c0001, 0x01836021, 0x8d8c8018, 0x304200ff,
+	0x24420008, 0x000220c3, 0x24020001, 0x3c010001, 0xa0220f80, 0x0124102b,
+	0x1040000c, 0x00003821, 0x24a6000e, 0x01602821, 0x8ca20000, 0x8ca30004,
+	0x24a50008, 0x24e70001, 0xacc20000, 0xacc30004, 0x00e4102b, 0x1440fff8,
+	0x24c60008, 0x00003821, 0x3c080001, 0x25080f9b, 0x91060000, 0x3c020001,
+	0x90420f9c, 0x2503000d, 0x00c32821, 0x00461023, 0x00021fc2, 0x00431021,
+	0x00021043, 0x1840000c, 0x00002021, 0x91020001, 0x00461023, 0x00021fc2,
+	0x00431021, 0x00021843, 0x94a20000, 0x24e70001, 0x00822021, 0x00e3102a,
+	0x1440fffb, 0x24a50002, 0x00041c02, 0x3082ffff, 0x00622021, 0x00041402,
+	0x00822021, 0x3c02ffff, 0x01821024, 0x3083ffff, 0x00431025, 0x3c010001,
+	0x080040fa, 0xac220fa0, 0x3c050001, 0x24a50f9c, 0x90a20000, 0x3c0c0001,
+	0x01836021, 0x8d8c8018, 0x000220c2, 0x1080000e, 0x00003821, 0x01603021,
+	0x24a5000c, 0x8ca20000, 0x8ca30004, 0x24a50008, 0x24e70001, 0xacc20000,
+	0xacc30004, 0x00e4102b, 0x1440fff8, 0x24c60008, 0x3c050001, 0x24a50f9c,
+	0x90a20000, 0x30430007, 0x24020004, 0x10620011, 0x28620005, 0x10400005,
+	0x24020002, 0x10620008, 0x000710c0, 0x080040fa, 0x00000000, 0x24020006,
+	0x1062000e, 0x000710c0, 0x080040fa, 0x00000000, 0x00a21821, 0x9463000c,
+	0x004b1021, 0x080040fa, 0xa4430000, 0x000710c0, 0x00a21821, 0x8c63000c,
+	0x004b1021, 0x080040fa, 0xac430000, 0x00a21821, 0x8c63000c, 0x004b2021,
+	0x00a21021, 0xac830000, 0x94420010, 0xa4820004, 0x95e70006, 0x3c020001,
+	0x90420f9c, 0x3c030001, 0x90630f9a, 0x00e2c823, 0x3c020001, 0x90420f9b,
+	0x24630028, 0x01e34021, 0x24420028, 0x15200012, 0x01e23021, 0x94c2000c,
+	0x3c010001, 0xa4220f98, 0x94c20004, 0x94c30006, 0x3c010001, 0xa4200f96,
+	0x3c010001, 0xa4200f92, 0x00021400, 0x00431025, 0x3c010001, 0xac220f8c,
+	0x95020004, 0x3c010001, 0x08004124, 0xa4220f90, 0x3c020001, 0x94420f90,
+	0x3c030001, 0x94630f92, 0x00431021, 0xa5020004, 0x3c020001, 0x94420f8c,
+	0xa4c20004, 0x3c020001, 0x8c420f8c, 0xa4c20006, 0x3c040001, 0x94840f92,
+	0x3c020001, 0x94420f90, 0x3c0a0001, 0x954a0f96, 0x00441821, 0x3063ffff,
+	0x0062182a, 0x24020002, 0x1122000b, 0x00832023, 0x3c030001, 0x94630f98,
+	0x30620009, 0x10400006, 0x3062fff6, 0xa4c2000c, 0x3c020001, 0x94420f98,
+	0x30420009, 0x01425023, 0x24020001, 0x1122001b, 0x29220002, 0x50400005,
+	0x24020002, 0x11200007, 0x31a2ffff, 0x08004197, 0x00000000, 0x1122001d,
+	0x24020016, 0x08004197, 0x31a2ffff, 0x3c0e0001, 0x95ce0fa0, 0x10800005,
+	0x01806821, 0x01c42021, 0x00041c02, 0x3082ffff, 0x00627021, 0x000e1027,
+	0xa502000a, 0x3c030001, 0x90630f9b, 0x31a2ffff, 0x00e21021, 0x0800418d,
+	0x00432023, 0x3c020001, 0x94420fa0, 0x00442021, 0x00041c02, 0x3082ffff,
+	0x00622021, 0x00807021, 0x00041027, 0x08004185, 0xa502000a, 0x3c050001,
+	0x24a50f9a, 0x90a30000, 0x14620002, 0x24e2fff2, 0xa5e20034, 0x90a20000,
+	0x00e21023, 0xa5020002, 0x3c030001, 0x94630fa0, 0x3c020001, 0x94420f7a,
+	0x30e5ffff, 0x00641821, 0x00451023, 0x00622023, 0x00041c02, 0x3082ffff,
+	0x00622021, 0x00041027, 0xa502000a, 0x3c030001, 0x90630f9c, 0x24620001,
+	0x14a20005, 0x00807021, 0x01631021, 0x90420000, 0x08004185, 0x00026200,
+	0x24620002, 0x14a20003, 0x306200fe, 0x004b1021, 0x944c0000, 0x3c020001,
+	0x94420fa2, 0x3183ffff, 0x3c040001, 0x90840f9b, 0x00431021, 0x00e21021,
+	0x00442023, 0x008a2021, 0x00041c02, 0x3082ffff, 0x00622021, 0x00041402,
+	0x00822021, 0x00806821, 0x00041027, 0xa4c20010, 0x31a2ffff, 0x000e1c00,
+	0x00431025, 0x3c040001, 0x24840f92, 0xade20010, 0x94820000, 0x3c050001,
+	0x94a50f96, 0x3c030001, 0x8c630f8c, 0x24420001, 0x00b92821, 0xa4820000,
+	0x3322ffff, 0x00622021, 0x0083182b, 0x3c010001, 0xa4250f96, 0x10600003,
+	0x24a2ffff, 0x3c010001, 0xa4220f96, 0x3c024000, 0x03021025, 0x3c010001,
+	0xac240f8c, 0xaf621008, 0x03e00008, 0x27bd0010, 0x3c030001, 0x90630f76,
+	0x27bdffe8, 0x24020001, 0xafbf0014, 0x10620026, 0xafb00010, 0x8f620cf4,
+	0x2442ffff, 0x3042007f, 0x00021100, 0x8c434000, 0x3c010001, 0xac230f84,
+	0x8c434008, 0x24444000, 0x8c5c4004, 0x30620040, 0x14400002, 0x24020088,
+	0x24020008, 0x3c010001, 0xa4220f88, 0x30620004, 0x10400005, 0x24020001,
+	0x3c010001, 0xa0220f77, 0x080041d5, 0x00031402, 0x3c010001, 0xa0200f77,
+	0x00031402, 0x3c010001, 0xa4220f74, 0x9483000c, 0x24020001, 0x3c010001,
+	0xa4200f70, 0x3c010001, 0xa0220f76, 0x3c010001, 0xa4230f82, 0x24020001,
+	0x1342001e, 0x00000000, 0x13400005, 0x24020003, 0x13420067, 0x00000000,
+	0x080042cf, 0x00000000, 0x3c020001, 0x94420f82, 0x241a0001, 0x3c010001,
+	0xa4200f7e, 0x3c010001, 0xa4200f72, 0x304407ff, 0x00021bc2, 0x00031823,
+	0x3063003e, 0x34630036, 0x00021242, 0x3042003c, 0x00621821, 0x3c010001,
+	0xa4240f78, 0x00832021, 0x24630030, 0x3c010001, 0xa4240f7a, 0x3c010001,
+	0xa4230f7c, 0x3c060001, 0x24c60f72, 0x94c50000, 0x94c30002, 0x3c040001,
+	0x94840f7a, 0x00651021, 0x0044102a, 0x10400013, 0x3c108000, 0x00a31021,
+	0xa4c20000, 0x3c02a000, 0xaf620cf4, 0x3c010001, 0xa0200f76, 0x8f641008,
+	0x00901024, 0x14400003, 0x00000000, 0x0c004064, 0x00000000, 0x8f620cf4,
+	0x00501024, 0x104000b7, 0x00000000, 0x0800420f, 0x00000000, 0x3c030001,
+	0x94630f70, 0x00851023, 0xa4c40000, 0x00621821, 0x3042ffff, 0x3c010001,
+	0xa4230f70, 0xaf620ce8, 0x3c020001, 0x94420f88, 0x34420024, 0xaf620cec,
+	0x94c30002, 0x3c020001, 0x94420f70, 0x14620012, 0x3c028000, 0x3c108000,
+	0x3c02a000, 0xaf620cf4, 0x3c010001, 0xa0200f76, 0x8f641008, 0x00901024,
+	0x14400003, 0x00000000, 0x0c004064, 0x00000000, 0x8f620cf4, 0x00501024,
+	0x1440fff7, 0x00000000, 0x080042cf, 0x241a0003, 0xaf620cf4, 0x3c108000,
+	0x8f641008, 0x00901024, 0x14400003, 0x00000000, 0x0c004064, 0x00000000,
+	0x8f620cf4, 0x00501024, 0x1440fff7, 0x00000000, 0x080042cf, 0x241a0003,
+	0x3c070001, 0x24e70f70, 0x94e20000, 0x03821021, 0xaf620ce0, 0x3c020001,
+	0x8c420f84, 0xaf620ce4, 0x3c050001, 0x94a50f74, 0x94e30000, 0x3c040001,
+	0x94840f78, 0x3c020001, 0x94420f7e, 0x00a32823, 0x00822023, 0x30a6ffff,
+	0x3083ffff, 0x00c3102b, 0x14400043, 0x00000000, 0x3c020001, 0x94420f7c,
+	0x00021400, 0x00621025, 0xaf620ce8, 0x94e20000, 0x3c030001, 0x94630f74,
+	0x00441021, 0xa4e20000, 0x3042ffff, 0x14430021, 0x3c020008, 0x3c020001,
+	0x90420f77, 0x10400006, 0x3c03000c, 0x3c020001, 0x94420f88, 0x34630624,
+	0x0800427c, 0x0000d021, 0x3c020001, 0x94420f88, 0x3c030008, 0x34630624,
+	0x00431025, 0xaf620cec, 0x3c108000, 0x3c02a000, 0xaf620cf4, 0x3c010001,
+	0xa0200f76, 0x8f641008, 0x00901024, 0x14400003, 0x00000000, 0x0c004064,
+	0x00000000, 0x8f620cf4, 0x00501024, 0x10400015, 0x00000000, 0x08004283,
+	0x00000000, 0x3c030001, 0x94630f88, 0x34420624, 0x3c108000, 0x00621825,
+	0x3c028000, 0xaf630cec, 0xaf620cf4, 0x8f641008, 0x00901024, 0x14400003,
+	0x00000000, 0x0c004064, 0x00000000, 0x8f620cf4, 0x00501024, 0x1440fff7,
+	0x00000000, 0x3c010001, 0x080042cf, 0xa4200f7e, 0x3c020001, 0x94420f7c,
+	0x00021400, 0x00c21025, 0xaf620ce8, 0x3c020001, 0x90420f77, 0x10400009,
+	0x3c03000c, 0x3c020001, 0x94420f88, 0x34630624, 0x0000d021, 0x00431025,
+	0xaf620cec, 0x080042c1, 0x3c108000, 0x3c020001, 0x94420f88, 0x3c030008,
+	0x34630604, 0x00431025, 0xaf620cec, 0x3c020001, 0x94420f7e, 0x00451021,
+	0x3c010001, 0xa4220f7e, 0x3c108000, 0x3c02a000, 0xaf620cf4, 0x3c010001,
+	0xa0200f76, 0x8f641008, 0x00901024, 0x14400003, 0x00000000, 0x0c004064,
+	0x00000000, 0x8f620cf4, 0x00501024, 0x1440fff7, 0x00000000, 0x8fbf0014,
+	0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffe0, 0x3c040001, 0x24840ee0,
+	0x00002821, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0c004380,
+	0xafa00014, 0x0000d021, 0x24020130, 0xaf625000, 0x3c010001, 0xa4200f70,
+	0x3c010001, 0xa0200f77, 0x8f636804, 0x3c020001, 0x3442e000, 0x00621824,
+	0x3c020001, 0x14620003, 0x00000000, 0x080042eb, 0x00000000, 0x8fbf0018,
+	0x03e00008, 0x27bd0020, 0x27bdffe8, 0x3c1bc000, 0xafbf0014, 0xafb00010,
+	0xaf60680c, 0x8f626804, 0x34420082, 0xaf626804, 0x8f634000, 0x24020b50,
+	0x3c010001, 0xac220f40, 0x24020b78, 0x3c010001, 0xac220f50, 0x34630002,
+	0xaf634000, 0x0c00431d, 0x00808021, 0x3c010001, 0xa0220f54, 0x304200ff,
+	0x24030002, 0x14430005, 0x00000000, 0x3c020001, 0x8c420f40, 0x08004310,
+	0xac5000c0, 0x3c020001, 0x8c420f40, 0xac5000bc, 0x8f624434, 0x8f634438,
+	0x8f644410, 0x3c010001, 0xac220f48, 0x3c010001, 0xac230f58, 0x3c010001,
+	0xac240f44, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x03e00008,
+	0x24020001, 0x27bdfff8, 0x18800009, 0x00002821, 0x8f63680c, 0x8f62680c,
+	0x1043fffe, 0x00000000, 0x24a50001, 0x00a4102a, 0x1440fff9, 0x00000000,
+	0x03e00008, 0x27bd0008, 0x8f634450, 0x3c020001, 0x8c420f48, 0x00031c02,
+	0x0043102b, 0x14400008, 0x3c038000, 0x3c040001, 0x8c840f58, 0x8f624450,
+	0x00021c02, 0x0083102b, 0x1040fffc, 0x3c038000, 0xaf634444, 0x8f624444,
+	0x00431024, 0x1440fffd, 0x00000000, 0x8f624448, 0x03e00008, 0x3042ffff,
+	0x3082ffff, 0x2442e000, 0x2c422001, 0x14400003, 0x3c024000, 0x0800434f,
+	0x2402ffff, 0x00822025, 0xaf645c38, 0x8f625c30, 0x30420002, 0x1440fffc,
+	0x00001021, 0x03e00008, 0x00000000, 0x8f624450, 0x3c030001, 0x8c630f44,
+	0x08004358, 0x3042ffff, 0x8f624450, 0x3042ffff, 0x0043102b, 0x1440fffc,
+	0x00000000, 0x03e00008, 0x00000000, 0x27bdffe0, 0x00802821, 0x3c040001,
+	0x24840ef0, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0c004380,
+	0xafa00014, 0x08004367, 0x00000000, 0x8fbf0018, 0x03e00008, 0x27bd0020,
+	0x3c020001, 0x3442d600, 0x3c030001, 0x3463d600, 0x3c040001, 0x3484ddff,
+	0x3c010001, 0xac220f60, 0x24020040, 0x3c010001, 0xac220f64, 0x3c010001,
+	0xac200f5c, 0xac600000, 0x24630004, 0x0083102b, 0x5040fffd, 0xac600000,
+	0x03e00008, 0x00000000, 0x00804821, 0x8faa0010, 0x3c020001, 0x8c420f5c,
+	0x3c040001, 0x8c840f64, 0x8fab0014, 0x24430001, 0x0044102b, 0x3c010001,
+	0xac230f5c, 0x14400003, 0x00004021, 0x3c010001, 0xac200f5c, 0x3c020001,
+	0x8c420f5c, 0x3c030001, 0x8c630f60, 0x91240000, 0x00021140, 0x00431021,
+	0x00481021, 0x25080001, 0xa0440000, 0x29020008, 0x1440fff4, 0x25290001,
+	0x3c020001, 0x8c420f5c, 0x3c030001, 0x8c630f60, 0x8f64680c, 0x00021140,
+	0x00431021, 0xac440008, 0xac45000c, 0xac460010, 0xac470014, 0xac4a0018,
+	0x03e00008, 0xac4b001c, 0x00000000, 0x00000000,
+};
+
+u32 tg3Tso5FwRodata[] = {
+	0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
+	0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000,
+	0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
+	0x00000000, 0x00000000, 0x00000000
+};
+
+u32 tg3Tso5FwData[] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x73746b6f, 
+	0x66666c64, 0x5f76312e, 0x312e3000, 0x00000000
+};
+
 /* tp->lock is held. */
 static int tg3_load_tso_firmware(struct tg3 *tp)
 {
 	struct fw_info info;
+	unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
 	int err, i;
 
-	info.text_base = TG3_TSO_FW_TEXT_ADDR;
-	info.text_len = TG3_TSO_FW_TEXT_LEN;
-	info.text_data = &tg3TsoFwText[0];
-	info.rodata_base = TG3_TSO_FW_RODATA_ADDR;
-	info.rodata_len = TG3_TSO_FW_RODATA_LEN;
-	info.rodata_data = &tg3TsoFwRodata[0];
-	info.data_base = TG3_TSO_FW_DATA_ADDR;
-	info.data_len = TG3_TSO_FW_DATA_LEN;
-	info.data_data = NULL;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		info.text_base = TG3_TSO5_FW_TEXT_ADDR;
+		info.text_len = TG3_TSO5_FW_TEXT_LEN;
+		info.text_data = &tg3Tso5FwText[0];
+		info.rodata_base = TG3_TSO5_FW_RODATA_ADDR;
+		info.rodata_len = TG3_TSO5_FW_RODATA_LEN;
+		info.rodata_data = &tg3Tso5FwRodata[0];
+		info.data_base = TG3_TSO5_FW_DATA_ADDR;
+		info.data_len = TG3_TSO5_FW_DATA_LEN;
+		info.data_data = &tg3Tso5FwData[0];
+		cpu_base = RX_CPU_BASE;
+		cpu_scratch_base = NIC_SRAM_MBUF_POOL_BASE5705;
+		cpu_scratch_size = (info.text_len +
+				    info.rodata_len +
+				    info.data_len +
+				    TG3_TSO5_FW_SBSS_LEN +
+				    TG3_TSO5_FW_BSS_LEN);
+	} else {
+		info.text_base = TG3_TSO_FW_TEXT_ADDR;
+		info.text_len = TG3_TSO_FW_TEXT_LEN;
+		info.text_data = &tg3TsoFwText[0];
+		info.rodata_base = TG3_TSO_FW_RODATA_ADDR;
+		info.rodata_len = TG3_TSO_FW_RODATA_LEN;
+		info.rodata_data = &tg3TsoFwRodata[0];
+		info.data_base = TG3_TSO_FW_DATA_ADDR;
+		info.data_len = TG3_TSO_FW_DATA_LEN;
+		info.data_data = NULL;
+		cpu_base = TX_CPU_BASE;
+		cpu_scratch_base = TX_CPU_SCRATCH_BASE;
+		cpu_scratch_size = TX_CPU_SCRATCH_SIZE;
+	}
 
-	err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
-				    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
+	err = tg3_load_firmware_cpu(tp, cpu_base,
+				    cpu_scratch_base, cpu_scratch_size,
 				    &info);
 	if (err)
 		return err;
 
-	/* Now startup only the TX cpu. */
-	tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff);
-	tw32(TX_CPU_BASE + CPU_PC,    TG3_TSO_FW_TEXT_ADDR);
+	/* Now startup the cpu. */
+	tw32(cpu_base + CPU_STATE, 0xffffffff);
+	tw32(cpu_base + CPU_PC,    info.text_base);
 
 	/* Flush posted writes. */
-	tr32(TX_CPU_BASE + CPU_PC);
+	tr32(cpu_base + CPU_PC);
 	for (i = 0; i < 5; i++) {
-		if (tr32(TX_CPU_BASE + CPU_PC) == TG3_TSO_FW_TEXT_ADDR)
+		if (tr32(cpu_base + CPU_PC) == info.text_base)
 			break;
-		tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff);
-		tw32(TX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
-		tw32(TX_CPU_BASE + CPU_PC,    TG3_TSO_FW_TEXT_ADDR);
+		tw32(cpu_base + CPU_STATE, 0xffffffff);
+		tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
+		tw32(cpu_base + CPU_PC,    info.text_base);
 
 		/* Flush posted writes. */
-		tr32(TX_CPU_BASE + CPU_PC);
+		tr32(cpu_base + CPU_PC);
 
 		udelay(1000);
 	}
 	if (i >= 5) {
 		printk(KERN_ERR PFX "tg3_load_tso_firmware fails for %s "
-		       "to set TX CPU PC, is %08x should be %08x\n",
-		       tp->dev->name, tr32(TX_CPU_BASE + CPU_PC),
-		       TG3_TSO_FW_TEXT_ADDR);
+		       "to set CPU PC, is %08x should be %08x\n",
+		       tp->dev->name, tr32(cpu_base + CPU_PC),
+		       info.text_base);
 		return -ENODEV;
 	}
-	tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff);
-	tw32(TX_CPU_BASE + CPU_MODE,  0x00000000);
+	tw32(cpu_base + CPU_STATE, 0xffffffff);
+	tw32(cpu_base + CPU_MODE,  0x00000000);
 
 	/* Flush posted writes. */
-	tr32(TX_CPU_BASE + CPU_MODE);
+	tr32(cpu_base + CPU_MODE);
 
 	return 0;
 }
 
-#endif /* TG3_DO_TSO != 0 */
+#endif /* TG3_TSO_SUPPORT != 0 */
 
 /* tp->lock is held. */
 static void __tg3_set_mac_addr(struct tg3 *tp)
@@ -3815,6 +4495,15 @@
 		tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
 	}
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		for (i = 0; i < 12; i++) {
+			tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
+			tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
+		}
+	}
+
 	addr_high = (tp->dev->dev_addr[0] +
 		     tp->dev->dev_addr[1] +
 		     tp->dev->dev_addr[2] +
@@ -3848,23 +4537,19 @@
 			   u32 nic_addr)
 {
 	tg3_write_mem(tp,
-		      (bdinfo_addr +
-		       TG3_BDINFO_HOST_ADDR +
-		       TG3_64BIT_REG_HIGH),
+		      (bdinfo_addr + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH),
 		      ((u64) mapping >> 32));
 	tg3_write_mem(tp,
-		      (bdinfo_addr +
-		       TG3_BDINFO_HOST_ADDR +
-		       TG3_64BIT_REG_LOW),
+		      (bdinfo_addr + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW),
 		      ((u64) mapping & 0xffffffff));
 	tg3_write_mem(tp,
-		      (bdinfo_addr +
-		       TG3_BDINFO_MAXLEN_FLAGS),
+		      (bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS),
 		       maxlen_flags);
-	tg3_write_mem(tp,
-		      (bdinfo_addr +
-		       TG3_BDINFO_NIC_ADDR),
-		      nic_addr);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)
+		tg3_write_mem(tp,
+			      (bdinfo_addr + TG3_BDINFO_NIC_ADDR),
+			      nic_addr);
 }
 
 static void __tg3_set_rx_mode(struct net_device *);
@@ -3872,8 +4557,8 @@
 /* tp->lock is held. */
 static int tg3_reset_hw(struct tg3 *tp)
 {
-	u32 val;
-	int i, err;
+	u32 val, rdmac_mode;
+	int i, err, limit;
 
 	tg3_disable_ints(tp);
 
@@ -3906,7 +4591,8 @@
 			break;
 		udelay(10);
 	}
-	if (i >= 100000) {
+	if (i >= 100000 &&
+	    !(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
 		printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, "
 		       "firmware will not restart magic=%08x\n",
 		       tp->dev->name, val);
@@ -3924,9 +4610,8 @@
 	 * B3 tigon3 silicon.  This bit has no effect on any
 	 * other revision.
 	 */
-	val = tr32(TG3PCI_CLOCK_CTRL);
-	val |= CLOCK_CTRL_DELAY_PCI_GRANT;
-	tw32(TG3PCI_CLOCK_CTRL, val);
+	tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
+	tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
 	tr32(TG3PCI_CLOCK_CTRL);
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
@@ -3936,12 +4621,21 @@
 		tw32(TG3PCI_PCISTATE, val);
 	}
 
+	/* Descriptor ring init may make accesses to the
+	 * NIC SRAM area to setup the TX descriptors, so we
+	 * can only do this after the hardware has been
+	 * successfully reset.
+	 */
+	tg3_init_rings(tp);
+
 	/* Clear statistics/status block in chip, and status block in ram. */
-	for (i = NIC_SRAM_STATS_BLK;
-	     i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
-	     i += sizeof(u32)) {
-		tg3_write_mem(tp, i, 0);
-		udelay(40);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		for (i = NIC_SRAM_STATS_BLK;
+	     	     i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
+	     	     i += sizeof(u32)) {
+			tg3_write_mem(tp, i, 0);
+			udelay(40);
+		}
 	}
 	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
 
@@ -3972,13 +4666,31 @@
 	     (65 << GRC_MISC_CFG_PRESCALAR_SHIFT));
 
 	/* Initialize MBUF/DESC pool. */
-	tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
-		tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
-	else
-		tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
-	tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
-	tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
+		else
+			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
+		tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
+		tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
+	}
+#if TG3_TSO_SUPPORT != 0
+	else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
+		int fw_len;
+
+		fw_len = (TG3_TSO5_FW_TEXT_LEN +
+			  TG3_TSO5_FW_RODATA_LEN +
+			  TG3_TSO5_FW_DATA_LEN +
+			  TG3_TSO5_FW_SBSS_LEN +
+			  TG3_TSO5_FW_BSS_LEN);
+		fw_len = (fw_len + (0x80 - 1)) & ~(0x80 - 1);
+		tw32(BUFMGR_MB_POOL_ADDR,
+		     NIC_SRAM_MBUF_POOL_BASE5705 + fw_len);
+		tw32(BUFMGR_MB_POOL_SIZE,
+		     NIC_SRAM_MBUF_POOL_SIZE5705 - fw_len - 0xa00);
+	}
+#endif
 
 	if (!(tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)) {
 		tw32(BUFMGR_MB_RDMA_LOW_WATER,
@@ -4025,6 +4737,9 @@
 		return -ENODEV;
 	}
 
+	/* Setup replenish threshold. */
+	tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8);
+
 	/* Initialize TG3_BDINFO's at:
 	 *  RCVDBDI_STD_BD:	standard eth size rx ring
 	 *  RCVDBDI_JUMBO_BD:	jumbo frame rx ring
@@ -4046,35 +4761,50 @@
 	     ((u64) tp->rx_std_mapping >> 32));
 	tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
 	     ((u64) tp->rx_std_mapping & 0xffffffff));
-	tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS,
-	     RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
 	tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
 	     NIC_SRAM_RX_BUFFER_DESC);
 
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
-	     BDINFO_FLAGS_DISABLED);
-
-	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
-		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
-		     ((u64) tp->rx_jumbo_mapping >> 32));
-		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
-		     ((u64) tp->rx_jumbo_mapping & 0xffffffff));
-		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
-		     RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
-		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
-		     NIC_SRAM_RX_JUMBO_BUFFER_DESC);
+	/* Don't even try to program the JUMBO/MINI buffer descriptor
+	 * configs on 5705.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS,
+		     RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT);
 	} else {
-		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
+		tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS,
+		     RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
+
+		tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
 		     BDINFO_FLAGS_DISABLED);
-	}
 
-	/* Setup replenish thresholds. */
-	tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8);
-	tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8);
+		/* Setup replenish threshold. */
+		tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8);
 
-	/* Clear out send RCB ring in SRAM. */
-	for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE)
-		tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED);
+		if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
+			tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
+			     ((u64) tp->rx_jumbo_mapping >> 32));
+			tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
+			     ((u64) tp->rx_jumbo_mapping & 0xffffffff));
+			tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
+			     RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
+			tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
+			     NIC_SRAM_RX_JUMBO_BUFFER_DESC);
+		} else {
+			tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
+			     BDINFO_FLAGS_DISABLED);
+		}
+
+	}
+
+	/* There is only one send ring on 5705, no need to explicitly
+	 * disable the others.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		/* Clear out send RCB ring in SRAM. */
+		for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE)
+			tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS,
+				      BDINFO_FLAGS_DISABLED);
+	}
 
 	tp->tx_prod = 0;
 	tp->tx_cons = 0;
@@ -4096,9 +4826,15 @@
 			       NIC_SRAM_TX_BUFFER_DESC);
 	}
 
-	for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK; i += TG3_BDINFO_SIZE) {
-		tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS,
-			      BDINFO_FLAGS_DISABLED);
+	/* There is only one receive return ring on 5705, no need to explicitly
+	 * disable the others.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK;
+		     i += TG3_BDINFO_SIZE) {
+			tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS,
+				      BDINFO_FLAGS_DISABLED);
+		}
 	}
 
 	tp->rx_rcb_ptr = 0;
@@ -4108,7 +4844,7 @@
 
 	tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB,
 		       tp->rx_rcb_mapping,
-		       (TG3_RX_RCB_RING_SIZE <<
+		       (TG3_RX_RCB_RING_SIZE(tp) <<
 			BDINFO_FLAGS_MAXLEN_SHIFT),
 		       0);
 
@@ -4145,8 +4881,36 @@
 	tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS);
 	tw32(RCVLPC_CONFIG, 0x0181);
 
+	/* Calculate RDMAC_MODE setting early, we need it to determine
+	 * the RCVLPC_STATE_ENABLE mask.
+	 */
+	rdmac_mode = (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
+		      RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
+		      RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
+		      RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
+		      RDMAC_MODE_LNGREAD_ENAB);
+	if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
+		rdmac_mode |= RDMAC_MODE_SPLIT_ENABLE;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		if (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
+			if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
+				rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128;
+			} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
+				   !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
+				rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
+			}
+		}
+	}
+
 	/* Receive/send statistics. */
-	tw32(RCVLPC_STATS_ENABLE, 0xffffff);
+	if ((rdmac_mode & RDMAC_MODE_FIFO_SIZE_128) &&
+	    (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
+		val = tr32(RCVLPC_STATS_ENABLE);
+		val &= ~RCVLPC_STATSENAB_LNGBRST_RFIX;
+		tw32(RCVLPC_STATS_ENABLE, val);
+	} else {
+		tw32(RCVLPC_STATS_ENABLE, 0xffffff);
+	}
 	tw32(RCVLPC_STATSCTRL, RCVLPC_STATSCTRL_ENABLE);
 	tw32(SNDDATAI_STATSENAB, 0xffffff);
 	tw32(SNDDATAI_STATSCTRL,
@@ -4162,33 +4926,43 @@
 	}
 
 	tw32(HOSTCC_RXCOL_TICKS, 0);
-	tw32(HOSTCC_RXMAX_FRAMES, 1);
-	tw32(HOSTCC_RXCOAL_TICK_INT, 0);
-	tw32(HOSTCC_RXCOAL_MAXF_INT, 1);
 	tw32(HOSTCC_TXCOL_TICKS, LOW_TXCOL_TICKS);
+	tw32(HOSTCC_RXMAX_FRAMES, 1);
 	tw32(HOSTCC_TXMAX_FRAMES, LOW_RXMAX_FRAMES);
-	tw32(HOSTCC_TXCOAL_TICK_INT, 0);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)
+		tw32(HOSTCC_RXCOAL_TICK_INT, 0);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)
+		tw32(HOSTCC_TXCOAL_TICK_INT, 0);
+	tw32(HOSTCC_RXCOAL_MAXF_INT, 1);
 	tw32(HOSTCC_TXCOAL_MAXF_INT, 0);
-	tw32(HOSTCC_STAT_COAL_TICKS,
-	     DEFAULT_STAT_COAL_TICKS);
 
-	/* Status/statistics block address. */
-	tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
-	     ((u64) tp->stats_mapping >> 32));
-	tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
-	     ((u64) tp->stats_mapping & 0xffffffff));
+	/* set status block DMA address */
 	tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
 	     ((u64) tp->status_mapping >> 32));
 	tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
 	     ((u64) tp->status_mapping & 0xffffffff));
-	tw32(HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK);
-	tw32(HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		/* Status/statistics block address.  See tg3_timer,
+		 * the tg3_periodic_fetch_stats call there, and
+		 * tg3_get_stats to see how this works for 5705 chips.
+		 */
+		tw32(HOSTCC_STAT_COAL_TICKS,
+		     DEFAULT_STAT_COAL_TICKS);
+		tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
+		     ((u64) tp->stats_mapping >> 32));
+		tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
+		     ((u64) tp->stats_mapping & 0xffffffff));
+		tw32(HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK);
+		tw32(HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK);
+	}
 
 	tw32(HOSTCC_MODE, HOSTCC_MODE_ENABLE | tp->coalesce_mode);
 
 	tw32(RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE);
 	tw32(RCVLPC_MODE, RCVLPC_MODE_ENABLE);
-	tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)
+		tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE);
 
 	tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
 		MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
@@ -4207,42 +4981,47 @@
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
 	tr32(MAILBOX_INTERRUPT_0);
 
-	tw32(DMAC_MODE, DMAC_MODE_ENABLE);
-	tr32(DMAC_MODE);
-	udelay(40);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		tw32(DMAC_MODE, DMAC_MODE_ENABLE);
+		tr32(DMAC_MODE);
+		udelay(40);
+	}
 
-	tw32(WDMAC_MODE, (WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB |
-			  WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB |
-			  WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB |
-			  WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
-			  WDMAC_MODE_LNGREAD_ENAB));
+	val = (WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB |
+	       WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB |
+	       WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB |
+	       WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
+	       WDMAC_MODE_LNGREAD_ENAB);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+	    (tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) != 0 &&
+	    !(tp->tg3_flags2 & TG3_FLG2_IS_5788))
+		val |= WDMAC_MODE_RX_ACCEL;
+	tw32(WDMAC_MODE, val);
 	tr32(WDMAC_MODE);
 	udelay(40);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
-	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
+	if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
 		val = tr32(TG3PCI_X_CAPS);
-		val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
-		val |= (PCIX_CAPS_MAX_BURST_5704 << PCIX_CAPS_BURST_SHIFT);
-		if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
-			val |= (tp->split_mode_max_reqs <<
-				PCIX_CAPS_SPLIT_SHIFT);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+			val &= ~PCIX_CAPS_BURST_MASK;
+			val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+			val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
+			val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+			if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
+				val |= (tp->split_mode_max_reqs <<
+					PCIX_CAPS_SPLIT_SHIFT);
+		}
 		tw32(TG3PCI_X_CAPS, val);
 	}
 
-	val = (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
-	       RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
-	       RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
-	       RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
-	       RDMAC_MODE_LNGREAD_ENAB);
-	if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
-		val |= RDMAC_MODE_SPLIT_ENABLE;
-	tw32(RDMAC_MODE, val);
+	tw32(RDMAC_MODE, rdmac_mode);
 	tr32(RDMAC_MODE);
 	udelay(40);
 
 	tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
-	tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)
+		tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
 	tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
 	tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
 	tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
@@ -4257,10 +5036,12 @@
 			return err;
 	}
 
-#if TG3_DO_TSO != 0
-	err = tg3_load_tso_firmware(tp);
-	if (err)
-		return err;
+#if TG3_TSO_SUPPORT != 0
+	if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
+		err = tg3_load_tso_firmware(tp);
+		if (err)
+			return err;
+	}
 #endif
 
 	tp->tx_mode = TX_MODE_ENABLE;
@@ -4287,9 +5068,11 @@
 
 	tw32(MAC_LED_CTRL, 0);
 	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
-	tw32(MAC_RX_MODE, RX_MODE_RESET);
-	tr32(MAC_RX_MODE);
-	udelay(10);
+	if (tp->phy_id == PHY_ID_SERDES) {
+		tw32(MAC_RX_MODE, RX_MODE_RESET);
+		tr32(MAC_RX_MODE);
+		udelay(10);
+	}
 	tw32(MAC_RX_MODE, tp->rx_mode);
 	tr32(MAC_RX_MODE);
 	udelay(10);
@@ -4323,22 +5106,48 @@
 	tw32(MAC_RCV_VALUE_0, 0xffffffff & RCV_RULE_DISABLE_MASK);
 	tw32(MAC_RCV_RULE_1,  0x86000004 & RCV_RULE_DISABLE_MASK);
 	tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK);
-#if 0
-	tw32(MAC_RCV_RULE_2,  0); tw32(MAC_RCV_VALUE_2,  0);
-	tw32(MAC_RCV_RULE_3,  0); tw32(MAC_RCV_VALUE_3,  0);
-#endif
-	tw32(MAC_RCV_RULE_4,  0); tw32(MAC_RCV_VALUE_4,  0);
-	tw32(MAC_RCV_RULE_5,  0); tw32(MAC_RCV_VALUE_5,  0);
-	tw32(MAC_RCV_RULE_6,  0); tw32(MAC_RCV_VALUE_6,  0);
-	tw32(MAC_RCV_RULE_7,  0); tw32(MAC_RCV_VALUE_7,  0);
-	tw32(MAC_RCV_RULE_8,  0); tw32(MAC_RCV_VALUE_8,  0);
-	tw32(MAC_RCV_RULE_9,  0); tw32(MAC_RCV_VALUE_9,  0);
-	tw32(MAC_RCV_RULE_10,  0); tw32(MAC_RCV_VALUE_10,  0);
-	tw32(MAC_RCV_RULE_11,  0); tw32(MAC_RCV_VALUE_11,  0);
-	tw32(MAC_RCV_RULE_12,  0); tw32(MAC_RCV_VALUE_12,  0);
-	tw32(MAC_RCV_RULE_13,  0); tw32(MAC_RCV_VALUE_13,  0);
-	tw32(MAC_RCV_RULE_14,  0); tw32(MAC_RCV_VALUE_14,  0);
-	tw32(MAC_RCV_RULE_15,  0); tw32(MAC_RCV_VALUE_15,  0);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+		limit = 8;
+	else
+		limit = 16;
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
+		limit -= 4;
+	switch (limit) {
+	case 16:
+		tw32(MAC_RCV_RULE_15,  0); tw32(MAC_RCV_VALUE_15,  0);
+	case 15:
+		tw32(MAC_RCV_RULE_14,  0); tw32(MAC_RCV_VALUE_14,  0);
+	case 14:
+		tw32(MAC_RCV_RULE_13,  0); tw32(MAC_RCV_VALUE_13,  0);
+	case 13:
+		tw32(MAC_RCV_RULE_12,  0); tw32(MAC_RCV_VALUE_12,  0);
+	case 12:
+		tw32(MAC_RCV_RULE_11,  0); tw32(MAC_RCV_VALUE_11,  0);
+	case 11:
+		tw32(MAC_RCV_RULE_10,  0); tw32(MAC_RCV_VALUE_10,  0);
+	case 10:
+		tw32(MAC_RCV_RULE_9,  0); tw32(MAC_RCV_VALUE_9,  0);
+	case 9:
+		tw32(MAC_RCV_RULE_8,  0); tw32(MAC_RCV_VALUE_8,  0);
+	case 8:
+		tw32(MAC_RCV_RULE_7,  0); tw32(MAC_RCV_VALUE_7,  0);
+	case 7:
+		tw32(MAC_RCV_RULE_6,  0); tw32(MAC_RCV_VALUE_6,  0);
+	case 6:
+		tw32(MAC_RCV_RULE_5,  0); tw32(MAC_RCV_VALUE_5,  0);
+	case 5:
+		tw32(MAC_RCV_RULE_4,  0); tw32(MAC_RCV_VALUE_4,  0);
+	case 4:
+		/* tw32(MAC_RCV_RULE_3,  0); tw32(MAC_RCV_VALUE_3,  0); */
+	case 3:
+		/* tw32(MAC_RCV_RULE_2,  0); tw32(MAC_RCV_VALUE_2,  0); */
+	case 2:
+	case 1:
+
+	default:
+		break;
+	};
 
 	if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)
 		tg3_enable_ints(tp);
@@ -4368,6 +5177,50 @@
 	return err;
 }
 
+#define TG3_STAT_ADD32(PSTAT, REG) \
+do {	u32 __val = tr32(REG); \
+	(PSTAT)->low += __val; \
+	if ((PSTAT)->low < __val) \
+		(PSTAT)->high += 1; \
+} while (0)
+
+static void tg3_periodic_fetch_stats(struct tg3 *tp)
+{
+	struct tg3_hw_stats *sp = tp->hw_stats;
+
+	if (!netif_carrier_ok(tp->dev))
+		return;
+
+	TG3_STAT_ADD32(&sp->tx_octets, MAC_TX_STATS_OCTETS);
+	TG3_STAT_ADD32(&sp->tx_collisions, MAC_TX_STATS_COLLISIONS);
+	TG3_STAT_ADD32(&sp->tx_xon_sent, MAC_TX_STATS_XON_SENT);
+	TG3_STAT_ADD32(&sp->tx_xoff_sent, MAC_TX_STATS_XOFF_SENT);
+	TG3_STAT_ADD32(&sp->tx_mac_errors, MAC_TX_STATS_MAC_ERRORS);
+	TG3_STAT_ADD32(&sp->tx_single_collisions, MAC_TX_STATS_SINGLE_COLLISIONS);
+	TG3_STAT_ADD32(&sp->tx_mult_collisions, MAC_TX_STATS_MULT_COLLISIONS);
+	TG3_STAT_ADD32(&sp->tx_deferred, MAC_TX_STATS_DEFERRED);
+	TG3_STAT_ADD32(&sp->tx_excessive_collisions, MAC_TX_STATS_EXCESSIVE_COL);
+	TG3_STAT_ADD32(&sp->tx_late_collisions, MAC_TX_STATS_LATE_COL);
+	TG3_STAT_ADD32(&sp->tx_ucast_packets, MAC_TX_STATS_UCAST);
+	TG3_STAT_ADD32(&sp->tx_mcast_packets, MAC_TX_STATS_MCAST);
+	TG3_STAT_ADD32(&sp->tx_bcast_packets, MAC_TX_STATS_BCAST);
+
+	TG3_STAT_ADD32(&sp->rx_octets, MAC_RX_STATS_OCTETS);
+	TG3_STAT_ADD32(&sp->rx_fragments, MAC_RX_STATS_FRAGMENTS);
+	TG3_STAT_ADD32(&sp->rx_ucast_packets, MAC_RX_STATS_UCAST);
+	TG3_STAT_ADD32(&sp->rx_mcast_packets, MAC_RX_STATS_MCAST);
+	TG3_STAT_ADD32(&sp->rx_bcast_packets, MAC_RX_STATS_BCAST);
+	TG3_STAT_ADD32(&sp->rx_fcs_errors, MAC_RX_STATS_FCS_ERRORS);
+	TG3_STAT_ADD32(&sp->rx_align_errors, MAC_RX_STATS_ALIGN_ERRORS);
+	TG3_STAT_ADD32(&sp->rx_xon_pause_rcvd, MAC_RX_STATS_XON_PAUSE_RECVD);
+	TG3_STAT_ADD32(&sp->rx_xoff_pause_rcvd, MAC_RX_STATS_XOFF_PAUSE_RECVD);
+	TG3_STAT_ADD32(&sp->rx_mac_ctrl_rcvd, MAC_RX_STATS_MAC_CTRL_RECVD);
+	TG3_STAT_ADD32(&sp->rx_xoff_entered, MAC_RX_STATS_XOFF_ENTERED);
+	TG3_STAT_ADD32(&sp->rx_frame_too_long_errors, MAC_RX_STATS_FRAME_TOO_LONG);
+	TG3_STAT_ADD32(&sp->rx_jabbers, MAC_RX_STATS_JABBERS);
+	TG3_STAT_ADD32(&sp->rx_undersize_packets, MAC_RX_STATS_UNDERSIZE);
+}
+
 static void tg3_timer(unsigned long __opaque)
 {
 	struct tg3 *tp = (struct tg3 *) __opaque;
@@ -4396,6 +5249,9 @@
 		return;
 	}
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+		tg3_periodic_fetch_stats(tp);
+
 	/* This part only runs once per second. */
 	if (!--tp->timer_counter) {
 		if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
@@ -4495,8 +5351,6 @@
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
 
-	tg3_init_rings(tp);
-
 	err = tg3_init_hw(tp);
 	if (err) {
 		tg3_halt(tp);
@@ -4855,7 +5709,9 @@
 		get_stat64(&hw_stats->rx_bcast_packets);
 		
 	stats->tx_packets = old_stats->tx_packets +
-		get_stat64(&hw_stats->COS_out_packets[0]);
+		get_stat64(&hw_stats->tx_ucast_packets) +
+		get_stat64(&hw_stats->tx_mcast_packets) +
+		get_stat64(&hw_stats->tx_bcast_packets);
 
 	stats->rx_bytes = old_stats->rx_bytes +
 		get_stat64(&hw_stats->rx_octets);
@@ -4998,16 +5854,20 @@
 
 #define TG3_REGDUMP_LEN		(32 * 1024)
 
-static u8 *tg3_get_regs(struct tg3 *tp)
+static int tg3_get_regs_len(struct net_device *dev)
 {
-	u8 *orig_p = kmalloc(TG3_REGDUMP_LEN, GFP_KERNEL);
-	u8 *p;
+	return TG3_REGDUMP_LEN;
+}
+
+static void tg3_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
+{
+	struct tg3 *tp = dev->priv;
+	u8 *orig_p = p;
 	int i;
 
-	if (orig_p == NULL)
-		return NULL;
+	regs->version = 0;
 
-	memset(orig_p, 0, TG3_REGDUMP_LEN);
+	memset(p, 0, TG3_REGDUMP_LEN);
 
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
@@ -5061,390 +5921,279 @@
 
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
-
-	return orig_p;
 }
 
-static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct tg3 *tp = dev->priv;
-	struct pci_dev *pci_dev = tp->pdev;
-	u32 ethcmd;
-
-	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
-		return -EFAULT;
-
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO:{
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_MODULE_NAME);
-		strcpy (info.version, DRV_MODULE_VERSION);
-		memset(&info.fw_version, 0, sizeof(info.fw_version));
-		strcpy (info.bus_info, pci_dev->slot_name);
-		info.eedump_len = 0;
-		info.regdump_len = TG3_REGDUMP_LEN;
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd cmd = { ETHTOOL_GSET };
-
-		if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
-		    tp->link_config.phy_is_low_power)
-			return -EAGAIN;
-		cmd.supported = (SUPPORTED_Autoneg);
-
-		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
-			cmd.supported |= (SUPPORTED_1000baseT_Half |
-					  SUPPORTED_1000baseT_Full);
-
-		if (tp->phy_id != PHY_ID_SERDES)
-			cmd.supported |= (SUPPORTED_100baseT_Half |
-					  SUPPORTED_100baseT_Full |
-					  SUPPORTED_10baseT_Half |
-					  SUPPORTED_10baseT_Full |
-					  SUPPORTED_MII);
-		else
-			cmd.supported |= SUPPORTED_FIBRE;
-
-		cmd.advertising = tp->link_config.advertising;
-		cmd.speed = tp->link_config.active_speed;
-		cmd.duplex = tp->link_config.active_duplex;
-		cmd.port = 0;
-		cmd.phy_address = PHY_ADDR;
-		cmd.transceiver = 0;
-		cmd.autoneg = tp->link_config.autoneg;
-		cmd.maxtxpkt = 0;
-		cmd.maxrxpkt = 0;
-		if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SSET: {
-		struct ethtool_cmd cmd;
-
-		if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
-		    tp->link_config.phy_is_low_power)
-			return -EAGAIN;
-
-		if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
-			return -EFAULT;
-
-		/* Fiber PHY only supports 1000 full/half */
-		if (cmd.autoneg == AUTONEG_ENABLE) {
-			if (tp->phy_id == PHY_ID_SERDES &&
-			    (cmd.advertising &
-			     (ADVERTISED_10baseT_Half |
-			      ADVERTISED_10baseT_Full |
-			      ADVERTISED_100baseT_Half |
-			      ADVERTISED_100baseT_Full)))
-				return -EINVAL;
-			if ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
-			    (cmd.advertising &
-			     (ADVERTISED_1000baseT_Half |
-			      ADVERTISED_1000baseT_Full)))
-				return -EINVAL;
-		} else {
-			if (tp->phy_id == PHY_ID_SERDES &&
-			    (cmd.speed == SPEED_10 ||
-			     cmd.speed == SPEED_100))
-				return -EINVAL;
-			if ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
-			    (cmd.speed == SPEED_10 ||
-			     cmd.speed == SPEED_100))
-				return -EINVAL;
-		}
-
-		spin_lock_irq(&tp->lock);
-		spin_lock(&tp->tx_lock);
-
-		tp->link_config.autoneg = cmd.autoneg;
-		if (cmd.autoneg == AUTONEG_ENABLE) {
-			tp->link_config.advertising = cmd.advertising;
-			tp->link_config.speed = SPEED_INVALID;
-			tp->link_config.duplex = DUPLEX_INVALID;
-		} else {
-			tp->link_config.speed = cmd.speed;
-			tp->link_config.duplex = cmd.duplex;
-		}
-
-		tg3_setup_phy(tp);
-		spin_unlock(&tp->tx_lock);
-		spin_unlock_irq(&tp->lock);
-
-		return 0;
-	}
+  	struct tg3 *tp = dev->priv;
+  
+	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
+					tp->link_config.phy_is_low_power)
+		return -EAGAIN;
 
-	case ETHTOOL_GREGS: {
-		struct ethtool_regs regs;
-		u8 *regbuf;
-		int ret;
-
-		if (copy_from_user(&regs, useraddr, sizeof(regs)))
-			return -EFAULT;
-		if (regs.len > TG3_REGDUMP_LEN)
-			regs.len = TG3_REGDUMP_LEN;
-		regs.version = 0;
-		if (copy_to_user(useraddr, &regs, sizeof(regs)))
-			return -EFAULT;
-
-		regbuf = tg3_get_regs(tp);
-		if (!regbuf)
-			return -ENOMEM;
+	cmd->supported = (SUPPORTED_Autoneg);
 
-		useraddr += offsetof(struct ethtool_regs, data);
-		ret = 0;
-		if (copy_to_user(useraddr, regbuf, regs.len))
-			ret = -EFAULT;
-		kfree(regbuf);
-		return ret;
-	}
-	case ETHTOOL_GWOL: {
-		struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
+	if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+		cmd->supported |= (SUPPORTED_1000baseT_Half |
+				   SUPPORTED_1000baseT_Full);
+
+	if (tp->phy_id != PHY_ID_SERDES)
+		cmd->supported |= (SUPPORTED_100baseT_Half |
+				  SUPPORTED_100baseT_Full |
+				  SUPPORTED_10baseT_Half |
+				  SUPPORTED_10baseT_Full |
+				  SUPPORTED_MII);
+	else
+		cmd->supported |= SUPPORTED_FIBRE;
+  
+	cmd->advertising = tp->link_config.advertising;
+	cmd->speed = tp->link_config.active_speed;
+	cmd->duplex = tp->link_config.active_duplex;
+	cmd->port = 0;
+	cmd->phy_address = PHY_ADDR;
+	cmd->transceiver = 0;
+	cmd->autoneg = tp->link_config.autoneg;
+	cmd->maxtxpkt = 0;
+	cmd->maxrxpkt = 0;
+	return 0;
+}
+  
+static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct tg3 *tp = dev->priv;
+  
+	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
+					tp->link_config.phy_is_low_power)
+		return -EAGAIN;
 
-		wol.supported = WAKE_MAGIC;
-		wol.wolopts = 0;
-		if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
-			wol.wolopts = WAKE_MAGIC;
-		memset(&wol.sopass, 0, sizeof(wol.sopass));
-		if (copy_to_user(useraddr, &wol, sizeof(wol)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SWOL: {
-		struct ethtool_wolinfo wol;
+	if (cmd->autoneg == AUTONEG_ENABLE) {
+		tp->link_config.advertising = cmd->advertising;
+		tp->link_config.speed = SPEED_INVALID;
+		tp->link_config.duplex = DUPLEX_INVALID;
+	} else {
+		tp->link_config.speed = cmd->speed;
+		tp->link_config.duplex = cmd->duplex;
+  	}
+  
+	tg3_setup_phy(tp);
+	spin_unlock(&tp->tx_lock);
+	spin_unlock_irq(&tp->lock);
+  
+	return 0;
+}
+  
+static void tg3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct tg3 *tp = dev->priv;
+  
+	strcpy(info->driver, DRV_MODULE_NAME);
+	strcpy(info->version, DRV_MODULE_VERSION);
+	strcpy(info->bus_info, pci_name(tp->pdev));
+}
+  
+static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct tg3 *tp = dev->priv;
+  
+	wol->supported = WAKE_MAGIC;
+	wol->wolopts = 0;
+	if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
+		wol->wolopts = WAKE_MAGIC;
+	memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+  
+static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct tg3 *tp = dev->priv;
+  
+	if (wol->wolopts & ~WAKE_MAGIC)
+		return -EINVAL;
+	if ((wol->wolopts & WAKE_MAGIC) &&
+	    tp->phy_id == PHY_ID_SERDES &&
+	    !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
+		return -EINVAL;
+  
+	spin_lock_irq(&tp->lock);
+	if (wol->wolopts & WAKE_MAGIC)
+		tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
+	spin_unlock_irq(&tp->lock);
+  
+	return 0;
+}
+  
+static u32 tg3_get_msglevel(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+	return tp->msg_enable;
+}
+  
+static void tg3_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct tg3 *tp = dev->priv;
+	tp->msg_enable = value;
+}
+  
+#if TG3_TSO_SUPPORT != 0
+static int tg3_set_tso(struct net_device *dev, u32 value)
+{
+	struct tg3 *tp = dev->priv;
 
-		if (copy_from_user(&wol, useraddr, sizeof(wol)))
-			return -EFAULT;
-		if (wol.wolopts & ~WAKE_MAGIC)
-			return -EINVAL;
-		if ((wol.wolopts & WAKE_MAGIC) &&
-		    tp->phy_id == PHY_ID_SERDES &&
-		    !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
+	if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
+		if (value)
 			return -EINVAL;
-
-		spin_lock_irq(&tp->lock);
-		if (wol.wolopts & WAKE_MAGIC)
-			tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
-		else
-			tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
-		spin_unlock_irq(&tp->lock);
-
-		return 0;
-	}
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = { ETHTOOL_GMSGLVL };
-		edata.data = tp->msg_enable;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		tp->msg_enable = edata.data;
 		return 0;
 	}
-	case ETHTOOL_NWAY_RST: {
-		u32 bmcr;
-		int r;
-
-		spin_lock_irq(&tp->lock);
-		tg3_readphy(tp, MII_BMCR, &bmcr);
-		tg3_readphy(tp, MII_BMCR, &bmcr);
-		r = -EINVAL;
-		if (bmcr & BMCR_ANENABLE) {
-			tg3_writephy(tp, MII_BMCR,
-				     bmcr | BMCR_ANRESTART);
-			r = 0;
-		}
-		spin_unlock_irq(&tp->lock);
-
-		return r;
-	}
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = { ETHTOOL_GLINK };
-		edata.data = netif_carrier_ok(tp->dev) ? 1 : 0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GRINGPARAM: {
-		struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
-
-		ering.rx_max_pending = TG3_RX_RING_SIZE - 1;
-		ering.rx_mini_max_pending = 0;
-		ering.rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
-
-		ering.rx_pending = tp->rx_pending;
-		ering.rx_mini_pending = 0;
-		ering.rx_jumbo_pending = tp->rx_jumbo_pending;
-		ering.tx_pending = tp->tx_pending;
-
-		if (copy_to_user(useraddr, &ering, sizeof(ering)))
-			return -EFAULT;
-		return 0;
+	return ethtool_op_set_tso(dev, value);
+}
+#endif
+  
+static int tg3_nway_reset(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+	u32 bmcr;
+	int r;
+  
+	spin_lock_irq(&tp->lock);
+	tg3_readphy(tp, MII_BMCR, &bmcr);
+	tg3_readphy(tp, MII_BMCR, &bmcr);
+	r = -EINVAL;
+	if (bmcr & BMCR_ANENABLE) {
+		tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART);
+		r = 0;
 	}
-	case ETHTOOL_SRINGPARAM: {
-		struct ethtool_ringparam ering;
+	spin_unlock_irq(&tp->lock);
+  
+	return r;
+}
+  
+static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+{
+	struct tg3 *tp = dev->priv;
+  
+	ering->rx_max_pending = TG3_RX_RING_SIZE - 1;
+	ering->rx_mini_max_pending = 0;
+	ering->rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
+
+	ering->rx_pending = tp->rx_pending;
+	ering->rx_mini_pending = 0;
+	ering->rx_jumbo_pending = tp->rx_jumbo_pending;
+	ering->tx_pending = tp->tx_pending;
+}
+  
+static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+{
+	struct tg3 *tp = dev->priv;
+  
+	if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
+	    (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
+	    (ering->tx_pending > TG3_TX_RING_SIZE - 1))
+		return -EINVAL;
+  
+	tg3_netif_stop(tp);
+	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
+  
+	tp->rx_pending = ering->rx_pending;
 
-		if (copy_from_user(&ering, useraddr, sizeof(ering)))
-			return -EFAULT;
+	if ((tp->tg3_flags2 & TG3_FLG2_MAX_RXPEND_64) &&
+	    tp->rx_pending > 64)
+		tp->rx_pending = 64;
+	tp->rx_jumbo_pending = ering->rx_jumbo_pending;
+	tp->tx_pending = ering->tx_pending;
 
-		if ((ering.rx_pending > TG3_RX_RING_SIZE - 1) ||
-		    (ering.rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
-		    (ering.tx_pending > TG3_TX_RING_SIZE - 1))
+	tg3_halt(tp);
+	tg3_init_hw(tp);
+	netif_wake_queue(tp->dev);
+	spin_unlock(&tp->tx_lock);
+	spin_unlock_irq(&tp->lock);
+	tg3_netif_start(tp);
+  
+	return 0;
+}
+  
+static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
+{
+	struct tg3 *tp = dev->priv;
+  
+	epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
+	epause->rx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0;
+	epause->tx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0;
+}
+  
+static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
+{
+	struct tg3 *tp = dev->priv;
+  
+	tg3_netif_stop(tp);
+	spin_lock_irq(&tp->lock);
+	spin_lock(&tp->tx_lock);
+	if (epause->autoneg)
+		tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
+	if (epause->rx_pause)
+		tp->tg3_flags |= TG3_FLAG_PAUSE_RX;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX;
+	if (epause->tx_pause)
+		tp->tg3_flags |= TG3_FLAG_PAUSE_TX;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX;
+	tg3_halt(tp);
+	tg3_init_hw(tp);
+	spin_unlock(&tp->tx_lock);
+	spin_unlock_irq(&tp->lock);
+	tg3_netif_start(tp);
+  
+	return 0;
+}
+  
+static u32 tg3_get_rx_csum(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+	return (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0;
+}
+  
+static int tg3_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct tg3 *tp = dev->priv;
+  
+	if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
+		if (data != 0)
 			return -EINVAL;
-
-		tg3_netif_stop(tp);
-		spin_lock_irq(&tp->lock);
-		spin_lock(&tp->tx_lock);
-
-		tp->rx_pending = ering.rx_pending;
-		tp->rx_jumbo_pending = ering.rx_jumbo_pending;
-		tp->tx_pending = ering.tx_pending;
-
-		tg3_halt(tp);
-		tg3_init_rings(tp);
-		tg3_init_hw(tp);
-		netif_wake_queue(tp->dev);
-		spin_unlock(&tp->tx_lock);
-		spin_unlock_irq(&tp->lock);
-		tg3_netif_start(tp);
-
-		return 0;
-	}
-	case ETHTOOL_GPAUSEPARAM: {
-		struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
-
-		epause.autoneg =
-			(tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
-		epause.rx_pause =
-			(tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0;
-		epause.tx_pause =
-			(tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0;
-		if (copy_to_user(useraddr, &epause, sizeof(epause)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SPAUSEPARAM: {
-		struct ethtool_pauseparam epause;
-
-		if (copy_from_user(&epause, useraddr, sizeof(epause)))
-			return -EFAULT;
-
-		tg3_netif_stop(tp);
-		spin_lock_irq(&tp->lock);
-		spin_lock(&tp->tx_lock);
-		if (epause.autoneg)
-			tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
-		else
-			tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
-		if (epause.rx_pause)
-			tp->tg3_flags |= TG3_FLAG_PAUSE_RX;
-		else
-			tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX;
-		if (epause.tx_pause)
-			tp->tg3_flags |= TG3_FLAG_PAUSE_TX;
-		else
-			tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX;
-		tg3_halt(tp);
-		tg3_init_rings(tp);
-		tg3_init_hw(tp);
-		spin_unlock(&tp->tx_lock);
-		spin_unlock_irq(&tp->lock);
-		tg3_netif_start(tp);
-
-		return 0;
-	}
-	case ETHTOOL_GRXCSUM: {
-		struct ethtool_value edata = { ETHTOOL_GRXCSUM };
-
-		edata.data =
-			(tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SRXCSUM: {
-		struct ethtool_value edata;
-
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-
-		if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
-			if (edata.data != 0)
-				return -EINVAL;
-			return 0;
-		}
-
-		spin_lock_irq(&tp->lock);
-		if (edata.data)
-			tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
-		else
-			tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
-		spin_unlock_irq(&tp->lock);
-
-		return 0;
-	}
-	case ETHTOOL_GTXCSUM: {
-		struct ethtool_value edata = { ETHTOOL_GTXCSUM };
-
-		edata.data =
-			(tp->dev->features & NETIF_F_IP_CSUM) != 0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_STXCSUM: {
-		struct ethtool_value edata;
-
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-
-		if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
-			if (edata.data != 0)
-				return -EINVAL;
-			return 0;
-		}
-
-		if (edata.data)
-			tp->dev->features |= NETIF_F_IP_CSUM;
-		else
-			tp->dev->features &= ~NETIF_F_IP_CSUM;
-
-		return 0;
-	}
-	case ETHTOOL_GSG: {
-		struct ethtool_value edata = { ETHTOOL_GSG };
-
-		edata.data =
-			(tp->dev->features & NETIF_F_SG) != 0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SSG: {
-		struct ethtool_value edata;
-
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-
-		if (edata.data)
-			tp->dev->features |= NETIF_F_SG;
-		else
-			tp->dev->features &= ~NETIF_F_SG;
-
-		return 0;
-	}
-	};
-
-	return -EOPNOTSUPP;
+  		return 0;
+  	}
+  
+	spin_lock_irq(&tp->lock);
+	if (data)
+		tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
+	spin_unlock_irq(&tp->lock);
+  
+	return 0;
 }
+  
+static int tg3_set_tx_csum(struct net_device *dev, u32 data)
+{
+	struct tg3 *tp = dev->priv;
+  
+	if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
+		if (data != 0)
+			return -EINVAL;
+  		return 0;
+  	}
+  
+	if (data)
+		dev->features |= NETIF_F_IP_CSUM;
+	else
+		dev->features &= ~NETIF_F_IP_CSUM;
 
+	return 0;
+}
+  
 static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
@@ -5452,8 +6201,6 @@
 	int err;
 
 	switch(cmd) {
-	case SIOCETHTOOL:
-		return tg3_ethtool_ioctl(dev, (void *) ifr->ifr_data);
 	case SIOCGMIIPHY:
 		data->phy_id = PHY_ADDR;
 
@@ -5517,11 +6264,42 @@
 }
 #endif
 
+static struct ethtool_ops tg3_ethtool_ops = {
+	.get_settings		= tg3_get_settings,
+	.set_settings		= tg3_set_settings,
+	.get_drvinfo		= tg3_get_drvinfo,
+	.get_regs_len		= tg3_get_regs_len,
+	.get_regs		= tg3_get_regs,
+	.get_wol		= tg3_get_wol,
+	.set_wol		= tg3_set_wol,
+	.get_msglevel		= tg3_get_msglevel,
+	.set_msglevel		= tg3_set_msglevel,
+	.nway_reset		= tg3_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_ringparam		= tg3_get_ringparam,
+	.set_ringparam		= tg3_set_ringparam,
+	.get_pauseparam		= tg3_get_pauseparam,
+	.set_pauseparam		= tg3_set_pauseparam,
+	.get_rx_csum		= tg3_get_rx_csum,
+	.set_rx_csum		= tg3_set_rx_csum,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= tg3_set_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+#if TG3_TSO_SUPPORT != 0
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= tg3_set_tso,
+#endif
+};
+
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
 static void __devinit tg3_nvram_init(struct tg3 *tp)
 {
 	int j;
 
+	if (tp->tg3_flags2 & TG3_FLG2_SUN_5704)
+		return;
+
 	tw32(GRC_EEPROM_ADDR,
 	     (EEPROM_ADDR_FSM_RESET |
 	      (EEPROM_DEFAULT_CLOCK_PERIOD <<
@@ -5594,6 +6372,11 @@
 {
 	int i, saw_done_clear;
 
+	if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) {
+		printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 5704\n");
+		return -EINVAL;
+	}
+
 	if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
 		return tg3_nvram_read_using_eeprom(tp, offset, val);
 
@@ -5709,6 +6492,7 @@
 		u32 nic_cfg;
 
 		tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
+		tp->nic_sram_data_cfg = nic_cfg;
 
 		eeprom_signature_found = 1;
 
@@ -5742,8 +6526,10 @@
 			eeprom_led_mode = led_mode_auto;
 			break;
 		};
-		if ((tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 ||
-		     tp->pci_chip_rev_id == CHIPREV_ID_5703_A2) &&
+
+		if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
+		     (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
+		     (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) &&
 		    (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP))
 			tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
 
@@ -5825,9 +6611,7 @@
 	}
 
 	/* Enable Ethernet@WireSpeed */
-	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
-	tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
-	tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
+	tg3_phy_set_wirespeed(tp);
 
 	if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) {
 		err = tg3_init_5401phy_dsp(tp);
@@ -5862,6 +6646,14 @@
 	unsigned char vpd_data[256];
 	int i;
 
+	if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) {
+		/* Sun decided not to put the necessary bits in the
+		 * NVRAM of their onboard tg3 parts :(
+		 */
+		strcpy(tp->board_part_number, "Sun 5704");
+		return;
+	}
+
 	for (i = 0; i < 256; i += 4) {
 		u32 tmp;
 
@@ -5918,6 +6710,34 @@
 	strcpy(tp->board_part_number, "none");
 }
 
+#ifdef CONFIG_SPARC64
+static int __devinit tg3_is_sun_5704(struct tg3 *tp)
+{
+	struct pci_dev *pdev = tp->pdev;
+	struct pcidev_cookie *pcp = pdev->sysdata;
+
+	if (pcp != NULL) {
+		int node = pcp->prom_node;
+		u32 venid, devid;
+		int err;
+
+		err = prom_getproperty(node, "subsystem-vendor-id",
+				       (char *) &venid, sizeof(venid));
+		if (err == 0 || err == -1)
+			return 0;
+		err = prom_getproperty(node, "subsystem-id",
+				       (char *) &devid, sizeof(devid));
+		if (err == 0 || err == -1)
+			return 0;
+
+		if (venid == PCI_VENDOR_ID_SUN &&
+		    devid == PCI_DEVICE_ID_TIGON3_5704)
+			return 1;
+	}
+	return 0;
+}
+#endif
+
 static int __devinit tg3_get_invariants(struct tg3 *tp)
 {
 	u32 misc_ctrl_reg;
@@ -5926,6 +6746,11 @@
 	u16 pci_cmd;
 	int err;
 
+#ifdef CONFIG_SPARC64
+	if (tg3_is_sun_5704(tp))
+		tp->tg3_flags2 |= TG3_FLG2_SUN_5704;
+#endif
+
 	/* If we have an AMD 762 or Intel ICH/ICH0 chipset, write
 	 * reordering to the mailbox registers done by the host
 	 * controller can cause major troubles.  We read back from
@@ -5942,7 +6767,7 @@
 
 	/* Force memory write invalidate off.  If we leave it on,
 	 * then on 5700_BX chips we have to enable a workaround.
-	 * The workaround is to set the TG3PCI_DMA_RW_CTRL boundry
+	 * The workaround is to set the TG3PCI_DMA_RW_CTRL boundary
 	 * to match the cacheline size.  The Broadcom driver have this
 	 * workaround but turns MWI off all the times so never uses
 	 * it.  This seems to suggest that the workaround is insufficient.
@@ -6084,7 +6909,15 @@
 		tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB;
 	}
 
+	/* A few boards don't want Ethernet@WireSpeed phy feature */
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) ||
+	    ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
+	     (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
+	     (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)))
+		tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
+
 	/* Only 5701 and later support tagged irq status mode.
+	 * Also, 5788 chips cannot use tagged irq status.
 	 *
 	 * However, since we are using NAPI avoid tagged irq status
 	 * because the interrupt condition is more difficult to
@@ -6141,7 +6974,8 @@
 	/* Determine if TX descriptors will reside in
 	 * main memory or in the chip SRAM.
 	 */
-	if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG)
+	if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
 		tp->tg3_flags |= TG3_FLAG_HOST_TXDS;
 
 	grc_misc_cfg = tr32(GRC_MISC_CFG);
@@ -6153,8 +6987,18 @@
 		tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ;
 	}
 
-	/* this one is limited to 10/100 only */
-	if (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5702FE)
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+	    (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
+	     grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
+		tp->tg3_flags2 |= TG3_FLG2_IS_5788;
+
+	/* these are limited to 10/100 only */
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+	     (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+	     tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
+	     (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901 ||
+	      tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2)))
 		tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
 
 	err = tg3_phy_probe(tp);
@@ -6234,11 +7078,44 @@
 	return err;
 }
 
+#ifdef CONFIG_SPARC64
+static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp)
+{
+	struct net_device *dev = tp->dev;
+	struct pci_dev *pdev = tp->pdev;
+	struct pcidev_cookie *pcp = pdev->sysdata;
+
+	if (pcp != NULL) {
+		int node = pcp->prom_node;
+
+		if (prom_getproplen(node, "local-mac-address") == 6) {
+			prom_getproperty(node, "local-mac-address",
+					 dev->dev_addr, 6);
+			return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+static int __devinit tg3_get_default_macaddr_sparc(struct tg3 *tp)
+{
+	struct net_device *dev = tp->dev;
+
+	memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+	return 0;
+}
+#endif
+
 static int __devinit tg3_get_device_address(struct tg3 *tp)
 {
 	struct net_device *dev = tp->dev;
 	u32 hi, lo, mac_offset;
 
+#ifdef CONFIG_SPARC64
+	if (!tg3_get_macaddr_sparc(tp))
+		return 0;
+#endif
+
 	if (PCI_FUNC(tp->pdev->devfn) == 0)
 		mac_offset = 0x7c;
 	else
@@ -6257,7 +7134,8 @@
 		dev->dev_addr[5] = (lo >>  0) & 0xff;
 	}
 	/* Next, try NVRAM. */
-	else if (!tg3_nvram_read(tp, mac_offset + 0, &hi) &&
+	else if (!(tp->tg3_flags & TG3_FLG2_SUN_5704) &&
+		 !tg3_nvram_read(tp, mac_offset + 0, &hi) &&
 		 !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
 		dev->dev_addr[0] = ((hi >> 16) & 0xff);
 		dev->dev_addr[1] = ((hi >> 24) & 0xff);
@@ -6279,9 +7157,13 @@
 		dev->dev_addr[0] = (hi >> 8) & 0xff;
 	}
 
-	if (!is_valid_ether_addr(&dev->dev_addr[0]))
+	if (!is_valid_ether_addr(&dev->dev_addr[0])) {
+#ifdef CONFIG_SPARC64
+		if (!tg3_get_default_macaddr_sparc(tp))
+			return 0;
+#endif
 		return -EINVAL;
-
+	}
 	return 0;
 }
 
@@ -6376,8 +7258,6 @@
 		goto out_nofree;
 	}
 
-	tw32(TG3PCI_CLOCK_CTRL, 0);
-
 	if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) == 0) {
 		tp->dma_rwctrl =
 			(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
@@ -6385,7 +7265,9 @@
 			(0x7 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
 			(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
 			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
-		/* XXX 5705 note: set MIN_DMA to zero here */
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+			tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA
+					    << DMA_RWCTRL_MIN_DMA_SHIFT);
 	} else {
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
 			tp->dma_rwctrl =
@@ -6486,8 +7368,15 @@
 		tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
 	}
 
+	tp->dma_rwctrl |= DMA_RWCTRL_ASSERT_ALL_BE;
+
 	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
 
+#if 0
+	/* Unneeded, already done by tg3_get_invariants.  */
+	tg3_switch_clocks(tp);
+#endif
+
 	ret = 0;
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
@@ -6592,12 +7481,35 @@
 	case PHY_ID_BCM5701:	return "5701";
 	case PHY_ID_BCM5703:	return "5703";
 	case PHY_ID_BCM5704:	return "5704";
+	case PHY_ID_BCM5705:	return "5705";
 	case PHY_ID_BCM8002:	return "8002";
 	case PHY_ID_SERDES:	return "serdes";
 	default:		return "unknown";
 	};
 }
 
+static struct pci_dev * __devinit tg3_find_5704_peer(struct tg3 *tp)
+{
+	struct pci_dev *peer = NULL;
+	unsigned int func;
+
+	for (func = 0; func < 7; func++) {
+		unsigned int devfn = tp->pdev->devfn;
+
+		devfn &= ~7;
+		devfn |= func;
+
+		if (devfn == tp->pdev->devfn)
+			continue;
+		peer = pci_find_slot(tp->pdev->bus->number, devfn);
+		if (peer)
+			break;
+	}
+	if (!peer || peer == tp->pdev)
+		BUG();
+	return peer;
+}
+
 static int __devinit tg3_init_one(struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
 {
@@ -6642,10 +7554,10 @@
 	}
 
 	/* Configure DMA attributes. */
-	if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) {
+	if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
 		pci_using_dac = 1;
 	} else {
-		err = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+		err = pci_set_dma_mask(pdev, 0xffffffffULL);
 		if (err) {
 			printk(KERN_ERR PFX "No usable DMA configuration, "
 			       "aborting.\n");
@@ -6673,9 +7585,6 @@
 	dev->vlan_rx_register = tg3_vlan_rx_register;
 	dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid;
 #endif
-#if TG3_DO_TSO != 0
-	dev->features |= NETIF_F_TSO;
-#endif
 
 	tp = dev->priv;
 	tp->pdev = pdev;
@@ -6740,6 +7649,7 @@
 	dev->do_ioctl = tg3_ioctl;
 	dev->tx_timeout = tg3_tx_timeout;
 	dev->poll = tg3_poll;
+	dev->ethtool_ops = &tg3_ethtool_ops;
 	dev->weight = 64;
 	dev->watchdog_timeo = TG3_TX_TIMEOUT;
 	dev->change_mtu = tg3_change_mtu;
@@ -6752,6 +7662,44 @@
 		goto err_out_iounmap;
 	}
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		tp->bufmgr_config.mbuf_read_dma_low_water =
+			DEFAULT_MB_RDMA_LOW_WATER_5705;
+		tp->bufmgr_config.mbuf_mac_rx_low_water =
+			DEFAULT_MB_MACRX_LOW_WATER_5705;
+		tp->bufmgr_config.mbuf_high_water =
+			DEFAULT_MB_HIGH_WATER_5705;
+	}
+
+#if TG3_TSO_SUPPORT != 0
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5705_A0 ||
+	    (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0 ||
+	    (tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
+		tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
+	} else {
+		tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
+	}
+
+	/* TSO is off by default, user can enable using ethtool.  */
+#if 0
+	if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)
+		dev->features |= NETIF_F_TSO;
+#endif
+
+#endif
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
+	    !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) &&
+	    !(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) {
+		tp->tg3_flags2 |= TG3_FLG2_MAX_RXPEND_64;
+		tp->rx_pending = 64;
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+		tp->pdev_peer = tg3_find_5704_peer(tp);
+
 	err = tg3_get_device_address(tp);
 	if (err) {
 		printk(KERN_ERR PFX "Could not obtain valid ethernet address, "
@@ -6774,6 +7722,9 @@
 	} else
 		tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
 
+	if (tp->tg3_flags2 & TG3_FLG2_IS_5788)
+		dev->features &= ~NETIF_F_HIGHDMA;
+
 	err = register_netdev(dev);
 	if (err) {
 		printk(KERN_ERR PFX "Cannot register net device, "
@@ -6866,7 +7817,6 @@
 		spin_lock_irq(&tp->lock);
 		spin_lock(&tp->tx_lock);
 
-		tg3_init_rings(tp);
 		tg3_init_hw(tp);
 
 		spin_unlock(&tp->tx_lock);
@@ -6897,7 +7847,6 @@
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
 
-	tg3_init_rings(tp);
 	tg3_init_hw(tp);
 	tg3_enable_ints(tp);
 
diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h
--- a/drivers/net/tg3.h	Tue Feb 18 11:12:48 2003
+++ b/drivers/net/tg3.h	Mon Aug 25 16:40:22 2003
@@ -24,6 +24,7 @@
 #define RX_COPY_THRESHOLD  		256
 
 #define RX_STD_MAX_SIZE			1536
+#define RX_STD_MAX_SIZE_5705		512
 #define RX_JUMBO_MAX_SIZE		0xdeadbeef /* XXX */
 
 /* First 256 bytes are a mirror of PCI config space. */
@@ -59,7 +60,7 @@
 #define  PCIX_CAPS_SPLIT_SHIFT		 20
 #define  PCIX_CAPS_BURST_MASK		 0x000c0000
 #define  PCIX_CAPS_BURST_SHIFT		 18
-#define  PCIX_CAPS_MAX_BURST_5704	 2
+#define  PCIX_CAPS_MAX_BURST_CPIOB	 2
 #define TG3PCI_PM_CAP_PTR		0x00000041
 #define TG3PCI_X_COMMAND		0x00000042
 #define TG3PCI_X_STATUS			0x00000044
@@ -115,11 +116,14 @@
 #define  CHIPREV_ID_5704_A0		 0x2000
 #define  CHIPREV_ID_5704_A1		 0x2001
 #define  CHIPREV_ID_5704_A2		 0x2002
+#define  CHIPREV_ID_5705_A0		 0x3000
+#define  CHIPREV_ID_5705_A1		 0x3001
 #define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700			 0x07
 #define   ASIC_REV_5701			 0x00
 #define   ASIC_REV_5703			 0x01
 #define   ASIC_REV_5704			 0x02
+#define   ASIC_REV_5705			 0x03
 #define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX		 0x70
 #define   CHIPREV_5700_BX		 0x71
@@ -180,6 +184,9 @@
 #define  CLOCK_CTRL_ALTCLK		 0x00001000
 #define  CLOCK_CTRL_PWRDOWN_PLL133	 0x00008000
 #define  CLOCK_CTRL_44MHZ_CORE		 0x00040000
+#define  CLOCK_CTRL_625_CORE		 0x00100000
+#define  CLOCK_CTRL_FORCE_CLKRUN	 0x00200000
+#define  CLOCK_CTRL_CLKRUN_OENABLE	 0x00400000
 #define  CLOCK_CTRL_DELAY_PCI_GRANT	 0x80000000
 #define TG3PCI_REG_BASE_ADDR		0x00000078
 #define TG3PCI_MEM_WIN_BASE_ADDR	0x0000007c
@@ -457,17 +464,89 @@
 #define MAC_RCV_RULE_CFG		0x00000500
 #define  RCV_RULE_CFG_DEFAULT_CLASS	0x00000008
 #define MAC_LOW_WMARK_MAX_RX_FRAME	0x00000504
-/* 0x504 --> 0x590 unused */
+/* 0x508 --> 0x520 unused */
+#define MAC_HASHREGU_0			0x00000520
+#define MAC_HASHREGU_1			0x00000524
+#define MAC_HASHREGU_2			0x00000528
+#define MAC_HASHREGU_3			0x0000052c
+#define MAC_EXTADDR_0_HIGH		0x00000530
+#define MAC_EXTADDR_0_LOW		0x00000534
+#define MAC_EXTADDR_1_HIGH		0x00000538
+#define MAC_EXTADDR_1_LOW		0x0000053c
+#define MAC_EXTADDR_2_HIGH		0x00000540
+#define MAC_EXTADDR_2_LOW		0x00000544
+#define MAC_EXTADDR_3_HIGH		0x00000548
+#define MAC_EXTADDR_3_LOW		0x0000054c
+#define MAC_EXTADDR_4_HIGH		0x00000550
+#define MAC_EXTADDR_4_LOW		0x00000554
+#define MAC_EXTADDR_5_HIGH		0x00000558
+#define MAC_EXTADDR_5_LOW		0x0000055c
+#define MAC_EXTADDR_6_HIGH		0x00000560
+#define MAC_EXTADDR_6_LOW		0x00000564
+#define MAC_EXTADDR_7_HIGH		0x00000568
+#define MAC_EXTADDR_7_LOW		0x0000056c
+#define MAC_EXTADDR_8_HIGH		0x00000570
+#define MAC_EXTADDR_8_LOW		0x00000574
+#define MAC_EXTADDR_9_HIGH		0x00000578
+#define MAC_EXTADDR_9_LOW		0x0000057c
+#define MAC_EXTADDR_10_HIGH		0x00000580
+#define MAC_EXTADDR_10_LOW		0x00000584
+#define MAC_EXTADDR_11_HIGH		0x00000588
+#define MAC_EXTADDR_11_LOW		0x0000058c
 #define MAC_SERDES_CFG			0x00000590
 #define MAC_SERDES_STAT			0x00000594
 /* 0x598 --> 0x600 unused */
 #define MAC_TX_MAC_STATE_BASE		0x00000600 /* 16 bytes */
 #define MAC_RX_MAC_STATE_BASE		0x00000610 /* 20 bytes */
 /* 0x624 --> 0x800 unused */
-#define MAC_RX_STATS_BASE		0x00000800 /* 26 32-bit words */
-/* 0x868 --> 0x880 unused */
-#define MAC_TX_STATS_BASE		0x00000880 /* 28 32-bit words */
-/* 0x8f0 --> 0xc00 unused */
+#define MAC_TX_STATS_OCTETS		0x00000800
+#define MAC_TX_STATS_RESV1		0x00000804
+#define MAC_TX_STATS_COLLISIONS		0x00000808
+#define MAC_TX_STATS_XON_SENT		0x0000080c
+#define MAC_TX_STATS_XOFF_SENT		0x00000810
+#define MAC_TX_STATS_RESV2		0x00000814
+#define MAC_TX_STATS_MAC_ERRORS		0x00000818
+#define MAC_TX_STATS_SINGLE_COLLISIONS	0x0000081c
+#define MAC_TX_STATS_MULT_COLLISIONS	0x00000820
+#define MAC_TX_STATS_DEFERRED		0x00000824
+#define MAC_TX_STATS_RESV3		0x00000828
+#define MAC_TX_STATS_EXCESSIVE_COL	0x0000082c
+#define MAC_TX_STATS_LATE_COL		0x00000830
+#define MAC_TX_STATS_RESV4_1		0x00000834
+#define MAC_TX_STATS_RESV4_2		0x00000838
+#define MAC_TX_STATS_RESV4_3		0x0000083c
+#define MAC_TX_STATS_RESV4_4		0x00000840
+#define MAC_TX_STATS_RESV4_5		0x00000844
+#define MAC_TX_STATS_RESV4_6		0x00000848
+#define MAC_TX_STATS_RESV4_7		0x0000084c
+#define MAC_TX_STATS_RESV4_8		0x00000850
+#define MAC_TX_STATS_RESV4_9		0x00000854
+#define MAC_TX_STATS_RESV4_10		0x00000858
+#define MAC_TX_STATS_RESV4_11		0x0000085c
+#define MAC_TX_STATS_RESV4_12		0x00000860
+#define MAC_TX_STATS_RESV4_13		0x00000864
+#define MAC_TX_STATS_RESV4_14		0x00000868
+#define MAC_TX_STATS_UCAST		0x0000086c
+#define MAC_TX_STATS_MCAST		0x00000870
+#define MAC_TX_STATS_BCAST		0x00000874
+#define MAC_TX_STATS_RESV5_1		0x00000878
+#define MAC_TX_STATS_RESV5_2		0x0000087c
+#define MAC_RX_STATS_OCTETS		0x00000880
+#define MAC_RX_STATS_RESV1		0x00000884
+#define MAC_RX_STATS_FRAGMENTS		0x00000888
+#define MAC_RX_STATS_UCAST		0x0000088c
+#define MAC_RX_STATS_MCAST		0x00000890
+#define MAC_RX_STATS_BCAST		0x00000894
+#define MAC_RX_STATS_FCS_ERRORS		0x00000898
+#define MAC_RX_STATS_ALIGN_ERRORS	0x0000089c
+#define MAC_RX_STATS_XON_PAUSE_RECVD	0x000008a0
+#define MAC_RX_STATS_XOFF_PAUSE_RECVD	0x000008a4
+#define MAC_RX_STATS_MAC_CTRL_RECVD	0x000008a8
+#define MAC_RX_STATS_XOFF_ENTERED	0x000008ac
+#define MAC_RX_STATS_FRAME_TOO_LONG	0x000008b0
+#define MAC_RX_STATS_JABBERS		0x000008b4
+#define MAC_RX_STATS_UNDERSIZE		0x000008b8
+/* 0x8bc --> 0xc00 unused */
 
 /* Send data initiator control registers */
 #define SNDDATAI_MODE			0x00000c00
@@ -599,6 +678,7 @@
 #define  RCVLPC_STATSCTRL_ENABLE	 0x00000001
 #define  RCVLPC_STATSCTRL_FASTUPD	 0x00000002
 #define RCVLPC_STATS_ENABLE		0x00002018
+#define  RCVLPC_STATSENAB_LNGBRST_RFIX	 0x00400000
 #define RCVLPC_STATS_INCMASK		0x0000201c
 /* 0x2020 --> 0x2100 unused */
 #define RCVLPC_SELLST_BASE		0x00002100 /* 16 16-byte entries */
@@ -812,13 +892,16 @@
 #define BUFMGR_MB_POOL_ADDR		0x00004408
 #define BUFMGR_MB_POOL_SIZE		0x0000440c
 #define BUFMGR_MB_RDMA_LOW_WATER	0x00004410
-#define  DEFAULT_MB_RDMA_LOW_WATER	 0x00000040
+#define  DEFAULT_MB_RDMA_LOW_WATER	 0x00000050
+#define  DEFAULT_MB_RDMA_LOW_WATER_5705	 0x00000000
 #define  DEFAULT_MB_RDMA_LOW_WATER_JUMBO 0x00000130
 #define BUFMGR_MB_MACRX_LOW_WATER	0x00004414
 #define  DEFAULT_MB_MACRX_LOW_WATER	  0x00000020
+#define  DEFAULT_MB_MACRX_LOW_WATER_5705  0x00000010
 #define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
 #define BUFMGR_MB_HIGH_WATER		0x00004418
 #define  DEFAULT_MB_HIGH_WATER		 0x00000060
+#define  DEFAULT_MB_HIGH_WATER_5705	 0x00000060
 #define  DEFAULT_MB_HIGH_WATER_JUMBO	 0x0000017c
 #define BUFMGR_RX_MB_ALLOC_REQ		0x0000441c
 #define  BUFMGR_MB_ALLOC_BIT		 0x10000000
@@ -854,6 +937,8 @@
 #define  RDMAC_MODE_LNGREAD_ENAB	 0x00000200
 #define  RDMAC_MODE_SPLIT_ENABLE	 0x00000800
 #define  RDMAC_MODE_SPLIT_RESET		 0x00001000
+#define  RDMAC_MODE_FIFO_SIZE_128	 0x00020000
+#define  RDMAC_MODE_FIFO_LONG_BURST	 0x00030000
 #define RDMAC_STATUS			0x00004804
 #define  RDMAC_STATUS_TGTABORT		 0x00000004
 #define  RDMAC_STATUS_MSTABORT		 0x00000008
@@ -877,6 +962,7 @@
 #define  WDMAC_MODE_FIFOURUN_ENAB	 0x00000080
 #define  WDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
 #define  WDMAC_MODE_LNGREAD_ENAB	 0x00000200
+#define  WDMAC_MODE_RX_ACCEL	 	 0x00000400
 #define WDMAC_STATUS			0x00004c04
 #define  WDMAC_STATUS_TGTABORT		 0x00000004
 #define  WDMAC_STATUS_MSTABORT		 0x00000008
@@ -1140,7 +1226,10 @@
 #define  GRC_MISC_CFG_BOARD_ID_5704	0x00000000
 #define  GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
 #define  GRC_MISC_CFG_BOARD_ID_5704_A2	0x00008000
+#define  GRC_MISC_CFG_BOARD_ID_5788	0x00010000
+#define  GRC_MISC_CFG_BOARD_ID_5788M	0x00018000
 #define  GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
+#define  GRC_MISC_CFG_KEEP_GPHY_POWER	0x04000000
 #define GRC_LOCAL_CTRL			0x00006808
 #define  GRC_LCLCTRL_INT_ACTIVE		0x00000001
 #define  GRC_LCLCTRL_CLEARINT		0x00000002
@@ -1275,6 +1364,7 @@
 #define  NIC_SRAM_DATA_CFG_WOL_ENABLE		 0x00000040
 #define  NIC_SRAM_DATA_CFG_ASF_ENABLE		 0x00000080
 #define  NIC_SRAM_DATA_CFG_EEPROM_WP		 0x00000100
+#define  NIC_SRAM_DATA_CFG_MINI_PCI		 0x00001000
 #define  NIC_SRAM_DATA_CFG_FIBER_WOL		 0x00004000
 
 #define NIC_SRAM_DATA_PHY_ID		0x00000b74
@@ -1312,6 +1402,8 @@
 #define NIC_SRAM_MBUF_POOL_BASE		0x00008000
 #define  NIC_SRAM_MBUF_POOL_SIZE96	 0x00018000
 #define  NIC_SRAM_MBUF_POOL_SIZE64	 0x00010000
+#define  NIC_SRAM_MBUF_POOL_BASE5705	0x00010000
+#define  NIC_SRAM_MBUF_POOL_SIZE5705	0x0000e000
 
 /* Currently this is fixed. */
 #define PHY_ADDR		0x01
@@ -1823,6 +1915,11 @@
 #define TG3_FLAG_INIT_COMPLETE		0x80000000
 	u32				tg3_flags2;
 #define TG3_FLG2_RESTART_TIMER		0x00000001
+#define TG3_FLG2_SUN_5704		0x00000002
+#define TG3_FLG2_NO_ETH_WIRE_SPEED	0x00000004
+#define TG3_FLG2_IS_5788		0x00000008
+#define TG3_FLG2_MAX_RXPEND_64		0x00000010
+#define TG3_FLG2_TSO_CAPABLE		0x00000020
 
 	u32				split_mode_max_reqs;
 #define SPLIT_MODE_5704_MAX_REQ		3
@@ -1867,6 +1964,7 @@
 #define PHY_ID_BCM5701			0x60008110
 #define PHY_ID_BCM5703			0x60008160
 #define PHY_ID_BCM5704			0x60008190
+#define PHY_ID_BCM5705			0x600081a0
 #define PHY_ID_BCM8002			0x60010140
 #define PHY_ID_SERDES			0xfeedbee0
 #define PHY_ID_INVALID			0xffffffff
@@ -1879,6 +1977,9 @@
 	enum phy_led_mode		led_mode;
 
 	char				board_part_number[24];
+	u32				nic_sram_data_cfg;
+	u32				pci_clock_ctrl;
+	struct pci_dev			*pdev_peer;
 
 	/* This macro assumes the passed PHY ID is already masked
 	 * with PHY_ID_MASK.
@@ -1887,6 +1988,7 @@
 	((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
 	 (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
 	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
+	 (X) == PHY_ID_BCM5705 || \
 	 (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
 
 	struct tg3_hw_stats		*hw_stats;
diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
--- a/drivers/net/tulip/tulip_core.c	Mon Jun 30 01:28:30 2003
+++ b/drivers/net/tulip/tulip_core.c	Sun Aug 17 10:56:20 2003
@@ -232,6 +232,7 @@
 	{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },
 	{ 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },	/* ALi 1563 integrated ethernet */
+	{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	/* 3Com 3CSOHO100B-TX */
 	{ } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
diff -Nru a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
--- a/drivers/net/wan/lmc/lmc_proto.c	Mon Jun  9 13:42:09 2003
+++ b/drivers/net/wan/lmc/lmc_proto.c	Sun Jun  8 03:39:03 2003
@@ -31,7 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <asm/segment.h>
-#include <asm/smp.h>
+#include <linux/smp.h>
 
 #include <linux/in.h>
 #include <linux/if_arp.h>
diff -Nru a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c
--- a/drivers/net/wan/sdla_chdlc.c	Sun Jun 29 08:09:51 2003
+++ b/drivers/net/wan/sdla_chdlc.c	Mon Dec  2 18:10:12 2002
@@ -3819,7 +3819,7 @@
 
 void s508_lock (sdla_t *card, unsigned long *smp_flags)
 {
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
 	spin_lock_irqsave(&card->wandev.lock, *smp_flags);
         if (card->next){
         	spin_lock(&card->next->wandev.lock);
@@ -3831,7 +3831,7 @@
 
 void s508_unlock (sdla_t *card, unsigned long *smp_flags)
 {
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
         if (card->next){
         	spin_unlock(&card->next->wandev.lock);
         }
diff -Nru a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c
--- a/drivers/net/wan/sdla_fr.c	Sun Jun 29 08:09:51 2003
+++ b/drivers/net/wan/sdla_fr.c	Mon Dec  2 18:10:12 2002
@@ -4707,13 +4707,13 @@
 {
 	if (card->hw.type != SDLA_S514){
 
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
 		spin_lock_irqsave(&card->wandev.lock, *smp_flags);
 #else
           	disable_irq(card->hw.irq);
 #endif
 	}else{
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
 		spin_lock(&card->u.f.if_send_lock);
 #endif
 	}
@@ -4725,13 +4725,13 @@
 {
 	if (card->hw.type != SDLA_S514){
 
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
 		spin_unlock_irqrestore (&card->wandev.lock, *smp_flags);
 #else
           	enable_irq(card->hw.irq);
 #endif
 	}else{
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
 		spin_unlock(&card->u.f.if_send_lock);
 #endif
 	}
diff -Nru a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
--- a/drivers/net/wan/sdla_ppp.c	Wed Apr 24 01:58:18 2002
+++ b/drivers/net/wan/sdla_ppp.c	Mon Dec  2 18:10:12 2002
@@ -3331,7 +3331,7 @@
 
 void s508_lock (sdla_t *card, unsigned long *smp_flags)
 {
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
 	spin_lock_irqsave(&card->wandev.lock, *smp_flags);
 #else
 	disable_irq(card->hw.irq);
@@ -3340,7 +3340,7 @@
 
 void s508_unlock (sdla_t *card, unsigned long *smp_flags)
 {
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
         spin_unlock_irqrestore(&card->wandev.lock, *smp_flags);
 #else
 	enable_irq(card->hw.irq);
diff -Nru a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c
--- a/drivers/net/wan/sdlamain.c	Fri Jun 14 16:17:12 2002
+++ b/drivers/net/wan/sdlamain.c	Mon Dec  2 18:10:12 2002
@@ -511,7 +511,7 @@
 	if (!card->configured){
 
 		/* Initialize the Spin lock */
-#if defined(__SMP__) || defined(LINUX_2_4) 
+#if defined(CONFIG_SMP) || defined(LINUX_2_4) 
 		printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name);
 #endif
 
diff -Nru a/drivers/net/wan/wanpipe_multppp.c b/drivers/net/wan/wanpipe_multppp.c
--- a/drivers/net/wan/wanpipe_multppp.c	Mon Feb  4 23:45:17 2002
+++ b/drivers/net/wan/wanpipe_multppp.c	Mon Dec  2 18:10:12 2002
@@ -2358,7 +2358,7 @@
 
 void s508_lock (sdla_t *card, unsigned long *smp_flags)
 {
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
 	spin_lock_irqsave(&card->wandev.lock, *smp_flags);
         if (card->next){
 		/* It is ok to use spin_lock here, since we
@@ -2372,7 +2372,7 @@
 
 void s508_unlock (sdla_t *card, unsigned long *smp_flags)
 {
-#if defined(__SMP__) || defined(LINUX_2_4)
+#if defined(CONFIG_SMP) || defined(LINUX_2_4)
 	if (card->next){
 		spin_unlock(&card->next->wandev.lock);
 	}
diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Tue Jul 29 08:49:48 2003
+++ b/drivers/net/wireless/airo.c	Tue Aug 26 16:46:28 2003
@@ -32,7 +32,6 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
-#include <linux/tqueue.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -83,7 +82,7 @@
 /* Support Cisco MIC feature */
 /* As this feature requires the AES encryption algorithm, it is not included
    in the kernel tree. If you want to enable it, you need to download the
-   aes.h, aestab.h and mic.h files from the CVS at
+   aes.c, aes.h and aestab.h files from the CVS at
    http://sf.net/projects/airo-linux/ Put the files in the same directory
    as airo.c and compile normally */
 #undef MICSUPPORT
@@ -305,6 +304,7 @@
 #define CMD_DEALLOCATETX 0x000c
 #define NOP		0x0010
 #define CMD_WORKAROUND	0x0011
+#define CMD_ALLOCATEAUX 0x0020
 #define CMD_ACCESS	0x0021
 #define CMD_PCIBAP	0x0022
 #define CMD_PCIAUX	0x0023
@@ -409,6 +409,7 @@
 #define EV_ALLOC 0x08
 #define EV_LINK 0x80
 #define EV_AWAKE 0x100
+#define EV_TXCPY 0x400
 #define EV_UNKNOWN 0x800
 #define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
 #define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX | EV_MIC )
@@ -619,14 +620,14 @@
 	u16 arlDelay;
 	u16 _reserved4[1];
 	/*---------- Aironet Extensions ----------*/
-	u16 magicAction;
+	u8 magicAction;
 #define MAGIC_ACTION_STSCHG 1
 #define MACIC_ACTION_RESUME 2
 #define MAGIC_IGNORE_MCAST (1<<8)
 #define MAGIC_IGNORE_BCAST (1<<9)
 #define MAGIC_SWITCH_TO_PSP (0<<10)
 #define MAGIC_STAY_IN_CAM (1<<10)
-	u16 magicControl;
+	u8 magicControl;
 	u16 autoWake;
 } ConfigRid;
 
@@ -639,7 +640,7 @@
 	u16 SSIDlen;
 	char SSID[32];
 	char apName[16];
-	char bssid[4][ETH_ALEN];
+	u8 bssid[4][ETH_ALEN];
 	u16 beaconPeriod;
 	u16 dimPeriod;
 	u16 atimDuration;
@@ -847,6 +848,7 @@
 #define AIROGMICRID		11
 #define AIROGMICSTATS		12
 #define AIROGFLAGS		13
+#define AIRORRID		15
 
 /* Leave gap of 40 commands after AIROGSTATSD32 for future */
 
@@ -963,8 +965,6 @@
 static void enable_interrupts(struct airo_info*);
 static void disable_interrupts(struct airo_info*);
 static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
-static u16 sendcommand(struct airo_info *ai, Cmd *pCmd);
-static void completecommand(struct airo_info *ai, Resp *pRsp);
 static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
 static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
@@ -984,6 +984,8 @@
 
 static void airo_interrupt( int irq, void* dev_id, struct pt_regs
 			    *regs);
+static int airo_thread(void *data);
+static void timer_func( struct net_device *dev );
 static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 #ifdef WIRELESS_EXT
 struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
@@ -994,10 +996,12 @@
 int flashcard(struct net_device *dev, aironet_ioctl *comp);
 #endif /* CISCO_EXT */
 #ifdef MICSUPPORT
-static void micinit(struct airo_info *ai, MICRid *micr);
-static void micsetup(struct airo_info *ai);
+static void micinit(struct airo_info *ai);
+static int micsetup(struct airo_info *ai);
 static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
 static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
+
+#include "aes.c"
 #endif
 
 struct airo_info {
@@ -1013,50 +1017,66 @@
 	int need_commit;	// Need to set config
 	char keyindex; // Used with auto wep
 	char defindex; // Used with auto wep
-	struct timer_list timer;
 	struct proc_dir_entry *proc_entry;
 	struct airo_info *next;
         spinlock_t aux_lock;
         unsigned long flags;
-#define FLAG_PROMISC   IFF_PROMISC	/* 0x100 - include/linux/if.h */
-#define FLAG_RADIO_OFF 0x02		/* User disabling of MAC */
-#define FLAG_RADIO_DOWN 0x08		/* ifup/ifdown disabling of MAC */
-#define FLAG_FLASHING  0x10
-#define FLAG_ADHOC        0x01 /* Needed by MIC */
-#define FLAG_MIC_CAPABLE  0x20
-#define FLAG_UPDATE_MULTI 0x40
-#define FLAG_UPDATE_UNI   0x80
-#define FLAG_802_11    0x200
-#define FLAG_PENDING_XMIT   0x400
-#define FLAG_PENDING_XMIT11 0x800
+#define FLAG_PROMISC	8	/* IFF_PROMISC 0x100 - include/linux/if.h */
+#define FLAG_RADIO_OFF	0	/* User disabling of MAC */
+#define FLAG_RADIO_DOWN	1	/* ifup/ifdown disabling of MAC */
+#define FLAG_RADIO_MASK 0x03
+#define FLAG_FLASHING	2
+#define FLAG_ADHOC	3	/* Needed by MIC */
+#define FLAG_MIC_CAPABLE 4
+#define FLAG_UPDATE_MULTI 5
+#define FLAG_UPDATE_UNI 6
+#define FLAG_802_11	7
+#define FLAG_PENDING_XMIT 9
+#define FLAG_PENDING_XMIT11 10
+#define FLAG_PCI	11
+#define JOB_MASK	0xff0000
+#define JOB_DIE		16
+#define JOB_XMIT	17
+#define JOB_XMIT11	18
+#define JOB_STATS	19
+#define JOB_PROMISC	20
+#define JOB_MIC		21
+#define JOB_EVENT	22
+#define JOB_AUTOWEP	23
 	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
 	unsigned short *flash;
 	tdsRssiEntry *rssi;
-	struct semaphore sem;
 	struct task_struct *task;
-	struct tq_struct stats_task;
-	struct tq_struct promisc_task;
+	struct semaphore sem;
+	pid_t thr_pid;
+	wait_queue_head_t thr_wait;
+	struct completion thr_exited;
+	unsigned long expires;
 	struct {
 		struct sk_buff *skb;
 		int fid;
-		struct tq_struct task;
 	} xmit, xmit11;
 	struct net_device *wifidev;
 #ifdef WIRELESS_EXT
 	struct iw_statistics	wstats;		// wireless stats
 	unsigned long		scan_timestamp;	/* Time started to scan */
-	struct tq_struct	event_task;
+#if WIRELESS_EXT > 15
+	struct iw_spy_data	spy_data;
+#else /* WIRELESS_EXT > 15 */
 #ifdef WIRELESS_SPY
 	int			spy_number;
 	u_char			spy_address[IW_MAX_SPY][ETH_ALEN];
 	struct iw_quality	spy_stat[IW_MAX_SPY];
 #endif /* WIRELESS_SPY */
+#endif /* WIRELESS_EXT > 15 */
 #endif /* WIRELESS_EXT */
+#ifdef MICSUPPORT
 	/* MIC stuff */
+	aes			cx;
 	mic_module		mod[2];
 	mic_statistics		micstats;
-	struct tq_struct 	mic_task;
+#endif
 };
 
 static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
@@ -1070,7 +1090,449 @@
 				struct airo_info *apriv );
 
 #ifdef MICSUPPORT
-#include "mic.h"
+/***********************************************************************
+ *                              MIC ROUTINES                           *
+ ***********************************************************************
+ */
+
+static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
+static void MoveWindow(miccntx *context, u32 micSeq);
+void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, aes *cx);
+void emmh32_init(emmh32_context *context);
+void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
+void emmh32_final(emmh32_context *context, u8 digest[4]);
+
+/* micinit - Initialize mic seed */
+
+static void micinit(struct airo_info *ai)
+{
+	MICRid mic_rid;
+
+	clear_bit(JOB_MIC, &ai->flags);
+	PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
+	up(&ai->sem);
+
+	ai->micstats.enabled = (mic_rid.state & 0x00FF) ? 1 : 0;
+
+	if (ai->micstats.enabled) {
+		/* Key must be valid and different */
+		if (mic_rid.multicastValid && (!ai->mod[0].mCtx.valid ||
+		    (memcmp (ai->mod[0].mCtx.key, mic_rid.multicast,
+			     sizeof(ai->mod[0].mCtx.key)) != 0))) {
+			/* Age current mic Context */
+			memcpy(&ai->mod[1].mCtx,&ai->mod[0].mCtx,sizeof(miccntx));
+			/* Initialize new context */
+			memcpy(&ai->mod[0].mCtx.key,mic_rid.multicast,sizeof(mic_rid.multicast));
+			ai->mod[0].mCtx.window  = 33; //Window always points to the middle
+			ai->mod[0].mCtx.rx      = 0;  //Rx Sequence numbers
+			ai->mod[0].mCtx.tx      = 0;  //Tx sequence numbers
+			ai->mod[0].mCtx.valid   = 1;  //Key is now valid
+  
+			/* Give key to mic seed */
+			emmh32_setseed(&ai->mod[0].mCtx.seed,mic_rid.multicast,sizeof(mic_rid.multicast), &ai->cx);
+		}
+
+		/* Key must be valid and different */
+		if (mic_rid.unicastValid && (!ai->mod[0].uCtx.valid || 
+		    (memcmp(ai->mod[0].uCtx.key, mic_rid.unicast,
+			    sizeof(ai->mod[0].uCtx.key)) != 0))) {
+			/* Age current mic Context */
+			memcpy(&ai->mod[1].uCtx,&ai->mod[0].uCtx,sizeof(miccntx));
+			/* Initialize new context */
+			memcpy(&ai->mod[0].uCtx.key,mic_rid.unicast,sizeof(mic_rid.unicast));
+	
+			ai->mod[0].uCtx.window  = 33; //Window always points to the middle
+			ai->mod[0].uCtx.rx      = 0;  //Rx Sequence numbers
+			ai->mod[0].uCtx.tx      = 0;  //Tx sequence numbers
+			ai->mod[0].uCtx.valid   = 1;  //Key is now valid
+	
+			//Give key to mic seed
+			emmh32_setseed(&ai->mod[0].uCtx.seed, mic_rid.unicast, sizeof(mic_rid.unicast), &ai->cx);
+		}
+	} else {
+      /* So next time we have a valid key and mic is enabled, we will update
+       * the sequence number if the key is the same as before.
+       */
+		ai->mod[0].uCtx.valid = 0;
+		ai->mod[0].mCtx.valid = 0;
+	}
+}
+
+/* micsetup - Get ready for business */
+
+static int micsetup(struct airo_info *ai) {
+	int i;
+
+	for (i=0; i < NUM_MODULES; i++) {
+		memset(&ai->mod[i].mCtx,0,sizeof(miccntx));
+		memset(&ai->mod[i].uCtx,0,sizeof(miccntx));
+	}
+	return SUCCESS;
+}
+
+char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
+
+/*===========================================================================
+ * Description: Mic a packet
+ *    
+ *      Inputs: etherHead * pointer to an 802.3 frame
+ *    
+ *     Returns: BOOLEAN if successful, otherwise false.
+ *             PacketTxLen will be updated with the mic'd packets size.
+ *
+ *    Caveats: It is assumed that the frame buffer will already
+ *             be big enough to hold the largets mic message possible.
+ *            (No memory allocation is done here).
+ *  
+ *    Author: sbraneky (10/15/01)
+ *    Merciless hacks by rwilcher (1/14/02)
+ */
+
+static int encapsulate(struct airo_info *ai ,etherHead *frame, MICBuffer *mic, int payLen)
+{
+	miccntx   *context;
+
+	// Determine correct context
+	// If not adhoc, always use unicast key
+
+	if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1))
+		context = &ai->mod[0].mCtx;
+	else
+		context = &ai->mod[0].uCtx;
+  
+	if (!context->valid)
+		return ERROR;
+
+	mic->typelen = htons(payLen + 16); //Length of Mic'd packet
+
+	memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap
+
+	// Add Tx sequence
+	mic->seq = htonl(context->tx);
+	context->tx += 2;
+
+	emmh32_init(&context->seed); // Mic the packet
+	emmh32_update(&context->seed,frame->da,ETH_ALEN * 2); // DA,SA
+	emmh32_update(&context->seed,(u8*)&mic->typelen,10); // Type/Length and Snap
+	emmh32_update(&context->seed,(u8*)&mic->seq,sizeof(mic->seq)); //SEQ
+	emmh32_update(&context->seed,frame->da + ETH_ALEN * 2,payLen); //payload
+	emmh32_final(&context->seed, (u8*)&mic->mic);
+
+	/*    New Type/length ?????????? */
+	mic->typelen = 0; //Let NIC know it could be an oversized packet
+	return SUCCESS;
+}
+
+typedef enum {
+    NONE,
+    NOMIC,
+    NOMICPLUMMED,
+    SEQUENCE,
+    INCORRECTMIC,
+} mic_error;
+
+/*===========================================================================
+ *  Description: Decapsulates a MIC'd packet and returns the 802.3 packet
+ *               (removes the MIC stuff) if packet is a valid packet.
+ *      
+ *       Inputs: etherHead  pointer to the 802.3 packet             
+ *     
+ *      Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE
+ *     
+ *      Author: sbraneky (10/15/01)
+ *    Merciless hacks by rwilcher (1/14/02)
+ *---------------------------------------------------------------------------
+ */
+
+static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen)
+{
+	int      i;
+	u32      micSEQ;
+	miccntx  *context;
+	u8       digest[4];
+	mic_error micError = NONE;
+
+	// Check if the packet is a Mic'd packet
+
+	if (!ai->micstats.enabled) {
+		//No Mic set or Mic OFF but we received a MIC'd packet.
+		if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) {
+			ai->micstats.rxMICPlummed++;
+			return ERROR;
+		}
+		return SUCCESS;
+	}
+
+	if (ntohs(mic->typelen) == 0x888E)
+		return SUCCESS;
+
+	if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) {
+	    // Mic enabled but packet isn't Mic'd
+		ai->micstats.rxMICPlummed++;
+	    	return ERROR;
+	}
+
+	micSEQ = ntohl(mic->seq);            //store SEQ as CPU order
+
+	//At this point we a have a mic'd packet and mic is enabled
+	//Now do the mic error checking.
+
+	//Receive seq must be odd
+	if ( (micSEQ & 1) == 0 ) {
+		ai->micstats.rxWrongSequence++;
+		return ERROR;
+	}
+
+	for (i = 0; i < NUM_MODULES; i++) {
+		int mcast = eth->da[0] & 1;
+		//Determine proper context 
+		context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx;
+	
+		//Make sure context is valid
+		if (!context->valid) {
+			if (i == 0)
+				micError = NOMICPLUMMED;
+			continue;                
+		}
+	       	//DeMic it 
+
+		if (!mic->typelen)
+			mic->typelen = htons(payLen + sizeof(MICBuffer) - 2);
+	
+		emmh32_init(&context->seed);
+		emmh32_update(&context->seed, eth->da, ETH_ALEN*2); 
+		emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap)); 
+		emmh32_update(&context->seed, (u8 *)&mic->seq,sizeof(mic->seq));	
+		emmh32_update(&context->seed, eth->da + ETH_ALEN*2,payLen);	
+		//Calculate MIC
+		emmh32_final(&context->seed, digest);
+	
+		if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match
+		  //Invalid Mic
+			if (i == 0)
+				micError = INCORRECTMIC;
+			continue;
+		}
+
+		//Check Sequence number if mics pass
+		if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) {
+			ai->micstats.rxSuccess++;
+			return SUCCESS;
+		}
+		if (i == 0)
+			micError = SEQUENCE;
+	}
+
+	// Update statistics
+	switch (micError) {
+		case NOMICPLUMMED: ai->micstats.rxMICPlummed++;   break;
+		case SEQUENCE:    ai->micstats.rxWrongSequence++; break;
+		case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break;
+		case NONE:  break;
+		case NOMIC: break;
+	}
+	return ERROR;
+}
+
+/*===========================================================================
+ * Description:  Checks the Rx Seq number to make sure it is valid
+ *               and hasn't already been received
+ *   
+ *     Inputs: miccntx - mic context to check seq against
+ *             micSeq  - the Mic seq number
+ *   
+ *    Returns: TRUE if valid otherwise FALSE. 
+ *
+ *    Author: sbraneky (10/15/01)
+ *    Merciless hacks by rwilcher (1/14/02)
+ *---------------------------------------------------------------------------
+ */
+
+static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq)
+{
+	u32 seq,index;
+
+	//Allow for the ap being rebooted - if it is then use the next 
+	//sequence number of the current sequence number - might go backwards
+
+	if (mcast) {
+		if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) {
+			clear_bit (FLAG_UPDATE_MULTI, &ai->flags);
+			context->window = (micSeq > 33) ? micSeq : 33;
+			context->rx     = 0;        // Reset rx
+		}
+	} else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) {
+		clear_bit (FLAG_UPDATE_UNI, &ai->flags);
+		context->window = (micSeq > 33) ? micSeq : 33; // Move window
+		context->rx     = 0;        // Reset rx
+	}
+
+	//Make sequence number relative to START of window
+	seq = micSeq - (context->window - 33);
+
+	//Too old of a SEQ number to check.
+	if ((u32)seq < 0)
+		return ERROR;
+    
+	if ( seq > 64 ) {
+		//Window is infinite forward
+		MoveWindow(context,micSeq);
+		return SUCCESS;
+	}
+
+	// We are in the window. Now check the context rx bit to see if it was already sent
+	seq >>= 1;         //divide by 2 because we only have odd numbers
+	index = 1 << seq;  //Get an index number
+
+	if (!(context->rx & index)) {
+		//micSEQ falls inside the window.
+		//Add seqence number to the list of received numbers.
+		context->rx |= index;
+
+		MoveWindow(context,micSeq);
+
+		return SUCCESS;
+	}
+	return ERROR;
+}
+
+static void MoveWindow(miccntx *context, u32 micSeq)
+{
+	u32 shift;
+
+	//Move window if seq greater than the middle of the window
+	if (micSeq > context->window) {
+		shift = (micSeq - context->window) >> 1;
+    
+		    //Shift out old
+		if (shift < 32)
+			context->rx >>= shift;
+		else
+			context->rx = 0;
+
+		context->window = micSeq;      //Move window
+	}
+}
+
+/*==============================================*/
+/*========== EMMH ROUTINES  ====================*/
+/*==============================================*/
+
+/* mic accumulate */
+#define MIC_ACCUM(val)	\
+	context->accum += (u64)(val) * context->coeff[coeff_position++];
+
+static unsigned char aes_counter[16];
+
+/* expand the key to fill the MMH coefficient array */
+void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, aes *cx)
+{
+  /* take the keying material, expand if necessary, truncate at 16-bytes */
+  /* run through AES counter mode to generate context->coeff[] */
+  
+	int i,j;
+	u32 counter;
+	u8 cipher[16];
+
+	set_key(pkey, 16, 1, cx);
+	counter = 0;
+	for (i = 0; i < (sizeof(context->coeff)/sizeof(context->coeff[0])); ) {
+		aes_counter[15] = (u8)(counter >> 0);
+		aes_counter[14] = (u8)(counter >> 8);
+		aes_counter[13] = (u8)(counter >> 16);
+		aes_counter[12] = (u8)(counter >> 24);
+		counter++;
+		encrypt(&aes_counter[0], &cipher[0], cx);
+		for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) {
+			context->coeff[i++] = ntohl(*(u32 *)&cipher[j]);
+			j += 4;
+		}
+	}
+}
+
+/* prepare for calculation of a new mic */
+void emmh32_init(emmh32_context *context)
+{
+	/* prepare for new mic calculation */
+	context->accum = 0;
+	context->position = 0;
+}
+
+/* add some bytes to the mic calculation */
+void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
+{
+	int	coeff_position, byte_position;
+  
+	if (len == 0) return;
+  
+	coeff_position = context->position >> 2;
+  
+	/* deal with partial 32-bit word left over from last update */
+	byte_position = context->position & 3;
+	if (byte_position) {
+		/* have a partial word in part to deal with */
+		do {
+			if (len == 0) return;
+			context->part.d8[byte_position++] = *pOctets++;
+			context->position++;
+			len--;
+		} while (byte_position < 4);
+		MIC_ACCUM(htonl(context->part.d32));
+	}
+
+	/* deal with full 32-bit words */
+	while (len >= 4) {
+		MIC_ACCUM(htonl(*(u32 *)pOctets));
+		context->position += 4;
+		pOctets += 4;
+		len -= 4;
+	}
+
+	/* deal with partial 32-bit word that will be left over from this update */
+	byte_position = 0;
+	while (len > 0) {
+		context->part.d8[byte_position++] = *pOctets++;
+		context->position++;
+		len--;
+	}
+}
+
+/* mask used to zero empty bytes for final partial word */
+static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
+
+/* calculate the mic */
+void emmh32_final(emmh32_context *context, u8 digest[4])
+{
+	int	coeff_position, byte_position;
+	u32	val;
+  
+	u64 sum, utmp;
+	s64 stmp;
+
+	coeff_position = context->position >> 2;
+  
+	/* deal with partial 32-bit word left over from last update */
+	byte_position = context->position & 3;
+	if (byte_position) {
+		/* have a partial word in part to deal with */
+		val = htonl(context->part.d32);
+		MIC_ACCUM(val & mask32[byte_position]);	/* zero empty bytes */
+	}
+
+	/* reduce the accumulated u64 to a 32-bit MIC */
+	sum = context->accum;
+	stmp = (sum  & 0xffffffffLL) - ((sum >> 32)  * 15);
+	utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15);
+	sum = utmp & 0xffffffffLL;
+	if (utmp > 0x10000000fLL)
+		sum -= 15;
+
+	val = (u32)sum;
+	digest[0] = (val>>24) & 0xFF;
+	digest[1] = (val>>16) & 0xFF;
+	digest[2] = (val>>8) & 0xFF;
+	digest[3] = val & 0xFF;
+}
 #endif
 
 static int readBSSListRid(struct airo_info *ai, int first,
@@ -1203,12 +1665,12 @@
 
 	ai->need_commit = 0;
 	checkThrottle(ai);
+	cfgr = ai->config;
+
 	if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
-		ai->flags |= FLAG_ADHOC;
+		set_bit(FLAG_ADHOC, &ai->flags);
 	else
-		ai->flags &= ~FLAG_ADHOC;
-
-	cfgr = ai->config;
+		clear_bit(FLAG_ADHOC, &ai->flags);
 
 	for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
 
@@ -1272,7 +1734,7 @@
 	struct airo_info *info = dev->priv;
 	Resp rsp;
 
-	if (info->flags & FLAG_FLASHING)
+	if (test_bit(FLAG_FLASHING, &info->flags))
 		return -EIO;
 
 	/* Make sure the card is configured.
@@ -1286,7 +1748,7 @@
 
 	if (info->wifidev != dev) {
 		/* Power on the MAC controller (which may have been disabled) */
-		info->flags &= ~FLAG_RADIO_DOWN;
+		clear_bit(FLAG_RADIO_DOWN, &info->flags);
 		enable_interrupts(info);
 	}
 	enable_MAC(info, &rsp, 1);
@@ -1344,7 +1806,7 @@
 	}
 }
 
-static void airo_do_xmit(struct net_device *dev) {
+static void airo_end_xmit(struct net_device *dev) {
 	u16 status;
 	int i;
 	struct airo_info *priv = dev->priv;
@@ -1352,17 +1814,10 @@
 	int fid = priv->xmit.fid;
 	u32 *fids = priv->fids;
 
-	if (down_trylock(&priv->sem) != 0) {
-		priv->flags |= FLAG_PENDING_XMIT;
-		netif_stop_queue(dev);
-		priv->xmit.task.routine = (void (*)(void *))airo_do_xmit;
-		priv->xmit.task.data = (void *)dev;
-		schedule_task(&priv->xmit.task);
-		return;
-	}
+	clear_bit(JOB_XMIT, &priv->flags);
+	clear_bit(FLAG_PENDING_XMIT, &priv->flags);
 	status = transmit_802_3_packet (priv, fids[fid], skb->data);
 	up(&priv->sem);
-	priv->flags &= ~FLAG_PENDING_XMIT;
 
 	i = 0;
 	if ( status == SUCCESS ) {
@@ -1406,11 +1861,17 @@
 	fids[i] |= (len << 16);
 	priv->xmit.skb = skb;
 	priv->xmit.fid = i;
-	airo_do_xmit(dev);
+	if (down_trylock(&priv->sem) != 0) {
+		set_bit(FLAG_PENDING_XMIT, &priv->flags);
+		netif_stop_queue(dev);
+		set_bit(JOB_XMIT, &priv->flags);
+		wake_up_interruptible(&priv->thr_wait);
+	} else
+		airo_end_xmit(dev);
 	return 0;
 }
 
-static void airo_do_xmit11(struct net_device *dev) {
+static void airo_end_xmit11(struct net_device *dev) {
 	u16 status;
 	int i;
 	struct airo_info *priv = dev->priv;
@@ -1418,17 +1879,10 @@
 	int fid = priv->xmit11.fid;
 	u32 *fids = priv->fids;
 
-	if (down_trylock(&priv->sem) != 0) {
-		priv->flags |= FLAG_PENDING_XMIT11;
-		netif_stop_queue(dev);
-		priv->xmit11.task.routine = (void (*)(void *))airo_do_xmit11;
-		priv->xmit11.task.data = (void *)dev;
-		schedule_task(&priv->xmit11.task);
-		return;
-	}
+	clear_bit(JOB_XMIT11, &priv->flags);
+	clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
 	status = transmit_802_11_packet (priv, fids[fid], skb->data);
 	up(&priv->sem);
-	priv->flags &= ~FLAG_PENDING_XMIT11;
 
 	i = MAX_FIDS / 2;
 	if ( status == SUCCESS ) {
@@ -1472,7 +1926,13 @@
 	fids[i] |= (len << 16);
 	priv->xmit11.skb = skb;
 	priv->xmit11.fid = i;
-	airo_do_xmit11(dev);
+	if (down_trylock(&priv->sem) != 0) {
+		set_bit(FLAG_PENDING_XMIT11, &priv->flags);
+		netif_stop_queue(dev);
+		set_bit(JOB_XMIT11, &priv->flags);
+		wake_up_interruptible(&priv->thr_wait);
+	} else
+		airo_end_xmit11(dev);
 	return 0;
 }
 
@@ -1480,29 +1940,24 @@
 	StatsRid stats_rid;
 	u32 *vals = stats_rid.vals;
 
-	if (down_trylock(&ai->sem) == 0) {
-		readStatsRid(ai, &stats_rid, RID_STATS, 0);
-		up(&ai->sem);
+	clear_bit(JOB_STATS, &ai->flags);
+	readStatsRid(ai, &stats_rid, RID_STATS, 0);
+	up(&ai->sem);
 
-		ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
-		ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
-		ai->stats.rx_bytes = vals[92];
-		ai->stats.tx_bytes = vals[91];
-		ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
-		ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
-		ai->stats.multicast = vals[43];
-		ai->stats.collisions = vals[89];
-
-		/* detailed rx_errors: */
-		ai->stats.rx_length_errors = vals[3];
-		ai->stats.rx_crc_errors = vals[4];
-		ai->stats.rx_frame_errors = vals[2];
-		ai->stats.rx_fifo_errors = vals[0];
-	} else {
-		ai->stats_task.routine = (void (*)(void *))airo_read_stats;
-		ai->stats_task.data = (void *)ai;
-		schedule_task(&ai->stats_task);
-	}
+	ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
+	ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
+	ai->stats.rx_bytes = vals[92];
+	ai->stats.tx_bytes = vals[91];
+	ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
+	ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
+	ai->stats.multicast = vals[43];
+	ai->stats.collisions = vals[89];
+
+	/* detailed rx_errors: */
+	ai->stats.rx_length_errors = vals[3];
+	ai->stats.rx_crc_errors = vals[4];
+	ai->stats.rx_frame_errors = vals[2];
+	ai->stats.rx_fifo_errors = vals[0];
 }
 
 struct net_device_stats *airo_get_stats(struct net_device *dev)
@@ -1510,46 +1965,37 @@
 	struct airo_info *local =  dev->priv;
 
 	/* Get stats out of the card if available */
-	airo_read_stats(local);
+	if (down_trylock(&local->sem) != 0) {
+		set_bit(JOB_STATS, &local->flags);
+		wake_up_interruptible(&local->thr_wait);
+	} else
+		airo_read_stats(local);
 
 	return &local->stats;
 }
 
-static void airo_end_promisc(struct airo_info *ai) {
-	Resp rsp;
-
-	if ((IN4500(ai, EVSTAT) & EV_CMD) != 0) {
-		completecommand(ai, &rsp);
-		up(&ai->sem);
-	} else {
-		ai->promisc_task.routine = (void (*)(void *))airo_end_promisc;
-		ai->promisc_task.data = (void *)ai;
-		schedule_task(&ai->promisc_task);
-	}
-}
-
 static void airo_set_promisc(struct airo_info *ai) {
 	Cmd cmd;
+	Resp rsp;
 
-	if (down_trylock(&ai->sem) == 0) {
-		memset(&cmd, 0, sizeof(cmd));
-		cmd.cmd=CMD_SETMODE;
-		cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
-		sendcommand(ai, &cmd);
-		airo_end_promisc(ai);
-	} else {
-		ai->promisc_task.routine = (void (*)(void *))airo_set_promisc;
-		ai->promisc_task.data = (void *)ai;
-		schedule_task(&ai->promisc_task);
-	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd=CMD_SETMODE;
+	clear_bit(JOB_PROMISC, &ai->flags);
+	cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
+	issuecommand(ai, &cmd, &rsp);
+	up(&ai->sem);
 }
 
 static void airo_set_multicast_list(struct net_device *dev) {
 	struct airo_info *ai = dev->priv;
 
 	if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
-		ai->flags ^= IFF_PROMISC;
-		airo_set_promisc(ai);
+		change_bit(FLAG_PROMISC, &ai->flags);
+		if (down_trylock(&ai->sem) != 0) {
+			set_bit(JOB_PROMISC, &ai->flags);
+			wake_up_interruptible(&ai->thr_wait);
+		} else
+			airo_set_promisc(ai);
 	}
 
 	if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
@@ -1563,6 +2009,7 @@
 	struct sockaddr *addr = p;
 	Resp rsp;
 
+	readConfigRid(ai, 1);
 	memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
 	ai->need_commit = 1;
 	disable_MAC(ai, 1);
@@ -1595,7 +2042,7 @@
 		 * That's the method that is most friendly towards the network
 		 * stack (i.e. the network stack won't try to broadcast
 		 * anything on the interface and routes are gone. Jean II */
-		ai->flags |= FLAG_RADIO_DOWN;
+		set_bit(FLAG_RADIO_DOWN, &ai->flags);
 		disable_MAC(ai, 1);
 #endif
 		disable_interrupts( ai );
@@ -1608,13 +2055,8 @@
 void stop_airo_card( struct net_device *dev, int freeres )
 {
 	struct airo_info *ai = dev->priv;
-	flush_scheduled_tasks();
 	disable_interrupts(ai);
 	free_irq( dev->irq, dev );
-	if (ai->flash)
-		kfree(ai->flash);
-	if (ai->rssi)
-		kfree(ai->rssi);
 	takedown_proc_entry( dev, ai );
 	if (ai->registered) {
 		unregister_netdev( dev );
@@ -1625,7 +2067,13 @@
 		}
 		ai->registered = 0;
 	}
-	if (auto_wep) del_timer_sync(&ai->timer);
+	set_bit(JOB_DIE, &ai->flags);
+	kill_proc(ai->thr_pid, SIGTERM, 1);
+	wait_for_completion(&ai->thr_exited);
+	if (ai->flash)
+		kfree(ai->flash);
+	if (ai->rssi)
+		kfree(ai->rssi);
 	if (freeres) {
 		/* PCMCIA frees this stuff, so only for PCI and ISA */
 	        release_region( dev->base_addr, 64 );
@@ -1726,9 +2174,15 @@
 	sema_init(&ai->sem, 1);
 	ai->need_commit = 0;
 	ai->config.len = 0;
+	init_waitqueue_head (&ai->thr_wait);
+	init_completion (&ai->thr_exited);
+	ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
+	if (ai->thr_pid < 0)
+		goto err_out_free;
+
 	rc = add_airo_dev( dev );
 	if (rc)
-		goto err_out_free;
+		goto err_out_thr;
 
 	/* The Airo-specific entries in the device structure. */
 	dev->hard_start_xmit = &airo_start_xmit;
@@ -1768,7 +2222,7 @@
 		}
 	} else {
 		ai->bap_read = fast_bap_read;
-		ai->flags |= FLAG_FLASHING;
+		set_bit(FLAG_FLASHING, &ai->flags);
 	}
 
 	rc = register_netdev(dev);
@@ -1799,6 +2253,10 @@
 	free_irq(dev->irq, dev);
 err_out_unlink:
 	del_airo_dev(dev);
+err_out_thr:
+	set_bit(JOB_DIE, &ai->flags);
+	kill_proc(ai->thr_pid, SIGTERM, 1);
+	wait_for_completion(&ai->thr_exited);
 err_out_free:
 	kfree(dev);
 	return NULL;
@@ -1862,38 +2320,108 @@
 	union iwreq_data wrqu;
 	StatusRid status_rid;
 
-	if (down_trylock(&ai->sem) == 0) {
-		PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
-		up(&ai->sem);
-		wrqu.data.length = 0;
-		wrqu.data.flags = 0;
-		memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
-		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	clear_bit(JOB_EVENT, &ai->flags);
+	PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
+	up(&ai->sem);
+	wrqu.data.length = 0;
+	wrqu.data.flags = 0;
+	memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 
-		/* Send event to user space */
-		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-	} else {
-		ai->event_task.routine = (void (*)(void *))airo_send_event;
-		ai->event_task.data = (void *)dev;
-		schedule_task(&ai->event_task);
-	}
+	/* Send event to user space */
+	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 }
 #endif
 
-static void airo_read_mic(struct airo_info *ai) {
-	MICRid mic_rid;
+static int airo_thread(void *data) {
+	struct net_device *dev = data;
+	struct airo_info *ai = dev->priv;
+	int locked;
+	
+	daemonize();
+	reparent_to_init();
+	spin_lock_irq(&current->sigmask_lock);
+	sigemptyset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
+	current->comm[sizeof(current->comm) - 1] = '\0';
+
+	while(1) {
+		if (signal_pending(current)) {
+			spin_lock_irq(&current->sigmask_lock);
+			flush_signals(current);
+			spin_unlock_irq(&current->sigmask_lock);
+		}
 
-	if (down_trylock(&ai->sem) == 0) {
-		PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
-		up(&ai->sem);
+		if (test_bit(JOB_DIE, &ai->flags))
+			break;
+
+		if (ai->flags & JOB_MASK) {
+			locked = down_interruptible(&ai->sem);
+		} else {
+			wait_queue_t wait;
+
+			init_waitqueue_entry(&wait, current);
+			add_wait_queue(&ai->thr_wait, &wait);
+			for (;;) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (ai->flags & JOB_MASK)
+					break;
+				if (ai->expires) {
+					if (time_after_eq(jiffies,ai->expires)){
+						set_bit(JOB_AUTOWEP,&ai->flags);
+						break;
+					}
+					if (!signal_pending(current)) {
+						schedule_timeout(ai->expires - jiffies);
+						continue;
+					}
+				} else if (!signal_pending(current)) {
+					schedule();
+					continue;
+				}
+				break;
+			}
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&ai->thr_wait, &wait);
+			locked = 1;
+		}
+
+		if (locked)
+			continue;
+
+		if (test_bit(JOB_DIE, &ai->flags)) {
+			up(&ai->sem);
+			break;
+		}
+
+		if (test_bit(FLAG_FLASHING, &ai->flags)) {
+			up(&ai->sem);
+			continue;
+		}
+
+		if (test_bit(JOB_XMIT, &ai->flags))
+			airo_end_xmit(dev);
+		else if (test_bit(JOB_XMIT11, &ai->flags))
+			airo_end_xmit11(dev);
+		else if (test_bit(JOB_STATS, &ai->flags))
+			airo_read_stats(ai);
+		else if (test_bit(JOB_PROMISC, &ai->flags))
+			airo_set_promisc(ai);
 #ifdef MICSUPPORT
-		micinit (ai, &mic_rid);
+		else if (test_bit(JOB_MIC, &ai->flags))
+			micinit(ai);
 #endif
-	} else {
-		ai->mic_task.routine = (void (*)(void *))airo_read_mic;
-		ai->mic_task.data = (void *)ai;
-		schedule_task(&ai->mic_task);
+#if WIRELESS_EXT > 13
+		else if (test_bit(JOB_EVENT, &ai->flags))
+			airo_send_event(dev);
+#endif
+		else if (test_bit(JOB_AUTOWEP, &ai->flags))
+			timer_func(dev);
 	}
+	complete_and_exit (&ai->thr_exited, 0);
 }
 
 static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
@@ -1922,8 +2450,15 @@
 
 		if ( status & EV_MIC ) {
 			OUT4500( apriv, EVACK, EV_MIC );
-			if (apriv->flags & FLAG_MIC_CAPABLE)
-				airo_read_mic( apriv );
+#ifdef MICSUPPORT
+			if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
+				if (down_trylock(&apriv->sem) != 0) {
+					set_bit(JOB_MIC, &apriv->flags);
+					wake_up_interruptible(&apriv->thr_wait);
+				} else
+					micinit (apriv);
+			}
+#endif
 		}
 		if ( status & EV_LINK ) {
 #if WIRELESS_EXT > 13
@@ -1965,15 +2500,18 @@
 #define RC_NOAUTH 9 /* Station requesting (Re)Association is not
 		       Authenticated with the responding station */
 			if (newStatus != ASSOCIATED) {
-				if (auto_wep && !timer_pending(&apriv->timer)) {
-					apriv->timer.expires = RUN_AT(HZ*3);
-		      			add_timer(&apriv->timer);
+				if (auto_wep && !apriv->expires) {
+					apriv->expires = RUN_AT(3*HZ);
+					wake_up_interruptible(&apriv->thr_wait);
 				}
 			} else {
 				struct task_struct *task = apriv->task;
+				if (auto_wep)
+					apriv->expires = 0;
 				if (task)
 					wake_up_process (task);
-				apriv->flags|=FLAG_UPDATE_UNI|FLAG_UPDATE_MULTI;
+				set_bit(FLAG_UPDATE_UNI, &apriv->flags);
+				set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
 			}
 #if WIRELESS_EXT > 13
 			/* Question : is ASSOCIATED the only status
@@ -1994,7 +2532,11 @@
 					wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
 					apriv->scan_timestamp = 0;
 				}
-				airo_send_event(dev);
+				if (down_trylock(&apriv->sem) != 0) {
+					set_bit(JOB_EVENT, &apriv->flags);
+					wake_up_interruptible(&apriv->thr_wait);
+				} else
+					airo_send_event(dev);
 			} else {
 				memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
 				wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -2025,7 +2567,7 @@
 			fid = IN4500( apriv, RXFID );
 
 			/* Get the packet length */
-			if (apriv->flags & FLAG_802_11) {
+			if (test_bit(FLAG_802_11, &apriv->flags)) {
 				bap_setup (apriv, fid, 4, BAP0);
 				bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
 				/* Bad CRC. Ignore packet */
@@ -2041,145 +2583,149 @@
 
 			if (len > 2312) {
 				printk( KERN_ERR "airo: Bad size %d\n", len );
-				len = 0;
+				goto badrx;
 			}
-			if (len) {
-				if (apriv->flags & FLAG_802_11) {
-					bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
-					fc = le16_to_cpu(fc);
-					switch (fc & 0xc) {
-						case 4:
-							if ((fc & 0xe0) == 0xc0)
-								hdrlen = 10;
-							else
-								hdrlen = 16;
-							break;
-						case 8:
-							if ((fc&0x300)==0x300){
-								hdrlen = 30;
-								break;
-							}
-						default:
-							hdrlen = 24;
-					}
-				} else
-					hdrlen = ETH_ALEN * 2;
+			if (len == 0)
+				goto badrx;
 
-				skb = dev_alloc_skb( len + hdrlen + 2 );
-				if ( !skb ) {
-					apriv->stats.rx_dropped++;
-					len = 0;
-				}
-			}
-			if (len) {
-				buffer = (u16*)skb_put (skb, len + hdrlen);
-				if (apriv->flags & FLAG_802_11) {
-					buffer[0] = fc;
-					bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
-					if (hdrlen == 24)
-						bap_read (apriv, tmpbuf, 6, BAP0);
-
-					bap_read (apriv, &gap, sizeof(gap), BAP0);
-					gap = le16_to_cpu(gap);
-					if (gap) {
-						if (gap <= 8)
-							bap_read (apriv, tmpbuf, gap, BAP0);
+			if (test_bit(FLAG_802_11, &apriv->flags)) {
+				bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
+				fc = le16_to_cpu(fc);
+				switch (fc & 0xc) {
+					case 4:
+						if ((fc & 0xe0) == 0xc0)
+							hdrlen = 10;
 						else
-							printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n");
-					}
-
-
-					bap_read (apriv, buffer + hdrlen/2, len, BAP0);
-				} else {
-					MICBuffer micbuf;
-					bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
-					if (apriv->micstats.enabled) {
-						bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
-						if (ntohs(micbuf.typelen) > 0x05DC)
-							bap_setup (apriv, fid, 0x44, BAP0);
-						else {
-							len -= sizeof(micbuf);
-							if (len < 48)
-								len = 48;
-							skb_trim (skb, len + hdrlen);
+							hdrlen = 16;
+						break;
+					case 8:
+						if ((fc&0x300)==0x300){
+							hdrlen = 30;
+							break;
 						}
-					}
-					bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
+					default:
+						hdrlen = 24;
+				}
+			} else
+				hdrlen = ETH_ALEN * 2;
+
+			skb = dev_alloc_skb( len + hdrlen + 2 );
+			if ( !skb ) {
+				apriv->stats.rx_dropped++;
+				goto badrx;
+			}
+			buffer = (u16*)skb_put (skb, len + hdrlen);
+			if (test_bit(FLAG_802_11, &apriv->flags)) {
+				buffer[0] = fc;
+				bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
+				if (hdrlen == 24)
+					bap_read (apriv, tmpbuf, 6, BAP0);
+
+				bap_read (apriv, &gap, sizeof(gap), BAP0);
+				gap = le16_to_cpu(gap);
+				if (gap) {
+					if (gap <= 8)
+						bap_read (apriv, tmpbuf, gap, BAP0);
+					else
+						printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n");
+				}
+				bap_read (apriv, buffer + hdrlen/2, len, BAP0);
+			} else {
+#ifdef MICSUPPORT
+				MICBuffer micbuf;
+#endif
+				bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
 #ifdef MICSUPPORT
-					if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
-						dev_kfree_skb_irq (skb);
-						len = 0;
+				if (apriv->micstats.enabled) {
+					bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
+					if (ntohs(micbuf.typelen) > 0x05DC)
+						bap_setup (apriv, fid, 0x44, BAP0);
+					else {
+						if (len <= sizeof(micbuf))
+							goto badmic;
+
+						len -= sizeof(micbuf);
+						skb_trim (skb, len + hdrlen);
 					}
+				}
 #endif
+				bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
+#ifdef MICSUPPORT
+				if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
+badmic:
+					dev_kfree_skb_irq (skb);
+badrx:
+					OUT4500( apriv, EVACK, EV_RX);
+					goto badrx;
 				}
+#endif
 			}
-			if (len) {
 #if WIRELESS_EXT > 15
 #ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
-				if (apriv->spy_data.spy_number > 0) {
-					char *sa;
-					struct iw_quality wstats;
-					/* Prepare spy data : addr + qual */
-					sa = (char*)buffer + ((apriv->flags & FLAG_802_11) ? 10 : 6);
-					if (!(apriv->flags & FLAG_802_11)) {
-						bap_setup (apriv, fid, 8, BAP0);
-						bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
-					}
-					wstats.qual = hdr.rssi[0];
-					if (apriv->rssi)
-						wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
-					else
-						wstats.level = (hdr.rssi[1] + 321) / 2;
-					wstats.updated = 3;	
-					/* Update spy records */
-					wireless_spy_update(dev, sa, &wstats);
-				}
+			if (apriv->spy_data.spy_number > 0) {
+				char *sa;
+				struct iw_quality wstats;
+				/* Prepare spy data : addr + qual */
+				if (!test_bit(FLAG_802_11, &apriv->flags)) {
+					sa = (char*)buffer + 6;
+					bap_setup (apriv, fid, 8, BAP0);
+					bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
+				} else
+					sa = (char*)buffer + 10;
+				wstats.qual = hdr.rssi[0];
+				if (apriv->rssi)
+					wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
+				else
+					wstats.level = (hdr.rssi[1] + 321) / 2;
+				wstats.updated = 3;	
+				/* Update spy records */
+				wireless_spy_update(dev, sa, &wstats);
+			}
 #endif /* IW_WIRELESS_SPY */
 #else /* WIRELESS_EXT > 15 */
 #ifdef WIRELESS_SPY
-				if (apriv->spy_number > 0) {
-					int i;
-					char *sa;
-
-					sa = (char*)buffer + ((apriv->flags & FLAG_802_11) ? 10 : 6);
-
-					for (i=0; i<apriv->spy_number; i++)
-						if (!memcmp(sa,apriv->spy_address[i],ETH_ALEN))
-						{
-							if (!(apriv->flags & FLAG_802_11)) {
-								bap_setup (apriv, fid, 8, BAP0);
-								bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
-							}
-							apriv->spy_stat[i].qual = hdr.rssi[0];
-							if (apriv->rssi)
-								apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
-							else
-								apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2;
-							apriv->spy_stat[i].noise = 0;
-							apriv->spy_stat[i].updated = 3;
-							break;
+			if (apriv->spy_number > 0) {
+				int i;
+				char *sa;
+
+				sa = (char*)buffer + (test_bit(FLAG_802_11, &apriv->flags) ? 10 : 6);
+
+				for (i=0; i<apriv->spy_number; i++)
+					if (!memcmp(sa,apriv->spy_address[i],ETH_ALEN))
+					{
+						if (!test_bit(FLAG_802_11, &apriv->flags)) {
+							bap_setup (apriv, fid, 8, BAP0);
+							bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
 						}
-				}
+						apriv->spy_stat[i].qual = hdr.rssi[0];
+						if (apriv->rssi)
+							apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
+						else
+							apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2;
+						apriv->spy_stat[i].noise = 0;
+						apriv->spy_stat[i].updated = 3;
+						break;
+					}
+			}
 #endif /* WIRELESS_SPY  */
 #endif /* WIRELESS_EXT > 15 */
-				OUT4500( apriv, EVACK, EV_RX);
+			OUT4500( apriv, EVACK, EV_RX);
 
-				if (apriv->flags & FLAG_802_11) {
-					skb->mac.raw = skb->data;
-					skb->pkt_type = PACKET_OTHERHOST;
-					skb->dev = apriv->wifidev;
-					skb->protocol = htons(ETH_P_802_2);
-				} else {
-					skb->dev = dev;
-					skb->protocol = eth_type_trans(skb,dev);
-				}
-				skb->dev->last_rx = jiffies;
-				skb->ip_summed = CHECKSUM_NONE;
+			if (test_bit(FLAG_802_11, &apriv->flags)) {
+				skb->mac.raw = skb->data;
+				skb->pkt_type = PACKET_OTHERHOST;
+				skb->dev = apriv->wifidev;
+				skb->protocol = htons(ETH_P_802_2);
+			} else {
+				skb->dev = dev;
+				skb->protocol = eth_type_trans(skb,dev);
+			}
+			skb->dev->last_rx = jiffies;
+			skb->ip_summed = CHECKSUM_NONE;
 
-				netif_rx( skb );
-			} else
-				OUT4500( apriv, EVACK, EV_RX);
+			netif_rx( skb );
 		}
+badrx:
 
 		/* Check to see if a packet has been transmitted */
 		if (  status & ( EV_TX|EV_TXEXC ) ) {
@@ -2202,10 +2748,10 @@
 				/* Set up to be used again */
 				apriv->fids[index] &= 0xffff;
 				if (index < MAX_FIDS / 2) {
-					if (!(apriv->flags & FLAG_PENDING_XMIT))
+					if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags))
 						netif_wake_queue(dev);
 				} else {
-					if (!(apriv->flags & FLAG_PENDING_XMIT11))
+					if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags))
 						netif_wake_queue(apriv->wifidev);
 				}
 			} else {
@@ -2265,7 +2811,7 @@
 	 * instead of this flag, but I don't trust it *within* the
 	 * open/close functions, and testing both flags together is
 	 * "cheaper" - Jean II */
-	if (ai->flags & (FLAG_RADIO_OFF|FLAG_RADIO_DOWN)) return SUCCESS;
+	if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_ENABLE;
 	if (!lock)
@@ -2384,12 +2930,15 @@
 				printk(KERN_WARNING "airo: unknown received signal level scale\n");
 		}
 		ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
+		ai->config.authType = AUTH_OPEN;
+		ai->config.modulation = MOD_CCK;
+		ai->config._reserved1a[0] = 2; /* ??? */
 
 #ifdef MICSUPPORT
-		if ((cap_rid.len==sizeof(cap_rid)) && (cap_rid.extSoftCap&1)) {
+		if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) &&
+		    (micsetup(ai) == SUCCESS)) {
 			ai->config.opmode |= MODE_MIC;
-			ai->flags |= FLAG_MIC_CAPABLE;
-			micsetup(ai);
+			set_bit(FLAG_MIC_CAPABLE, &ai->flags);
 		}
 #endif
 
@@ -2430,6 +2979,7 @@
 			memcpy(mySsid.ssids[i].ssid, ssids[i],
 			       mySsid.ssids[i].len);
 		}
+		mySsid.len = sizeof(mySsid);
 	}
 
 	status = writeConfigRid(ai, 1);
@@ -2455,34 +3005,15 @@
 		rc = readWepKeyRid(ai, &wkr, 0);
 	} while(lastindex != wkr.kindex);
 
-	if (auto_wep && !timer_pending(&ai->timer)) {
-		ai->timer.expires = RUN_AT(HZ*3);
-		add_timer(&ai->timer);
+	if (auto_wep) {
+		ai->expires = RUN_AT(3*HZ);
+		wake_up_interruptible(&ai->thr_wait);
 	}
-	return SUCCESS;
-}
-
-static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
-        // Im really paranoid about letting it run forever!
-	int max_tries = 600000;
 
-	if (sendcommand(ai, pCmd) == (u16)ERROR)
-		return ERROR;
-
-	while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
-		if (!in_interrupt() && (max_tries & 255) == 0)
-			schedule();
-	}
-	if ( max_tries == -1 ) {
-		printk( KERN_ERR
-			"airo: Max tries exceeded waiting for command\n" );
-                return ERROR;
-	}
-	completecommand(ai, pRsp);
 	return SUCCESS;
 }
 
-static u16 sendcommand(struct airo_info *ai, Cmd *pCmd) {
+static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
         // Im really paranoid about letting it run forever!
 	int max_tries = 600000;
 	u16 cmd;
@@ -2501,10 +3032,16 @@
 			"airo: Max tries exceeded when issueing command\n" );
                 return ERROR;
 	}
-	return SUCCESS;
-}
 
-static void completecommand(struct airo_info *ai, Resp *pRsp) {
+	while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
+		if (!in_interrupt() && (max_tries & 255) == 0)
+			schedule();
+	}
+	if ( max_tries == -1 ) {
+		printk( KERN_ERR
+			"airo: Max tries exceeded waiting for command\n" );
+                return ERROR;
+	}
 	// command completed
 	pRsp->status = IN4500(ai, STATUS);
 	pRsp->rsp0 = IN4500(ai, RESP0);
@@ -2517,6 +3054,8 @@
 	}
 	// acknowledge processing the status/response
 	OUT4500(ai, EVACK, EV_CMD);
+
+	return SUCCESS;
 }
 
 /* Sets up the bap to start exchange data.  whichbap should
@@ -2803,7 +3342,7 @@
 	len -= ETH_ALEN * 2;
 
 #ifdef MICSUPPORT
-	if ((ai->flags & FLAG_MIC_CAPABLE) && ai->micstats.enabled && 
+	if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && 
 	    (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
 		if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
 			return ERROR;
@@ -3306,7 +3845,7 @@
 			if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
 					ai->need_commit = 2;
 			ai->config.rmode &= 0xfe00;
-			ai->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &ai->flags);
 			ai->config.opmode &= 0xFF00;
 			ai->config.scanMode = SCANMODE_ACTIVE;
 			if ( line[0] == 'a' ) {
@@ -3316,11 +3855,11 @@
 				if ( line[0] == 'r' ) {
 					ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
 					ai->config.scanMode = SCANMODE_PASSIVE;
-					ai->flags |= FLAG_802_11;
+					set_bit (FLAG_802_11, &ai->flags);
 				} else if ( line[0] == 'y' ) {
 					ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
 					ai->config.scanMode = SCANMODE_PASSIVE;
-					ai->flags |= FLAG_802_11;
+					set_bit (FLAG_802_11, &ai->flags);
 				} else if ( line[0] == 'l' )
 					ai->config.rmode |= RXMODE_LANMON;
 			}
@@ -3331,9 +3870,9 @@
 		else if (!strncmp(line,"Radio: ", 7)) {
 			line += 7;
 			if (!strncmp(line,"off",3)) {
-				ai->flags |= FLAG_RADIO_OFF;
+				set_bit (FLAG_RADIO_OFF, &ai->flags);
 			} else {
-				ai->flags &= ~FLAG_RADIO_OFF;
+				clear_bit (FLAG_RADIO_OFF, &ai->flags);
 			}
 		}
 /*** NodeName processing */
@@ -3537,7 +4076,7 @@
 		     (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
 		     (ai->config.opmode & 0xFF) == 2 ? "AP" :
 		     (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
-		     ai->flags&FLAG_RADIO_OFF ? "off" : "on",
+		     test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
 		     ai->config.nodeName,
 		     ai->config.powerSaveMode == 0 ? "CAM" :
 		     ai->config.powerSaveMode == 1 ? "PSP" :
@@ -3615,6 +4154,8 @@
 		       offset < data->writelen ) offset++;
 		offset++;
 	}
+	if (i)
+		SSID_rid.len = sizeof(SSID_rid);
 	disable_MAC(ai, 1);
 	writeSsidRid(ai, &SSID_rid);
 	enable_MAC(ai, &rsp, 1);
@@ -4004,23 +4545,14 @@
    will switch WEP modes to see if that will help.  If the card is
    associated we will check every minute to see if anything has
    changed. */
-static void timer_func( u_long data ) {
-	struct net_device *dev = (struct net_device*)data;
+static void timer_func( struct net_device *dev ) {
 	struct airo_info *apriv = dev->priv;
-	u16 linkstat = IN4500(apriv, LINKSTAT);
 	Resp rsp;
 
-	if (!(apriv->flags & FLAG_FLASHING) && (linkstat != 0x400)) {
 /* We don't have a link so try changing the authtype */
-		if (down_trylock(&apriv->sem) != 0) {
-			apriv->timer.expires = RUN_AT(1);
-			add_timer(&apriv->timer);
-			return;
-		}
-
-		readConfigRid(apriv, 0);
-		disable_MAC(apriv, 0);
-		switch(apriv->config.authType) {
+	readConfigRid(apriv, 0);
+	disable_MAC(apriv, 0);
+	switch(apriv->config.authType) {
 		case AUTH_ENCRYPT:
 /* So drop to OPEN */
 			apriv->config.authType = AUTH_OPEN;
@@ -4039,16 +4571,15 @@
 			break;
 		default:  /* We'll escalate to SHAREDKEY */
 			apriv->config.authType = AUTH_SHAREDKEY;
-		}
-		apriv->need_commit = 1;
-		writeConfigRid(apriv, 0);
-		enable_MAC(apriv, &rsp, 0);
-		up(&apriv->sem);
+	}
+	apriv->need_commit = 1;
+	writeConfigRid(apriv, 0);
+	enable_MAC(apriv, &rsp, 0);
+	up(&apriv->sem);
 
 /* Schedule check to see if the change worked */
-		apriv->timer.expires = RUN_AT(HZ*3);
-		add_timer(&apriv->timer);
-	}
+	clear_bit(JOB_AUTOWEP, &apriv->flags);
+	apriv->expires = RUN_AT(HZ*3);
 }
 
 static int add_airo_dev( struct net_device *dev ) {
@@ -4056,15 +4587,6 @@
 	if ( !node )
 		return -ENOMEM;
 
-	if ( auto_wep ) {
-		struct airo_info *apriv=dev->priv;
-		struct timer_list *timer = &apriv->timer;
-
-		timer->function = timer_func;
-		timer->data = (u_long)dev;
-		init_timer(timer);
-	}
-
 	node->dev = dev;
 	node->next = airo_devices;
 	airo_devices = node;
@@ -4095,6 +4617,7 @@
 		return -ENODEV;
 
 	pci_set_drvdata(pdev, dev);
+	clear_bit (FLAG_PCI, &((struct airo_info *)dev->priv)->flags);
 	return 0;
 }
 
@@ -4136,11 +4659,19 @@
 
 static void __exit airo_cleanup_module( void )
 {
+	int is_pci = 0;
 	while( airo_devices ) {
 		printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
+#ifdef CONFIG_PCI
+		if (test_bit(FLAG_PCI, &((struct airo_info *)airo_devices->dev->priv)->flags))
+			is_pci = 1;
+#endif
 		stop_airo_card( airo_devices->dev, 1 );
 	}
 	remove_proc_entry("aironet", proc_root_driver);
+
+	if (is_pci)
+		pci_unregister_driver(&airo_driver);
 }
 
 #ifdef WIRELESS_EXT
@@ -4202,6 +4733,7 @@
 			printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m);
 			rc = -EINVAL;
 		} else {
+			readConfigRid(local, 1);
 			/* Yes ! We can set it !!! */
 			local->config.channelSet = (u16)(channel - 1);
 			local->need_commit = 1;
@@ -4222,6 +4754,7 @@
 	struct airo_info *local = dev->priv;
 	StatusRid status_rid;		/* Card status info */
 
+	readConfigRid(local, 1);
 	if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
 		status_rid.channel = local->config.channelSet;
 	else
@@ -4278,6 +4811,7 @@
 		       sizeof(SSID_rid.ssids[index].ssid));
 		memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
 		SSID_rid.ssids[index].len = dwrq->length - 1;
+		SSID_rid.len = sizeof(SSID_rid);
 	}
 	/* Write it to the card */
 	disable_MAC(local, 1);
@@ -4387,6 +4921,7 @@
 	if(dwrq->length > 16 + 1) {
 		return -E2BIG;
 	}
+	readConfigRid(local, 1);
 	memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
 	memcpy(local->config.nodeName, extra, dwrq->length);
 	local->need_commit = 1;
@@ -4405,6 +4940,7 @@
 {
 	struct airo_info *local = dev->priv;
 
+	readConfigRid(local, 1);
 	strncpy(extra, local->config.nodeName, 16);
 	extra[16] = '\0';
 	dwrq->length = strlen(extra) + 1;
@@ -4461,6 +4997,7 @@
 		return -EINVAL;
 	}
 
+	readConfigRid(local, 1);
 	/* Now, check if we want a fixed or auto value */
 	if(vwrq->fixed == 0) {
 		/* Fill all the rates up to this max rate */
@@ -4497,6 +5034,7 @@
 
 	vwrq->value = status_rid.currentXmitRate * 500000;
 	/* If more than one rate, set auto */
+	readConfigRid(local, 1);
 	vwrq->fixed = (local->config.rates[1] == 0);
 
 	return 0;
@@ -4519,6 +5057,7 @@
 	if((rthr < 0) || (rthr > 2312)) {
 		return -EINVAL;
 	}
+	readConfigRid(local, 1);
 	local->config.rtsThres = rthr;
 	local->need_commit = 1;
 
@@ -4536,6 +5075,7 @@
 {
 	struct airo_info *local = dev->priv;
 
+	readConfigRid(local, 1);
 	vwrq->value = local->config.rtsThres;
 	vwrq->disabled = (vwrq->value >= 2312);
 	vwrq->fixed = 1;
@@ -4561,6 +5101,7 @@
 		return -EINVAL;
 	}
 	fthr &= ~0x1;	/* Get an even value - is it really needed ??? */
+	readConfigRid(local, 1);
 	local->config.fragThresh = (u16)fthr;
 	local->need_commit = 1;
 
@@ -4578,6 +5119,7 @@
 {
 	struct airo_info *local = dev->priv;
 
+	readConfigRid(local, 1);
 	vwrq->value = local->config.fragThresh;
 	vwrq->disabled = (vwrq->value >= 2312);
 	vwrq->fixed = 1;
@@ -4597,6 +5139,7 @@
 	struct airo_info *local = dev->priv;
 	int commit = 1;
 
+	readConfigRid(local, 1);
 	if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
 		commit = 2;
 
@@ -4606,28 +5149,28 @@
 			local->config.opmode |= MODE_STA_IBSS;
 			local->config.rmode &= 0xfe00;
 			local->config.scanMode = SCANMODE_ACTIVE;
-			local->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_INFRA:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_STA_ESS;
 			local->config.rmode &= 0xfe00;
 			local->config.scanMode = SCANMODE_ACTIVE;
-			local->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_MASTER:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_AP;
 			local->config.rmode &= 0xfe00;
 			local->config.scanMode = SCANMODE_ACTIVE;
-			local->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_REPEAT:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_AP_RPTR;
 			local->config.rmode &= 0xfe00;
 			local->config.scanMode = SCANMODE_ACTIVE;
-			local->flags &= ~FLAG_802_11;
+			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_MONITOR:
 			local->config.opmode &= 0xFF00;
@@ -4635,7 +5178,7 @@
 			local->config.rmode &= 0xfe00;
 			local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
 			local->config.scanMode = SCANMODE_PASSIVE;
-			local->flags |= FLAG_802_11;
+			set_bit (FLAG_802_11, &local->flags);
 			break;
 		default:
 			return -EINVAL;
@@ -4656,6 +5199,7 @@
 {
 	struct airo_info *local = dev->priv;
 
+	readConfigRid(local, 1);
 	/* If not managed, assume it's ad-hoc */
 	switch (local->config.opmode & 0xFF) {
 		case MODE_STA_ESS:
@@ -4692,6 +5236,7 @@
 	if(!(cap_rid.softCap & 2)) {
 		return -EOPNOTSUPP;
 	} */
+	readConfigRid(local, 1);
 
 	/* Basic checking: do we have a key to set ?
 	 * Note : with the new API, it's impossible to get a NULL pointer.
@@ -4778,6 +5323,7 @@
 	if(!(cap_rid.softCap & 2)) {
 		return -EOPNOTSUPP;
 	}
+	readConfigRid(local, 1);
 	/* Check encryption mode */
 	switch(local->config.authType)	{
 		case AUTH_ENCRYPT:
@@ -4824,16 +5370,17 @@
 	readCapabilityRid(local, &cap_rid);
 
 	if (vwrq->disabled) {
-		local->flags |= FLAG_RADIO_OFF;
+		set_bit (FLAG_RADIO_OFF, &local->flags);
 		local->need_commit = 1;
 		return -EINPROGRESS;		/* Call commit handler */
 	}
 	if (vwrq->flags != IW_TXPOW_MWATT) {
 		return -EINVAL;
 	}
-	local->flags &= ~FLAG_RADIO_OFF;
+	clear_bit (FLAG_RADIO_OFF, &local->flags);
 	for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
 		if ((vwrq->value==cap_rid.txPowerLevels[i])) {
+			readConfigRid(local, 1);
 			local->config.txPower = vwrq->value;
 			local->need_commit = 1;
 			rc = -EINPROGRESS;	/* Call commit handler */
@@ -4853,9 +5400,10 @@
 {
 	struct airo_info *local = dev->priv;
 
+	readConfigRid(local, 1);
 	vwrq->value = local->config.txPower;
 	vwrq->fixed = 1;	/* No power control */
-	vwrq->disabled = (local->flags & FLAG_RADIO_OFF);
+	vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
 	vwrq->flags = IW_TXPOW_MWATT;
 
 	return 0;
@@ -4876,6 +5424,7 @@
 	if(vwrq->disabled) {
 		return -EINVAL;
 	}
+	readConfigRid(local, 1);
 	if(vwrq->flags & IW_RETRY_LIMIT) {
 		if(vwrq->flags & IW_RETRY_MAX)
 			local->config.longRetryLimit = vwrq->value;
@@ -4910,6 +5459,7 @@
 
 	vwrq->disabled = 0;      /* Can't be disabled */
 
+	readConfigRid(local, 1);
 	/* Note : by default, display the min retry number */
 	if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
 		vwrq->flags = IW_RETRY_LIFETIME;
@@ -5048,6 +5598,7 @@
 {
 	struct airo_info *local = dev->priv;
 
+	readConfigRid(local, 1);
 	if (vwrq->disabled) {
 		if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
 			return -EINVAL;
@@ -5104,6 +5655,7 @@
 {
 	struct airo_info *local = dev->priv;
 
+	readConfigRid(local, 1);
 	int mode = local->config.powerSaveMode;
 	if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
 		return 0;
@@ -5133,6 +5685,7 @@
 {
 	struct airo_info *local = dev->priv;
 
+	readConfigRid(local, 1);
 	local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
 	local->need_commit = 1;
 
@@ -5150,6 +5703,7 @@
 {
 	struct airo_info *local = dev->priv;
 
+	readConfigRid(local, 1);
 	vwrq->value = local->config.rssiThreshold;
 	vwrq->disabled = (vwrq->value == 0);
 	vwrq->fixed = 1;
@@ -5199,7 +5753,7 @@
 			      & status_rid.bssid[i][2]
 			      & status_rid.bssid[i][3]
 			      & status_rid.bssid[i][4]
-			      & status_rid.bssid[i][5])!=-1 &&
+			      & status_rid.bssid[i][5])!=0xff &&
 			     (status_rid.bssid[i][0]
 			      | status_rid.bssid[i][1]
 			      | status_rid.bssid[i][2]
@@ -5293,7 +5847,7 @@
 	capabilities = le16_to_cpu(list->cap);
 	if(capabilities & (CAP_ESS | CAP_IBSS)) {
 		if(capabilities & CAP_ESS)
-			iwe.u.mode = IW_MODE_INFRA;
+			iwe.u.mode = IW_MODE_MASTER;
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
 		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
@@ -5505,10 +6059,14 @@
 		writeSsidRid(local, &SSID_rid);
 		writeAPListRid(local, &APList_rid);
 	}
-	writeConfigRid(local, 1);
-	enable_MAC(local, &rsp, 1);
+	if (down_interruptible(&local->sem))
+		return -ERESTARTSYS;
+	writeConfigRid(local, 0);
+	enable_MAC(local, &rsp, 0);
 	if (local->need_commit > 1)
 		airo_set_promisc(local);
+	else
+		up(&local->sem);
 
 	return 0;
 }
@@ -5954,7 +6512,7 @@
 
 		/* Separate R/W functions bracket legality here
 		 */
-		if ( com.command <= AIROGMICSTATS )
+		if ( com.command <= AIRORRID )
 			rc = readrids(dev,&com);
 		else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
 			rc = writerids(dev,&com);
@@ -6044,9 +6602,10 @@
 static int readrids(struct net_device *dev, aironet_ioctl *comp) {
 	unsigned short ridcode;
 	unsigned char *iobuf;
+	int len;
 	struct airo_info *ai = dev->priv;
 
-	if (ai->flags & FLAG_FLASHING)
+	if (test_bit(FLAG_FLASHING, &ai->flags))
 		return -EIO;
 
 	switch(comp->command)
@@ -6071,11 +6630,14 @@
 	case AIROGSTAT:     ridcode = RID_STATUS;       break;
 	case AIROGSTATSD32: ridcode = RID_STATSDELTA;   break;
 	case AIROGSTATSC32: ridcode = RID_STATS;        break;
+#ifdef MICSUPPORT
 	case AIROGMICSTATS:
 		if (copy_to_user(comp->data, &ai->micstats,
 				 min((int)comp->len,(int)sizeof(ai->micstats))))
 			return -EFAULT;
 		return 0;
+#endif
+	case AIRORRID:      ridcode = comp->len;        break;
 	default:
 		return -EINVAL;
 		break;
@@ -6089,9 +6651,12 @@
 	 * then return it to the user
 	 * 9/22/2000 Honor user given length
 	 */
+	if (comp->command == AIRORRID)
+		len = le16_to_cpu(*(unsigned short *)iobuf); /* Yuck! */
+	else
+		len = comp->len;
 
-	if (copy_to_user(comp->data, iobuf,
-			 min((int)comp->len, (int)RIDS_SIZE))) {
+	if (copy_to_user(comp->data, iobuf, min(len, (int)RIDS_SIZE))) {
 		kfree (iobuf);
 		return -EFAULT;
 	}
@@ -6114,7 +6679,7 @@
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	if (ai->flags & FLAG_FLASHING)
+	if (test_bit(FLAG_FLASHING, &ai->flags))
 		return -EIO;
 
 	ridcode = 0;
@@ -6159,9 +6724,11 @@
 
 		PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDS_SIZE, 1);
 
+#ifdef MICSUPPORT
 		enabled = ai->micstats.enabled;
 		memset(&ai->micstats,0,sizeof(ai->micstats));
 		ai->micstats.enabled = enabled;
+#endif
 
 		if (copy_to_user(comp->data, iobuf,
 				 min((int)comp->len, (int)RIDS_SIZE))) {
@@ -6188,13 +6755,13 @@
 	if (comp->command == AIROPCFG) {
 		ConfigRid *cfg = (ConfigRid *)iobuf;
 
-		if (ai->flags & FLAG_MIC_CAPABLE)
+		if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
 			cfg->opmode |= MODE_MIC;
 
 		if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
-			ai->flags |= FLAG_ADHOC;
+			set_bit (FLAG_ADHOC, &ai->flags);
 		else
-			ai->flags &= ~FLAG_ADHOC;
+			clear_bit (FLAG_ADHOC, &ai->flags);
 	}
 
 	if((*writer)(ai, ridcode, iobuf,comp->len,1)) {
@@ -6305,7 +6872,7 @@
  */
 
 int setflashmode (struct airo_info *ai) {
-	ai->flags |= FLAG_FLASHING;
+	set_bit (FLAG_FLASHING, &ai->flags);
 
 	OUT4500(ai, SWS0, FLASH_COMMAND);
 	OUT4500(ai, SWS1, FLASH_COMMAND);
@@ -6321,7 +6888,7 @@
 	schedule_timeout (HZ/2); /* 500ms delay */
 
 	if(!waitbusy(ai)) {
-		ai->flags &= ~FLAG_FLASHING;
+		clear_bit (FLAG_FLASHING, &ai->flags);
 		printk(KERN_INFO "Waitbusy hang after setflash mode\n");
 		return -EIO;
 	}
@@ -6427,7 +6994,7 @@
 
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	schedule_timeout (HZ);          /* Added 12/7/00 */
-	ai->flags &= ~FLAG_FLASHING;
+	clear_bit (FLAG_FLASHING, &ai->flags);
 	status = setup_card(ai, dev->dev_addr);
 
 	for( i = 0; i < MAX_FIDS; i++ ) {
diff -Nru a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
--- a/drivers/net/yellowfin.c	Mon Jan  6 07:38:15 2003
+++ b/drivers/net/yellowfin.c	Sun Aug 31 06:33:37 2003
@@ -867,8 +867,6 @@
 	/* Calculate the next Tx descriptor entry. */
 	entry = yp->cur_tx % TX_RING_SIZE;
 
-	yp->tx_skbuff[entry] = skb;
-
 	if (gx_fix) {	/* Note: only works for paddable protocols e.g.  IP. */
 		int cacheline_end = ((unsigned long)skb->data + skb->len) % 32;
 		/* Fix GX chipset errata. */
@@ -885,6 +883,8 @@
 			return 0;
 		}
 	}
+	yp->tx_skbuff[entry] = skb;
+
 #ifdef NO_TXSTATS
 	yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev, 
 		skb->data, len, PCI_DMA_TODEVICE));
diff -Nru a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/zorro8390.c	Sat Jun 28 11:31:44 2003
@@ -0,0 +1,427 @@
+/*
+ *  Amiga Linux/m68k and Linux/PPC Zorro NS8390 Ethernet Driver
+ *
+ *  (C) Copyright 1998-2000 by some Elitist 680x0 Users(TM)
+ *
+ *  ---------------------------------------------------------------------------
+ *
+ *  This program is based on all the other NE2000 drivers for Linux
+ *
+ *  ---------------------------------------------------------------------------
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of the Linux
+ *  distribution for more details.
+ *
+ *  ---------------------------------------------------------------------------
+ *
+ *  The Ariadne II and X-Surf are Zorro-II boards containing Realtek RTL8019AS
+ *  Ethernet Controllers.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/zorro.h>
+
+#include <asm/system.h>
+
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+
+#include "8390.h"
+
+
+#define NE_BASE		(dev->base_addr)
+#define NE_CMD		(0x00*2)
+#define NE_DATAPORT	(0x10*2)	/* NatSemi-defined port window offset. */
+#define NE_RESET	(0x1f*2)	/* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT	(0x20*2)
+
+#define NE_EN0_ISR	(0x07*2)
+#define NE_EN0_DCFG	(0x0e*2)
+
+#define NE_EN0_RSARLO	(0x08*2)
+#define NE_EN0_RSARHI	(0x09*2)
+#define NE_EN0_RCNTLO	(0x0a*2)
+#define NE_EN0_RXCR	(0x0c*2)
+#define NE_EN0_TXCR	(0x0d*2)
+#define NE_EN0_RCNTHI	(0x0b*2)
+#define NE_EN0_IMR	(0x0f*2)
+
+#define NESM_START_PG	0x40	/* First page of TX buffer */
+#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
+
+
+#define WORDSWAP(a)	((((a)>>8)&0xff) | ((a)<<8))
+
+#ifdef MODULE
+static struct net_device *root_zorro8390_dev;
+#endif
+
+static const struct card_info {
+    zorro_id id;
+    const char *name;
+    unsigned int offset;
+} cards[] __initdata = {
+    { ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2, "Ariadne II", 0x0600 },
+    { ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, "X-Surf", 0x8600 },
+};
+
+static int __init zorro8390_probe(void);
+static int __init zorro8390_init(struct net_device *dev, unsigned long board,
+				 const char *name, unsigned long ioaddr);
+static int zorro8390_open(struct net_device *dev);
+static int zorro8390_close(struct net_device *dev);
+static void zorro8390_reset_8390(struct net_device *dev);
+static void zorro8390_get_8390_hdr(struct net_device *dev,
+				   struct e8390_pkt_hdr *hdr, int ring_page);
+static void zorro8390_block_input(struct net_device *dev, int count,
+				  struct sk_buff *skb, int ring_offset);
+static void zorro8390_block_output(struct net_device *dev, const int count,
+				   const unsigned char *buf,
+				   const int start_page);
+static void __exit zorro8390_cleanup(void);
+
+static int __init zorro8390_probe(void)
+{
+    struct net_device *dev;
+    struct zorro_dev *z = NULL;
+    unsigned long board, ioaddr;
+    int err = -ENODEV;
+    int i;
+
+    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+	for (i = ARRAY_SIZE(cards)-1; i >= 0; i--)
+	    if (z->id == cards[i].id)
+		break;
+	if (i < 0)
+	    continue;
+	board = z->resource.start;
+	ioaddr = board+cards[i].offset;
+	dev = init_etherdev(0, 0);
+	SET_MODULE_OWNER(dev);
+	if (!dev)
+	    return -ENOMEM;
+	if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name)) {
+	    kfree(dev);
+	    continue;
+	}
+	if ((err = zorro8390_init(dev, board, cards[i].name,
+				  ZTWO_VADDR(ioaddr)))) {
+	    release_mem_region(ioaddr, NE_IO_EXTENT*2);
+	    kfree(dev);
+	    return err;
+	}
+	err = 0;
+    }
+
+    if (err == -ENODEV)
+	printk("No Ariadne II or X-Surf ethernet card found.\n");
+    return err;
+}
+
+static int __init zorro8390_init(struct net_device *dev, unsigned long board,
+				 const char *name, unsigned long ioaddr)
+{
+    int i;
+    unsigned char SA_prom[32];
+    int start_page, stop_page;
+    static u32 zorro8390_offsets[16] = {
+	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+	0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+    };
+
+    /* Reset card. Who knows what dain-bramaged state it was left in. */
+    {
+	unsigned long reset_start_time = jiffies;
+
+	z_writeb(z_readb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+	while ((z_readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
+	    if (jiffies - reset_start_time > 2*HZ/100) {
+		printk(" not found (no reset ack).\n");
+		return -ENODEV;
+	    }
+
+	z_writeb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
+    }
+
+    /* Read the 16 bytes of station address PROM.
+       We must first initialize registers, similar to NS8390_init(eifdev, 0).
+       We can't reliably read the SAPROM address without this.
+       (I learned the hard way!). */
+    {
+	struct {
+	    u32 value;
+	    u32 offset;
+	} program_seq[] = {
+	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
+	    {0x48,	NE_EN0_DCFG},	/* Set byte-wide (0x48) access. */
+	    {0x00,	NE_EN0_RCNTLO},	/* Clear the count regs. */
+	    {0x00,	NE_EN0_RCNTHI},
+	    {0x00,	NE_EN0_IMR},	/* Mask completion irq. */
+	    {0xFF,	NE_EN0_ISR},
+	    {E8390_RXOFF, NE_EN0_RXCR},	/* 0x20  Set to monitor */
+	    {E8390_TXOFF, NE_EN0_TXCR},	/* 0x02  and loopback mode. */
+	    {32,	NE_EN0_RCNTLO},
+	    {0x00,	NE_EN0_RCNTHI},
+	    {0x00,	NE_EN0_RSARLO},	/* DMA starting at 0x0000. */
+	    {0x00,	NE_EN0_RSARHI},
+	    {E8390_RREAD+E8390_START, NE_CMD},
+	};
+	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+	    z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
+	}
+    }
+    for (i = 0; i < 16; i++) {
+	SA_prom[i] = z_readb(ioaddr + NE_DATAPORT);
+	(void)z_readb(ioaddr + NE_DATAPORT);
+    }
+
+    /* We must set the 8390 for word mode. */
+    z_writeb(0x49, ioaddr + NE_EN0_DCFG);
+    start_page = NESM_START_PG;
+    stop_page = NESM_STOP_PG;
+
+    dev->base_addr = ioaddr;
+    dev->irq = IRQ_AMIGA_PORTS;
+
+    /* Install the Interrupt handler */
+    i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, dev->name, dev);
+    if (i) return i;
+
+    /* Allocate dev->priv and fill in 8390 specific dev fields. */
+    if (ethdev_init(dev)) {
+	printk("Unable to get memory for dev->priv.\n");
+	return -ENOMEM;
+    }
+
+    for(i = 0; i < ETHER_ADDR_LEN; i++) {
+#ifdef DEBUG
+	printk(" %2.2x", SA_prom[i]);
+#endif
+	dev->dev_addr[i] = SA_prom[i];
+    }
+
+    printk("%s: %s at 0x%08lx, Ethernet Address "
+	   "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, name, board,
+	   dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+	   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+    ei_status.name = name;
+    ei_status.tx_start_page = start_page;
+    ei_status.stop_page = stop_page;
+    ei_status.word16 = 1;
+
+    ei_status.rx_start_page = start_page + TX_PAGES;
+
+    ei_status.reset_8390 = &zorro8390_reset_8390;
+    ei_status.block_input = &zorro8390_block_input;
+    ei_status.block_output = &zorro8390_block_output;
+    ei_status.get_8390_hdr = &zorro8390_get_8390_hdr;
+    ei_status.reg_offset = zorro8390_offsets;
+    dev->open = &zorro8390_open;
+    dev->stop = &zorro8390_close;
+#ifdef MODULE
+    ei_status.priv = (unsigned long)root_zorro8390_dev;
+    root_zorro8390_dev = dev;
+#endif
+    NS8390_init(dev, 0);
+    return 0;
+}
+
+static int zorro8390_open(struct net_device *dev)
+{
+    ei_open(dev);
+    return 0;
+}
+
+static int zorro8390_close(struct net_device *dev)
+{
+    if (ei_debug > 1)
+	printk("%s: Shutting down ethercard.\n", dev->name);
+    ei_close(dev);
+    return 0;
+}
+
+/* Hard reset the card.  This used to pause for the same period that a
+   8390 reset command required, but that shouldn't be necessary. */
+static void zorro8390_reset_8390(struct net_device *dev)
+{
+    unsigned long reset_start_time = jiffies;
+
+    if (ei_debug > 1)
+	printk("resetting the 8390 t=%ld...", jiffies);
+
+    z_writeb(z_readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+    ei_status.txing = 0;
+    ei_status.dmaing = 0;
+
+    /* This check _should_not_ be necessary, omit eventually. */
+    while ((z_readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
+	if (jiffies - reset_start_time > 2*HZ/100) {
+	    printk("%s: ne_reset_8390() did not complete.\n", dev->name);
+	    break;
+	}
+    z_writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+static void zorro8390_get_8390_hdr(struct net_device *dev,
+				   struct e8390_pkt_hdr *hdr, int ring_page)
+{
+    int nic_base = dev->base_addr;
+    int cnt;
+    short *ptrs;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+	printk("%s: DMAing conflict in ne_get_8390_hdr "
+	   "[DMAstat:%d][irqlock:%d].\n", dev->name, ei_status.dmaing,
+	   ei_status.irqlock);
+	return;
+    }
+
+    ei_status.dmaing |= 0x01;
+    z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    z_writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
+    z_writeb(0, nic_base + NE_EN0_RCNTHI);
+    z_writeb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
+    z_writeb(ring_page, nic_base + NE_EN0_RSARHI);
+    z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+    ptrs = (short*)hdr;
+    for (cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
+	*ptrs++ = z_readw(NE_BASE + NE_DATAPORT);
+
+    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+
+    hdr->count = WORDSWAP(hdr->count);
+
+    ei_status.dmaing &= ~0x01;
+}
+
+/* Block input and output, similar to the Crynwr packet driver.  If you
+   are porting to a new ethercard, look at the packet driver source for hints.
+   The NEx000 doesn't share the on-board packet memory -- you have to put
+   the packet out through the "remote DMA" dataport using z_writeb. */
+
+static void zorro8390_block_input(struct net_device *dev, int count,
+				  struct sk_buff *skb, int ring_offset)
+{
+    int nic_base = dev->base_addr;
+    char *buf = skb->data;
+    short *ptrs;
+    int cnt;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+	printk("%s: DMAing conflict in ne_block_input "
+	   "[DMAstat:%d][irqlock:%d].\n",
+	   dev->name, ei_status.dmaing, ei_status.irqlock);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    z_writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    z_writeb(count >> 8, nic_base + NE_EN0_RCNTHI);
+    z_writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
+    z_writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
+    z_writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+    ptrs = (short*)buf;
+    for (cnt = 0; cnt < (count>>1); cnt++)
+	*ptrs++ = z_readw(NE_BASE + NE_DATAPORT);
+    if (count & 0x01)
+	buf[count-1] = z_readb(NE_BASE + NE_DATAPORT);
+
+    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+}
+
+static void zorro8390_block_output(struct net_device *dev, int count,
+				   const unsigned char *buf,
+				   const int start_page)
+{
+    int nic_base = NE_BASE;
+    unsigned long dma_start;
+    short *ptrs;
+    int cnt;
+
+    /* Round the count up for word writes.  Do we need to do this?
+       What effect will an odd byte count have on the 8390?
+       I should check someday. */
+    if (count & 0x01)
+	count++;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+	printk("%s: DMAing conflict in ne_block_output."
+	   "[DMAstat:%d][irqlock:%d]\n", dev->name, ei_status.dmaing,
+	   ei_status.irqlock);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    /* We should already be in page 0, but to be safe... */
+    z_writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+
+   /* Now the normal output. */
+    z_writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    z_writeb(count >> 8,   nic_base + NE_EN0_RCNTHI);
+    z_writeb(0x00, nic_base + NE_EN0_RSARLO);
+    z_writeb(start_page, nic_base + NE_EN0_RSARHI);
+
+    z_writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+    ptrs = (short*)buf;
+    for (cnt = 0; cnt < count>>1; cnt++)
+	z_writew(*ptrs++, NE_BASE+NE_DATAPORT);
+
+    dma_start = jiffies;
+
+    while ((z_readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
+	if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+		printk("%s: timeout waiting for Tx RDC.\n", dev->name);
+		zorro8390_reset_8390(dev);
+		NS8390_init(dev,1);
+		break;
+	}
+
+    z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+    return;
+}
+
+static void __exit zorro8390_cleanup(void)
+{
+#ifdef MODULE
+    struct net_device *dev, *next;
+
+    while ((dev = root_zorro8390_dev)) {
+	next = (struct net_device *)(ei_status.priv);
+	unregister_netdev(dev);
+	free_irq(IRQ_AMIGA_PORTS, dev);
+	release_mem_region(ZTWO_PADDR(dev->base_addr), NE_IO_EXTENT*2);
+	kfree(dev);
+	root_zorro8390_dev = next;
+    }
+#endif
+}
+
+module_init(zorro8390_probe);
+module_exit(zorro8390_cleanup);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Wed Dec 18 04:29:54 2002
+++ b/drivers/pci/pci.c	Sun Aug 31 06:52:15 2003
@@ -907,8 +907,12 @@
 	pcibios_set_master(dev);
 }
 
+#ifndef HAVE_ARCH_PCI_MWI
+/* This can be overridden by arch code. */
+u8 pci_cache_line_size = L1_CACHE_BYTES >> 2;
+
 /**
- * pdev_set_mwi - arch helper function for pcibios_set_mwi
+ * pci_generic_prep_mwi - helper function for pci_set_mwi
  * @dev: the PCI device for which MWI is enabled
  *
  * Helper function for implementation the arch-specific pcibios_set_mwi
@@ -918,34 +922,33 @@
  * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success.
  */
 int
-pdev_set_mwi(struct pci_dev *dev)
+pci_generic_prep_mwi(struct pci_dev *dev)
 {
-	int rc = 0;
-	u8 cache_size;
+	u8 cacheline_size;
 
-	/*
-	 * Looks like this is necessary to deal with on all architectures,
-	 * even this %$#%$# N440BX Intel based thing doesn't get it right.
-	 * Ie. having two NICs in the machine, one will have the cache
-	 * line set at boot time, the other will not.
-	 */
-	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cache_size);
-	cache_size <<= 2;
-	if (cache_size != SMP_CACHE_BYTES) {
-		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly (%i bytes) by BIOS/FW.\n",
-		       dev->slot_name, cache_size);
-		if (cache_size > SMP_CACHE_BYTES) {
-			printk("PCI: %s cache line size too large - expecting %i.\n", dev->slot_name, SMP_CACHE_BYTES);
-			rc = -EINVAL;
-		} else {
-			printk("PCI: %s PCI cache line size corrected to %i.\n", dev->slot_name, SMP_CACHE_BYTES);
-			pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
-					      SMP_CACHE_BYTES >> 2);
-		}
-	}
+	if (!pci_cache_line_size)
+		return -EINVAL;		/* The system doesn't support MWI. */
+
+	/* Validate current setting: the PCI_CACHE_LINE_SIZE must be
+	   equal to or multiple of the right value. */
+	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);
+	if (cacheline_size >= pci_cache_line_size &&
+	    (cacheline_size % pci_cache_line_size) == 0)
+		return 0;
+
+	/* Write the correct value. */
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
+	/* Read it back. */
+	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);
+	if (cacheline_size == pci_cache_line_size)
+		return 0;
+
+	printk(KERN_WARNING "PCI: cache line size of %d is not supported "
+	       "by device %s\n", pci_cache_line_size << 2, dev->slot_name);
 
-	return rc;
+	return -EINVAL;
 }
+#endif /* !HAVE_ARCH_PCI_MWI */
 
 /**
  * pci_set_mwi - enables memory-write-invalidate PCI transaction
@@ -966,7 +969,7 @@
 #ifdef HAVE_ARCH_PCI_MWI
 	rc = pcibios_set_mwi(dev);
 #else
-	rc = pdev_set_mwi(dev);
+	rc = pci_generic_prep_mwi(dev);
 #endif
 
 	if (rc)
@@ -2148,7 +2151,7 @@
 EXPORT_SYMBOL(pci_set_master);
 EXPORT_SYMBOL(pci_set_mwi);
 EXPORT_SYMBOL(pci_clear_mwi);
-EXPORT_SYMBOL(pdev_set_mwi);
+EXPORT_SYMBOL(pci_generic_prep_mwi);
 EXPORT_SYMBOL(pci_set_dma_mask);
 EXPORT_SYMBOL(pci_dac_set_dma_mask);
 EXPORT_SYMBOL(pci_assign_resource);
diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids
--- a/drivers/pci/pci.ids	Wed Aug 13 08:41:23 2003
+++ b/drivers/pci/pci.ids	Sun Aug 31 01:20:32 2003
@@ -1934,6 +1934,7 @@
 	8001  Schizo PCI Bus Module
 	a000  Ultra IIi
 	a001  Ultra IIe
+	a801  Tomatillo PCI Bus Module
 108f  Systemsoft
 1090  Encore Computer Corporation
 1091  Intergraph Corporation
@@ -3409,7 +3410,8 @@
 		1148 5061  SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter
 		1148 5071  SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter
 		1148 9521  SK-9521 10/100/1000Base-T Adapter
-	4400  Gigabit Ethernet
+	4400 SK-9Dxx Gigabit Ethernet Adapter
+	4500 SK-9Mxx Gigabit Ethernet Adapter
 1149  Win System Corporation
 114a  VMIC
 	5579  VMIPCI-5579 (Reflective Memory Card)
@@ -5500,7 +5502,9 @@
 		1166 1648  NetXtreme CIOB-E 1000Base-T
 	164d  NetXtreme BCM5702FE Gigabit Ethernet
 	1653  NetXtreme BCM5705 Gigabit Ethernet
+	1654  NetXtreme BCM5705 Gigabit Ethernet
 	165d  NetXtreme BCM5705M Gigabit Ethernet
+	165e  NetXtreme BCM5705M Gigabit Ethernet
 	1696  NetXtreme BCM5782 Gigabit Ethernet
 		14e4 000d  NetXtreme BCM5782 1000Base-T
 	169c  NetXtreme BCM5788 Gigabit Ethernet
@@ -5525,6 +5529,8 @@
 	16c7  NetXtreme BCM5703 Gigabit Ethernet
 		14e4 0009  NetXtreme BCM5703 1000Base-T
 		14e4 000a  NetXtreme BCM5703 1000Base-SX
+	170d  NetXtreme BCM5901 Gigabit Ethernet
+	170e  NetXtreme BCM5901 Gigabit Ethernet
 	4210  BCM4210 iLine10 HomePNA 2.0
 	4211  BCM4211 iLine10 HomePNA 2.0 + V.90 56k modem
 	4212  BCM4212 v.90 56k modem
@@ -6066,8 +6072,10 @@
 1737  Linksys
 173b  Altima (nee Broadcom)
 	03e8  AC1000 Gigabit Ethernet
+	03e9  AC1001 Gigabit Ethernet
 	03ea  AC9100 Gigabit Ethernet
 		173b 0001  AC1002
+	03eb  AC1003 Gigabit Ethernet
 1743  Peppercon AG
 	8139  ROL/F-100 Fast Ethernet Adapter with ROL
 174b  PC Partner Limited
diff -Nru a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c
--- a/drivers/pnp/isapnp.c	Tue Aug  6 07:42:11 2002
+++ b/drivers/pnp/isapnp.c	Fri Jun  6 05:27:42 2003
@@ -510,7 +510,6 @@
                                                int dependent, int size)
 {
 	unsigned char tmp[3];
-	int i;
 	struct isapnp_irq *irq, *ptr;
 
 	isapnp_peek(tmp, size);
@@ -538,9 +537,13 @@
 	else
 		(*res)->irq = irq;
 #ifdef CONFIG_PCI
-	for (i=0; i<16; i++)
-		if (irq->map & (1<<i))
-			pcibios_penalize_isa_irq(i);
+	{
+		int i;
+
+		for (i=0; i<16; i++)
+			if (irq->map & (1<<i))
+				pcibios_penalize_isa_irq(i);
+	}
 #endif
 }
 
diff -Nru a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c
--- a/drivers/s390/net/ctctty.c	Fri Jun 27 04:39:05 2003
+++ b/drivers/s390/net/ctctty.c	Mon Dec  2 18:10:12 2002
@@ -42,7 +42,7 @@
 #define init_waitqueue_head(x) *(x)=NULL
 #define __set_current_state(state_value) \
 	do { current->state = state_value; } while (0)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 #define set_current_state(state_value) \
 	do { __set_current_state(state_value); mb(); } while (0)
 #else
diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
--- a/drivers/scsi/3w-xxxx.c	Tue Jul 29 11:07:42 2003
+++ b/drivers/scsi/3w-xxxx.c	Mon Dec  2 18:10:12 2002
@@ -178,7 +178,7 @@
 #include <linux/module.h>
 
 MODULE_AUTHOR ("3ware Inc.");
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver (SMP)");
 #else
 MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
diff -Nru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c	Sun Jun 29 08:10:09 2003
+++ b/drivers/scsi/aacraid/aachba.c	Sun Aug 17 09:56:09 2003
@@ -221,9 +221,7 @@
 static unsigned long aac_build_sg(Scsi_Cmnd* scsicmd, struct sgmap* sgmap);
 static unsigned long aac_build_sg64(Scsi_Cmnd* scsicmd, struct sgmap64* psg);
 static int aac_send_srb_fib(Scsi_Cmnd* scsicmd);
-#ifdef AAC_DETAILED_STATUS_INFO
 static char *aac_get_status_string(u32 status);
-#endif
 
 /*
  *	Non dasd selection is handled entirely in aachba now
@@ -231,8 +229,11 @@
  
 MODULE_PARM(nondasd, "i");
 MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
+MODULE_PARM(paemode, "i");
+MODULE_PARM_DESC(paemode, "Control whether dma addressing is using PAE. 0=off, 1=on");
 
 static int nondasd = -1;
+static int paemode = -1;
 
 /**
  *	aac_get_containers	-	list containers
@@ -298,6 +299,64 @@
 }
 
 /**
+ *	aac_get_container_name	-	get container name
+ */
+static int aac_get_container_name(struct aac_dev *dev, int cid, char * pid)
+{
+	struct fsa_scsi_hba *fsa_dev_ptr;
+	int status = 0;
+	struct aac_get_name *dinfo;
+	struct aac_get_name_resp *dresp;
+	struct fib * fibptr;
+	unsigned instance;
+
+	fsa_dev_ptr = &(dev->fsa_dev);
+	instance = dev->scsi_host_ptr->unique_id;
+
+	if (!(fibptr = fib_alloc(dev)))
+		return -ENOMEM;
+
+	fib_init(fibptr);
+	dinfo = (struct aac_get_name *) fib_data(fibptr);
+
+	dinfo->command = cpu_to_le32(VM_ContainerConfig);
+	dinfo->type = cpu_to_le32(CT_READ_NAME);
+	dinfo->cid = cpu_to_le32(cid);
+	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
+
+	status = fib_send(ContainerCommand,
+			    fibptr,
+			    sizeof (struct aac_get_name),
+			    FsaNormal,
+			    1, 1,
+			    NULL, NULL);
+	if (status < 0 ) {
+		printk(KERN_WARNING "aac_get_container_name: SendFIB failed.\n");
+	} else {
+		dresp = (struct aac_get_name_resp *)fib_data(fibptr);
+
+		status = (le32_to_cpu(dresp->status) != CT_OK)
+		      || (dresp->data[0] == '\0');
+		if (status == 0) {
+			char * sp = dresp->data;
+			char * dp = pid;
+			do {
+				if ((*sp == '\0')
+				 || ((dp - pid) >= sizeof(((struct aac_get_name_resp *)NULL)->data))) {
+					*dp = ' ';
+				} else {
+					*dp = *sp++;
+				}
+			} while (++dp < &pid[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]);
+		}
+	}
+	fib_complete(fibptr);
+	fib_free(fibptr);
+	fsa_dev[instance] = fsa_dev_ptr;
+	return status;
+}
+
+/**
  *	probe_container		-	query a logical volume
  *	@dev: device to query
  *	@cid: container identifier
@@ -569,8 +628,10 @@
 	if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
 		dev->pae_support = 1;
 	}
-	/* TODO - dmb temporary until fw can set this bit  */
-	dev->pae_support = (BITS_PER_LONG >= 64);
+
+	if(paemode != -1)
+		dev->pae_support = (paemode != 0);
+
 	if(dev->pae_support != 0) 
 	{
 		printk(KERN_INFO "%s%d: 64 Bit PAE enabled\n", dev->name, dev->id);
@@ -997,7 +1058,6 @@
 		memset(inq_data_ptr, 0, sizeof (struct inquiry_data));
 
 		inq_data_ptr->inqd_ver = 2;	/* claim compliance to SCSI-2 */
-		inq_data_ptr->inqd_dtq = 0x80;	/* set RMB bit to one indicating that the medium is removable */
 		inq_data_ptr->inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
 		inq_data_ptr->inqd_len = 31;
 		/*Format for "pad2" is  RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
@@ -1006,11 +1066,14 @@
 		 *	Set the Vendor, Product, and Revision Level
 		 *	see: <vendor>.c i.e. aac.c
 		 */
-		setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]);
-		if (scsicmd->target == scsicmd->host->this_id)
+		if (scsicmd->target == scsicmd->host->this_id) {
+			setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), (sizeof(container_types)/sizeof(char *)));
 			inq_data_ptr->inqd_pdt = INQD_PDT_PROC;	/* Processor device */
-		else
+		} else {
+			setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]);
+			aac_get_container_name(dev, cid, inq_data_ptr->inqd_pid);
 			inq_data_ptr->inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
+		}
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD;
 		__aac_io_done(scsicmd);
 		return 0;
@@ -1123,7 +1186,7 @@
 				SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND,
 			ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
 			__aac_io_done(scsicmd);
-			return -1;
+			return 0;
 	}
 }
 
@@ -1425,9 +1488,7 @@
 	case SRB_STATUS_FORCE_ABORT:
 	case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
 	default:
-#ifdef AAC_DETAILED_STATUS_INFO
 		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",le32_to_cpu(srbreply->srb_status&0x3f),aac_get_status_string(le32_to_cpu(srbreply->srb_status)), scsicmd->cmnd[0], le32_to_cpu(srbreply->scsi_status) );
-#endif
 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
 		break;
 	}
@@ -1525,7 +1586,7 @@
 		/*
 		 *	Build Scatter/Gather list
 		 */
-		fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry64));
+		fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) + ((srbcmd->sg.count & 0xff) * sizeof (struct sgentry64));
 
 		/*
 		 *	Now send the Fib to the adapter
@@ -1686,8 +1747,6 @@
 	return byte_count;
 }
 
-#ifdef AAC_DETAILED_STATUS_INFO
-
 struct aac_srb_status_info {
 	u32	status;
 	char	*str;
@@ -1742,4 +1801,3 @@
 	return "Bad Status Code";
 }
 
-#endif
diff -Nru a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
--- a/drivers/scsi/aacraid/aacraid.h	Sun Jun 29 08:10:09 2003
+++ b/drivers/scsi/aacraid/aacraid.h	Sun Aug 17 10:00:08 2003
@@ -1,3 +1,6 @@
+#define AAC_DRIVER_VERSION		0x01010300
+#define AAC_DRIVER_BUILD_DATE		__DATE__ " " __TIME__
+
 //#define dprintk(x) printk x
 #if (!defined(dprintk))
 # define dprintk(x)
@@ -759,7 +762,7 @@
 	 */	
 	dma_addr_t		hw_fib_pa;
 	struct hw_fib		*hw_fib_va;
-	ulong			fib_base_va;
+	struct hw_fib		*aif_base_va;
 	/*
 	 *	Fib Headers
 	 */
@@ -1176,6 +1179,31 @@
 	u32	   	type;           /* should be same as that requested */
 	u32		count;
 	struct aac_mntent mnt[1];
+};
+
+#define CT_READ_NAME 130
+struct aac_get_name {
+	u32		command;
+	u32		type;	// CT_READ_NAME
+	u32		cid;
+	u32		parm1;
+	u32		parm2;
+	u32		parm3;
+	u32		parm4;
+	u32		count;	// sizeof(((struct aac_get_name_resp *)NULL)->data)
+};
+
+#define CT_OK        218
+struct aac_get_name_resp {
+	u32		dummy0;
+	u32		dummy1;
+	u32		status;	// CT_OK
+	u32		parm1;
+	u32		parm2;
+	u32		parm3;
+	u32		parm4;
+	u32		parm5;
+	u8		data[16];
 };
 
 /*
diff -Nru a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
--- a/drivers/scsi/aacraid/commctrl.c	Sun Jun 29 08:10:09 2003
+++ b/drivers/scsi/aacraid/commctrl.c	Sun Aug 17 10:00:39 2003
@@ -362,7 +362,7 @@
  *	@dev: adapter
  *	@arg: ioctl arguments
  *
- *	This routine returns the firmware version.
+ *	This routine returns the driver version.
  *      Under Linux, there have been no version incompatibilities, so this is simple!
  */
 
@@ -371,14 +371,223 @@
 	struct revision response;
 
 	response.compat = 1;
-	response.version = dev->adapter_info.kernelrev;
-	response.build = dev->adapter_info.kernelbuild;
+	response.version = AAC_DRIVER_VERSION;
+	response.build = 9999;
 
 	if (copy_to_user(arg, &response, sizeof(response)))
 		return -EFAULT;
 	return 0;
 }
 
+/**
+ *
+ * aac_send_raw_scb
+ *
+ */
+
+int aac_send_raw_srb(struct aac_dev* dev, void* arg)
+{
+	struct fib* srbfib;
+	int status;
+	struct aac_srb *srbcmd;
+	struct aac_srb *user_srb = arg;
+	struct aac_srb_reply* user_reply;
+	struct aac_srb_reply* reply;
+	u32 fibsize = 0;
+	u32 flags = 0;
+	s32 rcode = 0;
+	u32 data_dir;
+	ulong sg_user[32];
+	ulong sg_list[32];
+	u32   sg_indx = 0;
+	u32 byte_count = 0;
+	u32 actual_fibsize = 0;
+	int i;
+
+
+	if (!capable(CAP_SYS_ADMIN)){
+		printk(KERN_DEBUG"aacraid: No permission to send raw srb\n"); 
+		return -EPERM;
+	}
+	/*
+	 *	Allocate and initialize a Fib then setup a BlockWrite command
+	 */
+	if (!(srbfib = fib_alloc(dev))) {
+		return -1;
+	}
+	fib_init(srbfib);
+
+	srbcmd = (struct aac_srb*) fib_data(srbfib);
+
+	if(copy_from_user((void*)&fibsize, (void*)&user_srb->count,sizeof(u32))){
+		printk(KERN_DEBUG"aacraid: Could not copy data size from user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+	if(copy_from_user(srbcmd, user_srb,fibsize)){
+		printk(KERN_DEBUG"aacraid: Could not copy srb from user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+	user_reply = arg+fibsize;
+
+	flags = srbcmd->flags;
+	// Fix up srb for endian and force some values
+	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);	// Force this
+	srbcmd->channel  = cpu_to_le32(srbcmd->channel);
+	srbcmd->target   = cpu_to_le32(srbcmd->target);
+	srbcmd->lun      = cpu_to_le32(srbcmd->lun);
+	srbcmd->flags    = cpu_to_le32(srbcmd->flags);
+	srbcmd->timeout  = cpu_to_le32(srbcmd->timeout);
+	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
+	srbcmd->cdb_size = cpu_to_le32(srbcmd->cdb_size);
+
+	switch(srbcmd->flags & (SRB_DataIn | SRB_DataOut)){
+	case SRB_DataOut:
+		data_dir = SCSI_DATA_WRITE;
+		break;
+	case (SRB_DataIn | SRB_DataOut):
+		data_dir = SCSI_DATA_UNKNOWN;  
+		break;
+	case SRB_DataIn:
+		data_dir = SCSI_DATA_READ;
+		break;
+	default:
+		data_dir = SCSI_DATA_NONE;
+	}
+	
+	if( dev->pae_support ==1 ) {
+		struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
+		byte_count = 0;
+
+		// This should also catch if user used the 32 bit sgmap
+		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry64));
+		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
+			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		if ((data_dir == SCSI_DATA_NONE) && psg->count) { // Dogs and cats sleeping with eachother - should not continue
+			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+
+		for (i = 0; i < psg->count; i++) {
+			dma_addr_t addr; 
+			u64 le_addr;
+			void* p;
+			p = kmalloc(psg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+			if(p == 0) {
+				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				psg->sg[i].count,i,psg->count);
+				rcode = -ENOMEM;
+				goto cleanup;
+			}
+			sg_user[i] = (ulong)psg->sg[i].addr;
+			sg_list[i] = (ulong)p; // save so we can clean up later
+			sg_indx = i + 1;
+
+			if( flags & SRB_DataOut ){
+				if(copy_from_user(p,psg->sg[i].addr,psg->sg[i].count)){
+					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, scsi_to_pci_dma_dir(data_dir));
+
+			le_addr = cpu_to_le64(addr);
+			psg->sg[i].addr[1] = (u32)(le_addr>>32);
+			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
+			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
+			byte_count += psg->sg[i].count;
+		}
+
+		srbcmd->count = cpu_to_le32(byte_count);
+		status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,0,0);
+	} else {
+		struct sgmap* psg = &srbcmd->sg;
+		byte_count = 0;
+
+		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
+			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		if ((data_dir == SCSI_DATA_NONE) && psg->count) { // Dogs and cats sleeping with eachother - should not continue
+			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		for (i = 0; i < psg->count; i++) {
+			dma_addr_t addr; 
+			void* p;
+			p = kmalloc(psg->sg[i].count,GFP_KERNEL);
+			if(p == 0) {
+				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				psg->sg[i].count,i,psg->count);
+				rcode = -ENOMEM;
+				goto cleanup;
+			}
+			sg_user[i] = (ulong)(psg->sg[i].addr);
+			sg_list[i] = (ulong)p; // save so we can clean up later
+			sg_indx = i + 1;
+
+			if( flags & SRB_DataOut ){
+				if(copy_from_user((void*)p,(void*)(ulong)(psg->sg[i].addr),psg->sg[i].count)){
+					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, scsi_to_pci_dma_dir(data_dir));
+
+			psg->sg[i].addr = cpu_to_le32(addr);
+			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
+			byte_count += psg->sg[i].count;
+		}
+		srbcmd->count = cpu_to_le32(byte_count);
+		status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, 0, 0);
+	}
+
+	if (status != 0){
+		printk(KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"); 
+		rcode = -1;
+		goto cleanup;
+	}
+
+	if( flags & SRB_DataIn ) {
+		for(i = 0 ; i < sg_indx; i++){
+			if(copy_to_user((void*)(sg_user[i]),(void*)(sg_list[i]),le32_to_cpu(srbcmd->sg.sg[i].count))){
+				printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n"); 
+				rcode = -EFAULT;
+				goto cleanup;
+
+			}
+		}
+	}
+
+	reply = (struct aac_srb_reply *) fib_data(srbfib);
+	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
+		printk(KERN_DEBUG"aacraid: Could not copy reply to user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+cleanup:
+	for(i=0; i < sg_indx; i++){
+		kfree((void*)sg_list[i]);
+	}
+	fib_complete(srbfib);
+	fib_free(srbfib);
+
+	return rcode;
+}
+
 
 struct aac_pci_info {
         u32 bus;
@@ -426,6 +635,9 @@
 		break;
 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
 		status = close_getadapter_fib(dev, arg);
+		break;
+	case FSACTL_SEND_RAW_SRB:
+		status = aac_send_raw_srb(dev,arg);
 		break;
 	case FSACTL_GET_PCI_INFO:
 		status = aac_get_pci_info(dev,arg);
diff -Nru a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
--- a/drivers/scsi/aacraid/comminit.c	Sun Jun 29 08:10:09 2003
+++ b/drivers/scsi/aacraid/comminit.c	Sun Aug 17 09:37:31 2003
@@ -84,14 +84,14 @@
 	 *	Adapter Fibs are the first thing allocated so that they
 	 *	start page aligned
 	 */
-	dev->fib_base_va = (ulong)base;
+	dev->aif_base_va = (struct hw_fib *)base;
 
 	/* We submit the physical address for AIF tags to limit to 32 bits */
-	init->AdapterFibsVirtualAddress = cpu_to_le32((u32)phys);
+	init->AdapterFibsVirtualAddress = cpu_to_le32(0);
 	init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
 	init->AdapterFibsSize = cpu_to_le32(fibsize);
 	init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
-	init->HostPhysMemPages = cpu_to_le32(num_physpages);		// number of 4k pages of host physical memory
+	init->HostPhysMemPages = cpu_to_le32((num_physpages << PAGE_SHIFT) / 4096);		// number of 4k pages of host physical memory
 
 	/*
 	 * Increment the base address by the amount already used
diff -Nru a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
--- a/drivers/scsi/aacraid/commsup.c	Sun Jun 29 08:10:09 2003
+++ b/drivers/scsi/aacraid/commsup.c	Sun Aug 17 09:39:34 2003
@@ -203,7 +203,7 @@
 	hw_fib->header.StructType = FIB_MAGIC;
 	hw_fib->header.Size = cpu_to_le16(sizeof(struct hw_fib));
 	hw_fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable);
-	hw_fib->header.SenderFibAddress = cpu_to_le32(fibptr->hw_fib_pa);
+	hw_fib->header.SenderFibAddress = 0; /* Filled in later if needed */
 	hw_fib->header.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa);
 	hw_fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
 }
@@ -450,8 +450,7 @@
 	 *	Map the fib into 32bits by using the fib number
 	 */
 
-//	hw_fib->header.SenderFibAddress = ((u32)(fibptr-dev->fibs)) << 1;
-	hw_fib->header.SenderFibAddress = cpu_to_le32((u32)(ulong)fibptr->hw_fib_pa);
+	hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr - dev->fibs)) << 1);
 	hw_fib->header.SenderData = (u32)(fibptr - dev->fibs);
 	/*
 	 *	Set FIB state to indicate where it came from and if we want a
@@ -792,7 +791,6 @@
 	struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
 	int busy;
 	u32 container;
-	mm_segment_t fs;
 
 	/* Sniff for container changes */
 	dprintk ((KERN_INFO "AifCmdDriverNotify=%x\n", le32_to_cpu(*(u32 *)aifcmd->data)));
@@ -859,18 +857,24 @@
 		 * go away. We need to check the access_count for the
 		 * device since we are not wanting the devices to go away.
 		 */
-		if (busy == 0 && proc_scsi != NULL) {
+		if ((busy == 0)
+		 && (proc_scsi != (struct proc_dir_entry *)NULL)) {
 			struct proc_dir_entry * entry;
 
 			dprintk((KERN_INFO "proc_scsi=%p ", proc_scsi));
-			for (entry = proc_scsi->subdir; entry != (struct proc_dir_entry *)NULL; entry = entry->next) {
+			for (entry = proc_scsi->subdir;
+			  entry != (struct proc_dir_entry *)NULL;
+			  entry = entry->next) {
 				dprintk(("\"%.*s\"[%d]=%x ", entry->namelen,
 				  entry->name, entry->namelen, entry->low_ino));
-				if ((entry->low_ino != 0) && (entry->namelen == 4) && (memcmp ("scsi", entry->name, 4) == 0)) {
+				if ((entry->low_ino != 0)
+				 && (entry->namelen == 4)
+				 && (memcmp ("scsi", entry->name, 4) == 0)) {
 					dprintk(("%p->write_proc=%p ", entry, entry->write_proc));
 					if (entry->write_proc != (int (*)(struct file *, const char *, unsigned long, void *))NULL) {
 						char buffer[80];
 						int length;
+						mm_segment_t fs;
 
 						sprintf (buffer,
 						  "scsi add-single-device %d %d %d %d\n",
@@ -879,12 +883,17 @@
 						  CONTAINER_TO_TARGET(container),
 						  CONTAINER_TO_LUN(container));
 						length = strlen (buffer);
-						dprintk((KERN_INFO "echo %.*s > /proc/scsi/scsi\n", length-1, buffer));
+						dprintk((KERN_INFO
+						  "echo %.*s > /proc/scsi/scsi\n",
+						  length-1,
+						  buffer));
 						fs = get_fs();
 						set_fs(get_ds());
-						length = entry->write_proc(NULL, buffer, length, NULL);
+						length = entry->write_proc(
+						  NULL, buffer, length, NULL);
 						set_fs(fs);
-						dprintk((KERN_INFO "returns %d\n", length));
+						dprintk((KERN_INFO
+						  "returns %d\n", length));
 					}
 					break;
 				}
diff -Nru a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
--- a/drivers/scsi/aacraid/dpcsup.c	Sun Jun 29 08:10:09 2003
+++ b/drivers/scsi/aacraid/dpcsup.c	Sun Aug 17 09:39:54 2003
@@ -74,12 +74,12 @@
 	 */
 	while(aac_consumer_get(dev, q, &entry))
 	{
-		u32 fast ;
-		fast = (entry->addr & cpu_to_le32(0x01));
-//		fib = &dev->fibs[(entry->addr >> 1)];
-//		hwfib = fib->hw_fib;
-		hwfib = bus_to_virt(le32_to_cpu(entry->addr & cpu_to_le32(~0x01)));
-		fib = &dev->fibs[hwfib->header.SenderData];
+		int fast;
+		u32 index;
+		index = le32_to_cpu(entry->addr);
+		fast = index & 0x01;
+		fib = &dev->fibs[index >> 1];
+		hwfib = fib->hw_fib;
 
 		aac_consumer_free(dev, q, HostNormRespQueue);
 		/*
@@ -178,13 +178,12 @@
 	while(aac_consumer_get(dev, q, &entry))
 	{
 		struct fib fibctx;
+		struct hw_fib * hw_fib;
+		u32 index;
 		struct fib *fib = &fibctx;
-		u32 hw_fib_pa = le32_to_cpu(entry->addr & cpu_to_le32(~0x01));
-		struct hw_fib * hw_fib_va = ((dev->comm_phys <= hw_fib_pa)
-		 && (hw_fib_pa < (dev->comm_phys + dev->comm_size)))
-		  ? dev->comm_addr + (hw_fib_pa - dev->comm_phys)
-		  : /* inconceivable */ bus_to_virt(hw_fib_pa);
-		dprintk((KERN_INFO "hw_fib_pa=%x hw_fib_va=%p\n", hw_fib_pa, hw_fib_va));
+
+		index = le32_to_cpu(entry->addr / sizeof(struct hw_fib));
+		hw_fib = &dev->aif_base_va[index];
 
 		/*
 		 *	Allocate a FIB at all costs. For non queued stuff
@@ -199,8 +198,8 @@
 		INIT_LIST_HEAD(&fib->fiblink);
 		fib->type = FSAFS_NTC_FIB_CONTEXT;
 		fib->size = sizeof(struct fib);
-		fib->hw_fib = hw_fib_va;
-		fib->data = hw_fib_va->data;
+		fib->hw_fib = hw_fib;
+		fib->data = hw_fib->data;
 		fib->dev = dev;
 		
 		if (dev->aif_thread && fib != &fibctx)
@@ -214,7 +213,7 @@
 			/*
 			 *	Set the status of this FIB
 			 */
-			*(u32 *)hw_fib_va->data = cpu_to_le32(ST_OK);
+			*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
 			fib_adapter_complete(fib, sizeof(u32));
 			spin_lock_irqsave(q->lock, flags);
 		}		
diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
--- a/drivers/scsi/aacraid/linit.c	Sun Jun 29 08:10:09 2003
+++ b/drivers/scsi/aacraid/linit.c	Sun Aug 17 09:59:51 2003
@@ -35,9 +35,6 @@
  *	
  */
 
-#define AAC_DRIVER_VERSION		"1.1.2"
-#define AAC_DRIVER_BUILD_DATE		__DATE__ " " __TIME__
-
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -56,15 +53,11 @@
 #include "aacraid.h"
 #include "sd.h"
 
-#define AAC_DRIVERNAME	"aacraid"
+#define AAC_DRIVER_NAME	"aacraid"
 
 MODULE_AUTHOR("Red Hat Inc and Adaptec");
 MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, Adaptec Advanced Raid Products, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
 MODULE_LICENSE("GPL");
-MODULE_PARM(paemode, "i");
-MODULE_PARM_DESC(paemode, "Control whether dma addressing is using PAE. 0=off, 1=on");
-
-static int paemode = -1;
 
 struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS];
 
@@ -107,15 +100,19 @@
 	{ 0x9005, 0x0285, 0x9005, 0x0292, aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 2 }, 		/* AAR-2810SA PCI SATA 8ch (Corsair-8) */
 	{ 0x9005, 0x0285, 0x9005, 0x0293, aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA ", 2 },		/* AAR-21610SA PCI SATA 16ch (Corsair-16) */
 	{ 0x9005, 0x0285, 0x9005, 0x0294, aac_rx_init, "aacraid",  "ADAPTEC ", "SO-DIMM SATA ZCR ", 2 },		/* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
-	/* ServeRAID */
-/*	{ 0x9005, 0x0250, 0x1014, 0x0279, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec         ", 2 }, */ /*  (Marco) */
-/*	{ 0x9005, 0x0250, 0x1014, 0x028c, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec         ", 2 }, */ /* (Sebring)*/
+	{ 0x9005, 0x0285, 0x0E11, 0x0295, aac_rx_init, "aacraid",  "ADAPTEC ", "SATA 6Channel   ", 1 }, 		/* SATA 6Ch (Bearcat) */
 
 	{ 0x9005, 0x0285, 0x1028, 0x0287, aac_rx_init, "percraid", "DELL    ", "PERC 320/DC     ", 2 },			/* Perc 320/DC*/
 	{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4 }, 		/* Adaptec 5400S (Mustang)*/
 	{ 0x1011, 0x0046, 0x9005, 0x0364, aac_sa_init, "aacraid",  "ADAPTEC ", "AAC-364         ", 4 },			/* Adaptec 5400S (Mustang)*/
 	{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4 },			/* Dell PERC2 "Quad Channel" */
-	{ 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4 }			/* HP NetRAID-4M */
+	{ 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4 },			/* HP NetRAID-4M */
+	{ 0x9005, 0x0285, 0x1028, PCI_ANY_ID,
+					  aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT },/* Dell Catchall */
+	{ 0x9005, 0x0285, 0x17aa, PCI_ANY_ID,
+					  aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT },/* Legend Catchall */
+	{ 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID,
+					  aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2, AAC_QUIRK_31BIT } /* Adaptec Catch All */
 };
 
 #define NUM_AACTYPES	(sizeof(aac_drivers) / sizeof(struct aac_driver_ident))
@@ -175,9 +172,15 @@
 	struct fsa_scsi_hba *fsa_dev_ptr;
 	char *name = NULL;
 	
-	printk(KERN_INFO "Red Hat/Adaptec aacraid driver (%s %s)\n", AAC_DRIVER_VERSION, AAC_DRIVER_BUILD_DATE);
-
+	printk(KERN_INFO "Red Hat/Adaptec %s driver (%d.%d-%d %s)\n",
+		AAC_DRIVER_NAME,
+		AAC_DRIVER_VERSION >> 24,
+		(AAC_DRIVER_VERSION >> 16) & 0xFF,
+		(AAC_DRIVER_VERSION >> 8) & 0xFF,
+		AAC_DRIVER_BUILD_DATE);
+		
 	/* setting up the proc directory structure */
+	
 	template->proc_name = "aacraid";
 	spin_unlock_irq(&io_request_lock);
 
@@ -607,7 +610,7 @@
 
 static int aac_eh_reset(Scsi_Cmnd* cmd)
 {
-	printk(KERN_ERR "aacraid: Host adapter reset request. SCSI hang ?\n");
+	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", AAC_DRIVER_NAME);
 	return FAILED;
 }
 
@@ -741,13 +744,41 @@
 static int aac_procinfo(char *proc_buffer, char **start_ptr,off_t offset,
 			int bytes_available, int host_no, int write)
 {
+	struct aac_dev * dev;
+	int index, ret, tmp;
+
 	if(write || offset > 0)
 		return 0;
 	*start_ptr = proc_buffer;
-	return sprintf(proc_buffer,
-	  "Adaptec Raid Controller %s %s, scsi hba number %d\n",
-	  AAC_DRIVER_VERSION, AAC_DRIVER_BUILD_DATE,
-	  host_no);
+	ret = sprintf(proc_buffer,
+		  "Adaptec Raid Controller %d.%d-%d %s, scsi hba number %d\n",
+		  AAC_DRIVER_VERSION >> 24,
+		  (AAC_DRIVER_VERSION >> 16) & 0xFF,
+		  (AAC_DRIVER_VERSION >> 8) & 0xFF,
+		  AAC_DRIVER_BUILD_DATE,
+		  host_no);
+	for (index = 0; index < aac_count; ++index) {
+		if (((dev = aac_devices[index]) != NULL) && dev->scsi_host_ptr->host_no == host_no)
+			break;
+	}
+	if (index >= aac_count || dev == NULL)
+		return ret;
+	tmp = dev->adapter_info.kernelrev;
+	ret += sprintf(proc_buffer + ret, "kernel: %d.%d-%d[%d]\n", 
+		tmp >> 24, (tmp >> 16) & 0xff, (tmp >> 8) & 0xff,
+		dev->adapter_info.kernelbuild);
+	tmp = dev->adapter_info.monitorrev;
+	ret += sprintf(proc_buffer + ret, "monitor: %d.%d-%d[%d]\n", 
+		tmp >> 24, (tmp >> 16) & 0xff, (tmp >> 8) & 0xff,
+		dev->adapter_info.monitorbuild);
+	tmp = dev->adapter_info.biosrev;
+	ret += sprintf(proc_buffer + ret, "bios: %d.%d-%d[%d]\n", 
+		tmp >> 24, (tmp >> 16) & 0xff, (tmp >> 8) & 0xff,
+		dev->adapter_info.biosbuild);
+	ret += sprintf(proc_buffer + ret, "serial: %x%x\n",
+		dev->adapter_info.serial[0],
+		dev->adapter_info.serial[1]);
+	return ret;
 }
 
 EXPORT_NO_SYMBOLS;
diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Thu Mar 27 13:28:51 2003
+++ b/drivers/scsi/ips.c	Mon Jun 16 14:04:16 2003
@@ -5,8 +5,8 @@
 /*             Jack Hammer, Adaptec, Inc.                                    */
 /*             David Jeffery, Adaptec, Inc.                                  */
 /*                                                                           */
-/* Copyright (C) 2000 IBM Corporation                                        */ 
-/* Copyright (C) 2003 Adaptec, Inc.                                          */ 
+/* Copyright (C) 2000 IBM Corporation                                        */
+/* Copyright (C) 2002,2003 Adaptec, 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      */
@@ -83,7 +83,7 @@
 /*            2.3.18 and later                                               */
 /*          - Sync with other changes from the 2.3 kernels                   */
 /* 4.00.06  - Fix timeout with initial FFDC command                          */
-/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@caldera.de>    */
+/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@infradead.org> */
 /* 4.10.00  - Add support for ServeRAID 4M/4L                                */
 /* 4.10.13  - Fix for dynamic unload and proc file system                    */
 /* 4.20.03  - Rename version to coincide with new release schedules          */
@@ -130,6 +130,7 @@
 /* 5.10.15  - remove unused code (sem, macros, etc.)                         */
 /* 5.30.00  - use __devexit_p()                                              */
 /* 6.00.00  - Add 6x Adapters and Battery Flash                              */
+/* 6.10.00  - Remove 1G Addressing Limitations                               */
 /*****************************************************************************/
 
 /*
@@ -150,7 +151,7 @@
  * nommap               - Don't use memory mapped I/O
  * ioctlsize            - Initial size of the IOCTL buffer
  */
- 
+
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/page.h>
@@ -182,75 +183,35 @@
 #include <linux/stat.h>
 #include <linux/config.h>
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-  #include <linux/spinlock.h>
-  #include <linux/init.h>
-#else
-  #include <asm/spinlock.h>
-#endif
+#include <linux/spinlock.h>
+#include <linux/init.h>
 
 #include <linux/smp.h>
 
 #ifdef MODULE
-   static char *ips = NULL;
-   MODULE_PARM(ips, "s");
+static char *ips = NULL;
+MODULE_PARM(ips, "s");
 #endif
 
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "6.00"
-#define IPS_VERSION_LOW         ".26 "
-
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
-struct proc_dir_entry proc_scsi_ips = {
-   0,
-   3, "ips",
-   S_IFDIR | S_IRUGO | S_IXUGO, 2
-};
-#endif
+#define IPS_VERSION_HIGH        "6.10"
+#define IPS_VERSION_LOW         ".24 "
 
 #if !defined(__i386__) && !defined(__ia64__)
-   #error "This driver has only been tested on the x86/ia64 platforms"
-#endif
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
-   #error "This driver only works with kernel 2.2.0 and later"
-#elif LINUX_VERSION_CODE <= LinuxVersionCode(2,3,18)
-    #define dma_addr_t uint32_t
-    
-    static inline void *pci_alloc_consistent(struct pci_dev *dev,int size,
-                                             dma_addr_t *dmahandle) {
-       void * ptr = kmalloc(size, GFP_ATOMIC); 
-       if(ptr){     
-          *dmahandle = (uint32_t)virt_to_bus(ptr);
-       }
-       return ptr;
-    }
-    
-    #define pci_free_consistent(a,size,address,dmahandle) kfree(address)
-    
-    #define pci_map_sg(a,b,n,z)       (n)
-    #define pci_unmap_sg(a,b,c,d)     
-    #define pci_map_single(a,b,c,d)   ((uint32_t)virt_to_bus(b))
-    #define pci_unmap_single(a,b,c,d) 
-    #ifndef sg_dma_address
-      #define sg_dma_address(x)         ((uint32_t)virt_to_bus((x)->address))
-      #define sg_dma_len(x)             ((x)->length)
-    #endif
-    #define pci_unregister_driver(x)
+#error "This driver has only been tested on the x86/ia64 platforms"
 #endif
 
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,5,0)
-    #define IPS_SG_ADDRESS(sg)       ((sg)->address)
-    #define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
-    #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
+#define IPS_SG_ADDRESS(sg)       ((sg)->address)
+#define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
+#define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
 #else
-    #define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \
+#define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \
                                      page_address((sg)->page)+(sg)->offset : 0)
-    #define IPS_LOCK_SAVE(lock,flags) spin_lock(lock)
-    #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock(lock)
+#define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0)
+#define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0)
 #endif
 
 #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
@@ -259,218 +220,144 @@
                          scsi_to_pci_dma_dir(scb->scsi_cmd->sc_data_direction))
 
 #ifdef IPS_DEBUG
-   #define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
-   #define DEBUG(i, s)           if (ips_debug >= i) printk(KERN_NOTICE s "\n");
-   #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v);
+#define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
+#define DEBUG(i, s)           if (ips_debug >= i) printk(KERN_NOTICE s "\n");
+#define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v);
 #else
-   #define METHOD_TRACE(s, i)
-   #define DEBUG(i, s)
-   #define DEBUG_VAR(i, s, v...)
+#define METHOD_TRACE(s, i)
+#define DEBUG(i, s)
+#define DEBUG_VAR(i, s, v...)
 #endif
 
 /*
  * global variables
  */
-static const char   ips_name[] = "ips";
-static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS];   /* Array of host controller structures */
-static ips_ha_t    *ips_ha[IPS_MAX_ADAPTERS];        /* Array of HA structures */
-static unsigned int ips_next_controller = 0;
-static unsigned int ips_num_controllers = 0;
-static unsigned int ips_released_controllers = 0;
-static int          ips_cmd_timeout = 60;
-static int          ips_reset_timeout = 60 * 5;
-static int          ips_force_memio = 1;             /* Always use Memory Mapped I/O    */
-static int          ips_force_i2o = 1;               /* Always use I2O command delivery */
-static int          ips_ioctlsize = IPS_IOCTL_SIZE;  /* Size of the ioctl buffer        */
-static int          ips_cd_boot = 0;                 /* Booting from Manager CD         */
-static char        *ips_FlashData = NULL;            /* CD Boot - Flash Data Buffer      */
-static long         ips_FlashDataInUse = 0;          /* CD Boot - Flash Data In Use Flag */
-static uint32_t     MaxLiteCmds = 32;                /* Max Active Cmds for a Lite Adapter */  
+static const char ips_name[] = "ips";
+static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS];	/* Array of host controller structures */
+static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS];	/* Array of HA structures */
+static unsigned int ips_next_controller;
+static unsigned int ips_num_controllers;
+static unsigned int ips_released_controllers;
+static int ips_cmd_timeout = 60;
+static int ips_reset_timeout = 60 * 5;
+static int ips_force_memio = 1;	/* Always use Memory Mapped I/O    */
+static int ips_force_i2o = 1;	/* Always use I2O command delivery */
+static int ips_ioctlsize = IPS_IOCTL_SIZE;	/* Size of the ioctl buffer        */
+static int ips_cd_boot;		/* Booting from Manager CD         */
+static char *ips_FlashData = NULL;	/* CD Boot - Flash Data Buffer      */
+static long ips_FlashDataInUse;	/* CD Boot - Flash Data In Use Flag */
+static uint32_t MaxLiteCmds = 32;	/* Max Active Cmds for a Lite Adapter */
+static Scsi_Host_Template ips_driver_template = IPS;
 
-IPS_DEFINE_COMPAT_TABLE( Compatable );               /* Version Compatability Table      */
+IPS_DEFINE_COMPAT_TABLE(Compatable);	/* Version Compatability Table      */
 
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
    /* This table describes all ServeRAID Adapters */
-   static struct  pci_device_id  ips_pci_table[]  __devinitdata = {
-           { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-           { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-           { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-           { 0, }
-   };
-
-   /* This table describes only Anaconda Family Adapters */
-   static struct  pci_device_id  ips_pci_table_anaconda[]  __devinitdata = {
-           { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-           { 0, }
-   };
-
-   /* This table describes only Sarasota ( ServeRAID 5i ) Adapters */
-   static struct  pci_device_id  ips_pci_table_5i[]  __devinitdata = {
-                   { 0x1014, 0x01BD, PCI_ANY_ID, 0x259, 0, 0 },
-                   { 0x1014, 0x01BD, PCI_ANY_ID, 0x258, 0, 0 },
-                   { 0, }
-                   };   
-
-   /* This table describes only Sebring ( ServeRAID 6i ) Adapters */
-   static struct  pci_device_id  ips_pci_table_6i[]  __devinitdata = {
-                   { 0x9005, 0x0250, PCI_ANY_ID, 0x28C, 0, 0 },
-                   { 0, }
-                   };   
-    
-   /* This table describes all i960 ( 4M, 4Mx, 4L, 4Lx ) Adapters */
-   static struct  pci_device_id  ips_pci_table_i960[]  __devinitdata = {
-                   { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-                   { 0, }
-                   };   
-
-   /* This table describes all Adaptec ( 6M ) Adapters */
-   static struct  pci_device_id  ips_pci_table_adaptec[]  __devinitdata = {
-                   { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-                   { 0, }
-                   };   
-
-   MODULE_DEVICE_TABLE( pci, ips_pci_table );
-
-   static char ips_hot_plug_name[] = "ips";
-   
-   static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
-   static void ips_remove_device(struct pci_dev *pci_dev);
-   
-   struct pci_driver ips_pci_driver = {
-       name:		ips_hot_plug_name,
-       id_table:	ips_pci_table,
-       probe:		ips_insert_device,
-       remove:		ips_remove_device,
-   }; 
-           
-   struct pci_driver ips_pci_driver_anaconda = {
-       name:		ips_hot_plug_name,
-       id_table:	ips_pci_table_anaconda,
-       probe:		ips_insert_device,
-       remove:		ips_remove_device,
-   }; 
-
-   struct pci_driver ips_pci_driver_5i = {
-       name:		ips_hot_plug_name,
-       id_table:	ips_pci_table_5i,
-       probe:		ips_insert_device,
-       remove:		ips_remove_device,
-   };
-           
-   struct pci_driver ips_pci_driver_6i = {
-       name:		ips_hot_plug_name,
-       id_table:	ips_pci_table_6i,
-       probe:		ips_insert_device,
-       remove:		ips_remove_device,
-   };
-
-   struct pci_driver ips_pci_driver_i960 = {
-       name:		ips_hot_plug_name,
-       id_table:	ips_pci_table_i960,
-       probe:		ips_insert_device,
-       remove:		ips_remove_device,
-   };
-
-   struct pci_driver ips_pci_driver_adaptec = {
-       name:		ips_hot_plug_name,
-       id_table:	ips_pci_table_adaptec,
-       probe:		ips_insert_device,
-       remove:		ips_remove_device,
-   };
+static struct pci_device_id ips_pci_table[] __devinitdata = {
+	{0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0},
+	{0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0},
+	{0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0},
+	{0,}
+};
 
-#endif
+MODULE_DEVICE_TABLE(pci, ips_pci_table);
+
+static char ips_hot_plug_name[] = "ips";
+
+static int __devinit ips_insert_device(struct pci_dev *pci_dev,
+				       const struct pci_device_id *ent);
+static void ips_remove_device(struct pci_dev *pci_dev);
+
+struct pci_driver ips_pci_driver = {
+	.name = ips_hot_plug_name,
+	.id_table = ips_pci_table,
+	.probe = ips_insert_device,
+	.remove = ips_remove_device,
+};
 
 /*
  * Necessary forward function protoypes
  */
 static int ips_halt(struct notifier_block *nb, ulong event, void *buf);
 
-#define MAX_ADAPTER_NAME 11
+#define MAX_ADAPTER_NAME 15
 
 static char ips_adapter_name[][30] = {
-   "ServeRAID",
-   "ServeRAID II",
-   "ServeRAID on motherboard",
-   "ServeRAID on motherboard",
-   "ServeRAID 3H",
-   "ServeRAID 3L",
-   "ServeRAID 4H",
-   "ServeRAID 4M",
-   "ServeRAID 4L",
-   "ServeRAID 4Mx",
-   "ServeRAID 4Lx",
-   "ServeRAID 5i",
-   "ServeRAID 5i",
-   "ServeRAID 6M",
-   "ServeRAID 6i"
+	"ServeRAID",
+	"ServeRAID II",
+	"ServeRAID on motherboard",
+	"ServeRAID on motherboard",
+	"ServeRAID 3H",
+	"ServeRAID 3L",
+	"ServeRAID 4H",
+	"ServeRAID 4M",
+	"ServeRAID 4L",
+	"ServeRAID 4Mx",
+	"ServeRAID 4Lx",
+	"ServeRAID 5i",
+	"ServeRAID 5i",
+	"ServeRAID 6M",
+	"ServeRAID 6i"
 };
 
-/* Init State 0 means we're only looking for a device to provide us the BIOS Adapter Ordering Table */
-/* Init State 1 is when we are actually enumerating the devices.                                    */
-static  int      InitState;
-/* IF BIOS wants to tell us the enumeration order, it puts a table in NVRAM Page 5 */
-static  uint8_t  AdapterOrder[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
 static struct notifier_block ips_notifier = {
-   ips_halt, NULL, 0
+	ips_halt, NULL, 0
 };
 
 /*
  * Direction table
  */
 static char ips_command_direction[] = {
-IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_OUT,
-IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_IN,   IPS_DATA_UNK,
-IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_IN,   IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_OUT,
-IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,
-IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_OUT,
-IPS_DATA_NONE, IPS_DATA_UNK,  IPS_DATA_IN,   IPS_DATA_UNK,  IPS_DATA_IN,
-IPS_DATA_UNK,  IPS_DATA_OUT,  IPS_DATA_IN,   IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_NONE, IPS_DATA_UNK,
-IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_OUT,
-IPS_DATA_OUT,  IPS_DATA_NONE, IPS_DATA_IN,   IPS_DATA_NONE, IPS_DATA_NONE,
-IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_OUT,
-IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_OUT,
-IPS_DATA_OUT,  IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_IN,   IPS_DATA_NONE,
-IPS_DATA_UNK,  IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK,
-IPS_DATA_NONE, IPS_DATA_OUT,  IPS_DATA_IN,   IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_OUT,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_IN,   IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK,  IPS_DATA_IN,   IPS_DATA_NONE,
-IPS_DATA_OUT,  IPS_DATA_UNK,  IPS_DATA_NONE, IPS_DATA_UNK,  IPS_DATA_OUT,
-IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_OUT,  IPS_DATA_NONE,
-IPS_DATA_UNK,  IPS_DATA_IN,   IPS_DATA_OUT,  IPS_DATA_IN,   IPS_DATA_IN,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_OUT,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,
-IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK,  IPS_DATA_UNK
+	IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT,
+	IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK,
+	IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
+	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,
+	IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
+	IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN,
+	IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK,
+	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
+	IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE,
+	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
+	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT,
+	IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE,
+	IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK,
+	IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE,
+	IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT,
+	IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE,
+	IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK
 };
 
 /*
@@ -480,9 +367,9 @@
 int ips_release(struct Scsi_Host *);
 int ips_eh_abort(Scsi_Cmnd *);
 int ips_eh_reset(Scsi_Cmnd *);
-int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
+int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
 int ips_biosparam(Disk *, kdev_t, int *);
-const char * ips_info(struct Scsi_Host *);
+const char *ips_info(struct Scsi_Host *);
 void do_ipsintr(int, void *, struct pt_regs *);
 static int ips_hainit(ips_ha_t *);
 static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
@@ -527,10 +414,9 @@
 static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
-static void ips_free_flash_copperhead(ips_ha_t *ha);
+static void ips_free_flash_copperhead(ips_ha_t * ha);
 static void ips_get_bios_version(ips_ha_t *, int);
 static void ips_identify_controller(ips_ha_t *);
-static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
 static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
 static void ips_enable_int_copperhead(ips_ha_t *);
 static void ips_enable_int_copperhead_memio(ips_ha_t *);
@@ -553,40 +439,43 @@
 static uint32_t ips_statupd_copperhead(ips_ha_t *);
 static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
 static uint32_t ips_statupd_morpheus(ips_ha_t *);
-static ips_scb_t * ips_getscb(ips_ha_t *);
+static ips_scb_t *ips_getscb(ips_ha_t *);
 static inline void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
 static inline void ips_putq_scb_tail(ips_scb_queue_t *, ips_scb_t *);
 static inline void ips_putq_wait_head(ips_wait_queue_t *, Scsi_Cmnd *);
 static inline void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
-static inline void ips_putq_copp_head(ips_copp_queue_t *, ips_copp_wait_item_t *);
-static inline void ips_putq_copp_tail(ips_copp_queue_t *, ips_copp_wait_item_t *);
-static inline ips_scb_t * ips_removeq_scb_head(ips_scb_queue_t *);
-static inline ips_scb_t * ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
-static inline Scsi_Cmnd * ips_removeq_wait_head(ips_wait_queue_t *);
-static inline Scsi_Cmnd * ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
-static inline ips_copp_wait_item_t * ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *);
-static inline ips_copp_wait_item_t * ips_removeq_copp_head(ips_copp_queue_t *);
+static inline void ips_putq_copp_head(ips_copp_queue_t *,
+				      ips_copp_wait_item_t *);
+static inline void ips_putq_copp_tail(ips_copp_queue_t *,
+				      ips_copp_wait_item_t *);
+static inline ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
+static inline ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
+static inline Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
+static inline Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
+static inline ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
+						     ips_copp_wait_item_t *);
+static inline ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
 
 static int ips_is_passthru(Scsi_Cmnd *);
 static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
 static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
 static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
+static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
+			       unsigned int count);
+static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
 
-int  ips_proc_info(char *, char **, off_t, int, int, int);
+int ips_proc_info(char *, char **, off_t, int, int, int);
 static int ips_host_info(ips_ha_t *, char *, off_t, int);
 static void copy_mem_info(IPS_INFOSTR *, char *, int);
 static int copy_info(IPS_INFOSTR *, char *, ...);
-static int ips_get_version_info(ips_ha_t *ha, IPS_VERSION_DATA *Buffer, int intr );
-static void ips_version_check(ips_ha_t *ha, int intr);
-static int ips_abort_init(ips_ha_t *ha, struct Scsi_Host *sh, int index);
-static int ips_init_phase2( int index );
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-static int ips_init_phase1( struct pci_dev *pci_dev, int *indexPtr );
-#else
-static int ips_init_oldphase1(Scsi_Host_Template *SHT);
-#endif
+static int ips_get_version_info(ips_ha_t * ha, IPS_VERSION_DATA * Buffer,
+				int intr);
+static void ips_version_check(ips_ha_t * ha, int intr);
+static int ips_abort_init(ips_ha_t * ha, int index);
+static int ips_init_phase2(int index);
 
+static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr);
+static int ips_register_scsi(int index);
 /*--------------------------------------------------------------------------*/
 /* Exported Functions                                                       */
 /*--------------------------------------------------------------------------*/
@@ -600,92 +489,52 @@
 /*   setup parameters to the driver                                         */
 /*                                                                          */
 /****************************************************************************/
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
 static int
-ips_setup(char *ips_str) {
-#else
-void
-ips_setup(char *ips_str, int *dummy) {
-#endif
-
-   int        i;
-   char      *key;
-   char      *value;
-   IPS_OPTION options[] = {
-      {"noi2o", &ips_force_i2o, 0},
-      {"nommap", &ips_force_memio, 0},
-      {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
-      {"cdboot", &ips_cd_boot, 0},
-      {"maxcmds", &MaxLiteCmds, 32},
-   };
-    
-   /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-   /* Search for value */
-   while ((key = strsep(&ips_str, ",."))) {
-      if (!*key)
-         continue;
-      value = strchr(key, ':');
-      if (value)
-         *value++ = '\0';
-     /*
-      * We now have key/value pairs.
-      * Update the variables
-      */
-      for (i = 0; i < (sizeof(options) / sizeof(options[0])); i++) {
-        if (strnicmp(key, options[i].option_name, strlen(options[i].option_name)) == 0) {
-           if (value)
-              *options[i].option_flag = simple_strtoul(value, NULL, 0);
-           else
-              *options[i].option_flag = options[i].option_value;
-           break;
-        }
-      }
-   }
-
-   return (1);
-
-#else
-
-   char   *p;
-   char    tokens[3] = {',', '.', 0};
-
-   for (key = strtok(ips_str, tokens); key; key = strtok(NULL, tokens)) {
-      p = key;
-
-      /* Search for value */
-      while ((p) && (*p != ':'))
-         p++;
-
-      if (p) {
-         *p = '\0';
-         value = p+1;
-      } else
-         value = NULL;
-                          
-      /*
-       * We now have key/value pairs.
-       * Update the variables
-       */
-      for (i = 0; i < (sizeof(options) / sizeof(options[0])); i++) {
-         if (strnicmp(key, options[i].option_name, strlen(ips_str)) == 0) {
-            if (value)
-               *options[i].option_flag = simple_strtoul(value, NULL, 0);
-            else
-               *options[i].option_flag = options[i].option_value;
-
-            break;
-         }
-      }
-   }
+ips_setup(char *ips_str)
+{
 
-#endif
+	int i;
+	char *key;
+	char *value;
+	IPS_OPTION options[] = {
+		{"noi2o", &ips_force_i2o, 0},
+		{"nommap", &ips_force_memio, 0},
+		{"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
+		{"cdboot", &ips_cd_boot, 0},
+		{"maxcmds", &MaxLiteCmds, 32},
+	};
+
+	/* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
+	/* Search for value */
+	while ((key = strsep(&ips_str, ",."))) {
+		if (!*key)
+			continue;
+		value = strchr(key, ':');
+		if (value)
+			*value++ = '\0';
+		/*
+		 * We now have key/value pairs.
+		 * Update the variables
+		 */
+		for (i = 0; i < (sizeof (options) / sizeof (options[0])); i++) {
+			if (strnicmp
+			    (key, options[i].option_name,
+			     strlen(options[i].option_name)) == 0) {
+				if (value)
+					*options[i].option_flag =
+					    simple_strtoul(value, NULL, 0);
+				else
+					*options[i].option_flag =
+					    options[i].option_value;
+				break;
+			}
+		}
+	}
 
+	return (1);
 }
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
 __setup("ips=", ips_setup);
-#endif
 
 /****************************************************************************/
 /*                                                                          */
@@ -699,682 +548,97 @@
 /*                                                                          */
 /****************************************************************************/
 int
-ips_detect(Scsi_Host_Template *SHT) {
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-   int  i;
-#endif
+ips_detect(Scsi_Host_Template * SHT)
+{
+	int i;
 
-   METHOD_TRACE("ips_detect", 1);
+	METHOD_TRACE("ips_detect", 1);
 
 #ifdef MODULE
-   if (ips)
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-      ips_setup(ips);
-#else
-      ips_setup(ips, NULL);
-#endif
-#endif
-
-   /* If Booting from the Manager CD, Allocate a large Flash        */
-   /* Buffer ( so we won't need to allocate one for each adapter ). */
-    if ( ips_cd_boot ) {            
-      ips_FlashData = ( char * ) __get_free_pages( GFP_KERNEL, 7 );   
-      if (ips_FlashData == NULL) {
-         /* The validity of this pointer is checked in ips_make_passthru() before it is used */
-         printk( KERN_WARNING "ERROR: Can't Allocate Large Buffer for Flashing\n" );
-      }
-   }                                                                               
-   /* initalize number of controllers */
-   ips_num_controllers = 0;
-   ips_next_controller = 0;
-   ips_released_controllers = 0;
-
-   if (!pci_present())
-      return (0);
-
-/**********************************************************************************/
-/* For Kernel Versions 2.4 or greater, use new PCI ( Hot Pluggable ) architecture */
-/**********************************************************************************/
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
- #if LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
-   spin_unlock_irq(&io_request_lock);
- #endif
-   SHT->proc_info = ips_proc_info;
-   SHT->proc_name = "ips";
-
-   /* There are several special cases ( which are too complicated to enumerate here ) where, due */
-   /* to System BIOS rules, the adapters must be enumerated in a certain order.  If ServeRAID    */
-   /* BIOS tells us the order, then we will follow it.  The first pass at init is simply to be   */
-   /* able to communicate with the first adapter to see if BIOS is telling us the order.         */ 
-   /* This does not apply to ia64 EFI BIOS.                                                      */
-
-#if !defined(__ia64__)
-   InitState = 0;
-   pci_module_init(&ips_pci_driver); /* Look for Any Adapter, to fill in the Adapter Order Table */
+	if (ips)
+		ips_setup(ips);
 #endif
 
-   InitState = 1;       
-   
-   if ( AdapterOrder[0] ) {  
-      /* BIOS has dictated the order that we should enumerate Adapters */
-      for ( i = 1; i <= AdapterOrder[0]; i++ ) {
-          switch (AdapterOrder[i]) {
-          case 'M':
-              pci_module_init(&ips_pci_driver_adaptec);     /* Ask for Adaptec Adapters */
-              break;
-          case 'S':
-              pci_module_init(&ips_pci_driver_5i);          /* Ask for 5i Adapters      */
-              pci_module_init(&ips_pci_driver_6i);          /* Ask for 6i Adapters      */
-              break;
-          case 'N':
-              pci_module_init(&ips_pci_driver_i960);        /* Ask for i960 Adapters    */
-              break;
-          case 'A':
-              pci_module_init(&ips_pci_driver_anaconda);    /* Ask for Anaconda Family Adapters */
-              break;
-          default:
-              i = AdapterOrder[0] + 1;                      /* Premature End of List - Ensure Loop Ends */
-              break;
-          }
-      }
-   }
-   else { 
-      /* No Adapter Order Table from BIOS, so sort things the old-fashioned way */
-
-      /* By definition, an Internal ( 5i or 6i ) Adapter MUST be enumerated first */
-      /* or the server may not boot properly. The adapters must be enumerated in  */
-      /* exactly the same order as BIOS for the machine to come up properly.      */
-      /*    NOTE: There will never be both a 5i and a 6i in the same machine.     */
-
-      pci_module_init(&ips_pci_driver_5i);          /* Ask for 5i Adapters First  */
-      if (ips_num_controllers) {                    /* If there is a 5i Adapter   */
-         pci_module_init(&ips_pci_driver_i960);     /*    Get all i960's next     */
-      }
-      else {
-         pci_module_init(&ips_pci_driver_6i);         /* Ask if any 6i Adapters   */
-         if (ips_num_controllers)                     /* If there is a 6i Adapter */
-            pci_module_init(&ips_pci_driver_adaptec); /*    Get all Adaptecs next */
-      }
-
-      pci_module_init(&ips_pci_driver);             /* Get all remaining Adapters */
-                                                    /*  ( in normal BUS order )   */
-   }
-
- #if LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
-   spin_lock_irq(&io_request_lock);
- #endif
-   if (ips_num_controllers > 0) 
-      register_reboot_notifier(&ips_notifier);
-
-   return (ips_num_controllers);
-#else
-   InitState = 1;
-   SHT->proc_info = ips_proc_info;
-   SHT->proc_dir = &proc_scsi_ips;
-   return ips_init_oldphase1(SHT);
-#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) */
-
-}
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
-
-/***********************************************************************************/
-/*   Sort the Device Structures                                                    */
-/*   Devices are sorted by groups ( type ) and then PCI address within each group  */  
-/*   This also results in the same ordering that results when using the 2.4 kernel */
-/*   architecture for initialization.                                              */
-/***********************************************************************************/
-
-static void 
-ips_sort_controllers(struct pci_dev *dev[]) {
-   struct pci_dev *tempdev[IPS_MAX_ADAPTERS];
-   struct pci_dev *lowestdev;
-   int             i, j;
-   int             temp_index = 0;    /* Index into tempdev[] array */    
-   int             lowIndex = 0;
-   int             newlowflag = 0;    /* Flag to indicate when a new low address has been found */
-   uint16_t        subdevice_id;
-   unsigned char   BusNumber;
-
-   /* Clear the Temporary Dev Structure */
-   for (i = 0; i < IPS_MAX_ADAPTERS; i++) 
-       tempdev[i] = NULL;
-
-   /* The Outer Loop goes thru each Adapter Type Supported */
-   for (j = 0; j < IPS_MAX_ADAPTER_TYPES; j++) {
-      lowestdev = NULL;
-      /* The Inner Loop Checks each Device still in the List and */
-      /* Finds the lowset adapter left ( by PCI boot order )     */
-      for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
-         if (dev[i]) {
-            if (lowestdev == NULL) {  /* If this is the first one found, it must be the lowest ! */
-               lowestdev = dev[i];
-               lowIndex = i;
-            }
-
-            /* If you find a Sarasota ( 5i ), it must always be treated as the first adapter */
-            if (dev[i]->device == IPS_DEVICEID_MORPHEUS) {
-                pci_read_config_word(dev[i], PCI_SUBSYSTEM_ID, &subdevice_id);
-                if ((subdevice_id == IPS_SUBDEVICEID_5I1) || 
-                    (subdevice_id == IPS_SUBDEVICEID_5I2)) {
-                     lowestdev = dev[i];
-                     lowIndex = i;
-                     break;
-                }
-            } 
-
-            /* If you find a Sebring ( 6i ), it must always be treated as the first adapter */
-            if (dev[i]->device == IPS_DEVICEID_MARCO) {
-                pci_read_config_word(dev[i], PCI_SUBSYSTEM_ID, &subdevice_id);
-                if (subdevice_id == IPS_SUBDEVICEID_6I) {
-                    lowestdev = dev[i];
-                    lowIndex = i;
-                    break;
-                }
-            }    
-
-            /* Determine if this device is at a lower PCI address than the current lowest device */
-            newlowflag = 0;
-
-            if (dev[i]->device == IPS_DEVICEID_MARCO)     /* System BIOS adds 1 to Marco Bus Number */
-                BusNumber = ( dev[i]->bus->number ) - 1;  /*        because of Bridge Chip          */
-            else
-                BusNumber = dev[i]->bus->number;
-
-            if (BusNumber < lowestdev->bus->number)        /* IF a lower BUS # */
-                newlowflag = i;
-
-            if ((BusNumber == lowestdev->bus->number) &&   /* If Same Bus #, but a lower device # */
-                (dev[i]->devfn < lowestdev->devfn)) 
-                newlowflag = i;
-
-            if ( newlowflag ) {
-                lowestdev = dev[i];
-                lowIndex = i;
-            }
-         }
-      }
-                                                                                     
-      if (lowestdev) {                       /* If we found another adapter */
-         tempdev[temp_index] = lowestdev;    /*    Add it in the list       */
-         dev[lowIndex] = NULL;               /*    Null it out so we don't find it again */
-         temp_index++;
-         /* Now get all the adapters that are the same type as the low one      . */
-         /* They will already be in order, so they don't need any further sorting.*/
-         for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
-            if (dev[i]) {
-               if (dev[i]->device == lowestdev->device) {
-                  tempdev[temp_index] = dev[i];  /* Add the same type adapter to the list */
-                  temp_index++;                    
-                  dev[i] = NULL;                 /* Null it out so we don't find it again */
-               }                           
-            }
-         }
-      }
-   }
-
-   /* Copy the Sorted Adapter Pointers ( tempdev[] ) to the Original Structure */
-   for (i = 0; i < IPS_MAX_ADAPTERS; i++) 
-       dev[i] = tempdev[i];
+	/* If Booting from the Manager CD, Allocate a large Flash        */
+	/* Buffer ( so we won't need to allocate one for each adapter ). */
+	if (ips_cd_boot) {
+		ips_FlashData = (char *) __get_free_pages(IPS_INIT_GFP, 7);
+		if (ips_FlashData == NULL) {
+			/* The validity of this pointer is checked in ips_make_passthru() before it is used */
+			printk(KERN_WARNING
+			       "ERROR: Can't Allocate Large Buffer for Flashing\n");
+		}
+	}
+
+	SHT->proc_info = ips_proc_info;
+	SHT->proc_name = "ips";
+
+	for (i = 0; i < ips_num_controllers; i++) {
+		if (ips_register_scsi(i))
+			ips_free(ips_ha[i]);
+		ips_released_controllers++;
+	}
 
+	return (ips_num_controllers);
 }
 
 /****************************************************************************/
-/*   Detect and initialize the driver for 2.2 kernels                       */
-/*                                                                          */
-/* NOTE: this routine is called under the io_request_lock spinlock          */
-/****************************************************************************/
-static int ips_init_oldphase1(Scsi_Host_Template *SHT){
-   struct Scsi_Host *sh;
-   ips_ha_t         *ha;
-   uint32_t          io_addr;
-   uint32_t          mem_addr;
-   uint32_t          io_len;
-   uint32_t          mem_len;
-   uint16_t          planer;
-   uint8_t           revision_id;
-   uint8_t           bus;
-   uint8_t           func;
-   uint8_t           irq;
-   uint16_t          subdevice_id;
-   int               i;
-   int               j;
-   uint32_t          count;
-   char             *ioremap_ptr;
-   char             *mem_ptr;
-   struct pci_dev   *dev[IPS_MAX_ADAPTERS];
-   dma_addr_t        dma_address;
-   uint32_t          currbar;
-   uint32_t          maskbar;
-   uint8_t           barnum;
-   uint32_t          IsDead;
-
-   METHOD_TRACE("ips_init_oldphase1", 1);
-   
-   for ( i = 0; i < IPS_MAX_ADAPTERS; i++ ) 
-       dev[i] = NULL;
-   
-   /* Find all the adapters that we support and save them in the dev[] structure */
-   i = 0;
-   dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_MORPHEUS, NULL);
-   while ( dev[i] ) {
-      i++;
-      dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_MORPHEUS, dev[i-1]);
-   }
-
-   dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_COPPERHEAD, NULL);
-   while ( dev[i] ) {
-       i++;
-       dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_COPPERHEAD, dev[i-1]);
-   }
-
-   dev[i] = pci_find_device(IPS_VENDORID_ADAPTEC, IPS_DEVICEID_MARCO, NULL);
-   while ( dev[i] ) {
-       i++;
-       dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_MARCO, dev[i-1]);
-   }
-     
-   /* Sort the Adapters */
-   if ( dev[0] ) 
-      ips_sort_controllers( dev );
-   else
-      return (0);    
-
-   /* Now scan and Initialize the controllers */
-   for ( i = 0; i < IPS_MAX_ADAPTERS; i++ ) {
-      if (!dev[i])
-         break;
-
-      if (ips_next_controller >= IPS_MAX_ADAPTERS)
-         break;
-
-      /* stuff that we get in dev */
-      irq = dev[i]->irq;
-      bus = dev[i]->bus->number;
-      func = dev[i]->devfn;
-
-      /* Init MEM/IO addresses to 0 */
-      mem_addr = 0;
-      io_addr = 0;
-      mem_len = 0;
-      io_len = 0;
-
-      for (j = 0; j < 2; j++) {
-         if (!dev[i]->base_address[j])
-            break;
-
-         if ((dev[i]->base_address[j] & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
-            barnum = PCI_BASE_ADDRESS_0 + (j * 4);
-            io_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_IO_MASK;
-
-            /* Get Size */
-            pci_read_config_dword(dev[i], barnum, &currbar);
-            pci_write_config_dword(dev[i], barnum, ~0);
-            pci_read_config_dword(dev[i], barnum, &maskbar);
-            pci_write_config_dword(dev[i], barnum, currbar);
-
-            io_len = ~(maskbar & PCI_BASE_ADDRESS_IO_MASK) + 1;
-        } else {
-            barnum = PCI_BASE_ADDRESS_0 + (j * 4);
-            mem_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_MEM_MASK;
-
-            /* Get Size */
-            pci_read_config_dword(dev[i], barnum, &currbar);
-            pci_write_config_dword(dev[i], barnum, ~0);
-            pci_read_config_dword(dev[i], barnum, &maskbar);
-            pci_write_config_dword(dev[i], barnum, currbar);
-
-            mem_len = ~(maskbar & PCI_BASE_ADDRESS_MEM_MASK) + 1;
-         }
-      }
-
-      /* setup memory mapped area (if applicable) */
-      if (mem_addr) {
-         uint32_t base;
-         uint32_t offs;
-
-         DEBUG_VAR(1, "(%s%d) detect, Memory region %x, size: %d",
-                   ips_name, ips_next_controller, mem_addr, mem_len);
-
-         base = mem_addr & PAGE_MASK;
-         offs = mem_addr - base;
-
-         ioremap_ptr = ioremap(base, PAGE_SIZE);
-         mem_ptr = ioremap_ptr + offs;
-      } else {
-         ioremap_ptr = NULL;
-         mem_ptr = NULL;
-      }
-
-      /* setup I/O mapped area (if applicable) */
-      if (io_addr) {
-         DEBUG_VAR(1, "(%s%d) detect, IO region %x, size: %d",
-                   ips_name, ips_next_controller, io_addr, io_len);
-
-         if (check_region(io_addr, io_len)) {
-             /* Couldn't allocate io space */
-            printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n",
-                   ips_name, ips_next_controller, io_addr, io_len);
-
-            ips_next_controller++;
-
-            continue;
-         }
-
-         request_region(io_addr, io_len, "ips");
-      }
-
-      /* get planer status */
-      if (pci_read_config_word(dev[i], 0x04, &planer)) {
-         printk(KERN_WARNING "(%s%d) can't get planer status.\n",
-                ips_name, ips_next_controller);
-
-         ips_next_controller++;
-
-         continue;
-      }
-
-      /* check to see if an onboard planer controller is disabled */
-      if (!(planer & 0x000C)) {
-
-         DEBUG_VAR(1, "(%s%d) detect, Onboard controller disabled by BIOS",
-                   ips_name, ips_next_controller);
-
-         ips_next_controller++;
-
-         continue;
-      }
-
-      DEBUG_VAR(1, "(%s%d) detect bus %d, func %x, irq %d, io %x, mem: %x, ptr: %p",
-                ips_name, ips_next_controller, bus, func, irq, io_addr, mem_addr, mem_ptr);
-
-      /* get the revision ID */
-      if (pci_read_config_byte(dev[i], PCI_REVISION_ID, &revision_id)) {
-          printk(KERN_WARNING "(%s%d) can't get revision id.\n",
-                 ips_name, ips_next_controller);
-
-        ips_next_controller++;
-        continue;
-      }
-
-      /* get the subdevice id */
-      if (pci_read_config_word(dev[i], PCI_SUBSYSTEM_ID, &subdevice_id)) {
-         printk(KERN_WARNING "(%s%d) can't get subdevice id.\n",
-                ips_name, ips_next_controller);
-
-         ips_next_controller++;
-
-         continue;
-      }
-
-      /* found a controller */
-      sh = scsi_register(SHT, sizeof(ips_ha_t));
-
-      if (sh == NULL) {
-         printk(KERN_WARNING "(%s%d) Unable to register controller with SCSI subsystem - skipping controller\n",
-                ips_name, ips_next_controller);
-
-         ips_next_controller++;
-
-         continue;
-      }
-
-      ha = IPS_HA(sh);
-      memset(ha, 0, sizeof(ips_ha_t));
-
-      ips_sh[ips_next_controller] = sh;
-      ips_ha[ips_next_controller] = ha;
-      ips_num_controllers++;
-      ha->active = 1;
-
-      ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_KERNEL);
-
-      if (!ha->enq) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n",
-                ips_name, ips_next_controller);
-         ips_abort_init(ha, sh, ips_next_controller);
-         ips_next_controller++;
-         ips_num_controllers--;
-
-         continue;
-      }
-
-      ha->adapt = pci_alloc_consistent(dev[i], sizeof(IPS_ADAPTER) + sizeof(IPS_IO_CMD), &dma_address);
-
-      if (!ha->adapt) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host adapt and dummy structure - skipping controller\n",
-                ips_name, ips_next_controller);
-         ips_abort_init(ha, sh, ips_next_controller);
-         ips_next_controller++;
-         ips_num_controllers--;
-
-         continue;
-      }
-      ha->adapt->hw_status_start = dma_address;
-      ha->dummy = (void *)ha->adapt + 1;
-
-      ha->conf = kmalloc(sizeof(IPS_CONF), GFP_KERNEL);
-
-      if (!ha->conf) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n",
-                ips_name, ips_next_controller);
-         ips_abort_init(ha, sh, ips_next_controller);
-         ips_next_controller++;
-         ips_num_controllers--;
-
-         continue;
-      }
-
-      ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_KERNEL);
-
-      if (!ha->nvram) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n",
-                ips_name, ips_next_controller);
-         ips_abort_init(ha, sh, ips_next_controller);
-         ips_next_controller++;
-         ips_num_controllers--;
-
-         continue;
-      }
-
-      ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_KERNEL);
-
-      if (!ha->subsys) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n",
-                ips_name, ips_next_controller);
-         ips_abort_init(ha, sh, ips_next_controller);
-         ips_next_controller++;
-         ips_num_controllers--;
-
-         continue;
-      }
-
-      for (count = PAGE_SIZE, ha->ioctl_order = 0;
-           count < ips_ioctlsize;
-           ha->ioctl_order++, count <<= 1);
-
-      ha->ioctl_data = (char *) __get_free_pages(GFP_KERNEL, ha->ioctl_order);
-      ha->ioctl_datasize = count;
-
-      if (!ha->ioctl_data) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data\n",
-                ips_name, ips_next_controller);
-
-         ha->ioctl_data = NULL;
-         ha->ioctl_order = 0;
-         ha->ioctl_datasize = 0;
-      }
-
-      /* Store away needed values for later use */
-      sh->io_port = io_addr;
-      sh->n_io_port = io_addr ? 255 : 0;
-      sh->unique_id = (io_addr) ? io_addr : mem_addr;
-      sh->irq = irq;
-      sh->select_queue_depths = ips_select_queue_depth;
-      sh->sg_tablesize = sh->hostt->sg_tablesize;
-      sh->can_queue = sh->hostt->can_queue;
-      sh->cmd_per_lun = sh->hostt->cmd_per_lun;
-      sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
-      sh->use_clustering = sh->hostt->use_clustering;
-
-      sh->wish_block = FALSE;
-
-      /* Store info in HA structure */
-      ha->irq = irq;
-      ha->io_addr = io_addr;
-      ha->io_len = io_len;
-      ha->mem_addr = mem_addr;
-      ha->mem_len = mem_len;
-      ha->mem_ptr = mem_ptr;
-      ha->ioremap_ptr = ioremap_ptr;
-      ha->host_num = ips_next_controller;
-      ha->revision_id = revision_id;
-      ha->slot_num = PCI_SLOT(dev[i]->devfn);
-      ha->device_id = dev[i]->device;
-      ha->subdevice_id = subdevice_id;
-      ha->pcidev = dev[i];
-
-      /*
-       * Setup Functions
-       */
-      ips_setup_funclist(ha);
-            
-      /* If Morpheus appears dead, reset it */
-      if ( ( IPS_IS_MORPHEUS( ha ) ) || ( IPS_IS_MARCO( ha ) ) ) {
-          IsDead = readl( ha->mem_ptr + IPS_REG_I960_MSG1 );
-          if ( IsDead == 0xDEADBEEF ) {
-              ips_reset_morpheus( ha );
-          }
-      }
-
-      /*
-       * Initialize the card if it isn't already
-       */
-
-      if (!(*ha->func.isinit)(ha)) {
-         if (!(*ha->func.init)(ha)) {
-            /*
-             * Initialization failed
-             */
-            printk(KERN_WARNING "(%s%d) unable to initialize controller - skipping controller\n",
-                   ips_name, ips_next_controller);
-            ips_abort_init(ha, sh, ips_next_controller);
-            ips_next_controller++;
-            ips_num_controllers--;
-
-            continue;
-         }
-      }
-
-      /* install the interrupt handler */
-      if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
-         printk(KERN_WARNING "(%s%d) unable to install interrupt handler - skipping controller\n",
-                ips_name, ips_next_controller);
-         ips_abort_init(ha, sh, ips_next_controller);
-         ips_next_controller++;
-         ips_num_controllers--;
-
-         continue;
-      }
-
-      /*
-       * Allocate a temporary SCB for initialization
-       */
-      ha->max_cmds = 1;
-      if (!ips_allocatescbs(ha)) {
-         /* couldn't allocate a temp SCB */
-         printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
-                ips_name, ips_next_controller);
-         free_irq(ha->irq, ha);
-         ips_abort_init(ha, sh, ips_next_controller);
-         ips_next_controller++;
-         ips_num_controllers--;
-
-         continue;
-      }
-
-      ips_next_controller++;
-   }
-
-   /*
-    * Do Phase 2 Initialization
-    * Controller init
-    */
-   for (i = 0; i < ips_next_controller; i++) {
-
-      if (ips_ha[i] == 0) {
-         printk(KERN_WARNING "(%s%d) ignoring bad controller\n", ips_name, i);
-         continue;
-      }
-
-      if (ips_init_phase2(i) != SUCCESS)
-         ips_num_controllers--;
-
-   }
-
-   if (ips_num_controllers > 0)
-      register_reboot_notifier(&ips_notifier);
-
-   return (ips_num_controllers);
-}
-#endif
-
-/****************************************************************************/
 /*   configure the function pointers to use the functions that will work    */
 /*   with the found version of the adapter                                  */
 /****************************************************************************/
-static void ips_setup_funclist(ips_ha_t *ha){
+static void
+ips_setup_funclist(ips_ha_t * ha)
+{
 
-   /*                                
-    * Setup Functions
-    */
-   if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
-      /* morpheus / marco / sebring */
-      ha->func.isintr = ips_isintr_morpheus;
-      ha->func.isinit = ips_isinit_morpheus;
-      ha->func.issue = ips_issue_i2o_memio;
-      ha->func.init = ips_init_morpheus;
-      ha->func.statupd = ips_statupd_morpheus;
-      ha->func.reset = ips_reset_morpheus;
-      ha->func.intr = ips_intr_morpheus;
-      ha->func.enableint = ips_enable_int_morpheus;
-   } else if (IPS_USE_MEMIO(ha)) {
-      /* copperhead w/MEMIO */
-      ha->func.isintr = ips_isintr_copperhead_memio;
-      ha->func.isinit = ips_isinit_copperhead_memio;
-      ha->func.init = ips_init_copperhead_memio;
-      ha->func.statupd = ips_statupd_copperhead_memio;
-      ha->func.statinit = ips_statinit_memio;
-      ha->func.reset = ips_reset_copperhead_memio;
-      ha->func.intr = ips_intr_copperhead;
-      ha->func.erasebios = ips_erase_bios_memio;
-      ha->func.programbios = ips_program_bios_memio;
-      ha->func.verifybios = ips_verify_bios_memio;
-      ha->func.enableint = ips_enable_int_copperhead_memio;
-      if (IPS_USE_I2O_DELIVER(ha))
-         ha->func.issue = ips_issue_i2o_memio;
-      else
-         ha->func.issue = ips_issue_copperhead_memio;
-   } else {
-      /* copperhead */
-      ha->func.isintr = ips_isintr_copperhead;
-      ha->func.isinit = ips_isinit_copperhead;
-      ha->func.init = ips_init_copperhead;
-      ha->func.statupd = ips_statupd_copperhead;
-      ha->func.statinit = ips_statinit;
-      ha->func.reset = ips_reset_copperhead;
-      ha->func.intr = ips_intr_copperhead;
-      ha->func.erasebios = ips_erase_bios;
-      ha->func.programbios = ips_program_bios;
-      ha->func.verifybios = ips_verify_bios;
-      ha->func.enableint = ips_enable_int_copperhead;
-
-      if (IPS_USE_I2O_DELIVER(ha))
-         ha->func.issue = ips_issue_i2o;
-      else
-         ha->func.issue = ips_issue_copperhead;
-   }
+	/*                                
+	 * Setup Functions
+	 */
+	if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
+		/* morpheus / marco / sebring */
+		ha->func.isintr = ips_isintr_morpheus;
+		ha->func.isinit = ips_isinit_morpheus;
+		ha->func.issue = ips_issue_i2o_memio;
+		ha->func.init = ips_init_morpheus;
+		ha->func.statupd = ips_statupd_morpheus;
+		ha->func.reset = ips_reset_morpheus;
+		ha->func.intr = ips_intr_morpheus;
+		ha->func.enableint = ips_enable_int_morpheus;
+	} else if (IPS_USE_MEMIO(ha)) {
+		/* copperhead w/MEMIO */
+		ha->func.isintr = ips_isintr_copperhead_memio;
+		ha->func.isinit = ips_isinit_copperhead_memio;
+		ha->func.init = ips_init_copperhead_memio;
+		ha->func.statupd = ips_statupd_copperhead_memio;
+		ha->func.statinit = ips_statinit_memio;
+		ha->func.reset = ips_reset_copperhead_memio;
+		ha->func.intr = ips_intr_copperhead;
+		ha->func.erasebios = ips_erase_bios_memio;
+		ha->func.programbios = ips_program_bios_memio;
+		ha->func.verifybios = ips_verify_bios_memio;
+		ha->func.enableint = ips_enable_int_copperhead_memio;
+		if (IPS_USE_I2O_DELIVER(ha))
+			ha->func.issue = ips_issue_i2o_memio;
+		else
+			ha->func.issue = ips_issue_copperhead_memio;
+	} else {
+		/* copperhead */
+		ha->func.isintr = ips_isintr_copperhead;
+		ha->func.isinit = ips_isinit_copperhead;
+		ha->func.init = ips_init_copperhead;
+		ha->func.statupd = ips_statupd_copperhead;
+		ha->func.statinit = ips_statinit;
+		ha->func.reset = ips_reset_copperhead;
+		ha->func.intr = ips_intr_copperhead;
+		ha->func.erasebios = ips_erase_bios;
+		ha->func.programbios = ips_program_bios;
+		ha->func.verifybios = ips_verify_bios;
+		ha->func.enableint = ips_enable_int_copperhead;
+
+		if (IPS_USE_I2O_DELIVER(ha))
+			ha->func.issue = ips_issue_i2o;
+		else
+			ha->func.issue = ips_issue_copperhead;
+	}
 }
 
 /****************************************************************************/
@@ -1387,79 +651,72 @@
 /*                                                                          */
 /****************************************************************************/
 int
-ips_release(struct Scsi_Host *sh) {
-   ips_scb_t *scb;
-   ips_ha_t  *ha;
-   int        i;
-
-   METHOD_TRACE("ips_release", 1);
-
-   for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++);
-
-   if (i == IPS_MAX_ADAPTERS) {
-      printk(KERN_WARNING "(%s) release, invalid Scsi_Host pointer.\n",
-            ips_name);
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-      BUG();
-#endif
-      return (FALSE);
-   }
+ips_release(struct Scsi_Host *sh)
+{
+	ips_scb_t *scb;
+	ips_ha_t *ha;
+	int i;
 
-   ha = IPS_HA(sh);
+	METHOD_TRACE("ips_release", 1);
 
-   if (!ha)
-      return (FALSE);
+	for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ;
 
-   /* flush the cache on the controller */
-   scb = &ha->scbs[ha->max_cmds-1];
+	if (i == IPS_MAX_ADAPTERS) {
+		printk(KERN_WARNING
+		       "(%s) release, invalid Scsi_Host pointer.\n", ips_name);
+		BUG();
+		return (FALSE);
+	}
 
-   ips_init_scb(ha, scb);
+	ha = IPS_HA(sh);
 
-   scb->timeout = ips_cmd_timeout;
-   scb->cdb[0] = IPS_CMD_FLUSH;
+	if (!ha)
+		return (FALSE);
 
-   scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
-   scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.flush_cache.state = IPS_NORM_STATE;
-   scb->cmd.flush_cache.reserved = 0;
-   scb->cmd.flush_cache.reserved2 = 0;
-   scb->cmd.flush_cache.reserved3 = 0;
-   scb->cmd.flush_cache.reserved4 = 0;
+	/* flush the cache on the controller */
+	scb = &ha->scbs[ha->max_cmds - 1];
 
-   if (InitState != 0)    /* If Not just Searching for the Adapter Order Table */
-      printk(KERN_NOTICE "(%s%d) Flushing Cache.\n", ips_name, ha->host_num);
+	ips_init_scb(ha, scb);
 
-   /* send command */
-   if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
-      printk(KERN_NOTICE "(%s%d) Incomplete Flush.\n", ips_name, ha->host_num);
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_FLUSH;
 
-   if (InitState != 0)    /* If Not just Searching for the Adapter Order Table */
-      printk(KERN_NOTICE "(%s%d) Flushing Complete.\n", ips_name, ha->host_num);
+	scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
+	scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.flush_cache.state = IPS_NORM_STATE;
+	scb->cmd.flush_cache.reserved = 0;
+	scb->cmd.flush_cache.reserved2 = 0;
+	scb->cmd.flush_cache.reserved3 = 0;
+	scb->cmd.flush_cache.reserved4 = 0;
 
-   ips_sh[i] = NULL;
-   ips_ha[i] = NULL;
+	printk(KERN_NOTICE "(%s%d) Flushing Cache.\n", ips_name, ha->host_num);
 
-   /* free extra memory */
-   ips_free(ha);
+	/* send command */
+	if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
+		printk(KERN_NOTICE "(%s%d) Incomplete Flush.\n", ips_name,
+		       ha->host_num);
 
-   /* Free I/O Region */
-   if (ha->io_addr)
-      release_region(ha->io_addr, ha->io_len);
+	printk(KERN_NOTICE "(%s%d) Flushing Complete.\n", ips_name,
+	       ha->host_num);
 
-   /* free IRQ */
-   free_irq(ha->irq, ha);
+	ips_sh[i] = NULL;
+	ips_ha[i] = NULL;
 
-   scsi_unregister(sh);
+	/* free extra memory */
+	ips_free(ha);
 
-   if (InitState != 0) {
-      ips_released_controllers++;
-      if (ips_num_controllers == ips_released_controllers){
-         unregister_reboot_notifier(&ips_notifier);
-         pci_unregister_driver(ha->pcidev->driver);
-      }
-   }
+	/* Free I/O Region */
+	if (ha->io_addr)
+		release_region(ha->io_addr, ha->io_len);
 
-   return (FALSE);
+	/* free IRQ */
+	free_irq(ha->irq, ha);
+
+	scsi_unregister(sh);
+
+	ips_released_controllers++;
+
+	return (FALSE);
 }
 
 /****************************************************************************/
@@ -1472,50 +729,54 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_halt(struct notifier_block *nb, ulong event, void *buf) {
-   ips_scb_t *scb;
-   ips_ha_t  *ha;
-   int        i;
-
-   if ((event != SYS_RESTART) && (event != SYS_HALT) &&
-       (event != SYS_POWER_OFF))
-      return (NOTIFY_DONE);
-
-   for (i = 0; i < ips_next_controller; i++) {
-      ha = (ips_ha_t *) ips_ha[i];
-
-      if (!ha)
-         continue;
-
-      if (!ha->active)
-         continue;
-
-      /* flush the cache on the controller */
-      scb = &ha->scbs[ha->max_cmds-1];
-
-      ips_init_scb(ha, scb);
-
-      scb->timeout = ips_cmd_timeout;
-      scb->cdb[0] = IPS_CMD_FLUSH;
-
-      scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
-      scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
-      scb->cmd.flush_cache.state = IPS_NORM_STATE;
-      scb->cmd.flush_cache.reserved = 0;
-      scb->cmd.flush_cache.reserved2 = 0;
-      scb->cmd.flush_cache.reserved3 = 0;
-      scb->cmd.flush_cache.reserved4 = 0;
-
-      printk(KERN_NOTICE "(%s%d) Flushing Cache.\n", ips_name, ha->host_num);
-
-      /* send command */
-      if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
-         printk(KERN_NOTICE "(%s%d) Incomplete Flush.\n", ips_name, ha->host_num);
-      else
-         printk(KERN_NOTICE "(%s%d) Flushing Complete.\n", ips_name, ha->host_num);
-   }
+ips_halt(struct notifier_block *nb, ulong event, void *buf)
+{
+	ips_scb_t *scb;
+	ips_ha_t *ha;
+	int i;
+
+	if ((event != SYS_RESTART) && (event != SYS_HALT) &&
+	    (event != SYS_POWER_OFF)) return (NOTIFY_DONE);
+
+	for (i = 0; i < ips_next_controller; i++) {
+		ha = (ips_ha_t *) ips_ha[i];
+
+		if (!ha)
+			continue;
+
+		if (!ha->active)
+			continue;
+
+		/* flush the cache on the controller */
+		scb = &ha->scbs[ha->max_cmds - 1];
+
+		ips_init_scb(ha, scb);
+
+		scb->timeout = ips_cmd_timeout;
+		scb->cdb[0] = IPS_CMD_FLUSH;
+
+		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
+		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
+		scb->cmd.flush_cache.state = IPS_NORM_STATE;
+		scb->cmd.flush_cache.reserved = 0;
+		scb->cmd.flush_cache.reserved2 = 0;
+		scb->cmd.flush_cache.reserved3 = 0;
+		scb->cmd.flush_cache.reserved4 = 0;
+
+		printk(KERN_NOTICE "(%s%d) Flushing Cache.\n", ips_name,
+		       ha->host_num);
+
+		/* send command */
+		if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) ==
+		    IPS_FAILURE) printk(KERN_NOTICE
+					"(%s%d) Incomplete Flush.\n", ips_name,
+					ha->host_num);
+		else
+			printk(KERN_NOTICE "(%s%d) Flushing Complete.\n",
+			       ips_name, ha->host_num);
+	}
 
-   return (NOTIFY_OK);
+	return (NOTIFY_OK);
 }
 
 /****************************************************************************/
@@ -1528,50 +789,51 @@
 /* Note: this routine is called under the io_request_lock                   */
 /****************************************************************************/
 int
-ips_eh_abort(Scsi_Cmnd *SC) {
-   ips_ha_t         *ha;
-   ips_copp_wait_item_t *item;
-   int ret;
-
-   METHOD_TRACE("ips_eh_abort", 1);
-
-   if (!SC)
-      return (FAILED);
-
-   ha = (ips_ha_t *) SC->host->hostdata;
-
-   if (!ha)
-      return (FAILED);
-
-   if (!ha->active)
-      return (FAILED);
-
-   if (SC->serial_number != SC->serial_number_at_timeout) {
-      /* HMM, looks like a bogus command */
-      DEBUG(1, "Abort called with bogus scsi command");
-
-      return (FAILED);
-   }
-
-   /* See if the command is on the copp queue */
-   item = ha->copp_waitlist.head;
-   while ((item) && (item->scsi_cmd != SC))
-      item = item->next;
-
-   if (item) {
-      /* Found it */
-      ips_removeq_copp(&ha->copp_waitlist, item);
-      ret = (SUCCESS);
-
-   /* See if the command is on the wait queue */
-   } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
-      /* command not sent yet */
-      ret = (SUCCESS);
-   } else {
-      /* command must have already been sent */
-      ret = (FAILED);
-   }
-   return ret;
+ips_eh_abort(Scsi_Cmnd * SC)
+{
+	ips_ha_t *ha;
+	ips_copp_wait_item_t *item;
+	int ret;
+
+	METHOD_TRACE("ips_eh_abort", 1);
+
+	if (!SC)
+		return (FAILED);
+
+	ha = (ips_ha_t *) SC->host->hostdata;
+
+	if (!ha)
+		return (FAILED);
+
+	if (!ha->active)
+		return (FAILED);
+
+	if (SC->serial_number != SC->serial_number_at_timeout) {
+		/* HMM, looks like a bogus command */
+		DEBUG(1, "Abort called with bogus scsi command");
+
+		return (FAILED);
+	}
+
+	/* See if the command is on the copp queue */
+	item = ha->copp_waitlist.head;
+	while ((item) && (item->scsi_cmd != SC))
+		item = item->next;
+
+	if (item) {
+		/* Found it */
+		ips_removeq_copp(&ha->copp_waitlist, item);
+		ret = (SUCCESS);
+
+		/* See if the command is on the wait queue */
+	} else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
+		/* command not sent yet */
+		ret = (SUCCESS);
+	} else {
+		/* command must have already been sent */
+		ret = (FAILED);
+	}
+	return ret;
 }
 
 /****************************************************************************/
@@ -1586,191 +848,194 @@
 /*                                                                          */
 /****************************************************************************/
 int
-ips_eh_reset(Scsi_Cmnd *SC) {
-   int                   ret;
-   int                   i;
-   ips_ha_t             *ha;
-   ips_scb_t            *scb;
-   ips_copp_wait_item_t *item;
+ips_eh_reset(Scsi_Cmnd * SC)
+{
+	int ret;
+	int i;
+	ips_ha_t *ha;
+	ips_scb_t *scb;
+	ips_copp_wait_item_t *item;
 
-   METHOD_TRACE("ips_eh_reset", 1);
+	METHOD_TRACE("ips_eh_reset", 1);
 
 #ifdef NO_IPS_RESET
-   return (FAILED);
+	return (FAILED);
 #else
 
-   if (!SC) {
-      DEBUG(1, "Reset called with NULL scsi command");
+	if (!SC) {
+		DEBUG(1, "Reset called with NULL scsi command");
 
-      return (FAILED);
-   }
+		return (FAILED);
+	}
 
-   ha = (ips_ha_t *) SC->host->hostdata;
+	ha = (ips_ha_t *) SC->host->hostdata;
 
-   if (!ha) {
-      DEBUG(1, "Reset called with NULL ha struct");
-
-      return (FAILED);
-   }
-
-   if (!ha->active)
-      return (FAILED);
-
-   /* See if the command is on the copp queue */
-   item = ha->copp_waitlist.head;
-   while ((item) && (item->scsi_cmd != SC))
-      item = item->next;
-
-   if (item) {
-      /* Found it */
-      ips_removeq_copp(&ha->copp_waitlist, item);
-      return (SUCCESS);
-   }
-
-   /* See if the command is on the wait queue */
-   if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
-      /* command not sent yet */
-      return (SUCCESS);
-   }
-
-   /* An explanation for the casual observer:                              */
-   /* Part of the function of a RAID controller is automatic error         */
-   /* detection and recovery.  As such, the only problem that physically   */
-   /* resetting an adapter will ever fix is when, for some reason,         */
-   /* the driver is not successfully communicating with the adapter.       */
-   /* Therefore, we will attempt to flush this adapter.  If that succeeds, */
-   /* then there's no real purpose in a physical reset. This will complete */
-   /* much faster and avoids any problems that might be caused by a        */
-   /* physical reset ( such as having to fail all the outstanding I/O's ). */
-                                                           
-   if (ha->ioctl_reset == 0) {          /* IF Not an IOCTL Requested Reset */
-      scb = &ha->scbs[ha->max_cmds-1];
-
-      ips_init_scb(ha, scb);
-
-      scb->timeout = ips_cmd_timeout;
-      scb->cdb[0] = IPS_CMD_FLUSH;
-
-      scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
-      scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
-      scb->cmd.flush_cache.state = IPS_NORM_STATE;
-      scb->cmd.flush_cache.reserved = 0;
-      scb->cmd.flush_cache.reserved2 = 0;
-      scb->cmd.flush_cache.reserved3 = 0;
-      scb->cmd.flush_cache.reserved4 = 0;
-
-      /* Attempt the flush command */
-      ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
-      if (ret == IPS_SUCCESS) {
-         printk(KERN_NOTICE "(%s%d) Reset Request - Flushed Cache\n", ips_name, ha->host_num);
-         return (SUCCESS);
-         }
-   }
-
-   /* Either we can't communicate with the adapter or it's an IOCTL request */
-   /* from a utility.  A physical reset is needed at this point.            */
-
-   ha->ioctl_reset = 0;             /* Reset the IOCTL Requested Reset Flag */
-
-   /*
-    * command must have already been sent
-    * reset the controller
-    */
-   printk(KERN_NOTICE "(%s%d) Resetting controller.\n",
-          ips_name, ha->host_num);
-   ret = (*ha->func.reset)(ha);
-
-   if (!ret) {
-      Scsi_Cmnd *scsi_cmd;
-
-      printk(KERN_NOTICE
-             "(%s%d) Controller reset failed - controller now offline.\n",
-             ips_name, ha->host_num);
-
-      /* Now fail all of the active commands */
-      DEBUG_VAR(1, "(%s%d) Failing active commands",
-                ips_name, ha->host_num);
-
-      while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
-         scb->scsi_cmd->result = DID_ERROR << 16;
-         scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-         ips_freescb(ha, scb);
-      }
-
-      /* Now fail all of the pending commands */
-      DEBUG_VAR(1, "(%s%d) Failing pending commands",
-                ips_name, ha->host_num);
-
-      while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
-         scsi_cmd->result = DID_ERROR;
-         scsi_cmd->scsi_done(scsi_cmd);
-      }
-
-      ha->active = FALSE;
-      return (FAILED);
-   }
-
-   if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
-      Scsi_Cmnd *scsi_cmd;
-
-      printk(KERN_NOTICE
-             "(%s%d) Controller reset failed - controller now offline.\n",
-             ips_name, ha->host_num);
-
-      /* Now fail all of the active commands */
-      DEBUG_VAR(1, "(%s%d) Failing active commands",
-                ips_name, ha->host_num);
-
-      while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
-         scb->scsi_cmd->result = DID_ERROR << 16;
-         scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-         ips_freescb(ha, scb);
-      }
-
-      /* Now fail all of the pending commands */
-      DEBUG_VAR(1, "(%s%d) Failing pending commands",
-                ips_name, ha->host_num);
-
-      while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
-         scsi_cmd->result = DID_ERROR << 16;
-         scsi_cmd->scsi_done(scsi_cmd);
-      }
-
-      ha->active = FALSE;
-      return (FAILED);
-   }
-
-   /* FFDC */
-   if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) {
-      struct timeval tv;
-
-      do_gettimeofday(&tv);
-      ha->last_ffdc = tv.tv_sec;
-      ha->reset_count++;
-      ips_ffdc_reset(ha, IPS_INTR_IORL);
-   }
-
-   /* Now fail all of the active commands */
-   DEBUG_VAR(1, "(%s%d) Failing active commands",
-             ips_name, ha->host_num);
-
-   while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
-      scb->scsi_cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
-      scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-      ips_freescb(ha, scb);
-   }
-
-   /* Reset DCDB active command bits */
-   for (i = 1; i < ha->nbus; i++)
-      ha->dcdb_active[i-1] = 0;
+	if (!ha) {
+		DEBUG(1, "Reset called with NULL ha struct");
+
+		return (FAILED);
+	}
+
+	if (!ha->active)
+		return (FAILED);
+
+	/* See if the command is on the copp queue */
+	item = ha->copp_waitlist.head;
+	while ((item) && (item->scsi_cmd != SC))
+		item = item->next;
+
+	if (item) {
+		/* Found it */
+		ips_removeq_copp(&ha->copp_waitlist, item);
+		return (SUCCESS);
+	}
+
+	/* See if the command is on the wait queue */
+	if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
+		/* command not sent yet */
+		return (SUCCESS);
+	}
+
+	/* An explanation for the casual observer:                              */
+	/* Part of the function of a RAID controller is automatic error         */
+	/* detection and recovery.  As such, the only problem that physically   */
+	/* resetting an adapter will ever fix is when, for some reason,         */
+	/* the driver is not successfully communicating with the adapter.       */
+	/* Therefore, we will attempt to flush this adapter.  If that succeeds, */
+	/* then there's no real purpose in a physical reset. This will complete */
+	/* much faster and avoids any problems that might be caused by a        */
+	/* physical reset ( such as having to fail all the outstanding I/O's ). */
+
+	if (ha->ioctl_reset == 0) {	/* IF Not an IOCTL Requested Reset */
+		scb = &ha->scbs[ha->max_cmds - 1];
+
+		ips_init_scb(ha, scb);
+
+		scb->timeout = ips_cmd_timeout;
+		scb->cdb[0] = IPS_CMD_FLUSH;
+
+		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
+		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
+		scb->cmd.flush_cache.state = IPS_NORM_STATE;
+		scb->cmd.flush_cache.reserved = 0;
+		scb->cmd.flush_cache.reserved2 = 0;
+		scb->cmd.flush_cache.reserved3 = 0;
+		scb->cmd.flush_cache.reserved4 = 0;
+
+		/* Attempt the flush command */
+		ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
+		if (ret == IPS_SUCCESS) {
+			printk(KERN_NOTICE
+			       "(%s%d) Reset Request - Flushed Cache\n",
+			       ips_name, ha->host_num);
+			return (SUCCESS);
+		}
+	}
+
+	/* Either we can't communicate with the adapter or it's an IOCTL request */
+	/* from a utility.  A physical reset is needed at this point.            */
+
+	ha->ioctl_reset = 0;	/* Reset the IOCTL Requested Reset Flag */
+
+	/*
+	 * command must have already been sent
+	 * reset the controller
+	 */
+	printk(KERN_NOTICE "(%s%d) Resetting controller.\n",
+	       ips_name, ha->host_num);
+	ret = (*ha->func.reset) (ha);
+
+	if (!ret) {
+		Scsi_Cmnd *scsi_cmd;
+
+		printk(KERN_NOTICE
+		       "(%s%d) Controller reset failed - controller now offline.\n",
+		       ips_name, ha->host_num);
+
+		/* Now fail all of the active commands */
+		DEBUG_VAR(1, "(%s%d) Failing active commands",
+			  ips_name, ha->host_num);
+
+		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
+			scb->scsi_cmd->result = DID_ERROR << 16;
+			scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			ips_freescb(ha, scb);
+		}
+
+		/* Now fail all of the pending commands */
+		DEBUG_VAR(1, "(%s%d) Failing pending commands",
+			  ips_name, ha->host_num);
+
+		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
+			scsi_cmd->result = DID_ERROR;
+			scsi_cmd->scsi_done(scsi_cmd);
+		}
+
+		ha->active = FALSE;
+		return (FAILED);
+	}
+
+	if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
+		Scsi_Cmnd *scsi_cmd;
+
+		printk(KERN_NOTICE
+		       "(%s%d) Controller reset failed - controller now offline.\n",
+		       ips_name, ha->host_num);
+
+		/* Now fail all of the active commands */
+		DEBUG_VAR(1, "(%s%d) Failing active commands",
+			  ips_name, ha->host_num);
+
+		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
+			scb->scsi_cmd->result = DID_ERROR << 16;
+			scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			ips_freescb(ha, scb);
+		}
+
+		/* Now fail all of the pending commands */
+		DEBUG_VAR(1, "(%s%d) Failing pending commands",
+			  ips_name, ha->host_num);
+
+		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
+			scsi_cmd->result = DID_ERROR << 16;
+			scsi_cmd->scsi_done(scsi_cmd);
+		}
+
+		ha->active = FALSE;
+		return (FAILED);
+	}
+
+	/* FFDC */
+	if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) {
+		struct timeval tv;
+
+		do_gettimeofday(&tv);
+		ha->last_ffdc = tv.tv_sec;
+		ha->reset_count++;
+		ips_ffdc_reset(ha, IPS_INTR_IORL);
+	}
+
+	/* Now fail all of the active commands */
+	DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num);
+
+	while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
+		scb->scsi_cmd->result =
+		    (DID_RESET << 16) | (SUGGEST_RETRY << 24);
+		scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+		ips_freescb(ha, scb);
+	}
+
+	/* Reset DCDB active command bits */
+	for (i = 1; i < ha->nbus; i++)
+		ha->dcdb_active[i - 1] = 0;
 
-   /* Reset the number of active IOCTLs */
-   ha->num_ioctl = 0;
+	/* Reset the number of active IOCTLs */
+	ha->num_ioctl = 0;
 
-   ips_next(ha, IPS_INTR_IORL);
+	ips_next(ha, IPS_INTR_IORL);
 
-   return (SUCCESS);
-#endif /* NO_IPS_RESET */
+	return (SUCCESS);
+#endif				/* NO_IPS_RESET */
 
 }
 
@@ -1787,103 +1052,92 @@
 /*                                                                          */
 /****************************************************************************/
 int
-ips_queue(Scsi_Cmnd *SC, void (*done) (Scsi_Cmnd *)) {
-   ips_ha_t         *ha;
-   ips_passthru_t   *pt;                                             
-
-   METHOD_TRACE("ips_queue", 1);
-
-   ha = (ips_ha_t *) SC->host->hostdata;
-
-   if (!ha)
-      return (1);
-
-   if (!ha->active)
-      return (DID_ERROR);
-
-   if (ips_is_passthru(SC)) {
-      if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
-         SC->result = DID_BUS_BUSY << 16;
-         done(SC);
-
-         return (0);
-      }
-   } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
-      SC->result = DID_BUS_BUSY << 16;
-      done(SC);
-
-      return (0);
-   }
-
-   SC->scsi_done = done;
-
-   DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)",
-             ips_name,
-             ha->host_num,
-             SC->cmnd[0],
-             SC->channel,
-             SC->target,
-             SC->lun);
-
-   /* Check for command to initiator IDs */
-   if ((SC->channel > 0) && (SC->target == ha->ha_id[SC->channel])) {
-      SC->result = DID_NO_CONNECT << 16;
-      done(SC);
-
-      return (0);
-   }
-
-   if (ips_is_passthru(SC)) {
-
-      ips_copp_wait_item_t *scratch;
-      
-      /* A Reset IOCTL is only sent by the boot CD in extreme cases.           */
-      /* There can never be any system activity ( network or disk ), but check */
-      /* anyway just as a good practice.                                       */
-      pt = (ips_passthru_t *) SC->request_buffer;                                
-      if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) &&            
-           (pt->CoppCP.cmd.reset.adapter_flag == 1))  {                         
-         if (ha->scb_activelist.count != 0) {
-             SC->result = DID_BUS_BUSY << 16;
-             done(SC);
-             return (0);
-         }
-         ha->ioctl_reset = 1;           /* This reset request is from an IOCTL */
-         ips_eh_reset(SC);                                                         
-         SC->result = DID_OK << 16;                                                
-         SC->scsi_done(SC);                                                        
-         return (0);                                                               
-      }
-
-      /* allocate space for the scribble */
-      scratch = kmalloc(sizeof(ips_copp_wait_item_t), GFP_ATOMIC);
-
-      if (!scratch) {
-         SC->result = DID_ERROR << 16;
-         done(SC);
-
-         return (0);
-      }
-
-      scratch->scsi_cmd = SC;
-      scratch->next = NULL;
-
-      ips_putq_copp_tail(&ha->copp_waitlist, scratch);
-   }
-   else {
-      ips_putq_wait_tail(&ha->scb_waitlist, SC);
-   }
-
-   ips_next(ha, IPS_INTR_IORL);
-   
-   /* If We were using the CD Boot Flash Buffer, Restore the Old Values */
-   if ( ips_FlashData == ha->ioctl_data ) {                               
-      ha->ioctl_data = ha->flash_data;                           
-      ha->ioctl_order = ha->flash_order;                          
-      ha->ioctl_datasize = ha->flash_datasize;                       
-      ips_FlashDataInUse = 0;                                             
-   }
-   return (0);
+ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
+{
+	ips_ha_t *ha;
+	ips_passthru_t *pt;
+
+	METHOD_TRACE("ips_queue", 1);
+
+	ha = (ips_ha_t *) SC->host->hostdata;
+
+	if (!ha)
+		return (1);
+
+	if (!ha->active)
+		return (DID_ERROR);
+
+	if (ips_is_passthru(SC)) {
+		if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
+			SC->result = DID_BUS_BUSY << 16;
+			done(SC);
+
+			return (0);
+		}
+	} else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
+		SC->result = DID_BUS_BUSY << 16;
+		done(SC);
+
+		return (0);
+	}
+
+	SC->scsi_done = done;
+
+	DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)",
+		  ips_name,
+		  ha->host_num, SC->cmnd[0], SC->channel, SC->target, SC->lun);
+
+	/* Check for command to initiator IDs */
+	if ((SC->channel > 0) && (SC->target == ha->ha_id[SC->channel])) {
+		SC->result = DID_NO_CONNECT << 16;
+		done(SC);
+
+		return (0);
+	}
+
+	if (ips_is_passthru(SC)) {
+
+		ips_copp_wait_item_t *scratch;
+
+		/* A Reset IOCTL is only sent by the boot CD in extreme cases.           */
+		/* There can never be any system activity ( network or disk ), but check */
+		/* anyway just as a good practice.                                       */
+		pt = (ips_passthru_t *) SC->request_buffer;
+		if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) &&
+		    (pt->CoppCP.cmd.reset.adapter_flag == 1)) {
+			if (ha->scb_activelist.count != 0) {
+				SC->result = DID_BUS_BUSY << 16;
+				done(SC);
+				return (0);
+			}
+			ha->ioctl_reset = 1;	/* This reset request is from an IOCTL */
+			ips_eh_reset(SC);
+			SC->result = DID_OK << 16;
+			SC->scsi_done(SC);
+			return (0);
+		}
+
+		/* allocate space for the scribble */
+		scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC);
+
+		if (!scratch) {
+			SC->result = DID_ERROR << 16;
+			done(SC);
+
+			return (0);
+		}
+
+		scratch->scsi_cmd = SC;
+		scratch->next = NULL;
+
+		ips_putq_copp_tail(&ha->copp_waitlist, scratch);
+	} else {
+		ips_putq_wait_tail(&ha->scb_waitlist, SC);
+	}
+
+	ips_next(ha, IPS_INTR_IORL);
+
+	return (0);
 }
 
 /****************************************************************************/
@@ -1896,48 +1150,49 @@
 /*                                                                          */
 /****************************************************************************/
 int
-ips_biosparam(Disk *disk, kdev_t dev, int geom[]) {
-   ips_ha_t         *ha;
-   int               heads;
-   int               sectors;
-   int               cylinders;
-
-   METHOD_TRACE("ips_biosparam", 1);
-
-   ha = (ips_ha_t *) disk->device->host->hostdata;
-
-   if (!ha)
-      /* ?!?! host adater info invalid */
-      return (0);
-
-   if (!ha->active)
-      return (0);
-
-   if (!ips_read_adapter_status(ha, IPS_INTR_ON))
-      /* ?!?! Enquiry command failed */
-      return (0);
-
-   if ((disk->capacity > 0x400000) &&
-       ((ha->enq->ucMiscFlag & 0x8) == 0)) {
-      heads = IPS_NORM_HEADS;
-      sectors = IPS_NORM_SECTORS;
-   } else {
-      heads = IPS_COMP_HEADS;
-      sectors = IPS_COMP_SECTORS;
-   }
-
-   cylinders = disk->capacity / (heads * sectors);
-
-   DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
-             heads, sectors, cylinders);
-
-   geom[0] = heads;
-   geom[1] = sectors;
-   geom[2] = cylinders;
+ips_biosparam(Disk * disk, kdev_t dev, int geom[])
+{
+	ips_ha_t *ha;
+	int heads;
+	int sectors;
+	int cylinders;
+
+	METHOD_TRACE("ips_biosparam", 1);
 
-   return (0);
+	ha = (ips_ha_t *) disk->device->host->hostdata;
+
+	if (!ha)
+		/* ?!?! host adater info invalid */
+		return (0);
+
+	if (!ha->active)
+		return (0);
+
+	if (!ips_read_adapter_status(ha, IPS_INTR_ON))
+		/* ?!?! Enquiry command failed */
+		return (0);
+
+	if ((disk->capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) {
+		heads = IPS_NORM_HEADS;
+		sectors = IPS_NORM_SECTORS;
+	} else {
+		heads = IPS_COMP_HEADS;
+		sectors = IPS_COMP_SECTORS;
+	}
+
+	cylinders = disk->capacity / (heads * sectors);
+
+	DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
+		  heads, sectors, cylinders);
+
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return (0);
 }
 
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_select_queue_depth                                     */
@@ -1948,39 +1203,67 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs) {
-   Scsi_Device *device;
-   ips_ha_t    *ha;
-   int          count = 0;
-   int          min;
-
-   ha = IPS_HA(host);
-   min = ha->max_cmds / 4;
-
-   for (device = scsi_devs; device; device = device->next) {
-     if (device->host == host) {
-        if ((device->channel == 0) && (device->type == 0))
-           count++;
-     }
-   }
-
-   for (device = scsi_devs; device; device = device->next) {
-      if (device->host == host) {
-         if ((device->channel == 0) && (device->type == 0)) {
-            device->queue_depth = ( ha->max_cmds - 1 ) / count;
-            if (device->queue_depth < min) 
-               device->queue_depth = min;
-         }
-         else {
-            device->queue_depth = 2;
-         }
-
-         if (device->queue_depth < 2)
-            device->queue_depth = 2;
-      }
-   }
+ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs)
+{
+	Scsi_Device *device;
+	ips_ha_t *ha;
+	int count = 0;
+	int min;
+
+	ha = IPS_HA(host);
+	min = ha->max_cmds / 4;
+
+	for (device = scsi_devs; device; device = device->next) {
+		if (device->host == host) {
+			if ((device->channel == 0) && (device->type == 0))
+				count++;
+		}
+	}
+
+	for (device = scsi_devs; device; device = device->next) {
+		if (device->host == host) {
+			if ((device->channel == 0) && (device->type == 0)) {
+				device->queue_depth =
+				    (ha->max_cmds - 1) / count;
+				if (device->queue_depth < min)
+					device->queue_depth = min;
+			} else {
+				device->queue_depth = 2;
+			}
+
+			if (device->queue_depth < 2)
+				device->queue_depth = 2;
+		}
+	}
 }
 
+#else
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_slave_configure                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Set queue depths on devices once scan is complete                      */
+/*                                                                          */
+/****************************************************************************/
+int
+ips_slave_configure(Scsi_Device * SDptr)
+{
+	ips_ha_t *ha;
+	int min;
+
+	ha = IPS_HA(SDptr->host);
+	if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) {
+		min = ha->max_cmds / 2;
+		if (ha->enq->ucLogDriveCount <= 2)
+			min = ha->max_cmds - 1;
+		scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
+	}
+	return 0;
+}
+#endif
+
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: do_ipsintr                                                 */
@@ -1991,30 +1274,37 @@
 /*                                                                          */
 /****************************************************************************/
 void
-do_ipsintr(int irq, void *dev_id, struct pt_regs *regs) {
-   ips_ha_t         *ha;
-   unsigned long     cpu_flags;
-   struct Scsi_Host *host;
-
-   METHOD_TRACE("do_ipsintr", 2);
-
-   ha = (ips_ha_t *) dev_id;
-   if (!ha) 
-      return;
-   host = ips_sh[ha->host_num];
-   IPS_LOCK_SAVE(host->host_lock, cpu_flags);
-
-   if (!ha->active) {
-      IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
-      return;
-   }
+do_ipsintr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	ips_ha_t *ha;
+	unsigned long cpu_flags;
+	struct Scsi_Host *host;
+
+	METHOD_TRACE("do_ipsintr", 2);
+
+	ha = (ips_ha_t *) dev_id;
+	if (!ha)
+		return;
+	host = ips_sh[ha->host_num];
+	/* interrupt during initialization */
+	if (!host) {
+		(*ha->func.intr) (ha);
+		return;
+	}
+
+	IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+
+	if (!ha->active) {
+		IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+		return;
+	}
 
-   (*ha->func.intr)(ha);
+	(*ha->func.intr) (ha);
 
-   IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+	IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
 
-   /* start the next command */
-   ips_next(ha, IPS_INTR_ON);
+	/* start the next command */
+	ips_next(ha, IPS_INTR_ON);
 }
 
 /****************************************************************************/
@@ -2029,54 +1319,55 @@
 /*                                                                          */
 /****************************************************************************/
 void
-ips_intr_copperhead(ips_ha_t *ha) {
-   ips_stat_t       *sp;
-   ips_scb_t        *scb;
-   IPS_STATUS        cstatus;
-   int               intrstatus;
-
-   METHOD_TRACE("ips_intr", 2);
-
-   if (!ha)
-      return;
-
-   if (!ha->active)
-      return;
-
-   intrstatus = (*ha->func.isintr)(ha);
-
-   if (!intrstatus) {
-      /*
-       * Unexpected/Shared interrupt
-       */
-
-      return;
-   }
-
-   while (TRUE) {
-      sp = &ha->sp;
-
-      intrstatus = (*ha->func.isintr)(ha);
-
-      if (!intrstatus)
-         break;
-      else
-         cstatus.value = (*ha->func.statupd)(ha);
-
-      if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
-         /* Spurious Interupt ? */
-         continue;
-      }
-
-      ips_chkstatus(ha, &cstatus);
-      scb = (ips_scb_t *) sp->scb_addr;
-
-      /*
-       * use the callback function to finish things up
-       * NOTE: interrupts are OFF for this
-       */
-      (*scb->callback) (ha, scb);
-   } /* end while */
+ips_intr_copperhead(ips_ha_t * ha)
+{
+	ips_stat_t *sp;
+	ips_scb_t *scb;
+	IPS_STATUS cstatus;
+	int intrstatus;
+
+	METHOD_TRACE("ips_intr", 2);
+
+	if (!ha)
+		return;
+
+	if (!ha->active)
+		return;
+
+	intrstatus = (*ha->func.isintr) (ha);
+
+	if (!intrstatus) {
+		/*
+		 * Unexpected/Shared interrupt
+		 */
+
+		return;
+	}
+
+	while (TRUE) {
+		sp = &ha->sp;
+
+		intrstatus = (*ha->func.isintr) (ha);
+
+		if (!intrstatus)
+			break;
+		else
+			cstatus.value = (*ha->func.statupd) (ha);
+
+		if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
+			/* Spurious Interupt ? */
+			continue;
+		}
+
+		ips_chkstatus(ha, &cstatus);
+		scb = (ips_scb_t *) sp->scb_addr;
+
+		/*
+		 * use the callback function to finish things up
+		 * NOTE: interrupts are OFF for this
+		 */
+		(*scb->callback) (ha, scb);
+	}			/* end while */
 }
 
 /****************************************************************************/
@@ -2091,60 +1382,62 @@
 /*                                                                          */
 /****************************************************************************/
 void
-ips_intr_morpheus(ips_ha_t *ha) {
-   ips_stat_t       *sp;
-   ips_scb_t        *scb;
-   IPS_STATUS        cstatus;
-   int               intrstatus;
+ips_intr_morpheus(ips_ha_t * ha)
+{
+	ips_stat_t *sp;
+	ips_scb_t *scb;
+	IPS_STATUS cstatus;
+	int intrstatus;
 
-   METHOD_TRACE("ips_intr_morpheus", 2);
+	METHOD_TRACE("ips_intr_morpheus", 2);
 
-   if (!ha)
-      return;
+	if (!ha)
+		return;
 
-   if (!ha->active)
-      return;
+	if (!ha->active)
+		return;
 
-   intrstatus = (*ha->func.isintr)(ha);
+	intrstatus = (*ha->func.isintr) (ha);
 
-   if (!intrstatus) {
-      /*
-       * Unexpected/Shared interrupt
-       */
+	if (!intrstatus) {
+		/*
+		 * Unexpected/Shared interrupt
+		 */
 
-      return;
-   }
+		return;
+	}
 
-   while (TRUE) {
-      sp = &ha->sp;
+	while (TRUE) {
+		sp = &ha->sp;
 
-      intrstatus = (*ha->func.isintr)(ha);
+		intrstatus = (*ha->func.isintr) (ha);
 
-      if (!intrstatus)
-         break;
-      else
-         cstatus.value = (*ha->func.statupd)(ha);
+		if (!intrstatus)
+			break;
+		else
+			cstatus.value = (*ha->func.statupd) (ha);
 
-      if (cstatus.value == 0xffffffff)
-         /* No more to process */
-         break;
+		if (cstatus.value == 0xffffffff)
+			/* No more to process */
+			break;
 
-      if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
-         printk(KERN_WARNING "(%s%d) Spurious interrupt; no ccb.\n",
-                ips_name, ha->host_num);
+		if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
+			printk(KERN_WARNING
+			       "(%s%d) Spurious interrupt; no ccb.\n", ips_name,
+			       ha->host_num);
 
-         continue;
-      }
+			continue;
+		}
 
-      ips_chkstatus(ha, &cstatus);
-      scb = (ips_scb_t *) sp->scb_addr;
+		ips_chkstatus(ha, &cstatus);
+		scb = (ips_scb_t *) sp->scb_addr;
 
-      /*
-       * use the callback function to finish things up
-       * NOTE: interrupts are OFF for this
-       */
-      (*scb->callback) (ha, scb);
-   } /* end while */
+		/*
+		 * use the callback function to finish things up
+		 * NOTE: interrupts are OFF for this
+		 */
+		(*scb->callback) (ha, scb);
+	}			/* end while */
 }
 
 /****************************************************************************/
@@ -2157,31 +1450,32 @@
 /*                                                                          */
 /****************************************************************************/
 const char *
-ips_info(struct Scsi_Host *SH) {
-   static char  buffer[256];
-   char        *bp;
-   ips_ha_t    *ha;
+ips_info(struct Scsi_Host *SH)
+{
+	static char buffer[256];
+	char *bp;
+	ips_ha_t *ha;
 
-   METHOD_TRACE("ips_info", 1);
+	METHOD_TRACE("ips_info", 1);
 
-   ha = IPS_HA(SH);
+	ha = IPS_HA(SH);
 
-   if (!ha)
-      return (NULL);
+	if (!ha)
+		return (NULL);
 
-   bp = &buffer[0];
-   memset(bp, 0, sizeof(buffer));
+	bp = &buffer[0];
+	memset(bp, 0, sizeof (buffer));
 
-   sprintf(bp, "%s%s%s", "IBM PCI ServeRAID ", IPS_VERSION_HIGH, IPS_VERSION_LOW );
+	sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ",
+		IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT);
 
-   if (ha->ad_type > 0 &&
-       ha->ad_type <= MAX_ADAPTER_NAME) {
-      strcat(bp, " <");
-      strcat(bp, ips_adapter_name[ha->ad_type-1]);
-      strcat(bp, ">");
-   }
+	if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) {
+		strcat(bp, " <");
+		strcat(bp, ips_adapter_name[ha->ad_type - 1]);
+		strcat(bp, ">");
+	}
 
-   return (bp);
+	return (bp);
 }
 
 /****************************************************************************/
@@ -2195,38 +1489,39 @@
 /****************************************************************************/
 int
 ips_proc_info(char *buffer, char **start, off_t offset,
-              int length, int hostno, int func) {
-   int           i;
-   int           ret;
-   ips_ha_t     *ha = NULL;
-
-   METHOD_TRACE("ips_proc_info", 1);
-
-   /* Find our host structure */
-   for (i = 0; i < ips_next_controller; i++) {
-      if (ips_sh[i]) {
-         if (ips_sh[i]->host_no == hostno) {
-            ha = (ips_ha_t *) ips_sh[i]->hostdata;
-            break;
-         }
-      }
-   }
-
-   if (!ha)
-      return (-EINVAL);
-
-   if (func) {
-      /* write */
-      return (0);
-   } else {
-      /* read */
-      if (start)
-         *start = buffer;
+	      int length, int hostno, int func)
+{
+	int i;
+	int ret;
+	ips_ha_t *ha = NULL;
+
+	METHOD_TRACE("ips_proc_info", 1);
+
+	/* Find our host structure */
+	for (i = 0; i < ips_next_controller; i++) {
+		if (ips_sh[i]) {
+			if (ips_sh[i]->host_no == hostno) {
+				ha = (ips_ha_t *) ips_sh[i]->hostdata;
+				break;
+			}
+		}
+	}
+
+	if (!ha)
+		return (-EINVAL);
+
+	if (func) {
+		/* write */
+		return (0);
+	} else {
+		/* read */
+		if (start)
+			*start = buffer;
 
-      ret = ips_host_info(ha, buffer, offset, length);
+		ret = ips_host_info(ha, buffer, offset, length);
 
-      return (ret);
-   }
+		return (ret);
+	}
 }
 
 /*--------------------------------------------------------------------------*/
@@ -2243,32 +1538,65 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_is_passthru(Scsi_Cmnd *SC) {
-   METHOD_TRACE("ips_is_passthru", 1);
+ips_is_passthru(Scsi_Cmnd * SC)
+{
+	METHOD_TRACE("ips_is_passthru", 1);
 
-   if (!SC)
-      return (0);
+	if (!SC)
+		return (0);
+
+	if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
+	    (SC->channel == 0) &&
+	    (SC->target == IPS_ADAPTER_ID) &&
+	    (SC->lun == 0) && SC->request_buffer) {
+		if ((!SC->use_sg) && SC->request_bufflen &&
+		    (((char *) SC->request_buffer)[0] == 'C') &&
+		    (((char *) SC->request_buffer)[1] == 'O') &&
+		    (((char *) SC->request_buffer)[2] == 'P') &&
+		    (((char *) SC->request_buffer)[3] == 'P'))
+			return 1;
+		else if (SC->use_sg) {
+			struct scatterlist *sg = SC->request_buffer;
+			char *buffer = IPS_SG_ADDRESS(sg);
+			if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
+			    buffer[2] == 'P' && buffer[3] == 'P')
+				return 1;
+		}
+	}
+	return 0;
+}
 
-   if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
-       (SC->channel == 0) &&
-       (SC->target == IPS_ADAPTER_ID) &&
-       (SC->lun == 0) &&
-        SC->request_buffer){
-      if((!SC->use_sg) && SC->request_bufflen &&
-         (((char *) SC->request_buffer)[0] == 'C') &&
-         (((char *) SC->request_buffer)[1] == 'O') &&
-         (((char *) SC->request_buffer)[2] == 'P') &&
-         (((char *) SC->request_buffer)[3] == 'P'))
-         return 1;
-      else if(SC->use_sg){
-         struct scatterlist *sg = SC->request_buffer;
-         char *buffer = IPS_SG_ADDRESS(sg);
-         if(buffer && buffer[0] == 'C' && buffer[1] == 'O' && 
-            buffer[2] == 'P' && buffer[3] == 'P')
-            return 1;
-      }
-   }
-   return 0;
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_alloc_passthru_buffer                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   allocate a buffer large enough for the ioctl data if the ioctl buffer  */
+/*   is too small or doesn't exist                                          */
+/****************************************************************************/
+static int
+ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
+{
+	void *bigger_buf;
+	int count;
+	int order;
+
+	if (ha->ioctl_data && length <= (PAGE_SIZE << ha->ioctl_order))
+		return 0;
+	/* there is no buffer or it's not big enough, allocate a new one */
+	for (count = PAGE_SIZE, order = 0;
+	     count < length; order++, count <<= 1) ;
+	bigger_buf = (void *) __get_free_pages(IPS_ATOMIC_GFP, order);
+	if (bigger_buf) {
+		/* free the old memory */
+		free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
+		/* use the new memory */
+		ha->ioctl_data = (char *) bigger_buf;
+		ha->ioctl_order = order;
+	} else {
+		return -1;
+	}
+	return 0;
 }
 
 /****************************************************************************/
@@ -2281,127 +1609,96 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb, int intr) {
-   ips_passthru_t *pt;
-   char *buffer;
-   int length = 0;
-
-   METHOD_TRACE("ips_make_passthru", 1);
-
-   if(!SC->use_sg){
-      buffer = SC->request_buffer;
-      length = SC->request_bufflen;
-   }else{
-      struct scatterlist *sg = SC->request_buffer;
-      int i;
-      for(i = 0; i < SC->use_sg; i++)
-         length += sg[i].length;
-
-      if (length < sizeof(ips_passthru_t)) {
-         /* wrong size */
-         DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
-             ips_name, ha->host_num);
-         return (IPS_FAILURE);
-      }else if(!ha->ioctl_data || length > (PAGE_SIZE << ha->ioctl_order)){
-         void *bigger_buf;
-         int count;
-         int order;
-         /* try to allocate a bigger buffer */
-         for (count = PAGE_SIZE, order = 0;
-              count < length;
-              order++, count <<= 1);
-         bigger_buf = (void *) __get_free_pages(GFP_ATOMIC, order);
-         if (bigger_buf) {
-            /* free the old memory */
-            free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
-            /* use the new memory */
-            ha->ioctl_data = (char *) bigger_buf;
-            ha->ioctl_order = order;
-            ha->ioctl_datasize = count;
-         } else {
-             pt = (ips_passthru_t*)IPS_SG_ADDRESS(sg);
-             pt->BasicStatus = 0x0B;
-             pt->ExtendedStatus = 0x00;
-             SC->result = DID_ERROR << 16;
-             return (IPS_FAILURE);
-         }
-      }
-      ha->ioctl_datasize = length;
-      length = 0;
-      for(i = 0; i < SC->use_sg; i++){
-         memcpy(&ha->ioctl_data[length], IPS_SG_ADDRESS(&sg[i]), sg[i].length);
-         length += sg[i].length;
-      }
-      pt = (ips_passthru_t *)ha->ioctl_data;
-      buffer = ha->ioctl_data;
-   }
-   if (!length || !buffer) {
-      /* no data */
-      DEBUG_VAR(1, "(%s%d) No passthru structure",
-                ips_name, ha->host_num);
-
-      return (IPS_FAILURE);
-   }
-   if (length < sizeof(ips_passthru_t)) {
-      /* wrong size */
-      DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
-             ips_name, ha->host_num);
-
-      return (IPS_FAILURE);
-   }
-   pt = (ips_passthru_t*) buffer;
-   /*
-    * Some notes about the passthru interface used
-    *
-    * IF the scsi op_code == 0x0d then we assume
-    * that the data came along with/goes with the
-    * packet we received from the sg driver. In this
-    * case the CmdBSize field of the pt structure is
-    * used for the size of the buffer.
-    */
-
-   switch (pt->CoppCmd) {
-   case IPS_NUMCTRLS:
-      memcpy(buffer + sizeof(ips_passthru_t),
-             &ips_num_controllers, sizeof(int));
-      SC->result = DID_OK << 16;
-
-      return (IPS_SUCCESS_IMM);
-
-   case IPS_CTRLINFO:
-      memcpy(buffer + sizeof(ips_passthru_t),
-             ha, sizeof(ips_ha_t));
-      SC->result = DID_OK << 16;
-
-      return (IPS_SUCCESS_IMM);
-
-   case IPS_COPPUSRCMD:
-   case IPS_COPPIOCCMD:
-      if (SC->cmnd[0] == IPS_IOCTL_COMMAND) {
-         if (length < (sizeof(ips_passthru_t) + pt->CmdBSize)) {
-            /* wrong size */
-            DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
-                      ips_name, ha->host_num);
-
-            return (IPS_FAILURE);
-         }
-
-         if(ha->device_id == IPS_DEVICEID_COPPERHEAD &&
-            pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)
-            return ips_flash_copperhead(ha, pt, scb);
-
-         if (ips_usrcmd(ha, pt, scb))
-            return (IPS_SUCCESS);
-         else
-            return (IPS_FAILURE);
-      } 
-     
-      break;
+ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr)
+{
+	ips_passthru_t *pt;
+	int length = 0;
+	int ret;
+
+	METHOD_TRACE("ips_make_passthru", 1);
+
+	if (!SC->use_sg) {
+		length = SC->request_bufflen;
+	} else {
+		struct scatterlist *sg = SC->request_buffer;
+		int i;
+		for (i = 0; i < SC->use_sg; i++)
+			length += sg[i].length;
+	}
+	if (length < sizeof (ips_passthru_t)) {
+		/* wrong size */
+		DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
+			  ips_name, ha->host_num);
+		return (IPS_FAILURE);
+	}
+	if (ips_alloc_passthru_buffer(ha, length)) {
+		/* allocation failure!  If ha->ioctl_data exists, use it to return
+		   some error codes.  Return a failed command to the scsi layer. */
+		if (ha->ioctl_data) {
+			pt = (ips_passthru_t *) ha->ioctl_data;
+			ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t));
+			pt->BasicStatus = 0x0B;
+			pt->ExtendedStatus = 0x00;
+			ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t));
+		}
+		return IPS_FAILURE;
+	}
+	ha->ioctl_datasize = length;
+
+	ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize);
+	pt = (ips_passthru_t *) ha->ioctl_data;
+
+	/*
+	 * Some notes about the passthru interface used
+	 *
+	 * IF the scsi op_code == 0x0d then we assume
+	 * that the data came along with/goes with the
+	 * packet we received from the sg driver. In this
+	 * case the CmdBSize field of the pt structure is
+	 * used for the size of the buffer.
+	 */
+
+	switch (pt->CoppCmd) {
+	case IPS_NUMCTRLS:
+		memcpy(ha->ioctl_data + sizeof (ips_passthru_t),
+		       &ips_num_controllers, sizeof (int));
+		ips_scmd_buf_write(SC, ha->ioctl_data,
+				   sizeof (ips_passthru_t) + sizeof (int));
+		SC->result = DID_OK << 16;
+
+		return (IPS_SUCCESS_IMM);
+
+	case IPS_COPPUSRCMD:
+	case IPS_COPPIOCCMD:
+		if (SC->cmnd[0] == IPS_IOCTL_COMMAND) {
+			if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) {
+				/* wrong size */
+				DEBUG_VAR(1,
+					  "(%s%d) Passthru structure wrong size",
+					  ips_name, ha->host_num);
+
+				return (IPS_FAILURE);
+			}
+
+			if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+			    pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) {
+				ret = ips_flash_copperhead(ha, pt, scb);
+				ips_scmd_buf_write(SC, ha->ioctl_data,
+						   sizeof (ips_passthru_t));
+				return ret;
+			}
+			if (ips_usrcmd(ha, pt, scb))
+				return (IPS_SUCCESS);
+			else
+				return (IPS_FAILURE);
+		}
 
-   } /* end switch */
+		break;
 
-         return (IPS_FAILURE);
-      }
+	}			/* end switch */
+
+	return (IPS_FAILURE);
+}
 
 /****************************************************************************/
 /* Routine Name: ips_flash_copperhead                                       */
@@ -2409,62 +1706,65 @@
 /*   Flash the BIOS/FW on a Copperhead style controller                     */
 /****************************************************************************/
 static int
-ips_flash_copperhead(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb){
-   int datasize, count;
+ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
+{
+	int datasize, count;
 
-   /* Trombone is the only copperhead that can do packet flash, but only
-    * for firmware. No one said it had to make sence. */
-   if(IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE){
-      if(ips_usrcmd(ha, pt, scb))
-         return IPS_SUCCESS;
-      else
-         return IPS_FAILURE;
-   }
-   pt->BasicStatus = 0x0B;
-   pt->ExtendedStatus = 0;
-   scb->scsi_cmd->result = DID_OK <<16;
-   /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */
-   /* avoid allocating a huge buffer per adapter ( which can fail ). */
-   if(pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
-      pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS){
-      pt->BasicStatus = 0;
-      return ips_flash_bios(ha, pt, scb);
-   }else if(pt->CoppCP.cmd.flashfw.packet_num == 0){
-      if(ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){
-         ha->flash_data  = ips_FlashData;
-         ha->flash_order = 7;
-         ha->flash_datasize = 0;
-      }else if(!ha->flash_data){
-         datasize = pt->CoppCP.cmd.flashfw.total_packets *
-                    pt->CoppCP.cmd.flashfw.count;
-         for (count = PAGE_SIZE, ha->flash_order = 0; count < datasize;
-              ha->flash_order++, count <<= 1);
-         ha->flash_data = (char *)__get_free_pages(GFP_ATOMIC, ha->flash_order);
-         ha->flash_datasize = 0;
-      }else
-         return IPS_FAILURE;
-   }else{
-      if(pt->CoppCP.cmd.flashfw.count + ha->flash_datasize >
-        (PAGE_SIZE << ha->flash_order)){
-         ips_free_flash_copperhead(ha);
-         printk(KERN_WARNING "failed size sanity check\n");
-         return IPS_FAILURE;
-      }
-   }
-   if(!ha->flash_data)
-      return IPS_FAILURE;
-   pt->BasicStatus = 0;
-   memcpy(&ha->flash_data[ha->flash_datasize], pt + 1,
-          pt->CoppCP.cmd.flashfw.count);
-   ha->flash_datasize += pt->CoppCP.cmd.flashfw.count;
-   if(pt->CoppCP.cmd.flashfw.packet_num ==
-      pt->CoppCP.cmd.flashfw.total_packets - 1){
-      if(pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE)
-         return ips_flash_bios(ha, pt, scb);
-      else if(pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE)
-         return ips_flash_firmware(ha, pt, scb);
-   }
-   return IPS_SUCCESS_IMM;
+	/* Trombone is the only copperhead that can do packet flash, but only
+	 * for firmware. No one said it had to make sence. */
+	if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) {
+		if (ips_usrcmd(ha, pt, scb))
+			return IPS_SUCCESS;
+		else
+			return IPS_FAILURE;
+	}
+	pt->BasicStatus = 0x0B;
+	pt->ExtendedStatus = 0;
+	scb->scsi_cmd->result = DID_OK << 16;
+	/* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */
+	/* avoid allocating a huge buffer per adapter ( which can fail ). */
+	if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
+	    pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
+		pt->BasicStatus = 0;
+		return ips_flash_bios(ha, pt, scb);
+	} else if (pt->CoppCP.cmd.flashfw.packet_num == 0) {
+		if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)) {
+			ha->flash_data = ips_FlashData;
+			ha->flash_order = 7;
+			ha->flash_datasize = 0;
+		} else if (!ha->flash_data) {
+			datasize = pt->CoppCP.cmd.flashfw.total_packets *
+			    pt->CoppCP.cmd.flashfw.count;
+			for (count = PAGE_SIZE, ha->flash_order = 0;
+			     count < datasize; ha->flash_order++, count <<= 1) ;
+			ha->flash_data =
+			    (char *) __get_free_pages(IPS_ATOMIC_GFP,
+						      ha->flash_order);
+			ha->flash_datasize = 0;
+		} else
+			return IPS_FAILURE;
+	} else {
+		if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize >
+		    (PAGE_SIZE << ha->flash_order)) {
+			ips_free_flash_copperhead(ha);
+			printk(KERN_WARNING "failed size sanity check\n");
+			return IPS_FAILURE;
+		}
+	}
+	if (!ha->flash_data)
+		return IPS_FAILURE;
+	pt->BasicStatus = 0;
+	memcpy(&ha->flash_data[ha->flash_datasize], pt + 1,
+	       pt->CoppCP.cmd.flashfw.count);
+	ha->flash_datasize += pt->CoppCP.cmd.flashfw.count;
+	if (pt->CoppCP.cmd.flashfw.packet_num ==
+	    pt->CoppCP.cmd.flashfw.total_packets - 1) {
+		if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE)
+			return ips_flash_bios(ha, pt, scb);
+		else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE)
+			return ips_flash_firmware(ha, pt, scb);
+	}
+	return IPS_SUCCESS_IMM;
 }
 
 /****************************************************************************/
@@ -2473,46 +1773,95 @@
 /*   flashes the bios of a copperhead adapter                               */
 /****************************************************************************/
 static int
-ips_flash_bios(ips_ha_t * ha, ips_passthru_t *pt, ips_scb_t *scb){
+ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
+{
 
-   if(pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
-      pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS){
-      if ((!ha->func.programbios) || (!ha->func.erasebios) ||
-          (!ha->func.verifybios))
-         goto error;
-      if((*ha->func.erasebios)(ha)){
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
-                   ips_name, ha->host_num);
-         goto error;
-      }else if ((*ha->func.programbios)(ha, ha->flash_data + IPS_BIOS_HEADER,
-          ha->flash_datasize - IPS_BIOS_HEADER, 0 )) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to flash",
-                   ips_name, ha->host_num);
-         goto error;
-      }else if ((*ha->func.verifybios)(ha, ha->flash_data + IPS_BIOS_HEADER,
-          ha->flash_datasize - IPS_BIOS_HEADER, 0 )) {
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
-                   ips_name, ha->host_num);
-         goto error;
-      }
-      ips_free_flash_copperhead(ha);
-      return IPS_SUCCESS_IMM;
-   }else if(pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
-      pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS){
-      if(!ha->func.erasebios)
-         goto error;
-      if((*ha->func.erasebios)(ha)){
-         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
-                   ips_name, ha->host_num);
-         goto error;
-      }
-      return IPS_SUCCESS_IMM;
-   }
-error:
-   pt->BasicStatus = 0x0B;
-   pt->ExtendedStatus = 0x00;
-   ips_free_flash_copperhead(ha);
-   return IPS_FAILURE;
+	if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
+	    pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) {
+		if ((!ha->func.programbios) || (!ha->func.erasebios) ||
+		    (!ha->func.verifybios)) goto error;
+		if ((*ha->func.erasebios) (ha)) {
+			DEBUG_VAR(1,
+				  "(%s%d) flash bios failed - unable to erase flash",
+				  ips_name, ha->host_num);
+			goto error;
+		} else
+		    if ((*ha->func.programbios)
+			(ha, ha->flash_data + IPS_BIOS_HEADER,
+			 ha->flash_datasize - IPS_BIOS_HEADER, 0)) {
+			DEBUG_VAR(1,
+				  "(%s%d) flash bios failed - unable to flash",
+				  ips_name, ha->host_num);
+			goto error;
+		} else
+		    if ((*ha->func.verifybios)
+			(ha, ha->flash_data + IPS_BIOS_HEADER,
+			 ha->flash_datasize - IPS_BIOS_HEADER, 0)) {
+			DEBUG_VAR(1,
+				  "(%s%d) flash bios failed - unable to verify flash",
+				  ips_name, ha->host_num);
+			goto error;
+		}
+		ips_free_flash_copperhead(ha);
+		return IPS_SUCCESS_IMM;
+	} else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
+		   pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
+		if (!ha->func.erasebios)
+			goto error;
+		if ((*ha->func.erasebios) (ha)) {
+			DEBUG_VAR(1,
+				  "(%s%d) flash bios failed - unable to erase flash",
+				  ips_name, ha->host_num);
+			goto error;
+		}
+		return IPS_SUCCESS_IMM;
+	}
+      error:
+	pt->BasicStatus = 0x0B;
+	pt->ExtendedStatus = 0x00;
+	ips_free_flash_copperhead(ha);
+	return IPS_FAILURE;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_fill_scb_sg_single                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Fill in a single scb sg_list element from an address                   */
+/*   return a -1 if a breakup occured                                       */
+/****************************************************************************/
+static inline int
+ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr,
+		       ips_scb_t * scb, int indx, unsigned int e_len)
+{
+
+	int ret_val = 0;
+
+	if ((scb->data_len + e_len) > ha->max_xfer) {
+		e_len = ha->max_xfer - scb->data_len;
+		scb->breakup = indx;
+		++scb->sg_break;
+		ret_val = -1;
+	} else {
+		scb->breakup = 0;
+		scb->sg_break = 0;
+	}
+	if (IPS_USE_ENH_SGLIST(ha)) {
+		scb->sg_list.enh_list[indx].address_lo =
+		    cpu_to_le32(pci_dma_lo32(busaddr));
+		scb->sg_list.enh_list[indx].address_hi =
+		    cpu_to_le32(pci_dma_hi32(busaddr));
+		scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len);
+	} else {
+		scb->sg_list.std_list[indx].address =
+		    cpu_to_le32(pci_dma_lo32(busaddr));
+		scb->sg_list.std_list[indx].length = cpu_to_le32(e_len);
+	}
+
+	++scb->sg_len;
+	scb->data_len += e_len;
+	return ret_val;
 }
 
 /****************************************************************************/
@@ -2521,49 +1870,51 @@
 /*   flashes the firmware of a copperhead adapter                           */
 /****************************************************************************/
 static int
-ips_flash_firmware(ips_ha_t * ha, ips_passthru_t *pt, ips_scb_t *scb){
-   IPS_SG_LIST *sg_list;
-   uint32_t cmd_busaddr;
-
-   if(pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE &&
-      pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW ){
-      memset(&pt->CoppCP.cmd, 0, sizeof(IPS_HOST_COMMAND));
-      pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD;
-      pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize);
-   }else{
-      pt->BasicStatus = 0x0B;
-      pt->ExtendedStatus = 0x00;
-      ips_free_flash_copperhead(ha);
-      return IPS_FAILURE;
-   }
-   /* Save the S/G list pointer so it doesn't get clobbered */
-   sg_list = scb->sg_list;
-   cmd_busaddr = scb->scb_busaddr;
-   /* copy in the CP */
-   memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IPS_IOCTL_CMD));
-   /* FIX stuff that might be wrong */
-   scb->sg_list = sg_list;
-   scb->scb_busaddr = cmd_busaddr;
-   scb->bus = scb->scsi_cmd->channel;
-   scb->target_id = scb->scsi_cmd->target;
-   scb->lun = scb->scsi_cmd->lun;
-   scb->sg_len = 0;
-   scb->data_len = 0;
-   scb->flags = 0;
-   scb->op_code = 0;
-   scb->callback = ipsintr_done;
-   scb->timeout = ips_cmd_timeout;
-
-   scb->data_len = ha->flash_datasize;
-   scb->data_busaddr = pci_map_single(ha->pcidev, ha->flash_data, scb->data_len,
-                                      IPS_DMA_DIR(scb));
-   scb->flags |= IPS_SCB_MAP_SINGLE;
-   scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.flashfw.buffer_addr = scb->data_busaddr;
-   if (pt->TimeOut)
-      scb->timeout = pt->TimeOut;
-   scb->scsi_cmd->result = DID_OK <<16;
-   return IPS_SUCCESS;
+ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
+{
+	IPS_SG_LIST sg_list;
+	uint32_t cmd_busaddr;
+
+	if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE &&
+	    pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) {
+		memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND));
+		pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD;
+		pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize);
+	} else {
+		pt->BasicStatus = 0x0B;
+		pt->ExtendedStatus = 0x00;
+		ips_free_flash_copperhead(ha);
+		return IPS_FAILURE;
+	}
+	/* Save the S/G list pointer so it doesn't get clobbered */
+	sg_list.list = scb->sg_list.list;
+	cmd_busaddr = scb->scb_busaddr;
+	/* copy in the CP */
+	memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
+	/* FIX stuff that might be wrong */
+	scb->sg_list.list = sg_list.list;
+	scb->scb_busaddr = cmd_busaddr;
+	scb->bus = scb->scsi_cmd->channel;
+	scb->target_id = scb->scsi_cmd->target;
+	scb->lun = scb->scsi_cmd->lun;
+	scb->sg_len = 0;
+	scb->data_len = 0;
+	scb->flags = 0;
+	scb->op_code = 0;
+	scb->callback = ipsintr_done;
+	scb->timeout = ips_cmd_timeout;
+
+	scb->data_len = ha->flash_datasize;
+	scb->data_busaddr =
+	    pci_map_single(ha->pcidev, ha->flash_data, scb->data_len,
+			   IPS_DMA_DIR(scb));
+	scb->flags |= IPS_SCB_MAP_SINGLE;
+	scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr);
+	if (pt->TimeOut)
+		scb->timeout = pt->TimeOut;
+	scb->scsi_cmd->result = DID_OK << 16;
+	return IPS_SUCCESS;
 }
 
 /****************************************************************************/
@@ -2572,12 +1923,13 @@
 /*   release the memory resources used to hold the flash image              */
 /****************************************************************************/
 static void
-ips_free_flash_copperhead(ips_ha_t *ha){
-   if(ha->flash_data == ips_FlashData)
-      test_and_clear_bit(0, &ips_FlashDataInUse);
-   else if(ha->flash_data)
-      free_pages((unsigned long)ha->flash_data, ha->flash_order);
-   ha->flash_data = NULL;
+ips_free_flash_copperhead(ips_ha_t * ha)
+{
+	if (ha->flash_data == ips_FlashData)
+		test_and_clear_bit(0, &ips_FlashDataInUse);
+	else if (ha->flash_data)
+		free_pages((unsigned long) ha->flash_data, ha->flash_order);
+	ha->flash_data = NULL;
 }
 
 /****************************************************************************/
@@ -2590,93 +1942,87 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_usrcmd(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb) {
-   IPS_SG_LIST *sg_list;
-   uint32_t cmd_busaddr;
-
-   METHOD_TRACE("ips_usrcmd", 1);
-
-   if ((!scb) || (!pt) || (!ha))
-      return (0);
-
-   /* Save the S/G list pointer so it doesn't get clobbered */
-   sg_list = scb->sg_list;
-   cmd_busaddr = scb->scb_busaddr;
-   /* copy in the CP */
-   memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IPS_IOCTL_CMD));
-   memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof(IPS_DCDB_TABLE));
-
-   /* FIX stuff that might be wrong */
-   scb->sg_list = sg_list;
-   scb->scb_busaddr = cmd_busaddr;
-   scb->bus = scb->scsi_cmd->channel;
-   scb->target_id = scb->scsi_cmd->target;
-   scb->lun = scb->scsi_cmd->lun;
-   scb->sg_len = 0;
-   scb->data_len = 0;
-   scb->flags = 0;
-   scb->op_code = 0;
-   scb->callback = ipsintr_done;
-   scb->timeout = ips_cmd_timeout;
-   scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-
-   /* we don't support DCDB/READ/WRITE Scatter Gather */
-   if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
-       (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
-       (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
-      return (0);
-
-   if (pt->CmdBSize) {
-      if(!scb->scsi_cmd->use_sg){
-         scb->data_len = pt->CmdBSize;
-         scb->data_busaddr = pci_map_single(ha->pcidev,
-                                            scb->scsi_cmd->request_buffer +
-                                            sizeof(ips_passthru_t),
-                                            pt->CmdBSize,
-                                            IPS_DMA_DIR(scb));
-         scb->flags |= IPS_SCB_MAP_SINGLE;
-      } else {
-         scb->data_len = pt->CmdBSize;
-         scb->data_busaddr = pci_map_single(ha->pcidev,
-                                            ha->ioctl_data +
-                                            sizeof(ips_passthru_t),
-                                            pt->CmdBSize,
-                                            IPS_DMA_DIR(scb));
-         scb->flags |= IPS_SCB_MAP_SINGLE;
-      }
-   } else {
-      scb->data_busaddr = 0L;
-   }
-
-   if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
-      scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
-                                          (unsigned long)&scb->dcdb -
-                                          (unsigned long)scb);
-
-   if (pt->CmdBSize) {
-      if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
-         scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
-      else
-         scb->cmd.basic_io.sg_addr = cpu_to_le32(scb->data_busaddr);
-   }
-
-   /* set timeouts */
-   if (pt->TimeOut) {
-      scb->timeout = pt->TimeOut;
-
-      if (pt->TimeOut <= 10)
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
-      else if (pt->TimeOut <= 60)
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
-      else
-         scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
-   }
+ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
+{
+	IPS_SG_LIST sg_list;
+	uint32_t cmd_busaddr;
+
+	METHOD_TRACE("ips_usrcmd", 1);
+
+	if ((!scb) || (!pt) || (!ha))
+		return (0);
+
+	/* Save the S/G list pointer so it doesn't get clobbered */
+	sg_list.list = scb->sg_list.list;
+	cmd_busaddr = scb->scb_busaddr;
+	/* copy in the CP */
+	memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
+	memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE));
+
+	/* FIX stuff that might be wrong */
+	scb->sg_list.list = sg_list.list;
+	scb->scb_busaddr = cmd_busaddr;
+	scb->bus = scb->scsi_cmd->channel;
+	scb->target_id = scb->scsi_cmd->target;
+	scb->lun = scb->scsi_cmd->lun;
+	scb->sg_len = 0;
+	scb->data_len = 0;
+	scb->flags = 0;
+	scb->op_code = 0;
+	scb->callback = ipsintr_done;
+	scb->timeout = ips_cmd_timeout;
+	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+
+	/* we don't support DCDB/READ/WRITE Scatter Gather */
+	if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
+	    (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
+	    (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
+		return (0);
+
+	if (pt->CmdBSize) {
+		scb->data_len = pt->CmdBSize;
+		scb->data_busaddr = pci_map_single(ha->pcidev,
+						   ha->ioctl_data +
+						   sizeof (ips_passthru_t),
+						   pt->CmdBSize,
+						   IPS_DMA_DIR(scb));
+		scb->flags |= IPS_SCB_MAP_SINGLE;
+	} else {
+		scb->data_busaddr = 0L;
+	}
+
+	if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
+		scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
+							 (unsigned long) &scb->
+							 dcdb -
+							 (unsigned long) scb);
+
+	if (pt->CmdBSize) {
+		if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
+			scb->dcdb.buffer_pointer =
+			    cpu_to_le32(scb->data_busaddr);
+		else
+			scb->cmd.basic_io.sg_addr =
+			    cpu_to_le32(scb->data_busaddr);
+	}
+
+	/* set timeouts */
+	if (pt->TimeOut) {
+		scb->timeout = pt->TimeOut;
+
+		if (pt->TimeOut <= 10)
+			scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
+		else if (pt->TimeOut <= 60)
+			scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
+		else
+			scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+	}
 
-   /* assume success */
-   scb->scsi_cmd->result = DID_OK << 16;
+	/* assume success */
+	scb->scsi_cmd->result = DID_OK << 16;
 
-   /* success */
-   return (1);
+	/* success */
+	return (1);
 }
 
 /****************************************************************************/
@@ -2689,43 +2035,34 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_cleanup_passthru(ips_ha_t *ha, ips_scb_t *scb) {
-   ips_passthru_t *pt;
+ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
+{
+	ips_passthru_t *pt;
+
+	METHOD_TRACE("ips_cleanup_passthru", 1);
+
+	if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) {
+		DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
+			  ips_name, ha->host_num);
 
-   METHOD_TRACE("ips_cleanup_passthru", 1);
+		return;
+	}
+	pt = (ips_passthru_t *) ha->ioctl_data;
 
-   if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) {
-      DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
-                ips_name, ha->host_num);
-
-      return ;
-   }
-   if(!scb->scsi_cmd->use_sg)
-      pt = (ips_passthru_t *) scb->scsi_cmd->request_buffer;
-   else
-      pt = (ips_passthru_t *) ha->ioctl_data;
-
-   /* Copy data back to the user */
-   if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)        /* Copy DCDB Back to Caller's Area */
-      memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof(IPS_DCDB_TABLE));
-   
-   pt->BasicStatus = scb->basic_status;
-   pt->ExtendedStatus = scb->extended_status;
-   pt->AdapterType = ha->ad_type;
-
-   if(ha->device_id == IPS_DEVICEID_COPPERHEAD && 
-     (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD || 
-     scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
-      ips_free_flash_copperhead(ha);
-
-   if(scb->scsi_cmd->use_sg){
-      int i, length = 0;
-      struct scatterlist *sg = scb->scsi_cmd->request_buffer;
-      for(i = 0; i < scb->scsi_cmd->use_sg; i++){
-         memcpy(IPS_SG_ADDRESS(&sg[i]), &ha->ioctl_data[length], sg[i].length);
-         length += sg[i].length;
-      }
-   }
+	/* Copy data back to the user */
+	if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)	/* Copy DCDB Back to Caller's Area */
+		memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE));
+
+	pt->BasicStatus = scb->basic_status;
+	pt->ExtendedStatus = scb->extended_status;
+	pt->AdapterType = ha->ad_type;
+
+	if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+	    (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
+	     scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
+		ips_free_flash_copperhead(ha);
+
+	ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize);
 }
 
 /****************************************************************************/
@@ -2738,75 +2075,88 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_host_info(ips_ha_t *ha, char *ptr, off_t offset, int len) {
-   IPS_INFOSTR info;
+ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len)
+{
+	IPS_INFOSTR info;
 
-   METHOD_TRACE("ips_host_info", 1);
+	METHOD_TRACE("ips_host_info", 1);
 
-   info.buffer = ptr;
-   info.length = len;
-   info.offset = offset;
-   info.pos = 0;
-   info.localpos = 0;
-
-   copy_info(&info, "\nIBM ServeRAID General Information:\n\n");
-
-   if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) &&
-       (le16_to_cpu(ha->nvram->adapter_type) != 0))
-      copy_info(&info, "\tController Type                   : %s\n", ips_adapter_name[ha->ad_type-1]);
-   else
-      copy_info(&info, "\tController Type                   : Unknown\n");
-
-   if (ha->io_addr)
-      copy_info(&info, "\tIO region                         : 0x%lx (%d bytes)\n",
-                ha->io_addr, ha->io_len);
-
-   if (ha->mem_addr) {
-      copy_info(&info, "\tMemory region                     : 0x%lx (%d bytes)\n",
-                ha->mem_addr, ha->mem_len);
-      copy_info(&info, "\tShared memory address             : 0x%lx\n", ha->mem_ptr);
-   }
-
-   copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
-
-   if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG)
-      copy_info(&info, "\tBIOS Version                      : %c%c%c%c%c%c%c%c\n",
-                ha->nvram->bios_high[0], ha->nvram->bios_high[1],
-                ha->nvram->bios_high[2], ha->nvram->bios_high[3],
-                ha->nvram->bios_low[0], ha->nvram->bios_low[1],
-                ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
-
-   copy_info(&info, "\tFirmware Version                  : %c%c%c%c%c%c%c%c\n",
-             ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
-             ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
-             ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
-             ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]);
-
-   copy_info(&info, "\tBoot Block Version                : %c%c%c%c%c%c%c%c\n",
-             ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
-             ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
-             ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
-             ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]);
-
-   copy_info(&info, "\tDriver Version                    : %s%s\n",
-             IPS_VERSION_HIGH, IPS_VERSION_LOW);
-
-   copy_info(&info, "\tMax Physical Devices              : %d\n",
-             ha->enq->ucMaxPhysicalDevices);
-   copy_info(&info, "\tMax Active Commands               : %d\n",
-             ha->max_cmds);
-   copy_info(&info, "\tCurrent Queued Commands           : %d\n",
-             ha->scb_waitlist.count);
-   copy_info(&info, "\tCurrent Active Commands           : %d\n",
-             ha->scb_activelist.count - ha->num_ioctl);
-   copy_info(&info, "\tCurrent Queued PT Commands        : %d\n",
-             ha->copp_waitlist.count);
-   copy_info(&info, "\tCurrent Active PT Commands        : %d\n",
-             ha->num_ioctl);
+	info.buffer = ptr;
+	info.length = len;
+	info.offset = offset;
+	info.pos = 0;
+	info.localpos = 0;
+
+	copy_info(&info, "\nIBM ServeRAID General Information:\n\n");
+
+	if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) &&
+	    (le16_to_cpu(ha->nvram->adapter_type) != 0))
+		copy_info(&info, "\tController Type                   : %s\n",
+			  ips_adapter_name[ha->ad_type - 1]);
+	else
+		copy_info(&info,
+			  "\tController Type                   : Unknown\n");
+
+	if (ha->io_addr)
+		copy_info(&info,
+			  "\tIO region                         : 0x%lx (%d bytes)\n",
+			  ha->io_addr, ha->io_len);
+
+	if (ha->mem_addr) {
+		copy_info(&info,
+			  "\tMemory region                     : 0x%lx (%d bytes)\n",
+			  ha->mem_addr, ha->mem_len);
+		copy_info(&info,
+			  "\tShared memory address             : 0x%lx\n",
+			  ha->mem_ptr);
+	}
+
+	copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
+
+	if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG)
+		copy_info(&info,
+			  "\tBIOS Version                      : %c%c%c%c%c%c%c%c\n",
+			  ha->nvram->bios_high[0], ha->nvram->bios_high[1],
+			  ha->nvram->bios_high[2], ha->nvram->bios_high[3],
+			  ha->nvram->bios_low[0], ha->nvram->bios_low[1],
+			  ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
+
+	copy_info(&info,
+		  "\tFirmware Version                  : %c%c%c%c%c%c%c%c\n",
+		  ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
+		  ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
+		  ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
+		  ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]);
+
+	copy_info(&info,
+		  "\tBoot Block Version                : %c%c%c%c%c%c%c%c\n",
+		  ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
+		  ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
+		  ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
+		  ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]);
+
+	copy_info(&info, "\tDriver Version                    : %s%s\n",
+		  IPS_VERSION_HIGH, IPS_VERSION_LOW);
+
+	copy_info(&info, "\tDriver Build                      : %d\n",
+		  IPS_BUILD_IDENT);
+
+	copy_info(&info, "\tMax Physical Devices              : %d\n",
+		  ha->enq->ucMaxPhysicalDevices);
+	copy_info(&info, "\tMax Active Commands               : %d\n",
+		  ha->max_cmds);
+	copy_info(&info, "\tCurrent Queued Commands           : %d\n",
+		  ha->scb_waitlist.count);
+	copy_info(&info, "\tCurrent Active Commands           : %d\n",
+		  ha->scb_activelist.count - ha->num_ioctl);
+	copy_info(&info, "\tCurrent Queued PT Commands        : %d\n",
+		  ha->copp_waitlist.count);
+	copy_info(&info, "\tCurrent Active PT Commands        : %d\n",
+		  ha->num_ioctl);
 
-   copy_info(&info, "\n");
+	copy_info(&info, "\n");
 
-   return (info.localpos);
+	return (info.localpos);
 }
 
 /****************************************************************************/
@@ -2819,28 +2169,29 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-copy_mem_info(IPS_INFOSTR *info, char *data, int len) {
-   METHOD_TRACE("copy_mem_info", 1);
+copy_mem_info(IPS_INFOSTR * info, char *data, int len)
+{
+	METHOD_TRACE("copy_mem_info", 1);
 
-   if (info->pos + len < info->offset) {
-      info->pos += len;
-      return;
-   }
-
-   if (info->pos < info->offset) {
-      data += (info->offset - info->pos);
-      len -= (info->offset - info->pos);
-      info->pos += (info->offset - info->pos);
-   }
-
-   if (info->localpos + len > info->length)
-      len = info->length - info->localpos;
-
-   if (len > 0) {
-      memcpy(info->buffer + info->localpos, data, len);
-      info->pos += len;
-      info->localpos += len;
-   }
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+
+	if (info->pos < info->offset) {
+		data += (info->offset - info->pos);
+		len -= (info->offset - info->pos);
+		info->pos += (info->offset - info->pos);
+	}
+
+	if (info->localpos + len > info->length)
+		len = info->length - info->localpos;
+
+	if (len > 0) {
+		memcpy(info->buffer + info->localpos, data, len);
+		info->pos += len;
+		info->localpos += len;
+	}
 }
 
 /****************************************************************************/
@@ -2853,20 +2204,21 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-copy_info(IPS_INFOSTR *info, char *fmt, ...) {
-   va_list args;
-   char buf[128];
-   int len;
+copy_info(IPS_INFOSTR * info, char *fmt, ...)
+{
+	va_list args;
+	char buf[128];
+	int len;
 
-   METHOD_TRACE("copy_info", 1);
+	METHOD_TRACE("copy_info", 1);
 
-   va_start(args, fmt);
-   len = vsprintf(buf, fmt, args);
-   va_end(args);
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
 
-   copy_mem_info(info, buf, len);
+	copy_mem_info(info, buf, len);
 
-   return (len);
+	return (len);
 }
 
 /****************************************************************************/
@@ -2879,71 +2231,73 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_identify_controller(ips_ha_t *ha) {
-   METHOD_TRACE("ips_identify_controller", 1);
+ips_identify_controller(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_identify_controller", 1);
 
-   switch (ha->device_id) {
-   case IPS_DEVICEID_COPPERHEAD:
-      if (ha->revision_id <= IPS_REVID_SERVERAID) {
-         ha->ad_type = IPS_ADTYPE_SERVERAID;
-      } else if (ha->revision_id == IPS_REVID_SERVERAID2) {
-         ha->ad_type = IPS_ADTYPE_SERVERAID2;
-      } else if (ha->revision_id == IPS_REVID_NAVAJO) {
-         ha->ad_type = IPS_ADTYPE_NAVAJO;
-      } else if ((ha->revision_id == IPS_REVID_SERVERAID2) && (ha->slot_num == 0)) {
-         ha->ad_type = IPS_ADTYPE_KIOWA;
-      } else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
-                 (ha->revision_id <= IPS_REVID_CLARINETP3)) {
-         if (ha->enq->ucMaxPhysicalDevices == 15)
-            ha->ad_type = IPS_ADTYPE_SERVERAID3L;
-         else
-            ha->ad_type = IPS_ADTYPE_SERVERAID3;
-      } else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
-                 (ha->revision_id <= IPS_REVID_TROMBONE64)) {
-         ha->ad_type = IPS_ADTYPE_SERVERAID4H;
-      }
-      break;
-
-   case IPS_DEVICEID_MORPHEUS:
-      switch (ha->subdevice_id) {
-      case IPS_SUBDEVICEID_4L:
-         ha->ad_type = IPS_ADTYPE_SERVERAID4L;
-         break;
-
-      case IPS_SUBDEVICEID_4M:
-         ha->ad_type = IPS_ADTYPE_SERVERAID4M;
-         break;
-
-      case IPS_SUBDEVICEID_4MX:
-         ha->ad_type = IPS_ADTYPE_SERVERAID4MX;
-         break;
-
-      case IPS_SUBDEVICEID_4LX:
-         ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
-         break;
-
-      case IPS_SUBDEVICEID_5I2:
-         ha->ad_type = IPS_ADTYPE_SERVERAID5I2;
-         break;
-
-      case IPS_SUBDEVICEID_5I1:
-         ha->ad_type = IPS_ADTYPE_SERVERAID5I1;
-         break;
-      }
-
-      break;
-
-   case IPS_DEVICEID_MARCO:
-      switch (ha->subdevice_id) {
-      case IPS_SUBDEVICEID_6M:
-          ha->ad_type = IPS_ADTYPE_SERVERAID6M;
-          break;
-      case IPS_SUBDEVICEID_6I:
-          ha->ad_type = IPS_ADTYPE_SERVERAID6I;
-          break;
-      }
-      break;
-   }
+	switch (ha->device_id) {
+	case IPS_DEVICEID_COPPERHEAD:
+		if (ha->revision_id <= IPS_REVID_SERVERAID) {
+			ha->ad_type = IPS_ADTYPE_SERVERAID;
+		} else if (ha->revision_id == IPS_REVID_SERVERAID2) {
+			ha->ad_type = IPS_ADTYPE_SERVERAID2;
+		} else if (ha->revision_id == IPS_REVID_NAVAJO) {
+			ha->ad_type = IPS_ADTYPE_NAVAJO;
+		} else if ((ha->revision_id == IPS_REVID_SERVERAID2)
+			   && (ha->slot_num == 0)) {
+			ha->ad_type = IPS_ADTYPE_KIOWA;
+		} else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
+			   (ha->revision_id <= IPS_REVID_CLARINETP3)) {
+			if (ha->enq->ucMaxPhysicalDevices == 15)
+				ha->ad_type = IPS_ADTYPE_SERVERAID3L;
+			else
+				ha->ad_type = IPS_ADTYPE_SERVERAID3;
+		} else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
+			   (ha->revision_id <= IPS_REVID_TROMBONE64)) {
+			ha->ad_type = IPS_ADTYPE_SERVERAID4H;
+		}
+		break;
+
+	case IPS_DEVICEID_MORPHEUS:
+		switch (ha->subdevice_id) {
+		case IPS_SUBDEVICEID_4L:
+			ha->ad_type = IPS_ADTYPE_SERVERAID4L;
+			break;
+
+		case IPS_SUBDEVICEID_4M:
+			ha->ad_type = IPS_ADTYPE_SERVERAID4M;
+			break;
+
+		case IPS_SUBDEVICEID_4MX:
+			ha->ad_type = IPS_ADTYPE_SERVERAID4MX;
+			break;
+
+		case IPS_SUBDEVICEID_4LX:
+			ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
+			break;
+
+		case IPS_SUBDEVICEID_5I2:
+			ha->ad_type = IPS_ADTYPE_SERVERAID5I2;
+			break;
+
+		case IPS_SUBDEVICEID_5I1:
+			ha->ad_type = IPS_ADTYPE_SERVERAID5I1;
+			break;
+		}
+
+		break;
+
+	case IPS_DEVICEID_MARCO:
+		switch (ha->subdevice_id) {
+		case IPS_SUBDEVICEID_6M:
+			ha->ad_type = IPS_ADTYPE_SERVERAID6M;
+			break;
+		case IPS_SUBDEVICEID_6I:
+			ha->ad_type = IPS_ADTYPE_SERVERAID6I;
+			break;
+		}
+		break;
+	}
 }
 
 /****************************************************************************/
@@ -2956,158 +2310,164 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_get_bios_version(ips_ha_t *ha, int intr) {
-   ips_scb_t *scb;
-   int        ret;
-   uint8_t   major;
-   uint8_t   minor;
-   uint8_t   subminor;
-   uint8_t  *buffer;
-   char       hexDigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
-
-   METHOD_TRACE("ips_get_bios_version", 1);
-
-   major = 0;
-   minor = 0;
-
-   strncpy(ha->bios_version, "       ?", 8);
-
-   if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
-      if (IPS_USE_MEMIO(ha)) {
-         /* Memory Mapped I/O */
-
-         /* test 1st byte */
-         writel(0, ha->mem_ptr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
-            return;
-
-         writel(1, ha->mem_ptr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
-            return;
-
-         /* Get Major version */
-         writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         major = readb(ha->mem_ptr + IPS_REG_FLDP);
-
-         /* Get Minor version */
-         writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-         minor = readb(ha->mem_ptr + IPS_REG_FLDP);
-
-         /* Get SubMinor version */
-         writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-         subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
-
-      } else {
-         /* Programmed I/O */
-
-         /* test 1st byte */
-         outl(0, ha->io_addr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
-            return ;
-
-         outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
-            return ;
-
-         /* Get Major version */
-         outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         major = inb(ha->io_addr + IPS_REG_FLDP);
-
-         /* Get Minor version */
-         outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         minor = inb(ha->io_addr + IPS_REG_FLDP);
-
-         /* Get SubMinor version */
-         outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         subminor = inb(ha->io_addr + IPS_REG_FLDP);
-
-      }
-   } else {
-      /* Morpheus Family - Send Command to the card */
-
-      buffer = kmalloc(0x1000, GFP_ATOMIC);
-      if (!buffer)
-         return;
-
-      memset(buffer, 0, 0x1000);
-
-      scb = &ha->scbs[ha->max_cmds-1];
-
-      ips_init_scb(ha, scb);
-
-      scb->timeout = ips_cmd_timeout;
-      scb->cdb[0] = IPS_CMD_RW_BIOSFW;
-
-      scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW;
-      scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
-      scb->cmd.flashfw.type = 1;
-      scb->cmd.flashfw.direction = 0;
-      scb->cmd.flashfw.count = cpu_to_le32(0x800);
-      scb->cmd.flashfw.total_packets = 1;
-      scb->cmd.flashfw.packet_num = 0;
-      scb->data_len = 0x1000;
-      scb->data_busaddr = pci_map_single(ha->pcidev, buffer, scb->data_len,
-                                         IPS_DMA_DIR(scb));
-      scb->cmd.flashfw.buffer_addr = scb->data_busaddr;
-      scb->flags |= IPS_SCB_MAP_SINGLE;
-
-      /* issue the command */
-      if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
-          (ret == IPS_SUCCESS_IMM) ||
-          ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
-         /* Error occurred */
-         kfree(buffer);
-
-         return;
-      }
-
-      if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) {
-         major    = buffer[0x1ff + 0xC0];  /* Offset 0x1ff after the header (0xc0) */
-         minor    = buffer[0x1fe + 0xC0];  /* Offset 0x1fe after the header (0xc0) */
-         subminor = buffer[0x1fd + 0xC0];  /* Offset 0x1fd after the header (0xc0) */
-      } else {
-         return;
-      }
-
-      kfree(buffer);
-   }
-
-   ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4];
-   ha->bios_version[1] = '.';
-   ha->bios_version[2] = hexDigits[major & 0x0F];
-   ha->bios_version[3] = hexDigits[subminor];
-   ha->bios_version[4] = '.';
-   ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4];
-   ha->bios_version[6] = hexDigits[minor & 0x0F];
-   ha->bios_version[7] = 0;
+ips_get_bios_version(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
+	uint8_t major;
+	uint8_t minor;
+	uint8_t subminor;
+	uint8_t *buffer;
+	char hexDigits[] =
+	    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
+		    'D', 'E', 'F' };
+
+	METHOD_TRACE("ips_get_bios_version", 1);
+
+	major = 0;
+	minor = 0;
+
+	strncpy(ha->bios_version, "       ?", 8);
+
+	if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
+		if (IPS_USE_MEMIO(ha)) {
+			/* Memory Mapped I/O */
+
+			/* test 1st byte */
+			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
+				return;
+
+			writel(1, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
+				return;
+
+			/* Get Major version */
+			writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			major = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+			/* Get Minor version */
+			writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+			minor = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+			/* Get SubMinor version */
+			writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+			subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+		} else {
+			/* Programmed I/O */
+
+			/* test 1st byte */
+			outl(0, ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
+				return;
+
+			outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
+				return;
+
+			/* Get Major version */
+			outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			major = inb(ha->io_addr + IPS_REG_FLDP);
+
+			/* Get Minor version */
+			outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			minor = inb(ha->io_addr + IPS_REG_FLDP);
+
+			/* Get SubMinor version */
+			outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			subminor = inb(ha->io_addr + IPS_REG_FLDP);
+
+		}
+	} else {
+		/* Morpheus Family - Send Command to the card */
+
+		buffer = kmalloc(0x1000, IPS_ATOMIC_GFP);
+		if (!buffer)
+			return;
+
+		memset(buffer, 0, 0x1000);
+
+		scb = &ha->scbs[ha->max_cmds - 1];
+
+		ips_init_scb(ha, scb);
+
+		scb->timeout = ips_cmd_timeout;
+		scb->cdb[0] = IPS_CMD_RW_BIOSFW;
+
+		scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW;
+		scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
+		scb->cmd.flashfw.type = 1;
+		scb->cmd.flashfw.direction = 0;
+		scb->cmd.flashfw.count = cpu_to_le32(0x800);
+		scb->cmd.flashfw.total_packets = 1;
+		scb->cmd.flashfw.packet_num = 0;
+		scb->data_len = 0x1000;
+		scb->data_busaddr =
+		    pci_map_single(ha->pcidev, buffer, scb->data_len,
+				   IPS_DMA_DIR(scb));
+		scb->cmd.flashfw.buffer_addr = scb->data_busaddr;
+		scb->flags |= IPS_SCB_MAP_SINGLE;
+
+		/* issue the command */
+		if (
+		    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
+		     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+		    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
+			/* Error occurred */
+			kfree(buffer);
+
+			return;
+		}
+
+		if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) {
+			major = buffer[0x1ff + 0xC0];	/* Offset 0x1ff after the header (0xc0) */
+			minor = buffer[0x1fe + 0xC0];	/* Offset 0x1fe after the header (0xc0) */
+			subminor = buffer[0x1fd + 0xC0];	/* Offset 0x1fd after the header (0xc0) */
+		} else {
+			kfree(buffer);
+			return;
+		}
+
+		kfree(buffer);
+	}
+
+	ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4];
+	ha->bios_version[1] = '.';
+	ha->bios_version[2] = hexDigits[major & 0x0F];
+	ha->bios_version[3] = hexDigits[subminor];
+	ha->bios_version[4] = '.';
+	ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4];
+	ha->bios_version[6] = hexDigits[minor & 0x0F];
+	ha->bios_version[7] = 0;
 }
 
 /****************************************************************************/
@@ -3122,129 +2482,134 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_hainit(ips_ha_t *ha) {
-   int            i;
-   struct timeval tv;
-
-   METHOD_TRACE("ips_hainit", 1);
-
-   if (!ha)
-      return (0);
-
-   if (ha->func.statinit)
-      (*ha->func.statinit)(ha);
-
-   if (ha->func.enableint)
-      (*ha->func.enableint)(ha);
-
-   /* Send FFDC */
-   ha->reset_count = 1;
-   do_gettimeofday(&tv);
-   ha->last_ffdc = tv.tv_sec;
-   ips_ffdc_reset(ha, IPS_INTR_IORL);
-
-   if (!ips_read_config(ha, IPS_INTR_IORL)) {
-      printk(KERN_WARNING "(%s%d) unable to read config from controller.\n",
-             ips_name, ha->host_num);
-
-      return (0);
-   } /* end if */
-
-   if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) {
-      printk(KERN_WARNING "(%s%d) unable to read controller status.\n",
-             ips_name, ha->host_num);
-
-      return (0);
-   }
-
-   /* Identify this controller */
-   ips_identify_controller(ha);
-
-   if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
-      printk(KERN_WARNING "(%s%d) unable to read subsystem parameters.\n",
-             ips_name, ha->host_num);
-
-      return (0);
-   }
-
-   /* write nvram user page 5 */
-   if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
-      printk(KERN_WARNING "(%s%d) unable to write driver info to controller.\n",
-             ips_name, ha->host_num);
-
-      return (0);
-   }
-
-   /* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */
-   if ( (ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1) ) 
-      ips_clear_adapter(ha, IPS_INTR_IORL);
-   
-   /* set limits on SID, LUN, BUS */
-   ha->ntargets = IPS_MAX_TARGETS + 1;
-   ha->nlun = 1;
-   ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1;
-
-   switch (ha->conf->logical_drive[0].ucStripeSize) {
-   case 4:
-      ha->max_xfer = 0x10000;
-      break;
-
-   case 5:
-      ha->max_xfer = 0x20000;
-      break;
-
-   case 6:
-      ha->max_xfer = 0x40000;
-      break;
-
-   case 7:
-   default:
-      ha->max_xfer = 0x80000;
-      break;
-   }
-
-   /* setup max concurrent commands */
-   if (le32_to_cpu(ha->subsys->param[4]) & 0x1) {
-      /* Use the new method */
-      ha->max_cmds = ha->enq->ucConcurrentCmdCount;
-   } else {
-      /* use the old method */
-      switch (ha->conf->logical_drive[0].ucStripeSize) {
-      case 4:
-         ha->max_cmds = 32;
-         break;
-
-      case 5:
-         ha->max_cmds = 16;
-         break;
-
-      case 6:
-         ha->max_cmds = 8;
-         break;
-
-      case 7:
-      default:
-         ha->max_cmds = 4;
-         break;
-      }
-   }
-
-   /* Limit the Active Commands on a Lite Adapter */
-   if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) ||
-       (ha->ad_type == IPS_ADTYPE_SERVERAID4L) ||
-       (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) {
-      if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds)) 
-         ha->max_cmds = MaxLiteCmds;
-   }
-
-   /* set controller IDs */
-   ha->ha_id[0] = IPS_ADAPTER_ID;
-   for (i = 1; i < ha->nbus; i++) {
-      ha->ha_id[i] = ha->conf->init_id[i-1] & 0x1f;
-      ha->dcdb_active[i-1] = 0;
-   }
+ips_hainit(ips_ha_t * ha)
+{
+	int i;
+	struct timeval tv;
+
+	METHOD_TRACE("ips_hainit", 1);
 
-   return (1);
+	if (!ha)
+		return (0);
+
+	if (ha->func.statinit)
+		(*ha->func.statinit) (ha);
+
+	if (ha->func.enableint)
+		(*ha->func.enableint) (ha);
+
+	/* Send FFDC */
+	ha->reset_count = 1;
+	do_gettimeofday(&tv);
+	ha->last_ffdc = tv.tv_sec;
+	ips_ffdc_reset(ha, IPS_INTR_IORL);
+
+	if (!ips_read_config(ha, IPS_INTR_IORL)) {
+		printk(KERN_WARNING
+		       "(%s%d) unable to read config from controller.\n",
+		       ips_name, ha->host_num);
+
+		return (0);
+	}
+	/* end if */
+	if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) {
+		printk(KERN_WARNING
+		       "(%s%d) unable to read controller status.\n", ips_name,
+		       ha->host_num);
+
+		return (0);
+	}
+
+	/* Identify this controller */
+	ips_identify_controller(ha);
+
+	if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
+		printk(KERN_WARNING
+		       "(%s%d) unable to read subsystem parameters.\n",
+		       ips_name, ha->host_num);
+
+		return (0);
+	}
+
+	/* write nvram user page 5 */
+	if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
+		printk(KERN_WARNING
+		       "(%s%d) unable to write driver info to controller.\n",
+		       ips_name, ha->host_num);
+
+		return (0);
+	}
+
+	/* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */
+	if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1))
+		ips_clear_adapter(ha, IPS_INTR_IORL);
+
+	/* set limits on SID, LUN, BUS */
+	ha->ntargets = IPS_MAX_TARGETS + 1;
+	ha->nlun = 1;
+	ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1;
+
+	switch (ha->conf->logical_drive[0].ucStripeSize) {
+	case 4:
+		ha->max_xfer = 0x10000;
+		break;
+
+	case 5:
+		ha->max_xfer = 0x20000;
+		break;
+
+	case 6:
+		ha->max_xfer = 0x40000;
+		break;
+
+	case 7:
+	default:
+		ha->max_xfer = 0x80000;
+		break;
+	}
+
+	/* setup max concurrent commands */
+	if (le32_to_cpu(ha->subsys->param[4]) & 0x1) {
+		/* Use the new method */
+		ha->max_cmds = ha->enq->ucConcurrentCmdCount;
+	} else {
+		/* use the old method */
+		switch (ha->conf->logical_drive[0].ucStripeSize) {
+		case 4:
+			ha->max_cmds = 32;
+			break;
+
+		case 5:
+			ha->max_cmds = 16;
+			break;
+
+		case 6:
+			ha->max_cmds = 8;
+			break;
+
+		case 7:
+		default:
+			ha->max_cmds = 4;
+			break;
+		}
+	}
+
+	/* Limit the Active Commands on a Lite Adapter */
+	if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) ||
+	    (ha->ad_type == IPS_ADTYPE_SERVERAID4L) ||
+	    (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) {
+		if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds))
+			ha->max_cmds = MaxLiteCmds;
+	}
+
+	/* set controller IDs */
+	ha->ha_id[0] = IPS_ADAPTER_ID;
+	for (i = 1; i < ha->nbus; i++) {
+		ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f;
+		ha->dcdb_active[i - 1] = 0;
+	}
+
+	return (1);
 }
 
 /****************************************************************************/
@@ -3257,275 +2622,238 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_next(ips_ha_t *ha, int intr) {
-   ips_scb_t            *scb;
-   Scsi_Cmnd            *SC;
-   Scsi_Cmnd            *p;
-   Scsi_Cmnd            *q;
-   ips_copp_wait_item_t *item;
-   int                   ret;
-   unsigned long         cpu_flags = 0;
-   struct Scsi_Host *host;
-   METHOD_TRACE("ips_next", 1);
-
-   if (!ha)
-      return ;
-   host = ips_sh[ha->host_num];
-   /*
-    * Block access to the queue function so
-    * this command won't time out
-    */
-   if(intr == IPS_INTR_ON)
-      IPS_LOCK_SAVE(host->host_lock, cpu_flags);
-   
-   if ((ha->subsys->param[3] & 0x300000)  && ( ha->scb_activelist.count == 0 )) {
-      struct timeval tv;
-
-      do_gettimeofday(&tv);
-
-      if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
-         ha->last_ffdc = tv.tv_sec;
-         ips_ffdc_time(ha);
-      }
-   }
-
-   /*
-    * Send passthru commands
-    * These have priority over normal I/O
-    * but shouldn't affect performance too much
-    * since we limit the number that can be active
-    * on the card at any one time
-    */
-   while ((ha->num_ioctl < IPS_MAX_IOCTL) &&
-          (ha->copp_waitlist.head) &&
-          (scb = ips_getscb(ha))) {
-
-      item = ips_removeq_copp_head(&ha->copp_waitlist);
-      ha->num_ioctl++;
-      if(intr == IPS_INTR_ON)
-         IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
-      scb->scsi_cmd = item->scsi_cmd;
-      kfree(item);
-
-      ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
-
-      if(intr == IPS_INTR_ON)
-         IPS_LOCK_SAVE(host->host_lock, cpu_flags);
-      switch (ret) {
-      case IPS_FAILURE:
-         if (scb->scsi_cmd) {
-            scb->scsi_cmd->result = DID_ERROR << 16;
-            scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-         }
-
-         ips_freescb(ha, scb);
-         break;
-      case IPS_SUCCESS_IMM:
-         if (scb->scsi_cmd) {
-            scb->scsi_cmd->result = DID_OK << 16;
-            scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-         }
-
-         ips_freescb(ha, scb);
-         break;
-      default:
-         break;
-      } /* end case */
-
-      if (ret != IPS_SUCCESS) {
-         ha->num_ioctl--;
-         continue;
-     }
-
-      ret = ips_send_cmd(ha, scb);
-
-      if (ret == IPS_SUCCESS) 
-         ips_putq_scb_head(&ha->scb_activelist, scb);
-      else
-         ha->num_ioctl--;
-
-      switch(ret) {
-      case IPS_FAILURE:
-         if (scb->scsi_cmd) {
-            scb->scsi_cmd->result = DID_ERROR << 16;
-         }
-
-         ips_freescb(ha, scb);
-         break;
-      case IPS_SUCCESS_IMM:
-         ips_freescb(ha, scb);
-         break;
-      default:
-         break;
-      } /* end case */
-
-   }
-
-
-   /*
-    * Send "Normal" I/O commands
-    */
-    
-   p = ha->scb_waitlist.head;
-   while ((p) && (scb = ips_getscb(ha))) {
-      if ((p->channel > 0) && (ha->dcdb_active[p->channel-1] & (1 << p->target))) {
-         ips_freescb(ha, scb);
-         p = (Scsi_Cmnd *) p->host_scribble;
-         continue;
-      }
-
-      q = p;
-      SC = ips_removeq_wait(&ha->scb_waitlist, q);
-
-      if(intr == IPS_INTR_ON)
-         IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); /* Unlock HA after command is taken off queue */
-
-      SC->result = DID_OK;
-      SC->host_scribble = NULL;
-
-      memset(SC->sense_buffer, 0, sizeof(SC->sense_buffer));
-
-      scb->target_id = SC->target;
-      scb->lun = SC->lun;
-      scb->bus = SC->channel;
-      scb->scsi_cmd = SC;
-      scb->breakup = 0;
-      scb->data_len = 0;
-      scb->callback = ipsintr_done;
-      scb->timeout = ips_cmd_timeout;
-      memset(&scb->cmd, 0, 16);
-
-      /* copy in the CDB */
-      memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
-
-      /* Now handle the data buffer */
-      if (SC->use_sg) {
-         struct scatterlist *sg;
-         int                 i;
-
-         sg = SC->request_buffer;
-         scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
-                                    scsi_to_pci_dma_dir(SC->sc_data_direction));
-         scb->flags |= IPS_SCB_MAP_SG;
-         if (scb->sg_count == 1) {
-            if (sg_dma_len(sg) > ha->max_xfer) {
-     	       scb->breakup = 1;
-               scb->data_len = ha->max_xfer;
-            } else
-               scb->data_len = sg_dma_len(sg);
-
-            scb->dcdb.transfer_length = scb->data_len;
-            scb->data_busaddr = sg_dma_address(sg);
-            scb->sg_len = 0;
-         } else {
-            /* Check for the first Element being bigger than MAX_XFER */
-            if (sg_dma_len(&sg[0]) > ha->max_xfer) {
-               scb->sg_list[0].address = cpu_to_le32(sg_dma_address(&sg[0]));
-               scb->sg_list[0].length = ha->max_xfer;
-               scb->data_len = ha->max_xfer;
-               scb->breakup = 0; 
-               scb->sg_break=1;  
-               scb->sg_len = 1;
-            } else {
-               for (i = 0; i < scb->sg_count; i++) {
-                  scb->sg_list[i].address = cpu_to_le32(sg_dma_address(&sg[i]));
-                  scb->sg_list[i].length = cpu_to_le32(sg_dma_len(&sg[i]));
-            
-                  if (scb->data_len + sg_dma_len(&sg[i]) > ha->max_xfer) {
-                     /*
-                      * Data Breakup required
-                      */
-                     scb->breakup = i;
-                     break;
-                  }
-               
-                  scb->data_len += sg_dma_len(&sg[i]);
-               }
-
-               if (!scb->breakup)
-                  scb->sg_len = scb->sg_count;
-               else
-                  scb->sg_len = scb->breakup;
-            }
-
-            scb->dcdb.transfer_length = scb->data_len;
-            scb->data_busaddr = scb->sg_busaddr;
-         }
-      } else {
-         if (SC->request_bufflen) {
-            if (SC->request_bufflen > ha->max_xfer) {
-               /*
-                * Data breakup required
-                */
-               scb->breakup = 1;
-               scb->data_len = ha->max_xfer;
-            } else {
-               scb->data_len = SC->request_bufflen;
-            }
-
-            scb->dcdb.transfer_length = scb->data_len;
-            scb->data_busaddr = pci_map_single(ha->pcidev, SC->request_buffer,
-                                               scb->data_len,
-                                               scsi_to_pci_dma_dir(SC->sc_data_direction));
-            scb->flags |= IPS_SCB_MAP_SINGLE;
-            scb->sg_len = 0;
-         } else {
-            scb->data_busaddr = 0L;
-            scb->sg_len = 0;
-            scb->data_len = 0;
-            scb->dcdb.transfer_length = 0;
-         }
-
-      }
-
-      scb->dcdb.cmd_attribute = ips_command_direction[scb->scsi_cmd->cmnd[0]];
-
-      if (!scb->dcdb.cmd_attribute & 0x3)
-         scb->dcdb.transfer_length = 0;
-
-      if (scb->data_len >= IPS_MAX_XFER) {
-         scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
-         scb->dcdb.transfer_length = 0;
-      }
-      if(intr == IPS_INTR_ON)
-         IPS_LOCK_SAVE(host->host_lock, cpu_flags);
-      
-      ret = ips_send_cmd(ha, scb);
-
-      switch(ret) {
-      case IPS_SUCCESS:
-         ips_putq_scb_head(&ha->scb_activelist, scb);
-         break;
-      case IPS_FAILURE:
-         if (scb->scsi_cmd) {
-            scb->scsi_cmd->result = DID_ERROR << 16;
-            scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-         }
-
-         if (scb->bus)
-            ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
-
-         ips_freescb(ha, scb);
-         break;
-      case IPS_SUCCESS_IMM:
-         if (scb->scsi_cmd)
-            scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-
-         if (scb->bus)
-            ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
-
-         ips_freescb(ha, scb);
-         break;
-      default:
-         break;
-      } /* end case */
+ips_next(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	Scsi_Cmnd *SC;
+	Scsi_Cmnd *p;
+	Scsi_Cmnd *q;
+	ips_copp_wait_item_t *item;
+	int ret;
+	unsigned long cpu_flags = 0;
+	struct Scsi_Host *host;
+	METHOD_TRACE("ips_next", 1);
+
+	if (!ha)
+		return;
+	host = ips_sh[ha->host_num];
+	/*
+	 * Block access to the queue function so
+	 * this command won't time out
+	 */
+	if (intr == IPS_INTR_ON)
+		IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+
+	if ((ha->subsys->param[3] & 0x300000)
+	    && (ha->scb_activelist.count == 0)) {
+		struct timeval tv;
+
+		do_gettimeofday(&tv);
+
+		if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
+			ha->last_ffdc = tv.tv_sec;
+			ips_ffdc_time(ha);
+		}
+	}
+
+	/*
+	 * Send passthru commands
+	 * These have priority over normal I/O
+	 * but shouldn't affect performance too much
+	 * since we limit the number that can be active
+	 * on the card at any one time
+	 */
+	while ((ha->num_ioctl < IPS_MAX_IOCTL) &&
+	       (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) {
+
+		item = ips_removeq_copp_head(&ha->copp_waitlist);
+		ha->num_ioctl++;
+		if (intr == IPS_INTR_ON)
+			IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+		scb->scsi_cmd = item->scsi_cmd;
+		kfree(item);
+
+		ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
+
+		if (intr == IPS_INTR_ON)
+			IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+		switch (ret) {
+		case IPS_FAILURE:
+			if (scb->scsi_cmd) {
+				scb->scsi_cmd->result = DID_ERROR << 16;
+				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			}
+
+			ips_freescb(ha, scb);
+			break;
+		case IPS_SUCCESS_IMM:
+			if (scb->scsi_cmd) {
+				scb->scsi_cmd->result = DID_OK << 16;
+				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			}
+
+			ips_freescb(ha, scb);
+			break;
+		default:
+			break;
+		}		/* end case */
+
+		if (ret != IPS_SUCCESS) {
+			ha->num_ioctl--;
+			continue;
+		}
+
+		ret = ips_send_cmd(ha, scb);
+
+		if (ret == IPS_SUCCESS)
+			ips_putq_scb_head(&ha->scb_activelist, scb);
+		else
+			ha->num_ioctl--;
+
+		switch (ret) {
+		case IPS_FAILURE:
+			if (scb->scsi_cmd) {
+				scb->scsi_cmd->result = DID_ERROR << 16;
+			}
+
+			ips_freescb(ha, scb);
+			break;
+		case IPS_SUCCESS_IMM:
+			ips_freescb(ha, scb);
+			break;
+		default:
+			break;
+		}		/* end case */
+
+	}
+
+	/*
+	 * Send "Normal" I/O commands
+	 */
+
+	p = ha->scb_waitlist.head;
+	while ((p) && (scb = ips_getscb(ha))) {
+		if ((p->channel > 0)
+		    && (ha->dcdb_active[p->channel - 1] & (1 << p->target))) {
+			ips_freescb(ha, scb);
+			p = (Scsi_Cmnd *) p->host_scribble;
+			continue;
+		}
+
+		q = p;
+		SC = ips_removeq_wait(&ha->scb_waitlist, q);
+
+		if (intr == IPS_INTR_ON)
+			IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);	/* Unlock HA after command is taken off queue */
+
+		SC->result = DID_OK;
+		SC->host_scribble = NULL;
+
+		memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer));
+
+		scb->target_id = SC->target;
+		scb->lun = SC->lun;
+		scb->bus = SC->channel;
+		scb->scsi_cmd = SC;
+		scb->breakup = 0;
+		scb->data_len = 0;
+		scb->callback = ipsintr_done;
+		scb->timeout = ips_cmd_timeout;
+		memset(&scb->cmd, 0, 16);
+
+		/* copy in the CDB */
+		memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
+
+		/* Now handle the data buffer */
+		if (SC->use_sg) {
+			struct scatterlist *sg;
+			int i;
+
+			sg = SC->request_buffer;
+			scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
+						   scsi_to_pci_dma_dir(SC->
+								       sc_data_direction));
+			scb->flags |= IPS_SCB_MAP_SG;
+			for (i = 0; i < scb->sg_count; i++) {
+				if (ips_fill_scb_sg_single
+				    (ha, sg_dma_address(&sg[i]), scb, i,
+				     sg_dma_len(&sg[i])) < 0)
+					break;
+			}
+			scb->dcdb.transfer_length = scb->data_len;
+		} else {
+			if (SC->request_bufflen) {
+				scb->data_busaddr =
+				    pci_map_single(ha->pcidev,
+						   SC->request_buffer,
+						   SC->request_bufflen,
+						   scsi_to_pci_dma_dir(SC->
+								       sc_data_direction));
+				scb->flags |= IPS_SCB_MAP_SINGLE;
+				ips_fill_scb_sg_single(ha, scb->data_busaddr,
+						       scb, 0,
+						       SC->request_bufflen);
+				scb->dcdb.transfer_length = scb->data_len;
+			} else {
+				scb->data_busaddr = 0L;
+				scb->sg_len = 0;
+				scb->data_len = 0;
+				scb->dcdb.transfer_length = 0;
+			}
+
+		}
+
+		scb->dcdb.cmd_attribute =
+		    ips_command_direction[scb->scsi_cmd->cmnd[0]];
+
+		if (!(scb->dcdb.cmd_attribute & 0x3))
+			scb->dcdb.transfer_length = 0;
+
+		if (scb->data_len >= IPS_MAX_XFER) {
+			scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
+			scb->dcdb.transfer_length = 0;
+		}
+		if (intr == IPS_INTR_ON)
+			IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+
+		ret = ips_send_cmd(ha, scb);
+
+		switch (ret) {
+		case IPS_SUCCESS:
+			ips_putq_scb_head(&ha->scb_activelist, scb);
+			break;
+		case IPS_FAILURE:
+			if (scb->scsi_cmd) {
+				scb->scsi_cmd->result = DID_ERROR << 16;
+				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			}
+
+			if (scb->bus)
+				ha->dcdb_active[scb->bus - 1] &=
+				    ~(1 << scb->target_id);
+
+			ips_freescb(ha, scb);
+			break;
+		case IPS_SUCCESS_IMM:
+			if (scb->scsi_cmd)
+				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+
+			if (scb->bus)
+				ha->dcdb_active[scb->bus - 1] &=
+				    ~(1 << scb->target_id);
+
+			ips_freescb(ha, scb);
+			break;
+		default:
+			break;
+		}		/* end case */
 
-      p = (Scsi_Cmnd *) p->host_scribble;
+		p = (Scsi_Cmnd *) p->host_scribble;
 
-   } /* end while */
+	}			/* end while */
 
-   if(intr == IPS_INTR_ON)
-      IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+	if (intr == IPS_INTR_ON)
+		IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
 }
 
 /****************************************************************************/
@@ -3540,19 +2868,20 @@
 /*                                                                          */
 /****************************************************************************/
 static inline void
-ips_putq_scb_head(ips_scb_queue_t *queue, ips_scb_t *item) {
-   METHOD_TRACE("ips_putq_scb_head", 1);
+ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item)
+{
+	METHOD_TRACE("ips_putq_scb_head", 1);
 
-   if (!item)
-      return ;
+	if (!item)
+		return;
 
-   item->q_next = queue->head;
-   queue->head = item;
+	item->q_next = queue->head;
+	queue->head = item;
 
-   if (!queue->tail)
-      queue->tail = item;
+	if (!queue->tail)
+		queue->tail = item;
 
-   queue->count++;
+	queue->count++;
 }
 
 /****************************************************************************/
@@ -3567,23 +2896,24 @@
 /*                                                                          */
 /****************************************************************************/
 static inline void
-ips_putq_scb_tail(ips_scb_queue_t *queue, ips_scb_t *item) {
-   METHOD_TRACE("ips_putq_scb_tail", 1);
+ips_putq_scb_tail(ips_scb_queue_t * queue, ips_scb_t * item)
+{
+	METHOD_TRACE("ips_putq_scb_tail", 1);
 
-   if (!item)
-      return ;
+	if (!item)
+		return;
 
-   item->q_next = NULL;
+	item->q_next = NULL;
 
-   if (queue->tail)
-      queue->tail->q_next = item;
+	if (queue->tail)
+		queue->tail->q_next = item;
 
-   queue->tail = item;
+	queue->tail = item;
 
-   if (!queue->head)
-      queue->head = item;
+	if (!queue->head)
+		queue->head = item;
 
-   queue->count++;
+	queue->count++;
 }
 
 /****************************************************************************/
@@ -3598,26 +2928,27 @@
 /*                                                                          */
 /****************************************************************************/
 static inline ips_scb_t *
-ips_removeq_scb_head(ips_scb_queue_t *queue) {
-   ips_scb_t  *item;
+ips_removeq_scb_head(ips_scb_queue_t * queue)
+{
+	ips_scb_t *item;
 
-   METHOD_TRACE("ips_removeq_scb_head", 1);
+	METHOD_TRACE("ips_removeq_scb_head", 1);
 
-   item = queue->head;
+	item = queue->head;
 
-   if (!item) {
-      return (NULL);
-   }
+	if (!item) {
+		return (NULL);
+	}
 
-   queue->head = item->q_next;
-   item->q_next = NULL;
+	queue->head = item->q_next;
+	item->q_next = NULL;
 
-   if (queue->tail == item)
-      queue->tail = NULL;
+	if (queue->tail == item)
+		queue->tail = NULL;
 
-   queue->count--;
+	queue->count--;
 
-   return (item);
+	return (item);
 }
 
 /****************************************************************************/
@@ -3632,37 +2963,38 @@
 /*                                                                          */
 /****************************************************************************/
 static inline ips_scb_t *
-ips_removeq_scb(ips_scb_queue_t *queue, ips_scb_t *item) {
-   ips_scb_t  *p;
+ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
+{
+	ips_scb_t *p;
 
-   METHOD_TRACE("ips_removeq_scb", 1);
+	METHOD_TRACE("ips_removeq_scb", 1);
 
-   if (!item)
-      return (NULL);
+	if (!item)
+		return (NULL);
 
-   if (item == queue->head) {
-      return (ips_removeq_scb_head(queue));
-   }
+	if (item == queue->head) {
+		return (ips_removeq_scb_head(queue));
+	}
 
-   p = queue->head;
+	p = queue->head;
 
-   while ((p) && (item != p->q_next))
-      p = p->q_next;
+	while ((p) && (item != p->q_next))
+		p = p->q_next;
 
-   if (p) {
-      /* found a match */
-      p->q_next = item->q_next;
+	if (p) {
+		/* found a match */
+		p->q_next = item->q_next;
 
-      if (!item->q_next)
-         queue->tail = p;
+		if (!item->q_next)
+			queue->tail = p;
 
-      item->q_next = NULL;
-      queue->count--;
+		item->q_next = NULL;
+		queue->count--;
 
-      return (item);
-   }
+		return (item);
+	}
 
-   return (NULL);
+	return (NULL);
 }
 
 /****************************************************************************/
@@ -3677,19 +3009,20 @@
 /*                                                                          */
 /****************************************************************************/
 static inline void
-ips_putq_wait_head(ips_wait_queue_t *queue, Scsi_Cmnd *item) {
-   METHOD_TRACE("ips_putq_wait_head", 1);
+ips_putq_wait_head(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+{
+	METHOD_TRACE("ips_putq_wait_head", 1);
 
-   if (!item)
-      return ;
+	if (!item)
+		return;
 
-   item->host_scribble = (char *) queue->head;
-   queue->head = item;
+	item->host_scribble = (char *) queue->head;
+	queue->head = item;
 
-   if (!queue->tail)
-      queue->tail = item;
+	if (!queue->tail)
+		queue->tail = item;
 
-   queue->count++;
+	queue->count++;
 }
 
 /****************************************************************************/
@@ -3704,23 +3037,24 @@
 /*                                                                          */
 /****************************************************************************/
 static inline void
-ips_putq_wait_tail(ips_wait_queue_t *queue, Scsi_Cmnd *item) {
-   METHOD_TRACE("ips_putq_wait_tail", 1);
+ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+{
+	METHOD_TRACE("ips_putq_wait_tail", 1);
 
-   if (!item)
-      return ;
+	if (!item)
+		return;
 
-   item->host_scribble = NULL;
+	item->host_scribble = NULL;
 
-   if (queue->tail)
-      queue->tail->host_scribble = (char *)item;
+	if (queue->tail)
+		queue->tail->host_scribble = (char *) item;
 
-   queue->tail = item;
+	queue->tail = item;
 
-   if (!queue->head)
-      queue->head = item;
+	if (!queue->head)
+		queue->head = item;
 
-   queue->count++;
+	queue->count++;
 }
 
 /****************************************************************************/
@@ -3735,26 +3069,27 @@
 /*                                                                          */
 /****************************************************************************/
 static inline Scsi_Cmnd *
-ips_removeq_wait_head(ips_wait_queue_t *queue) {
-   Scsi_Cmnd  *item;
+ips_removeq_wait_head(ips_wait_queue_t * queue)
+{
+	Scsi_Cmnd *item;
 
-   METHOD_TRACE("ips_removeq_wait_head", 1);
+	METHOD_TRACE("ips_removeq_wait_head", 1);
 
-   item = queue->head;
+	item = queue->head;
 
-   if (!item) {
-      return (NULL);
-   }
+	if (!item) {
+		return (NULL);
+	}
 
-   queue->head = (Scsi_Cmnd *) item->host_scribble;
-   item->host_scribble = NULL;
+	queue->head = (Scsi_Cmnd *) item->host_scribble;
+	item->host_scribble = NULL;
 
-   if (queue->tail == item)
-      queue->tail = NULL;
+	if (queue->tail == item)
+		queue->tail = NULL;
 
-   queue->count--;
+	queue->count--;
 
-   return (item);
+	return (item);
 }
 
 /****************************************************************************/
@@ -3769,37 +3104,38 @@
 /*                                                                          */
 /****************************************************************************/
 static inline Scsi_Cmnd *
-ips_removeq_wait(ips_wait_queue_t *queue, Scsi_Cmnd *item) {
-   Scsi_Cmnd  *p;
+ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+{
+	Scsi_Cmnd *p;
 
-   METHOD_TRACE("ips_removeq_wait", 1);
+	METHOD_TRACE("ips_removeq_wait", 1);
 
-   if (!item)
-      return (NULL);
+	if (!item)
+		return (NULL);
 
-   if (item == queue->head) {
-      return (ips_removeq_wait_head(queue));
-   }
+	if (item == queue->head) {
+		return (ips_removeq_wait_head(queue));
+	}
 
-   p = queue->head;
+	p = queue->head;
 
-   while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
-      p = (Scsi_Cmnd *) p->host_scribble;
+	while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
+		p = (Scsi_Cmnd *) p->host_scribble;
 
-   if (p) {
-      /* found a match */
-      p->host_scribble = item->host_scribble;
+	if (p) {
+		/* found a match */
+		p->host_scribble = item->host_scribble;
 
-      if (!item->host_scribble)
-         queue->tail = p;
+		if (!item->host_scribble)
+			queue->tail = p;
 
-      item->host_scribble = NULL;
-      queue->count--;
+		item->host_scribble = NULL;
+		queue->count--;
 
-      return (item);
-   }
+		return (item);
+	}
 
-   return (NULL);
+	return (NULL);
 }
 
 /****************************************************************************/
@@ -3814,19 +3150,20 @@
 /*                                                                          */
 /****************************************************************************/
 static inline void
-ips_putq_copp_head(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) {
-   METHOD_TRACE("ips_putq_copp_head", 1);
+ips_putq_copp_head(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
+{
+	METHOD_TRACE("ips_putq_copp_head", 1);
 
-   if (!item)
-      return ;
+	if (!item)
+		return;
 
-   item->next = queue->head;
-   queue->head = item;
+	item->next = queue->head;
+	queue->head = item;
 
-   if (!queue->tail)
-      queue->tail = item;
+	if (!queue->tail)
+		queue->tail = item;
 
-   queue->count++;
+	queue->count++;
 }
 
 /****************************************************************************/
@@ -3841,23 +3178,24 @@
 /*                                                                          */
 /****************************************************************************/
 static inline void
-ips_putq_copp_tail(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) {
-   METHOD_TRACE("ips_putq_copp_tail", 1);
+ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
+{
+	METHOD_TRACE("ips_putq_copp_tail", 1);
 
-   if (!item)
-      return ;
+	if (!item)
+		return;
 
-   item->next = NULL;
+	item->next = NULL;
 
-   if (queue->tail)
-      queue->tail->next = item;
+	if (queue->tail)
+		queue->tail->next = item;
 
-   queue->tail = item;
+	queue->tail = item;
 
-   if (!queue->head)
-      queue->head = item;
+	if (!queue->head)
+		queue->head = item;
 
-   queue->count++;
+	queue->count++;
 }
 
 /****************************************************************************/
@@ -3872,26 +3210,27 @@
 /*                                                                          */
 /****************************************************************************/
 static inline ips_copp_wait_item_t *
-ips_removeq_copp_head(ips_copp_queue_t *queue) {
-   ips_copp_wait_item_t *item;
+ips_removeq_copp_head(ips_copp_queue_t * queue)
+{
+	ips_copp_wait_item_t *item;
 
-   METHOD_TRACE("ips_removeq_copp_head", 1);
+	METHOD_TRACE("ips_removeq_copp_head", 1);
 
-   item = queue->head;
+	item = queue->head;
 
-   if (!item) {
-      return (NULL);
-   }
+	if (!item) {
+		return (NULL);
+	}
 
-   queue->head = item->next;
-   item->next = NULL;
+	queue->head = item->next;
+	item->next = NULL;
 
-   if (queue->tail == item)
-      queue->tail = NULL;
+	if (queue->tail == item)
+		queue->tail = NULL;
 
-   queue->count--;
+	queue->count--;
 
-   return (item);
+	return (item);
 }
 
 /****************************************************************************/
@@ -3906,37 +3245,38 @@
 /*                                                                          */
 /****************************************************************************/
 static inline ips_copp_wait_item_t *
-ips_removeq_copp(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) {
-   ips_copp_wait_item_t *p;
+ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
+{
+	ips_copp_wait_item_t *p;
 
-   METHOD_TRACE("ips_removeq_copp", 1);
+	METHOD_TRACE("ips_removeq_copp", 1);
 
-   if (!item)
-      return (NULL);
+	if (!item)
+		return (NULL);
 
-   if (item == queue->head) {
-      return (ips_removeq_copp_head(queue));
-   }
+	if (item == queue->head) {
+		return (ips_removeq_copp_head(queue));
+	}
 
-   p = queue->head;
+	p = queue->head;
 
-   while ((p) && (item != p->next))
-      p = p->next;
+	while ((p) && (item != p->next))
+		p = p->next;
 
-   if (p) {
-      /* found a match */
-      p->next = item->next;
+	if (p) {
+		/* found a match */
+		p->next = item->next;
 
-      if (!item->next)
-         queue->tail = p;
+		if (!item->next)
+			queue->tail = p;
 
-      item->next = NULL;
-      queue->count--;
+		item->next = NULL;
+		queue->count--;
 
-      return (item);
-   }
+		return (item);
+	}
 
-   return (NULL);
+	return (NULL);
 }
 
 /****************************************************************************/
@@ -3949,16 +3289,16 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ipsintr_blocking(ips_ha_t *ha, ips_scb_t *scb) {
-   METHOD_TRACE("ipsintr_blocking", 2);
+ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb)
+{
+	METHOD_TRACE("ipsintr_blocking", 2);
 
-   ips_freescb(ha, scb);
-   if ((ha->waitflag == TRUE) &&
-       (ha->cmd_in_progress == scb->cdb[0])) {
-      ha->waitflag = FALSE;
+	ips_freescb(ha, scb);
+	if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) {
+		ha->waitflag = FALSE;
 
-      return ;
-   }
+		return;
+	}
 }
 
 /****************************************************************************/
@@ -3971,25 +3311,27 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ipsintr_done(ips_ha_t *ha, ips_scb_t *scb) {
-   METHOD_TRACE("ipsintr_done", 2);
+ipsintr_done(ips_ha_t * ha, ips_scb_t * scb)
+{
+	METHOD_TRACE("ipsintr_done", 2);
 
-   if (!scb) {
-      printk(KERN_WARNING "(%s%d) Spurious interrupt; scb NULL.\n",
-             ips_name, ha->host_num);
+	if (!scb) {
+		printk(KERN_WARNING "(%s%d) Spurious interrupt; scb NULL.\n",
+		       ips_name, ha->host_num);
 
-      return ;
-   }
+		return;
+	}
 
-   if (scb->scsi_cmd == NULL) {
-      /* unexpected interrupt */
-      printk(KERN_WARNING "(%s%d) Spurious interrupt; scsi_cmd not set.\n",
-             ips_name, ha->host_num);
+	if (scb->scsi_cmd == NULL) {
+		/* unexpected interrupt */
+		printk(KERN_WARNING
+		       "(%s%d) Spurious interrupt; scsi_cmd not set.\n",
+		       ips_name, ha->host_num);
 
-      return;
-   }
+		return;
+	}
 
-   ips_done(ha, scb);
+	ips_done(ha, scb);
 }
 
 /****************************************************************************/
@@ -4002,180 +3344,118 @@
 /*  ASSUMED to be called form within the request lock                       */
 /****************************************************************************/
 static void
-ips_done(ips_ha_t *ha, ips_scb_t *scb) {
-   int ret;
+ips_done(ips_ha_t * ha, ips_scb_t * scb)
+{
+	int ret;
 
-   METHOD_TRACE("ips_done", 1);
+	METHOD_TRACE("ips_done", 1);
 
-   if (!scb)
-      return ;
+	if (!scb)
+		return;
 
-   if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
-      ips_cleanup_passthru(ha, scb);
-      ha->num_ioctl--;
-   } else {
-      /*
-       * Check to see if this command had too much
-       * data and had to be broke up.  If so, queue
-       * the rest of the data and continue.
-       */
-      if ((scb->breakup) || (scb->sg_break)) {
-         /* we had a data breakup */
-         uint8_t bk_save;
-
-         bk_save = scb->breakup;
-         scb->breakup = 0;
-
-         if (scb->sg_count) {
-            /* S/G request */
-            struct scatterlist *sg;
-            int                 i;
-
-            sg = scb->scsi_cmd->request_buffer;
-
-            if (scb->sg_count == 1) {
-               if (sg_dma_len(sg) - (bk_save * ha->max_xfer) > ha->max_xfer) {
-                  /* Further breakup required */
-                  scb->data_len = ha->max_xfer;
-                  scb->data_busaddr = sg_dma_address(sg) + (bk_save * ha->max_xfer);
-                  scb->breakup = bk_save + 1;
-               } else {
-                  scb->data_len = sg_dma_len(sg) - (bk_save * ha->max_xfer);
-                  scb->data_busaddr = sg_dma_address(sg) + (bk_save * ha->max_xfer);
-               }
-
-               scb->dcdb.transfer_length = scb->data_len;
-               scb->sg_len = 0;
-            } else {
-               /* We're here because there was MORE than one s/g unit. */
-	            /* bk_save points to which sg unit to look at           */
-	            /* sg_break points to how far through this unit we are  */
-	            /* NOTE: We will not move from one sg to another here,  */
-               /*    just finish the one we are in.  Not the most      */
-               /*    efficient, but it keeps it from getting too hacky */
-
-		         /* IF sg_break is non-zero, then just work on this current sg piece, */
-               /* pointed to by bk_save                                             */
-               if (scb->sg_break) {
-                  scb->sg_len = 1;
-                  scb->sg_list[0].address = sg_dma_address(&sg[bk_save])
-                                            + ha->max_xfer*scb->sg_break;
-                  if (ha->max_xfer > sg_dma_len(&sg[bk_save]) - ha->max_xfer * scb->sg_break) 
-                     scb->sg_list[0].length = sg_dma_len(&sg[bk_save]) - ha->max_xfer * scb->sg_break;
-                  else 
-                     scb->sg_list[0].length = ha->max_xfer;
-                  scb->sg_break++;              /* MUST GO HERE for math below to work */
-                  scb->data_len = scb->sg_list[0].length;;
-
-                  if (sg_dma_len(&sg[bk_save]) <= ha->max_xfer * scb->sg_break ) {
-                     scb->sg_break = 0;         /* No more work in this unit */
-                     if (( bk_save + 1 ) >= scb->sg_count) 
-                        scb->breakup = 0;
-                     else
-                        scb->breakup = bk_save + 1;
-                  }
-               } else {
-			         /* ( sg_break == 0 ), so this is our first look at a new sg piece */
-                  if (sg_dma_len(&sg[bk_save]) > ha->max_xfer) {
-                     scb->sg_list[0].address = sg_dma_address(&sg[bk_save]);
-                     scb->sg_list[0].length = ha->max_xfer;
-                     scb->breakup = bk_save;
-                     scb->sg_break = 1;
-                     scb->data_len = ha->max_xfer;
-                     scb->sg_len = 1;
- 	          } else {
-	         /* OK, the next sg is a short one, so loop until full */
-                     scb->data_len = 0;
-                     scb->sg_len = 0;
-                     scb->sg_break = 0;
-                     /*   We're only doing full units here */
-                     for (i = bk_save; i < scb->sg_count; i++) {
-                        scb->sg_list[i - bk_save].address = sg_dma_address(&sg[i]);
-                        scb->sg_list[i - bk_save].length = cpu_to_le32(sg_dma_len(&sg[i]));
-                        if (scb->data_len + sg_dma_len(&sg[i]) > ha->max_xfer) {
-                           scb->breakup = i;  /* sneaky, if not more work, than breakup is 0 */
-                           break;
-                        }
-                        scb->data_len += sg_dma_len(&sg[i]);
-                        scb->sg_len++;           /* only if we didn't get too big */
-		  		         }
-			         }
-		         }
-
-               /* Also, we need to be sure we don't queue work ( breakup != 0 )
-                  if no more sg units for next time */
-               scb->dcdb.transfer_length = scb->data_len;
-               scb->data_busaddr = scb->sg_busaddr;
-            }
-                                              
-         } else {
-            /* Non S/G Request */
-            pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
-                             IPS_DMA_DIR(scb));
-            if ((scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) > ha->max_xfer) {
-               /* Further breakup required */
-               scb->data_len = ha->max_xfer;
-               scb->data_busaddr = pci_map_single(ha->pcidev,
-                                           scb->scsi_cmd->request_buffer +
-                                           (bk_save * ha->max_xfer),
-                                           scb->data_len, IPS_DMA_DIR(scb));
-               scb->breakup = bk_save + 1;
-            } else {
-               scb->data_len = scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer);
-               scb->data_busaddr = pci_map_single(ha->pcidev,
-                                           scb->scsi_cmd->request_buffer +
-                                           (bk_save * ha->max_xfer),
-                                           scb->data_len, IPS_DMA_DIR(scb));
-	    }
-
-            scb->dcdb.transfer_length = scb->data_len;
-            scb->sg_len = 0;
-         }
-
-         scb->dcdb.cmd_attribute |= ips_command_direction[scb->scsi_cmd->cmnd[0]];
-
-         if (!scb->dcdb.cmd_attribute & 0x3)
-            scb->dcdb.transfer_length = 0;
-
-         if (scb->data_len >= IPS_MAX_XFER) {
-            scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
-            scb->dcdb.transfer_length = 0;
-         }
-
-         ret = ips_send_cmd(ha, scb);
-
-         switch(ret) {
-         case IPS_FAILURE:
-            if (scb->scsi_cmd) {
-               scb->scsi_cmd->result = DID_ERROR << 16;
-               scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-            }
-
-            ips_freescb(ha, scb);
-            break;
-         case IPS_SUCCESS_IMM:
-            if (scb->scsi_cmd) {
-               scb->scsi_cmd->result = DID_ERROR << 16;
-               scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-            }
-
-            ips_freescb(ha, scb);
-            break;
-         default:
-            break;
-         } /* end case */
-
-         return ;
-      }
-   } /* end if passthru */
-
-   if (scb->bus) {
-      ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
-   }
+	if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
+		ips_cleanup_passthru(ha, scb);
+		ha->num_ioctl--;
+	} else {
+		/*
+		 * Check to see if this command had too much
+		 * data and had to be broke up.  If so, queue
+		 * the rest of the data and continue.
+		 */
+		if ((scb->breakup) || (scb->sg_break)) {
+			/* we had a data breakup */
+			scb->data_len = 0;
+
+			if (scb->sg_count) {
+				/* S/G request */
+				struct scatterlist *sg;
+				int ips_sg_index = 0;
+				int sg_dma_index;
+
+				sg = scb->scsi_cmd->request_buffer;
+
+				/* Spin forward to last dma chunk */
+				sg_dma_index = scb->breakup;
+
+				/* Take care of possible partial on last chunk */
+				ips_fill_scb_sg_single(ha,
+						       sg_dma_address(&sg
+								      [sg_dma_index]),
+						       scb, ips_sg_index++,
+						       sg_dma_len(&sg
+								  [sg_dma_index]));
+
+				for (; sg_dma_index < scb->sg_count;
+				     sg_dma_index++) {
+					if (ips_fill_scb_sg_single
+					    (ha,
+					     sg_dma_address(&sg[sg_dma_index]),
+					     scb, ips_sg_index++,
+					     sg_dma_len(&sg[sg_dma_index])) < 0)
+						break;
+
+				}
+
+			} else {
+				/* Non S/G Request */
+				(void) ips_fill_scb_sg_single(ha,
+							      scb->
+							      data_busaddr +
+							      (scb->sg_break *
+							       ha->max_xfer),
+							      scb, 0,
+							      scb->scsi_cmd->
+							      request_bufflen -
+							      (scb->sg_break *
+							       ha->max_xfer));
+			}
+
+			scb->dcdb.transfer_length = scb->data_len;
+			scb->dcdb.cmd_attribute |=
+			    ips_command_direction[scb->scsi_cmd->cmnd[0]];
+
+			if (!(scb->dcdb.cmd_attribute & 0x3))
+				scb->dcdb.transfer_length = 0;
+
+			if (scb->data_len >= IPS_MAX_XFER) {
+				scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
+				scb->dcdb.transfer_length = 0;
+			}
+
+			ret = ips_send_cmd(ha, scb);
+
+			switch (ret) {
+			case IPS_FAILURE:
+				if (scb->scsi_cmd) {
+					scb->scsi_cmd->result = DID_ERROR << 16;
+					scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+				}
+
+				ips_freescb(ha, scb);
+				break;
+			case IPS_SUCCESS_IMM:
+				if (scb->scsi_cmd) {
+					scb->scsi_cmd->result = DID_ERROR << 16;
+					scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+				}
+
+				ips_freescb(ha, scb);
+				break;
+			default:
+				break;
+			}	/* end case */
+
+			return;
+		}
+	}			/* end if passthru */
+
+	if (scb->bus) {
+		ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id);
+	}
 
-   scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+	scb->scsi_cmd->scsi_done(scb->scsi_cmd);
 
-   ips_freescb(ha, scb);
+	ips_freescb(ha, scb);
 }
 
 /****************************************************************************/
@@ -4188,118 +3468,130 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_map_status(ips_ha_t *ha, ips_scb_t *scb, ips_stat_t *sp) {
-   int       errcode;
-   int       device_error;
-   uint32_t  transfer_len;
-   IPS_DCDB_TABLE_TAPE *tapeDCDB;
-
-   METHOD_TRACE("ips_map_status", 1);
-
-   if (scb->bus) {
-      DEBUG_VAR(2, "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x",
-                ips_name,
-                ha->host_num,
-                scb->scsi_cmd->channel,
-                scb->scsi_cmd->target,
-                scb->scsi_cmd->lun,
-                scb->basic_status,
-                scb->extended_status,
-                scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0,
-                scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0,
-                scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0);
-   }
-
-   /* default driver error */
-   errcode = DID_ERROR;
-   device_error = 0;
-
-   switch (scb->basic_status & IPS_GSC_STATUS_MASK) {
-   case IPS_CMD_TIMEOUT:
-      errcode = DID_TIME_OUT;
-      break;
-
-   case IPS_INVAL_OPCO:
-   case IPS_INVAL_CMD_BLK:
-   case IPS_INVAL_PARM_BLK:
-   case IPS_LD_ERROR:
-   case IPS_CMD_CMPLT_WERROR:
-      break;
-
-   case IPS_PHYS_DRV_ERROR:
-      switch (scb->extended_status) {
-      case IPS_ERR_SEL_TO:
-         if (scb->bus)
-            errcode = DID_NO_CONNECT;
-
-         break;
-
-      case IPS_ERR_OU_RUN:   
-         if ( ( scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB ) ||
-              ( scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG ) ) {
-             tapeDCDB = ( IPS_DCDB_TABLE_TAPE * ) &scb->dcdb;
-             transfer_len = tapeDCDB->transfer_length;
-         } else {
-             transfer_len = ( uint32_t ) scb->dcdb.transfer_length;
-         }
-
-        if ((scb->bus) && (transfer_len < scb->data_len)) {
-            /* Underrun - set default to no error */
-            errcode = DID_OK;
-
-            /* Restrict access to physical DASD */
-            if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
-                ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == TYPE_DISK)) {
-               /* underflow -- no error               */
-               /* restrict access to physical DASD    */
-               errcode = DID_TIME_OUT;
-               break;
-            }
-         } else
-            errcode = DID_ERROR;
-
-         break;
-
-      case IPS_ERR_RECOVERY:
-         /* don't fail recovered errors */
-         if (scb->bus)
-            errcode = DID_OK;
-
-         break;
-
-      case IPS_ERR_HOST_RESET:
-      case IPS_ERR_DEV_RESET:
-         errcode = DID_RESET;
-         break;
-
-      case IPS_ERR_CKCOND:
-         if (scb->bus) {
-            if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) ||
-                (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)) {
-               tapeDCDB = (IPS_DCDB_TABLE_TAPE *) &scb->dcdb;
-               memcpy(scb->scsi_cmd->sense_buffer, tapeDCDB->sense_info,
-                      sizeof(scb->scsi_cmd->sense_buffer));
-            } else {
-               memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
-                      sizeof(scb->scsi_cmd->sense_buffer));
-            }
-            device_error = 2; /* check condition */
-         }
-
-         errcode = DID_OK;
-
-         break;
-
-      default:
-         errcode = DID_ERROR;
-         break;
+ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
+{
+	int errcode;
+	int device_error;
+	uint32_t transfer_len;
+	IPS_DCDB_TABLE_TAPE *tapeDCDB;
+
+	METHOD_TRACE("ips_map_status", 1);
+
+	if (scb->bus) {
+		DEBUG_VAR(2,
+			  "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x",
+			  ips_name, ha->host_num, scb->scsi_cmd->channel,
+			  scb->scsi_cmd->target, scb->scsi_cmd->lun,
+			  scb->basic_status, scb->extended_status,
+			  scb->extended_status ==
+			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0,
+			  scb->extended_status ==
+			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0,
+			  scb->extended_status ==
+			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0);
+	}
+
+	/* default driver error */
+	errcode = DID_ERROR;
+	device_error = 0;
+
+	switch (scb->basic_status & IPS_GSC_STATUS_MASK) {
+	case IPS_CMD_TIMEOUT:
+		errcode = DID_TIME_OUT;
+		break;
+
+	case IPS_INVAL_OPCO:
+	case IPS_INVAL_CMD_BLK:
+	case IPS_INVAL_PARM_BLK:
+	case IPS_LD_ERROR:
+	case IPS_CMD_CMPLT_WERROR:
+		break;
+
+	case IPS_PHYS_DRV_ERROR:
+		switch (scb->extended_status) {
+		case IPS_ERR_SEL_TO:
+			if (scb->bus)
+				errcode = DID_NO_CONNECT;
+
+			break;
+
+		case IPS_ERR_OU_RUN:
+			if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) ||
+			    (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)) {
+				tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
+				transfer_len = tapeDCDB->transfer_length;
+			} else {
+				transfer_len =
+				    (uint32_t) scb->dcdb.transfer_length;
+			}
+
+			if ((scb->bus) && (transfer_len < scb->data_len)) {
+				/* Underrun - set default to no error */
+				errcode = DID_OK;
+
+				/* Restrict access to physical DASD */
+				if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
+				    ((((char
+					*) scb->scsi_cmd->buffer)[0] & 0x1f) ==
+				     TYPE_DISK)) {
+					/* underflow -- no error               */
+					/* restrict access to physical DASD    */
+					errcode = DID_TIME_OUT;
+					break;
+				}
+			} else
+				errcode = DID_ERROR;
+
+			break;
+
+		case IPS_ERR_RECOVERY:
+			/* don't fail recovered errors */
+			if (scb->bus)
+				errcode = DID_OK;
+
+			break;
+
+		case IPS_ERR_HOST_RESET:
+		case IPS_ERR_DEV_RESET:
+			errcode = DID_RESET;
+			break;
+
+		case IPS_ERR_CKCOND:
+			if (scb->bus) {
+				if (
+				    (scb->cmd.dcdb.op_code ==
+				     IPS_CMD_EXTENDED_DCDB)
+				    || (scb->cmd.dcdb.op_code ==
+					IPS_CMD_EXTENDED_DCDB_SG)) {
+					tapeDCDB =
+					    (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
+					memcpy(scb->scsi_cmd->sense_buffer,
+					       tapeDCDB->sense_info,
+					       sizeof (scb->scsi_cmd->
+						       sense_buffer));
+				} else {
+					memcpy(scb->scsi_cmd->sense_buffer,
+					       scb->dcdb.sense_info,
+					       sizeof (scb->scsi_cmd->
+						       sense_buffer));
+				}
+				device_error = 2;	/* check condition */
+			}
+
+			errcode = DID_OK;
+
+			break;
+
+		default:
+			errcode = DID_ERROR;
+			break;
 
-      } /* end switch */
-   } /* end switch */
+		}		/* end switch */
+	}			/* end switch */
 
-   scb->scsi_cmd->result = device_error | (errcode << 16);
+	scb->scsi_cmd->result = device_error | (errcode << 16);
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -4314,25 +3606,90 @@
 /*   actually need to wait.                                                 */
 /****************************************************************************/
 static int
-ips_send_wait(ips_ha_t *ha, ips_scb_t *scb, int timeout, int intr) {
-   int       ret;
+ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
+{
+	int ret;
 
-   METHOD_TRACE("ips_send_wait", 1);
+	METHOD_TRACE("ips_send_wait", 1);
 
-   if (intr != IPS_FFDC) {      /* Won't be Waiting if this is a Time Stamp */
-      ha->waitflag = TRUE;
-      ha->cmd_in_progress = scb->cdb[0];
-   }
-   scb->callback = ipsintr_blocking;
-   ret = ips_send_cmd(ha, scb);
+	if (intr != IPS_FFDC) {	/* Won't be Waiting if this is a Time Stamp */
+		ha->waitflag = TRUE;
+		ha->cmd_in_progress = scb->cdb[0];
+	}
+	scb->callback = ipsintr_blocking;
+	ret = ips_send_cmd(ha, scb);
 
-   if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
-      return (ret);
+	if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
+		return (ret);
 
-   if (intr != IPS_FFDC)       /* Don't Wait around if this is a Time Stamp */
-      ret = ips_wait(ha, timeout, intr);
+	if (intr != IPS_FFDC)	/* Don't Wait around if this is a Time Stamp */
+		ret = ips_wait(ha, timeout, intr);
 
-   return (ret);
+	return (ret);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_scmd_buf_write                                         */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*  Write data to Scsi_Cmnd request_buffer at proper offsets                */
+/****************************************************************************/
+static void
+ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
+		   int count)
+{
+	if (scmd->use_sg) {
+		int i;
+		unsigned int min_cnt, xfer_cnt;
+		char *cdata = (char *) data;
+		struct scatterlist *sg = scmd->request_buffer;
+		for (i = 0, xfer_cnt = 0;
+		     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
+			if (!IPS_SG_ADDRESS(&sg[i]))
+				return;
+			min_cnt = min(count - xfer_cnt, sg[i].length);
+			memcpy(IPS_SG_ADDRESS(&sg[i]), &cdata[xfer_cnt],
+			       min_cnt);
+			xfer_cnt += min_cnt;
+		}
+
+	} else {
+		unsigned int min_cnt = min(count, scmd->request_bufflen);
+		memcpy(scmd->request_buffer, data, min_cnt);
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_scmd_buf_read                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*  Copy data from a Scsi_Cmnd to a new, linear buffer                      */
+/****************************************************************************/
+static void
+ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned
+		  int count)
+{
+	if (scmd->use_sg) {
+		int i;
+		unsigned int min_cnt, xfer_cnt;
+		char *cdata = (char *) data;
+		struct scatterlist *sg = scmd->request_buffer;
+		for (i = 0, xfer_cnt = 0;
+		     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
+			if (!IPS_SG_ADDRESS(&sg[i]))
+				return;
+			min_cnt = min(count - xfer_cnt, sg[i].length);
+			memcpy(&cdata[xfer_cnt], IPS_SG_ADDRESS(&sg[i]),
+			       min_cnt);
+			xfer_cnt += min_cnt;
+		}
+
+	} else {
+		unsigned int min_cnt = min(count, scmd->request_bufflen);
+		memcpy(data, scmd->request_buffer, min_cnt);
+	}
 }
 
 /****************************************************************************/
@@ -4345,288 +3702,402 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_send_cmd(ips_ha_t *ha, ips_scb_t *scb) {
-   int       ret;
-   char     *sp;
-   int       device_error;
-   IPS_DCDB_TABLE_TAPE *tapeDCDB;
-   int       TimeOut;
-
-   METHOD_TRACE("ips_send_cmd", 1);
-
-   ret = IPS_SUCCESS;
-
-   if (!scb->scsi_cmd) {
-      /* internal command */
-
-      if (scb->bus > 0) {
-         /* Controller commands can't be issued */
-         /* to real devices -- fail them        */
-         if ((ha->waitflag == TRUE) &&
-             (ha->cmd_in_progress == scb->cdb[0])) {
-            ha->waitflag = FALSE;
-         }
-
-         return (1);
-      }
-   } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) {
-      /* command to logical bus -- interpret */
-      if(ha->scb_waitlist.count + ha->scb_activelist.count > 32)
-         mod_timer(&scb->scsi_cmd->eh_timeout, jiffies + 120 * HZ);
-      ret = IPS_SUCCESS_IMM;
-
-      switch (scb->scsi_cmd->cmnd[0]) {
-      case ALLOW_MEDIUM_REMOVAL:
-      case REZERO_UNIT:
-      case ERASE:
-      case WRITE_FILEMARKS:
-      case SPACE:
-         scb->scsi_cmd->result = DID_ERROR << 16;
-         break;
-
-      case START_STOP:
-         scb->scsi_cmd->result = DID_OK << 16;
-
-      case TEST_UNIT_READY:
-      case INQUIRY:
-         scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
-         scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
-         scb->cmd.logical_info.reserved = 0;
-         scb->cmd.logical_info.reserved2 = 0;
-         scb->data_len = sizeof(ha->adapt->logical_drive_info);
-         scb->data_busaddr = pci_map_single(ha->pcidev,
-                                            &ha->adapt->logical_drive_info,
-                                            scb->data_len, IPS_DMA_DIR(scb));
-         scb->flags |= IPS_SCB_MAP_SINGLE;
-         scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
-         ret = IPS_SUCCESS;
-         break;
-
-      case REQUEST_SENSE:
-         ips_reqsen(ha, scb);
-         scb->scsi_cmd->result = DID_OK << 16;
-         break;
-
-      case READ_6:
-      case WRITE_6:
-         if (!scb->sg_len) {
-            scb->cmd.basic_io.op_code =
-            (scb->scsi_cmd->cmnd[0] == READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE;
-         } else {
-            scb->cmd.basic_io.op_code =
-            (scb->scsi_cmd->cmnd[0] == READ_6) ? IPS_CMD_READ_SG : IPS_CMD_WRITE_SG;
-         }
-
-         scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-         scb->cmd.basic_io.log_drv = scb->target_id;
-         scb->cmd.basic_io.sg_count = scb->sg_len;
-         scb->cmd.basic_io.sg_addr = cpu_to_le32(scb->data_busaddr);
-
-         if (scb->cmd.basic_io.lba)
-            scb->cmd.basic_io.lba = cpu_to_le32(le32_to_cpu(scb->cmd.basic_io.lba) +
-                                                le16_to_cpu(scb->cmd.basic_io.sector_count));
-         else
-            scb->cmd.basic_io.lba = (((scb->scsi_cmd->cmnd[1] & 0x1f) << 16) |
-                                     (scb->scsi_cmd->cmnd[2] << 8) |
-                                     (scb->scsi_cmd->cmnd[3]));
-
-         scb->cmd.basic_io.sector_count = cpu_to_le16(scb->data_len / IPS_BLKSIZE);
-
-         if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0)
-            scb->cmd.basic_io.sector_count = cpu_to_le16(256);
-
-         scb->cmd.basic_io.reserved = 0;
-         ret = IPS_SUCCESS;
-         break;
-
-      case READ_10:
-      case WRITE_10:
-         if (!scb->sg_len) {
-            scb->cmd.basic_io.op_code =
-            (scb->scsi_cmd->cmnd[0] == READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE;
-         } else {
-            scb->cmd.basic_io.op_code =
-            (scb->scsi_cmd->cmnd[0] == READ_10) ? IPS_CMD_READ_SG : IPS_CMD_WRITE_SG;
-         }
-
-         scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-         scb->cmd.basic_io.log_drv = scb->target_id;
-         scb->cmd.basic_io.sg_count = scb->sg_len;
-         scb->cmd.basic_io.sg_addr = cpu_to_le32(scb->data_busaddr);
-
-         if (scb->cmd.basic_io.lba)
-            scb->cmd.basic_io.lba = cpu_to_le32(le32_to_cpu(scb->cmd.basic_io.lba) +
-                                                le16_to_cpu(scb->cmd.basic_io.sector_count));
-         else
-            scb->cmd.basic_io.lba = ((scb->scsi_cmd->cmnd[2] << 24) |
-                                     (scb->scsi_cmd->cmnd[3] << 16) |
-                                     (scb->scsi_cmd->cmnd[4] << 8) |
-                                     scb->scsi_cmd->cmnd[5]);
-
-         scb->cmd.basic_io.sector_count = cpu_to_le16(scb->data_len / IPS_BLKSIZE);
-
-         scb->cmd.basic_io.reserved = 0;
-
-         if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) {
-            /*
-             * This is a null condition
-             * we don't have to do anything
-             * so just return
-             */
-            scb->scsi_cmd->result = DID_OK << 16;
-         } else
-            ret = IPS_SUCCESS;
-
-         break;
-
-      case RESERVE:
-      case RELEASE:
-         scb->scsi_cmd->result = DID_OK << 16;
-         break;
-
-      case MODE_SENSE:
-         scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
-         scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-         scb->data_len = sizeof(*ha->enq);
-         scb->data_busaddr = pci_map_single(ha->pcidev, ha->enq,
-                                            scb->data_len, IPS_DMA_DIR(scb));
-         scb->cmd.basic_io.sg_addr = scb->data_busaddr;
-         scb->flags |= IPS_SCB_MAP_SINGLE;
-         ret = IPS_SUCCESS;
-         break;
-
-      case READ_CAPACITY:
-         scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
-         scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
-         scb->cmd.logical_info.reserved = 0;
-         scb->cmd.logical_info.reserved2 = 0;
-         scb->cmd.logical_info.reserved3 = 0;
-         scb->data_len = sizeof(ha->adapt->logical_drive_info);
-         scb->data_busaddr = pci_map_single(ha->pcidev,
-                                            &ha->adapt->logical_drive_info,
-                                            scb->data_len, IPS_DMA_DIR(scb));
-         scb->flags |= IPS_SCB_MAP_SINGLE;
-         scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
-         ret = IPS_SUCCESS;
-         break;
-
-      case SEND_DIAGNOSTIC:
-      case REASSIGN_BLOCKS:
-      case FORMAT_UNIT:
-      case SEEK_10:
-      case VERIFY:
-      case READ_DEFECT_DATA:
-      case READ_BUFFER:
-      case WRITE_BUFFER:
-         scb->scsi_cmd->result = DID_OK << 16;
-         break;
-
-      default:
-         /* Set the Return Info to appear like the Command was */
-         /* attempted, a Check Condition occurred, and Sense   */
-         /* Data indicating an Invalid CDB OpCode is returned. */
-         sp = (char *) scb->scsi_cmd->sense_buffer;
-         memset(sp, 0, sizeof(scb->scsi_cmd->sense_buffer));
-  
-         sp[0] = 0x70;             /* Error Code               */ 
-         sp[2] = ILLEGAL_REQUEST;  /* Sense Key 5 Illegal Req. */
-         sp[7] = 0x0A;             /* Additional Sense Length  */
-         sp[12] = 0x20;            /* ASC = Invalid OpCode     */
-         sp[13] = 0x00;            /* ASCQ                     */
-   
-         device_error = 2;         /* Indicate Check Condition */
-         scb->scsi_cmd->result = device_error | (DID_OK << 16);
-         break;
-      } /* end switch */
-   } /* end if */
-
-   if (ret == IPS_SUCCESS_IMM)
-      return (ret);
-
-   /* setup DCDB */
-   if (scb->bus > 0) {
-      if (!scb->sg_len)
-         scb->cmd.dcdb.op_code = IPS_CMD_DCDB;
-      else
-         scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG;
-
-      /* If we already know the Device is Not there, no need to attempt a Command   */
-      /* This also protects an NT FailOver Controller from getting CDB's sent to it */
-      if ( ha->conf->dev[scb->bus-1][scb->target_id].ucState == 0 ) {
-         scb->scsi_cmd->result = DID_NO_CONNECT << 16;
-         return (IPS_SUCCESS_IMM); 
-      }
-
-      ha->dcdb_active[scb->bus-1] |= (1 << scb->target_id);
-      scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
-      scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
-                                               (unsigned long)&scb->dcdb -
-                                               (unsigned long)scb);
-      scb->cmd.dcdb.reserved = 0;
-      scb->cmd.dcdb.reserved2 = 0;
-      scb->cmd.dcdb.reserved3 = 0;   
-
-      TimeOut = scb->scsi_cmd->timeout_per_command;
-
-      if (ha->subsys->param[4] & 0x00100000) {          /* If NEW Tape DCDB is Supported */
-         if (!scb->sg_len)
-            scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB;
-         else
-            scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB_SG;
- 
-         tapeDCDB = (IPS_DCDB_TABLE_TAPE *) &scb->dcdb; /* Use Same Data Area as Old DCDB Struct */
-         tapeDCDB->device_address = ((scb->bus - 1) << 4) | scb->target_id;
-         tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
-         tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;   /* Always Turn OFF 64K Size Flag */
-
-         if (TimeOut) {
-            if (TimeOut < ( 10 * HZ ))                  
-                tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;     /* TimeOut is 10 Seconds */
-            else if (TimeOut < (60 * HZ)) 
-                tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;     /* TimeOut is 60 Seconds */
-            else if (TimeOut < (1200 * HZ)) 
-                tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;    /* TimeOut is 20 Minutes */
-         }
-
-         tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
-         tapeDCDB->reserved_for_LUN = 0;
-         tapeDCDB->transfer_length = scb->data_len;
-         tapeDCDB->buffer_pointer = cpu_to_le32(scb->data_busaddr);
-         tapeDCDB->sg_count = scb->sg_len;
-         tapeDCDB->sense_length = sizeof(tapeDCDB->sense_info);
-         tapeDCDB->scsi_status = 0;
-         tapeDCDB->reserved = 0;
-         memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
-      } else {
-         scb->dcdb.device_address = ((scb->bus - 1) << 4) | scb->target_id;
-         scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
-
-         if (TimeOut) {
-            if (TimeOut < (10 * HZ))                  
-                scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;     /* TimeOut is 10 Seconds */
-            else if (TimeOut < (60 * HZ)) 
-                scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;     /* TimeOut is 60 Seconds */
-            else if (TimeOut < (1200 * HZ)) 
-                scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;    /* TimeOut is 20 Minutes */
-         }
-         
-         scb->dcdb.transfer_length = scb->data_len;
-         if ( scb->dcdb.cmd_attribute & IPS_TRANSFER64K ) 
-             scb->dcdb.transfer_length = 0;
-         scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
-         scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
-         scb->dcdb.sense_length = sizeof(scb->dcdb.sense_info);
-         scb->dcdb.sg_count = scb->sg_len;
-         scb->dcdb.reserved = 0;
-         memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
-         scb->dcdb.scsi_status = 0;
-         scb->dcdb.reserved2[0] = 0;
-         scb->dcdb.reserved2[1] = 0;
-         scb->dcdb.reserved2[2] = 0;
-      }
-   }
+ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
+{
+	int ret;
+	char *sp;
+	int device_error;
+	IPS_DCDB_TABLE_TAPE *tapeDCDB;
+	int TimeOut;
+
+	METHOD_TRACE("ips_send_cmd", 1);
+
+	ret = IPS_SUCCESS;
+
+	if (!scb->scsi_cmd) {
+		/* internal command */
+
+		if (scb->bus > 0) {
+			/* Controller commands can't be issued */
+			/* to real devices -- fail them        */
+			if ((ha->waitflag == TRUE) &&
+			    (ha->cmd_in_progress == scb->cdb[0])) {
+				ha->waitflag = FALSE;
+			}
+
+			return (1);
+		}
+	} else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) {
+		/* command to logical bus -- interpret */
+		ret = IPS_SUCCESS_IMM;
+
+		switch (scb->scsi_cmd->cmnd[0]) {
+		case ALLOW_MEDIUM_REMOVAL:
+		case REZERO_UNIT:
+		case ERASE:
+		case WRITE_FILEMARKS:
+		case SPACE:
+			scb->scsi_cmd->result = DID_ERROR << 16;
+			break;
+
+		case START_STOP:
+			scb->scsi_cmd->result = DID_OK << 16;
+
+		case TEST_UNIT_READY:
+		case INQUIRY:
+			if (scb->target_id == IPS_ADAPTER_ID) {
+				/*
+				 * Either we have a TUR
+				 * or we have a SCSI inquiry
+				 */
+				if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY)
+					scb->scsi_cmd->result = DID_OK << 16;
+
+				if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
+					IPS_SCSI_INQ_DATA inquiry;
+
+					memset(&inquiry, 0,
+					       sizeof (IPS_SCSI_INQ_DATA));
+
+					inquiry.DeviceType =
+					    IPS_SCSI_INQ_TYPE_PROCESSOR;
+					inquiry.DeviceTypeQualifier =
+					    IPS_SCSI_INQ_LU_CONNECTED;
+					inquiry.Version = IPS_SCSI_INQ_REV2;
+					inquiry.ResponseDataFormat =
+					    IPS_SCSI_INQ_RD_REV2;
+					inquiry.AdditionalLength = 31;
+					inquiry.Flags[0] =
+					    IPS_SCSI_INQ_Address16;
+					inquiry.Flags[1] =
+					    IPS_SCSI_INQ_WBus16 |
+					    IPS_SCSI_INQ_Sync;
+					strncpy(inquiry.VendorId, "IBM     ",
+						8);
+					strncpy(inquiry.ProductId,
+						"SERVERAID       ", 16);
+					strncpy(inquiry.ProductRevisionLevel,
+						"1.00", 4);
+
+					ips_scmd_buf_write(scb->scsi_cmd,
+							   &inquiry,
+							   sizeof (inquiry));
+
+					scb->scsi_cmd->result = DID_OK << 16;
+				}
+			} else {
+				scb->cmd.logical_info.op_code =
+				    IPS_CMD_GET_LD_INFO;
+				scb->cmd.logical_info.command_id =
+				    IPS_COMMAND_ID(ha, scb);
+				scb->cmd.logical_info.reserved = 0;
+				scb->cmd.logical_info.reserved2 = 0;
+				scb->data_len =
+				    sizeof (ha->adapt->logical_drive_info);
+				scb->data_busaddr =
+				    pci_map_single(ha->pcidev,
+						   &ha->adapt->
+						   logical_drive_info,
+						   scb->data_len,
+						   IPS_DMA_DIR(scb));
+				scb->flags |= IPS_SCB_MAP_SINGLE;
+				scb->cmd.logical_info.buffer_addr =
+				    scb->data_busaddr;
+				ret = IPS_SUCCESS;
+			}
+
+			break;
+
+		case REQUEST_SENSE:
+			ips_reqsen(ha, scb);
+			scb->scsi_cmd->result = DID_OK << 16;
+			break;
+
+		case READ_6:
+		case WRITE_6:
+			if (!scb->sg_len) {
+				scb->cmd.basic_io.op_code =
+				    (scb->scsi_cmd->cmnd[0] ==
+				     READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE;
+				scb->cmd.basic_io.enhanced_sg = 0;
+				scb->cmd.basic_io.sg_addr =
+				    cpu_to_le32(scb->data_busaddr);
+			} else {
+				scb->cmd.basic_io.op_code =
+				    (scb->scsi_cmd->cmnd[0] ==
+				     READ_6) ? IPS_CMD_READ_SG :
+				    IPS_CMD_WRITE_SG;
+				scb->cmd.basic_io.enhanced_sg =
+				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
+				scb->cmd.basic_io.sg_addr =
+				    cpu_to_le32(scb->sg_busaddr);
+			}
+
+			scb->cmd.basic_io.segment_4G = 0;
+			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+			scb->cmd.basic_io.log_drv = scb->target_id;
+			scb->cmd.basic_io.sg_count = scb->sg_len;
+
+			if (scb->cmd.basic_io.lba)
+				scb->cmd.basic_io.lba =
+				    cpu_to_le32(le32_to_cpu
+						(scb->cmd.basic_io.lba) +
+						le16_to_cpu(scb->cmd.basic_io.
+							    sector_count));
+			else
+				scb->cmd.basic_io.lba =
+				    (((scb->
+				       scsi_cmd->cmnd[1] & 0x1f) << 16) | (scb->
+									   scsi_cmd->
+									   cmnd
+									   [2]
+									   << 8)
+				     | (scb->scsi_cmd->cmnd[3]));
+
+			scb->cmd.basic_io.sector_count =
+			    cpu_to_le16(scb->data_len / IPS_BLKSIZE);
+
+			if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0)
+				scb->cmd.basic_io.sector_count =
+				    cpu_to_le16(256);
+
+			ret = IPS_SUCCESS;
+			break;
+
+		case READ_10:
+		case WRITE_10:
+			if (!scb->sg_len) {
+				scb->cmd.basic_io.op_code =
+				    (scb->scsi_cmd->cmnd[0] ==
+				     READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE;
+				scb->cmd.basic_io.enhanced_sg = 0;
+				scb->cmd.basic_io.sg_addr =
+				    cpu_to_le32(scb->data_busaddr);
+			} else {
+				scb->cmd.basic_io.op_code =
+				    (scb->scsi_cmd->cmnd[0] ==
+				     READ_10) ? IPS_CMD_READ_SG :
+				    IPS_CMD_WRITE_SG;
+				scb->cmd.basic_io.enhanced_sg =
+				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
+				scb->cmd.basic_io.sg_addr =
+				    cpu_to_le32(scb->sg_busaddr);
+			}
+
+			scb->cmd.basic_io.segment_4G = 0;
+			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+			scb->cmd.basic_io.log_drv = scb->target_id;
+			scb->cmd.basic_io.sg_count = scb->sg_len;
+
+			if (scb->cmd.basic_io.lba)
+				scb->cmd.basic_io.lba =
+				    cpu_to_le32(le32_to_cpu
+						(scb->cmd.basic_io.lba) +
+						le16_to_cpu(scb->cmd.basic_io.
+							    sector_count));
+			else
+				scb->cmd.basic_io.lba =
+				    ((scb->
+				      scsi_cmd->cmnd[2] << 24) | (scb->
+								  scsi_cmd->
+								  cmnd[3] << 16)
+				     | (scb->scsi_cmd->cmnd[4] << 8) | scb->
+				     scsi_cmd->cmnd[5]);
+
+			scb->cmd.basic_io.sector_count =
+			    cpu_to_le16(scb->data_len / IPS_BLKSIZE);
+
+			if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) {
+				/*
+				 * This is a null condition
+				 * we don't have to do anything
+				 * so just return
+				 */
+				scb->scsi_cmd->result = DID_OK << 16;
+			} else
+				ret = IPS_SUCCESS;
+
+			break;
+
+		case RESERVE:
+		case RELEASE:
+			scb->scsi_cmd->result = DID_OK << 16;
+			break;
+
+		case MODE_SENSE:
+			scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
+			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+			scb->cmd.basic_io.segment_4G = 0;
+			scb->cmd.basic_io.enhanced_sg = 0;
+			scb->data_len = sizeof (*ha->enq);
+			scb->data_busaddr = pci_map_single(ha->pcidev, ha->enq,
+							   scb->data_len,
+							   IPS_DMA_DIR(scb));
+			scb->cmd.basic_io.sg_addr = scb->data_busaddr;
+			scb->flags |= IPS_SCB_MAP_SINGLE;
+			ret = IPS_SUCCESS;
+			break;
+
+		case READ_CAPACITY:
+			scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
+			scb->cmd.logical_info.command_id =
+			    IPS_COMMAND_ID(ha, scb);
+			scb->cmd.logical_info.reserved = 0;
+			scb->cmd.logical_info.reserved2 = 0;
+			scb->cmd.logical_info.reserved3 = 0;
+			scb->data_len = sizeof (ha->adapt->logical_drive_info);
+			scb->data_busaddr = pci_map_single(ha->pcidev,
+							   &ha->adapt->
+							   logical_drive_info,
+							   scb->data_len,
+							   IPS_DMA_DIR(scb));
+			scb->flags |= IPS_SCB_MAP_SINGLE;
+			scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
+			ret = IPS_SUCCESS;
+			break;
+
+		case SEND_DIAGNOSTIC:
+		case REASSIGN_BLOCKS:
+		case FORMAT_UNIT:
+		case SEEK_10:
+		case VERIFY:
+		case READ_DEFECT_DATA:
+		case READ_BUFFER:
+		case WRITE_BUFFER:
+			scb->scsi_cmd->result = DID_OK << 16;
+			break;
+
+		default:
+			/* Set the Return Info to appear like the Command was */
+			/* attempted, a Check Condition occurred, and Sense   */
+			/* Data indicating an Invalid CDB OpCode is returned. */
+			sp = (char *) scb->scsi_cmd->sense_buffer;
+			memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer));
+
+			sp[0] = 0x70;	/* Error Code               */
+			sp[2] = ILLEGAL_REQUEST;	/* Sense Key 5 Illegal Req. */
+			sp[7] = 0x0A;	/* Additional Sense Length  */
+			sp[12] = 0x20;	/* ASC = Invalid OpCode     */
+			sp[13] = 0x00;	/* ASCQ                     */
+
+			device_error = 2;	/* Indicate Check Condition */
+			scb->scsi_cmd->result = device_error | (DID_OK << 16);
+			break;
+		}		/* end switch */
+	}
+	/* end if */
+	if (ret == IPS_SUCCESS_IMM)
+		return (ret);
+
+	/* setup DCDB */
+	if (scb->bus > 0) {
+
+		/* If we already know the Device is Not there, no need to attempt a Command   */
+		/* This also protects an NT FailOver Controller from getting CDB's sent to it */
+		if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) {
+			scb->scsi_cmd->result = DID_NO_CONNECT << 16;
+			return (IPS_SUCCESS_IMM);
+		}
+
+		ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id);
+		scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
+		scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
+							 (unsigned long) &scb->
+							 dcdb -
+							 (unsigned long) scb);
+		scb->cmd.dcdb.reserved = 0;
+		scb->cmd.dcdb.reserved2 = 0;
+		scb->cmd.dcdb.reserved3 = 0;
+		scb->cmd.dcdb.segment_4G = 0;
+		scb->cmd.dcdb.enhanced_sg = 0;
+
+		TimeOut = scb->scsi_cmd->timeout_per_command;
+
+		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
+			if (!scb->sg_len) {
+				scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB;
+			} else {
+				scb->cmd.dcdb.op_code =
+				    IPS_CMD_EXTENDED_DCDB_SG;
+				scb->cmd.dcdb.enhanced_sg =
+				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
+			}
+
+			tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;	/* Use Same Data Area as Old DCDB Struct */
+			tapeDCDB->device_address =
+			    ((scb->bus - 1) << 4) | scb->target_id;
+			tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
+			tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;	/* Always Turn OFF 64K Size Flag */
+
+			if (TimeOut) {
+				if (TimeOut < (10 * HZ))
+					tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */
+				else if (TimeOut < (60 * HZ))
+					tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */
+				else if (TimeOut < (1200 * HZ))
+					tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */
+			}
+
+			tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
+			tapeDCDB->reserved_for_LUN = 0;
+			tapeDCDB->transfer_length = scb->data_len;
+			if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)
+				tapeDCDB->buffer_pointer =
+				    cpu_to_le32(scb->sg_busaddr);
+			else
+				tapeDCDB->buffer_pointer =
+				    cpu_to_le32(scb->data_busaddr);
+			tapeDCDB->sg_count = scb->sg_len;
+			tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info);
+			tapeDCDB->scsi_status = 0;
+			tapeDCDB->reserved = 0;
+			memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd,
+			       scb->scsi_cmd->cmd_len);
+		} else {
+			if (!scb->sg_len) {
+				scb->cmd.dcdb.op_code = IPS_CMD_DCDB;
+			} else {
+				scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG;
+				scb->cmd.dcdb.enhanced_sg =
+				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
+			}
+
+			scb->dcdb.device_address =
+			    ((scb->bus - 1) << 4) | scb->target_id;
+			scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
+
+			if (TimeOut) {
+				if (TimeOut < (10 * HZ))
+					scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */
+				else if (TimeOut < (60 * HZ))
+					scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */
+				else if (TimeOut < (1200 * HZ))
+					scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */
+			}
+
+			scb->dcdb.transfer_length = scb->data_len;
+			if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K)
+				scb->dcdb.transfer_length = 0;
+			if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG)
+				scb->dcdb.buffer_pointer =
+				    cpu_to_le32(scb->sg_busaddr);
+			else
+				scb->dcdb.buffer_pointer =
+				    cpu_to_le32(scb->data_busaddr);
+			scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
+			scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info);
+			scb->dcdb.sg_count = scb->sg_len;
+			scb->dcdb.reserved = 0;
+			memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd,
+			       scb->scsi_cmd->cmd_len);
+			scb->dcdb.scsi_status = 0;
+			scb->dcdb.reserved2[0] = 0;
+			scb->dcdb.reserved2[1] = 0;
+			scb->dcdb.reserved2[2] = 0;
+		}
+	}
 
-   return ((*ha->func.issue)(ha, scb));
+	return ((*ha->func.issue) (ha, scb));
 }
 
 /****************************************************************************/
@@ -4639,169 +4110,151 @@
 /*   Assumed to be called with the HA lock                                  */
 /****************************************************************************/
 static void
-ips_chkstatus(ips_ha_t *ha, IPS_STATUS *pstatus) {
-   ips_scb_t  *scb;
-   ips_stat_t *sp;
-   uint8_t     basic_status;
-   uint8_t     ext_status;
-   int         errcode;
-
-   METHOD_TRACE("ips_chkstatus", 1);
-
-   scb = &ha->scbs[pstatus->fields.command_id];
-   scb->basic_status = basic_status = pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK;
-   scb->extended_status = ext_status = pstatus->fields.extended_status;
-
-   sp = &ha->sp;
-   sp->residue_len = 0;
-   sp->scb_addr = (void *) scb;
-
-   /* Remove the item from the active queue */
-   ips_removeq_scb(&ha->scb_activelist, scb);
-
-   if (!scb->scsi_cmd)
-      /* internal commands are handled in do_ipsintr */
-      return ;
-
-   DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)",
-             ips_name,
-             ha->host_num,
-             scb->cdb[0],
-             scb->cmd.basic_io.command_id,
-             scb->bus,
-             scb->target_id,
-             scb->lun);
-
-   if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd)))
-      /* passthru - just returns the raw result */
-      return ;
-
-   errcode = DID_OK;
-
-   if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) ||
-       ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) {
-
-      if (scb->bus == 0) {
-         if ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR) {
-            DEBUG_VAR(1, "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
-                      ips_name, ha->host_num,
-                      scb->cmd.basic_io.op_code, basic_status, ext_status);
-         }
-
-         switch (scb->scsi_cmd->cmnd[0]) {
-         case ALLOW_MEDIUM_REMOVAL:
-         case REZERO_UNIT:
-         case ERASE:
-         case WRITE_FILEMARKS:
-         case SPACE:
-            errcode = DID_ERROR;
-            break;
-
-         case START_STOP:
-            break;
-
-         case TEST_UNIT_READY:
-            if (scb->target_id == IPS_ADAPTER_ID) 
-               break;
-
-            if (!ips_online(ha, scb)) {
-               errcode = DID_TIME_OUT;
-            }
-            break;
-
-         case INQUIRY:
-            if (scb->target_id == IPS_ADAPTER_ID) {
-               IPS_SCSI_INQ_DATA inquiry;
-
-               memset(&inquiry, 0, sizeof(IPS_SCSI_INQ_DATA));
-
-               inquiry.DeviceType = IPS_SCSI_INQ_TYPE_PROCESSOR;
-               inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
-               inquiry.Version = IPS_SCSI_INQ_REV2;
-               inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
-               inquiry.AdditionalLength = 31;
-               inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
-               inquiry.Flags[1] = IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync;
-               strncpy(inquiry.VendorId, "IBM     ", 8);
-               strncpy(inquiry.ProductId, "SERVERAID       ", 16);
-               strncpy(inquiry.ProductRevisionLevel, "1.00", 4);
-
-               memcpy(scb->scsi_cmd->request_buffer, &inquiry, scb->scsi_cmd->request_bufflen);
-
-               scb->scsi_cmd->result = DID_OK << 16;
-               break;
-            }
-
-            if (ips_online(ha, scb)) {
-               ips_inquiry(ha, scb);
-            } else {
-               errcode = DID_TIME_OUT;
-            }
-            break;
-
-         case REQUEST_SENSE:
-            ips_reqsen(ha, scb);
-            break;
-
-         case READ_6:
-         case WRITE_6:
-         case READ_10:
-         case WRITE_10:
-         case RESERVE:
-         case RELEASE:
-            break;
-
-         case MODE_SENSE:
-            if (!ips_online(ha, scb) || !ips_msense(ha, scb)) {
-               errcode = DID_ERROR;
-            }
-            break;
-
-         case READ_CAPACITY:
-            if (ips_online(ha, scb))
-               ips_rdcap(ha, scb);
-            else {
-               errcode = DID_TIME_OUT;
-            }
-            break;
-
-         case SEND_DIAGNOSTIC:
-         case REASSIGN_BLOCKS:
-            break;
-
-         case FORMAT_UNIT:
-            errcode = DID_ERROR;
-            break;
-
-         case SEEK_10:
-         case VERIFY:
-         case READ_DEFECT_DATA:
-         case READ_BUFFER:
-         case WRITE_BUFFER:
-            break;
-
-         default:
-            errcode = DID_ERROR;
-         } /* end switch */
-
-         scb->scsi_cmd->result = errcode << 16;
-      } else { /* bus == 0 */
-         /* restrict access to physical drives */
-         if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
-             ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == TYPE_DISK)) {
-
-            scb->scsi_cmd->result = DID_TIME_OUT << 16;
-         }
-      } /* else */
-   } else { /* recovered error / success */
-      if (scb->bus == 0) {
-         DEBUG_VAR(1, "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
-                   ips_name, ha->host_num,
-                   scb->cmd.basic_io.op_code, basic_status, ext_status);
-      }
+ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
+{
+	ips_scb_t *scb;
+	ips_stat_t *sp;
+	uint8_t basic_status;
+	uint8_t ext_status;
+	int errcode;
+
+	METHOD_TRACE("ips_chkstatus", 1);
+
+	scb = &ha->scbs[pstatus->fields.command_id];
+	scb->basic_status = basic_status =
+	    pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK;
+	scb->extended_status = ext_status = pstatus->fields.extended_status;
+
+	sp = &ha->sp;
+	sp->residue_len = 0;
+	sp->scb_addr = (void *) scb;
+
+	/* Remove the item from the active queue */
+	ips_removeq_scb(&ha->scb_activelist, scb);
+
+	if (!scb->scsi_cmd)
+		/* internal commands are handled in do_ipsintr */
+		return;
+
+	DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)",
+		  ips_name,
+		  ha->host_num,
+		  scb->cdb[0],
+		  scb->cmd.basic_io.command_id,
+		  scb->bus, scb->target_id, scb->lun);
+
+	if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd)))
+		/* passthru - just returns the raw result */
+		return;
+
+	errcode = DID_OK;
+
+	if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) ||
+	    ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) {
+
+		if (scb->bus == 0) {
+			if ((basic_status & IPS_GSC_STATUS_MASK) ==
+			    IPS_CMD_RECOVERED_ERROR) {
+				DEBUG_VAR(1,
+					  "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
+					  ips_name, ha->host_num,
+					  scb->cmd.basic_io.op_code,
+					  basic_status, ext_status);
+			}
+
+			switch (scb->scsi_cmd->cmnd[0]) {
+			case ALLOW_MEDIUM_REMOVAL:
+			case REZERO_UNIT:
+			case ERASE:
+			case WRITE_FILEMARKS:
+			case SPACE:
+				errcode = DID_ERROR;
+				break;
+
+			case START_STOP:
+				break;
+
+			case TEST_UNIT_READY:
+				if (!ips_online(ha, scb)) {
+					errcode = DID_TIME_OUT;
+				}
+				break;
+
+			case INQUIRY:
+				if (ips_online(ha, scb)) {
+					ips_inquiry(ha, scb);
+				} else {
+					errcode = DID_TIME_OUT;
+				}
+				break;
+
+			case REQUEST_SENSE:
+				ips_reqsen(ha, scb);
+				break;
+
+			case READ_6:
+			case WRITE_6:
+			case READ_10:
+			case WRITE_10:
+			case RESERVE:
+			case RELEASE:
+				break;
+
+			case MODE_SENSE:
+				if (!ips_online(ha, scb)
+				    || !ips_msense(ha, scb)) {
+					errcode = DID_ERROR;
+				}
+				break;
+
+			case READ_CAPACITY:
+				if (ips_online(ha, scb))
+					ips_rdcap(ha, scb);
+				else {
+					errcode = DID_TIME_OUT;
+				}
+				break;
+
+			case SEND_DIAGNOSTIC:
+			case REASSIGN_BLOCKS:
+				break;
+
+			case FORMAT_UNIT:
+				errcode = DID_ERROR;
+				break;
+
+			case SEEK_10:
+			case VERIFY:
+			case READ_DEFECT_DATA:
+			case READ_BUFFER:
+			case WRITE_BUFFER:
+				break;
+
+			default:
+				errcode = DID_ERROR;
+			}	/* end switch */
+
+			scb->scsi_cmd->result = errcode << 16;
+		} else {	/* bus == 0 */
+			/* restrict access to physical drives */
+			if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
+			    ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) ==
+			     TYPE_DISK)) {
+
+				scb->scsi_cmd->result = DID_TIME_OUT << 16;
+			}
+		}		/* else */
+	} else {		/* recovered error / success */
+		if (scb->bus == 0) {
+			DEBUG_VAR(1,
+				  "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
+				  ips_name, ha->host_num,
+				  scb->cmd.basic_io.op_code, basic_status,
+				  ext_status);
+		}
 
-      ips_map_status(ha, scb, sp);
-   } /* else */
+		ips_map_status(ha, scb, sp);
+	}			/* else */
 }
 
 /****************************************************************************/
@@ -4814,25 +4267,30 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_online(ips_ha_t *ha, ips_scb_t *scb) {
-   METHOD_TRACE("ips_online", 1);
-
-   if (scb->target_id >= IPS_MAX_LD)
-      return (0);
+ips_online(ips_ha_t * ha, ips_scb_t * scb)
+{
+	METHOD_TRACE("ips_online", 1);
 
-   if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) {
-      memset(&ha->adapt->logical_drive_info, 0, sizeof(ha->adapt->logical_drive_info));
+	if (scb->target_id >= IPS_MAX_LD)
+		return (0);
 
-      return (0);
-   }
-
-   if (ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_OFFLINE &&
-       ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_FREE &&
-       ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_CRS &&
-       ha->adapt->logical_drive_info.drive_info[scb->target_id].state != IPS_LD_SYS)
-      return (1);
-   else
-      return (0);
+	if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) {
+		memset(&ha->adapt->logical_drive_info, 0,
+		       sizeof (ha->adapt->logical_drive_info));
+
+		return (0);
+	}
+
+	if (ha->adapt->logical_drive_info.drive_info[scb->target_id].state !=
+	    IPS_LD_OFFLINE
+	    && ha->adapt->logical_drive_info.drive_info[scb->target_id].state !=
+	    IPS_LD_FREE
+	    && ha->adapt->logical_drive_info.drive_info[scb->target_id].state !=
+	    IPS_LD_CRS
+	    && ha->adapt->logical_drive_info.drive_info[scb->target_id].state !=
+	    IPS_LD_SYS) return (1);
+	else
+		return (0);
 }
 
 /****************************************************************************/
@@ -4845,27 +4303,29 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_inquiry(ips_ha_t *ha, ips_scb_t *scb) {
-   IPS_SCSI_INQ_DATA inquiry;
+ips_inquiry(ips_ha_t * ha, ips_scb_t * scb)
+{
+	IPS_SCSI_INQ_DATA inquiry;
 
-   METHOD_TRACE("ips_inquiry", 1);
+	METHOD_TRACE("ips_inquiry", 1);
 
-   memset(&inquiry, 0, sizeof(IPS_SCSI_INQ_DATA));
+	memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA));
 
-   inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD;
-   inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
-   inquiry.Version = IPS_SCSI_INQ_REV2;
-   inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
-   inquiry.AdditionalLength = 31;
-   inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
-   inquiry.Flags[1] = IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync;
-   strncpy(inquiry.VendorId, "IBM     ", 8);
-   strncpy(inquiry.ProductId, "SERVERAID       ", 16);
-   strncpy(inquiry.ProductRevisionLevel, "1.00", 4);
+	inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD;
+	inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
+	inquiry.Version = IPS_SCSI_INQ_REV2;
+	inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
+	inquiry.AdditionalLength = 31;
+	inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
+	inquiry.Flags[1] =
+	    IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue;
+	strncpy(inquiry.VendorId, "IBM     ", 8);
+	strncpy(inquiry.ProductId, "SERVERAID       ", 16);
+	strncpy(inquiry.ProductRevisionLevel, "1.00", 4);
 
-   memcpy(scb->scsi_cmd->request_buffer, &inquiry, scb->scsi_cmd->request_bufflen);
+	ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry));
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -4878,20 +4338,24 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_rdcap(ips_ha_t *ha, ips_scb_t *scb) {
-   IPS_SCSI_CAPACITY *cap;
+ips_rdcap(ips_ha_t * ha, ips_scb_t * scb)
+{
+	IPS_SCSI_CAPACITY cap;
 
-   METHOD_TRACE("ips_rdcap", 1);
+	METHOD_TRACE("ips_rdcap", 1);
 
-   if (scb->scsi_cmd->bufflen < 8)
-      return (0);
+	if (scb->scsi_cmd->bufflen < 8)
+		return (0);
 
-   cap = (IPS_SCSI_CAPACITY *) scb->scsi_cmd->request_buffer;
+	cap.lba =
+	    cpu_to_be32(le32_to_cpu
+			(ha->adapt->logical_drive_info.
+			 drive_info[scb->target_id].sector_count) - 1);
+	cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE);
 
-   cap->lba = cpu_to_be32(le32_to_cpu(ha->adapt->logical_drive_info.drive_info[scb->target_id].sector_count) - 1);
-   cap->len = cpu_to_be32((uint32_t) IPS_BLKSIZE);
+	ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap));
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -4904,72 +4368,78 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_msense(ips_ha_t *ha, ips_scb_t *scb) {
-   uint16_t               heads;
-   uint16_t               sectors;
-   uint32_t               cylinders;
-   IPS_SCSI_MODE_PAGE_DATA mdata;
-
-   METHOD_TRACE("ips_msense", 1);
-
-   if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 &&
-       (ha->enq->ucMiscFlag & 0x8) == 0) {
-      heads = IPS_NORM_HEADS;
-      sectors = IPS_NORM_SECTORS;
-   } else {
-      heads = IPS_COMP_HEADS;
-      sectors = IPS_COMP_SECTORS;
-   }
-
-   cylinders = (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) - 1) / (heads * sectors);
-
-   memset(&mdata, 0, sizeof(IPS_SCSI_MODE_PAGE_DATA));
-
-   mdata.hdr.BlockDescLength = 8;
-
-   switch (scb->scsi_cmd->cmnd[2] & 0x3f) {
-   case 0x03: /* page 3 */
-      mdata.pdata.pg3.PageCode = 3;
-      mdata.pdata.pg3.PageLength = sizeof(IPS_SCSI_MODE_PAGE3);
-      mdata.hdr.DataLength = 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength;
-      mdata.pdata.pg3.TracksPerZone = 0;
-      mdata.pdata.pg3.AltSectorsPerZone = 0;
-      mdata.pdata.pg3.AltTracksPerZone = 0;
-      mdata.pdata.pg3.AltTracksPerVolume = 0;
-      mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors);
-      mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE);
-      mdata.pdata.pg3.Interleave = cpu_to_be16(1);
-      mdata.pdata.pg3.TrackSkew = 0;
-      mdata.pdata.pg3.CylinderSkew = 0;
-      mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector;
-      break;
-
-   case 0x4:
-      mdata.pdata.pg4.PageCode = 4;
-      mdata.pdata.pg4.PageLength = sizeof(IPS_SCSI_MODE_PAGE4);
-      mdata.hdr.DataLength = 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength;
-      mdata.pdata.pg4.CylindersHigh = cpu_to_be16((cylinders >> 8) & 0xFFFF);
-      mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF);
-      mdata.pdata.pg4.Heads = heads;
-      mdata.pdata.pg4.WritePrecompHigh = 0;
-      mdata.pdata.pg4.WritePrecompLow = 0;
-      mdata.pdata.pg4.ReducedWriteCurrentHigh = 0;
-      mdata.pdata.pg4.ReducedWriteCurrentLow = 0;
-      mdata.pdata.pg4.StepRate = cpu_to_be16(1);
-      mdata.pdata.pg4.LandingZoneHigh = 0;
-      mdata.pdata.pg4.LandingZoneLow = 0;
-      mdata.pdata.pg4.flags = 0;
-      mdata.pdata.pg4.RotationalOffset = 0;
-      mdata.pdata.pg4.MediumRotationRate = 0;
-      break;
-
-   default:
-      return (0);
-   } /* end switch */
+ips_msense(ips_ha_t * ha, ips_scb_t * scb)
+{
+	uint16_t heads;
+	uint16_t sectors;
+	uint32_t cylinders;
+	IPS_SCSI_MODE_PAGE_DATA mdata;
+
+	METHOD_TRACE("ips_msense", 1);
+
+	if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 &&
+	    (ha->enq->ucMiscFlag & 0x8) == 0) {
+		heads = IPS_NORM_HEADS;
+		sectors = IPS_NORM_SECTORS;
+	} else {
+		heads = IPS_COMP_HEADS;
+		sectors = IPS_COMP_SECTORS;
+	}
+
+	cylinders =
+	    (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) -
+	     1) / (heads * sectors);
+
+	memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA));
+
+	mdata.hdr.BlockDescLength = 8;
+
+	switch (scb->scsi_cmd->cmnd[2] & 0x3f) {
+	case 0x03:		/* page 3 */
+		mdata.pdata.pg3.PageCode = 3;
+		mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3);
+		mdata.hdr.DataLength =
+		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength;
+		mdata.pdata.pg3.TracksPerZone = 0;
+		mdata.pdata.pg3.AltSectorsPerZone = 0;
+		mdata.pdata.pg3.AltTracksPerZone = 0;
+		mdata.pdata.pg3.AltTracksPerVolume = 0;
+		mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors);
+		mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE);
+		mdata.pdata.pg3.Interleave = cpu_to_be16(1);
+		mdata.pdata.pg3.TrackSkew = 0;
+		mdata.pdata.pg3.CylinderSkew = 0;
+		mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector;
+		break;
+
+	case 0x4:
+		mdata.pdata.pg4.PageCode = 4;
+		mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4);
+		mdata.hdr.DataLength =
+		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength;
+		mdata.pdata.pg4.CylindersHigh =
+		    cpu_to_be16((cylinders >> 8) & 0xFFFF);
+		mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF);
+		mdata.pdata.pg4.Heads = heads;
+		mdata.pdata.pg4.WritePrecompHigh = 0;
+		mdata.pdata.pg4.WritePrecompLow = 0;
+		mdata.pdata.pg4.ReducedWriteCurrentHigh = 0;
+		mdata.pdata.pg4.ReducedWriteCurrentLow = 0;
+		mdata.pdata.pg4.StepRate = cpu_to_be16(1);
+		mdata.pdata.pg4.LandingZoneHigh = 0;
+		mdata.pdata.pg4.LandingZoneLow = 0;
+		mdata.pdata.pg4.flags = 0;
+		mdata.pdata.pg4.RotationalOffset = 0;
+		mdata.pdata.pg4.MediumRotationRate = 0;
+		break;
+
+	default:
+		return (0);
+	}			/* end switch */
 
-   memcpy(scb->scsi_cmd->request_buffer, &mdata, scb->scsi_cmd->request_bufflen);
+	ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata));
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -4982,21 +4452,23 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_reqsen(ips_ha_t *ha, ips_scb_t *scb) {
-   IPS_SCSI_REQSEN reqsen;
+ips_reqsen(ips_ha_t * ha, ips_scb_t * scb)
+{
+	IPS_SCSI_REQSEN reqsen;
 
-   METHOD_TRACE("ips_reqsen", 1);
+	METHOD_TRACE("ips_reqsen", 1);
 
-   memset(&reqsen, 0, sizeof(IPS_SCSI_REQSEN));
+	memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN));
 
-   reqsen.ResponseCode = IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR;
-   reqsen.AdditionalLength = 10;
-   reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE;
-   reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE;
+	reqsen.ResponseCode =
+	    IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR;
+	reqsen.AdditionalLength = 10;
+	reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE;
+	reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE;
 
-   memcpy(scb->scsi_cmd->request_buffer, &reqsen, scb->scsi_cmd->request_bufflen);
+	ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen));
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -5009,60 +4481,63 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_free(ips_ha_t *ha) {
+ips_free(ips_ha_t * ha)
+{
 
-   METHOD_TRACE("ips_free", 1);
+	METHOD_TRACE("ips_free", 1);
 
-   if (ha) {
-      if (ha->enq) {
-         kfree(ha->enq);
-         ha->enq = NULL;
-      }
-
-      if (ha->conf) {
-         kfree(ha->conf);
-         ha->conf = NULL;
-      }
-
-      if (ha->adapt) {
-         pci_free_consistent(ha->pcidev,sizeof(IPS_ADAPTER)+ sizeof(IPS_IO_CMD),
-                             ha->adapt, ha->adapt->hw_status_start);
-         ha->adapt = NULL;
-      }
-
-      if (ha->nvram) {
-         kfree(ha->nvram);
-         ha->nvram = NULL;
-      }
-
-      if (ha->subsys) {
-         kfree(ha->subsys);
-         ha->subsys = NULL;
-      }
-
-      if (ha->ioctl_data) {
-         free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
-         ha->ioctl_data = NULL;
-         ha->ioctl_datasize = 0;
-         ha->ioctl_order = 0;
-      }
-      ips_deallocatescbs(ha, ha->max_cmds);
-
-      /* free memory mapped (if applicable) */
-      if (ha->mem_ptr) {
-         iounmap(ha->ioremap_ptr);
-         ha->ioremap_ptr = NULL;
-         ha->mem_ptr = NULL;
-      }
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-      if (ha->mem_addr) 
-          release_mem_region(ha->mem_addr, ha->mem_len);
-#endif
-      ha->mem_addr = 0;
+	if (ha) {
+		if (ha->enq) {
+			kfree(ha->enq);
+			ha->enq = NULL;
+		}
+
+		if (ha->conf) {
+			kfree(ha->conf);
+			ha->conf = NULL;
+		}
+
+		if (ha->adapt) {
+			pci_free_consistent(ha->pcidev,
+					    sizeof (IPS_ADAPTER) +
+					    sizeof (IPS_IO_CMD), ha->adapt,
+					    ha->adapt->hw_status_start);
+			ha->adapt = NULL;
+		}
+
+		if (ha->nvram) {
+			kfree(ha->nvram);
+			ha->nvram = NULL;
+		}
+
+		if (ha->subsys) {
+			kfree(ha->subsys);
+			ha->subsys = NULL;
+		}
+
+		if (ha->ioctl_data) {
+			free_pages((unsigned long) ha->ioctl_data,
+				   ha->ioctl_order);
+			ha->ioctl_data = NULL;
+			ha->ioctl_datasize = 0;
+			ha->ioctl_order = 0;
+		}
+		ips_deallocatescbs(ha, ha->max_cmds);
+
+		/* free memory mapped (if applicable) */
+		if (ha->mem_ptr) {
+			iounmap(ha->ioremap_ptr);
+			ha->ioremap_ptr = NULL;
+			ha->mem_ptr = NULL;
+		}
+
+		if (ha->mem_addr)
+			release_mem_region(ha->mem_addr, ha->mem_len);
+		ha->mem_addr = 0;
 
-   }
+	}
 }
+
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_deallocatescbs                                         */
@@ -5073,15 +4548,18 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_deallocatescbs(ips_ha_t *ha, int cmds) {
-   if (ha->scbs) {
-      pci_free_consistent(ha->pcidev,sizeof(IPS_SG_LIST) * IPS_MAX_SG *
-                          cmds, ha->scbs->sg_list, ha->scbs->sg_busaddr);
-      pci_free_consistent(ha->pcidev, sizeof(ips_scb_t) * cmds,
-                          ha->scbs, ha->scbs->scb_busaddr);
-      ha->scbs = NULL;
-   } /* end if */
-return 1;
+ips_deallocatescbs(ips_ha_t * ha, int cmds)
+{
+	if (ha->scbs) {
+		pci_free_consistent(ha->pcidev,
+				    IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds,
+				    ha->scbs->sg_list.list,
+				    ha->scbs->sg_busaddr);
+		pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds,
+				    ha->scbs, ha->scbs->scb_busaddr);
+		ha->scbs = NULL;
+	}			/* end if */
+	return 1;
 }
 
 /****************************************************************************/
@@ -5094,44 +4572,59 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_allocatescbs(ips_ha_t *ha) {
-   ips_scb_t *scb_p;
-   IPS_SG_LIST* ips_sg;
-   int        i;
-   dma_addr_t command_dma, sg_dma;
-   
-   METHOD_TRACE("ips_allocatescbs", 1);
-
-   /* Allocate memory for the SCBs */
-   ha->scbs = pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof(ips_scb_t),
-	                           &command_dma);
-   if (ha->scbs == NULL)
-      return 0;
-   ips_sg = pci_alloc_consistent(ha->pcidev, sizeof(IPS_SG_LIST) * IPS_MAX_SG * 
-	                         ha->max_cmds, &sg_dma);
-   if(ips_sg == NULL){
-      pci_free_consistent(ha->pcidev,ha->max_cmds * sizeof(ips_scb_t),ha->scbs, command_dma);
-      return 0;
-   }
-
-   memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t));
-
-   for (i = 0; i < ha->max_cmds; i++) {
-      scb_p = &ha->scbs[i];
-      scb_p->scb_busaddr = command_dma + sizeof(ips_scb_t) * i;
-      /* set up S/G list */
-      scb_p->sg_list = ips_sg + i * IPS_MAX_SG;
-      scb_p->sg_busaddr = sg_dma + sizeof(IPS_SG_LIST) * IPS_MAX_SG * i;
-
-      /* add to the free list */
-      if (i < ha->max_cmds - 1) {
-         scb_p->q_next = ha->scb_freelist;
-         ha->scb_freelist = scb_p;
-      }
-   }
+ips_allocatescbs(ips_ha_t * ha)
+{
+	ips_scb_t *scb_p;
+	IPS_SG_LIST ips_sg;
+	int i;
+	dma_addr_t command_dma, sg_dma;
+
+	METHOD_TRACE("ips_allocatescbs", 1);
+
+	/* Allocate memory for the SCBs */
+	ha->scbs =
+	    pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t),
+				 &command_dma);
+	if (ha->scbs == NULL)
+		return 0;
+	ips_sg.list =
+	    pci_alloc_consistent(ha->pcidev,
+				 IPS_SGLIST_SIZE(ha) * IPS_MAX_SG *
+				 ha->max_cmds, &sg_dma);
+	if (ips_sg.list == NULL) {
+		pci_free_consistent(ha->pcidev,
+				    ha->max_cmds * sizeof (ips_scb_t), ha->scbs,
+				    command_dma);
+		return 0;
+	}
+
+	memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t));
+
+	for (i = 0; i < ha->max_cmds; i++) {
+		scb_p = &ha->scbs[i];
+		scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i;
+		/* set up S/G list */
+		if (IPS_USE_ENH_SGLIST(ha)) {
+			scb_p->sg_list.enh_list =
+			    ips_sg.enh_list + i * IPS_MAX_SG;
+			scb_p->sg_busaddr =
+			    sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
+		} else {
+			scb_p->sg_list.std_list =
+			    ips_sg.std_list + i * IPS_MAX_SG;
+			scb_p->sg_busaddr =
+			    sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
+		}
+
+		/* add to the free list */
+		if (i < ha->max_cmds - 1) {
+			scb_p->q_next = ha->scb_freelist;
+			ha->scb_freelist = scb_p;
+		}
+	}
 
-   /* success */
-   return (1);
+	/* success */
+	return (1);
 }
 
 /****************************************************************************/
@@ -5144,36 +4637,37 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_init_scb(ips_ha_t *ha, ips_scb_t *scb) {
-   IPS_SG_LIST *sg_list;
-   uint32_t cmd_busaddr, sg_busaddr;
-   METHOD_TRACE("ips_init_scb", 1);
-
-   if (scb == NULL)
-      return ;
-
-   sg_list = scb->sg_list;
-   cmd_busaddr = scb->scb_busaddr;
-   sg_busaddr = scb->sg_busaddr;
-   /* zero fill */
-   memset(scb, 0, sizeof(ips_scb_t));
-   memset(ha->dummy, 0, sizeof(IPS_IO_CMD));
-
-   /* Initialize dummy command bucket */
-   ha->dummy->op_code = 0xFF;
-   ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start
-                                      + sizeof(IPS_ADAPTER));
-   ha->dummy->command_id = IPS_MAX_CMDS;
-
-   /* set bus address of scb */
-   scb->scb_busaddr = cmd_busaddr;
-   scb->sg_busaddr = sg_busaddr;
-   scb->sg_list = sg_list;
-
-   /* Neptune Fix */
-   scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE);
-   scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start
-                                           + sizeof(IPS_ADAPTER));
+ips_init_scb(ips_ha_t * ha, ips_scb_t * scb)
+{
+	IPS_SG_LIST sg_list;
+	uint32_t cmd_busaddr, sg_busaddr;
+	METHOD_TRACE("ips_init_scb", 1);
+
+	if (scb == NULL)
+		return;
+
+	sg_list.list = scb->sg_list.list;
+	cmd_busaddr = scb->scb_busaddr;
+	sg_busaddr = scb->sg_busaddr;
+	/* zero fill */
+	memset(scb, 0, sizeof (ips_scb_t));
+	memset(ha->dummy, 0, sizeof (IPS_IO_CMD));
+
+	/* Initialize dummy command bucket */
+	ha->dummy->op_code = 0xFF;
+	ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start
+				       + sizeof (IPS_ADAPTER));
+	ha->dummy->command_id = IPS_MAX_CMDS;
+
+	/* set bus address of scb */
+	scb->scb_busaddr = cmd_busaddr;
+	scb->sg_busaddr = sg_busaddr;
+	scb->sg_list.list = sg_list.list;
+
+	/* Neptune Fix */
+	scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE);
+	scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start
+					      + sizeof (IPS_ADAPTER));
 }
 
 /****************************************************************************/
@@ -5188,22 +4682,23 @@
 /*                                                                          */
 /****************************************************************************/
 static ips_scb_t *
-ips_getscb(ips_ha_t *ha) {
-   ips_scb_t     *scb;
+ips_getscb(ips_ha_t * ha)
+{
+	ips_scb_t *scb;
 
-   METHOD_TRACE("ips_getscb", 1);
+	METHOD_TRACE("ips_getscb", 1);
 
-   if ((scb = ha->scb_freelist) == NULL) {
+	if ((scb = ha->scb_freelist) == NULL) {
 
-      return (NULL);
-   }
+		return (NULL);
+	}
 
-   ha->scb_freelist = scb->q_next;
-   scb->q_next = NULL;
+	ha->scb_freelist = scb->q_next;
+	scb->q_next = NULL;
 
-   ips_init_scb(ha, scb);
+	ips_init_scb(ha, scb);
 
-   return (scb);
+	return (scb);
 }
 
 /****************************************************************************/
@@ -5218,22 +4713,22 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_freescb(ips_ha_t *ha, ips_scb_t *scb) {
+ips_freescb(ips_ha_t * ha, ips_scb_t * scb)
+{
 
-   METHOD_TRACE("ips_freescb", 1);
-   if(scb->flags & IPS_SCB_MAP_SG)
-      pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer,
-                   scb->scsi_cmd->use_sg,
-                   IPS_DMA_DIR(scb));
-   else if(scb->flags & IPS_SCB_MAP_SINGLE)
-      pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
-                       IPS_DMA_DIR(scb));
-
-   /* check to make sure this is not our "special" scb */
-   if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
-      scb->q_next = ha->scb_freelist;
-      ha->scb_freelist = scb;
-   }
+	METHOD_TRACE("ips_freescb", 1);
+	if (scb->flags & IPS_SCB_MAP_SG)
+		pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer,
+			     scb->scsi_cmd->use_sg, IPS_DMA_DIR(scb));
+	else if (scb->flags & IPS_SCB_MAP_SINGLE)
+		pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
+				 IPS_DMA_DIR(scb));
+
+	/* check to make sure this is not our "special" scb */
+	if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
+		scb->q_next = ha->scb_freelist;
+		ha->scb_freelist = scb;
+	}
 }
 
 /****************************************************************************/
@@ -5246,19 +4741,20 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_isinit_copperhead(ips_ha_t *ha) {
-   uint8_t scpr;
-   uint8_t isr;
-
-   METHOD_TRACE("ips_isinit_copperhead", 1);
-
-   isr = inb(ha->io_addr + IPS_REG_HISR);
-   scpr = inb(ha->io_addr + IPS_REG_SCPR);
-
-   if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
-       return (0);
-   else
-       return (1);
+ips_isinit_copperhead(ips_ha_t * ha)
+{
+	uint8_t scpr;
+	uint8_t isr;
+
+	METHOD_TRACE("ips_isinit_copperhead", 1);
+
+	isr = inb(ha->io_addr + IPS_REG_HISR);
+	scpr = inb(ha->io_addr + IPS_REG_SCPR);
+
+	if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
+		return (0);
+	else
+		return (1);
 }
 
 /****************************************************************************/
@@ -5271,19 +4767,20 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_isinit_copperhead_memio(ips_ha_t *ha) {
-   uint8_t isr=0;
-   uint8_t scpr;
-
-   METHOD_TRACE("ips_is_init_copperhead_memio", 1);
-
-   isr = readb(ha->mem_ptr + IPS_REG_HISR);
-   scpr = readb(ha->mem_ptr + IPS_REG_SCPR);
-
-   if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
-       return (0);
-   else
-       return (1);
+ips_isinit_copperhead_memio(ips_ha_t * ha)
+{
+	uint8_t isr = 0;
+	uint8_t scpr;
+
+	METHOD_TRACE("ips_is_init_copperhead_memio", 1);
+
+	isr = readb(ha->mem_ptr + IPS_REG_HISR);
+	scpr = readb(ha->mem_ptr + IPS_REG_SCPR);
+
+	if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
+		return (0);
+	else
+		return (1);
 }
 
 /****************************************************************************/
@@ -5296,21 +4793,22 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_isinit_morpheus(ips_ha_t *ha) {
-   uint32_t post;
-   uint32_t bits;
-
-   METHOD_TRACE("ips_is_init_morpheus", 1);
-
-   post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
-   bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
-
-   if (post == 0)
-       return (0);
-   else if (bits & 0x3)
-       return (0);
-   else
-       return (1);
+ips_isinit_morpheus(ips_ha_t * ha)
+{
+	uint32_t post;
+	uint32_t bits;
+
+	METHOD_TRACE("ips_is_init_morpheus", 1);
+
+	post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+	bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+	if (post == 0)
+		return (0);
+	else if (bits & 0x3)
+		return (0);
+	else
+		return (1);
 }
 
 /****************************************************************************/
@@ -5322,10 +4820,12 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_enable_int_copperhead(ips_ha_t *ha) {
-   METHOD_TRACE("ips_enable_int_copperhead", 1);
+ips_enable_int_copperhead(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_enable_int_copperhead", 1);
 
-   outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI);
+	outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI);
+	inb(ha->io_addr + IPS_REG_HISR);	// Ensure PCI Posting Completes
 }
 
 /****************************************************************************/
@@ -5337,10 +4837,12 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_enable_int_copperhead_memio(ips_ha_t *ha) {
-   METHOD_TRACE("ips_enable_int_copperhead_memio", 1);
+ips_enable_int_copperhead_memio(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_enable_int_copperhead_memio", 1);
 
-   writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
+	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
+	readb(ha->mem_ptr + IPS_REG_HISR);	// Ensure PCI Posting Completes
 }
 
 /****************************************************************************/
@@ -5352,14 +4854,16 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_enable_int_morpheus(ips_ha_t *ha) {
-   uint32_t  Oimr;
+ips_enable_int_morpheus(ips_ha_t * ha)
+{
+	uint32_t Oimr;
 
-   METHOD_TRACE("ips_enable_int_morpheus", 1);
+	METHOD_TRACE("ips_enable_int_morpheus", 1);
 
-   Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
-   Oimr &= ~0x08;
-   writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
+	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
+	Oimr &= ~0x08;
+	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
+	readl(ha->mem_ptr + IPS_REG_I960_OIMR);	// Ensure PCI Posting Completes
 }
 
 /****************************************************************************/
@@ -5372,86 +4876,88 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_init_copperhead(ips_ha_t *ha) {
-   uint8_t  Isr;
-   uint8_t  Cbsp;
-   uint8_t  PostByte[IPS_MAX_POST_BYTES];
-   uint8_t  ConfigByte[IPS_MAX_CONFIG_BYTES];
-   int      i, j;
-
-   METHOD_TRACE("ips_init_copperhead", 1);
-
-   for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
-      for (j = 0; j < 45; j++) {
-         Isr = inb(ha->io_addr + IPS_REG_HISR);
-         if (Isr & IPS_BIT_GHI)
-            break;
-
-         /* Delay for 1 Second */
-         MDELAY(IPS_ONE_SEC);
-       }
-
-      if (j >= 45)
-         /* error occurred */
-         return (0);
-
-      PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
-      outb(Isr, ha->io_addr + IPS_REG_HISR);
-   }
-
-   if (PostByte[0] < IPS_GOOD_POST_STATUS) {
-      printk(KERN_WARNING "(%s%d) reset controller fails (post status %x %x).\n",
-             ips_name, ha->host_num, PostByte[0], PostByte[1]);
-
-      return (0);
-   }
-
-   for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
-      for (j = 0; j < 240; j++) {
-         Isr = inb(ha->io_addr + IPS_REG_HISR);
-         if (Isr & IPS_BIT_GHI)
-            break;
-
-         /* Delay for 1 Second */
-         MDELAY(IPS_ONE_SEC);
-      }
-
-      if (j >= 240)
-         /* error occurred */
-         return (0);
-
-      ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
-      outb(Isr, ha->io_addr + IPS_REG_HISR);
-   }
-
-   for (i = 0; i < 240; i++) {
-      Cbsp = inb(ha->io_addr + IPS_REG_CBSP);
-
-      if ((Cbsp & IPS_BIT_OP) == 0)
-         break; 
-
-      /* Delay for 1 Second */
-      MDELAY(IPS_ONE_SEC);
-   }
-
-   if (i >= 240)
-      /* reset failed */
-      return (0);
-
-   /* setup CCCR */
-   outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR);
-
-   /* Enable busmastering */
-   outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
-
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      /* fix for anaconda64 */
-      outl(0, ha->io_addr + IPS_REG_NDAE);
+ips_init_copperhead(ips_ha_t * ha)
+{
+	uint8_t Isr;
+	uint8_t Cbsp;
+	uint8_t PostByte[IPS_MAX_POST_BYTES];
+	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
+	int i, j;
+
+	METHOD_TRACE("ips_init_copperhead", 1);
+
+	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
+		for (j = 0; j < 45; j++) {
+			Isr = inb(ha->io_addr + IPS_REG_HISR);
+			if (Isr & IPS_BIT_GHI)
+				break;
+
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (j >= 45)
+			/* error occurred */
+			return (0);
+
+		PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
+		outb(Isr, ha->io_addr + IPS_REG_HISR);
+	}
+
+	if (PostByte[0] < IPS_GOOD_POST_STATUS) {
+		printk(KERN_WARNING
+		       "(%s%d) reset controller fails (post status %x %x).\n",
+		       ips_name, ha->host_num, PostByte[0], PostByte[1]);
+
+		return (0);
+	}
+
+	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
+		for (j = 0; j < 240; j++) {
+			Isr = inb(ha->io_addr + IPS_REG_HISR);
+			if (Isr & IPS_BIT_GHI)
+				break;
+
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (j >= 240)
+			/* error occurred */
+			return (0);
+
+		ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
+		outb(Isr, ha->io_addr + IPS_REG_HISR);
+	}
+
+	for (i = 0; i < 240; i++) {
+		Cbsp = inb(ha->io_addr + IPS_REG_CBSP);
+
+		if ((Cbsp & IPS_BIT_OP) == 0)
+			break;
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+	}
+
+	if (i >= 240)
+		/* reset failed */
+		return (0);
+
+	/* setup CCCR */
+	outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR);
+
+	/* Enable busmastering */
+	outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
+
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		/* fix for anaconda64 */
+		outl(0, ha->io_addr + IPS_REG_NDAE);
 
-   /* Enable interrupts */
-   outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);
+	/* Enable interrupts */
+	outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -5464,87 +4970,89 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_init_copperhead_memio(ips_ha_t *ha) {
-   uint8_t  Isr=0;
-   uint8_t  Cbsp;
-   uint8_t  PostByte[IPS_MAX_POST_BYTES];
-   uint8_t  ConfigByte[IPS_MAX_CONFIG_BYTES];
-   int      i, j;
-
-   METHOD_TRACE("ips_init_copperhead_memio", 1);
-
-   for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
-      for (j = 0; j < 45; j++) {
-         Isr = readb(ha->mem_ptr + IPS_REG_HISR);
-         if (Isr & IPS_BIT_GHI)
-            break;
-
-         /* Delay for 1 Second */
-         MDELAY(IPS_ONE_SEC);
-      }
-
-      if (j >= 45)
-         /* error occurred */
-         return (0);
-
-      PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
-      writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
-   }
-
-   if (PostByte[0] < IPS_GOOD_POST_STATUS) {
-      printk(KERN_WARNING "(%s%d) reset controller fails (post status %x %x).\n",
-             ips_name, ha->host_num, PostByte[0], PostByte[1]);
-
-      return (0);
-   }
-
-   for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
-      for (j = 0; j < 240; j++) {
-         Isr = readb(ha->mem_ptr + IPS_REG_HISR);
-         if (Isr & IPS_BIT_GHI)
-            break;
-
-         /* Delay for 1 Second */
-         MDELAY(IPS_ONE_SEC);
-      }
-
-      if (j >= 240)
-         /* error occurred */
-         return (0);
-
-      ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
-      writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
-   }
-
-   for (i = 0; i < 240; i++) {
-      Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP);
-
-      if ((Cbsp & IPS_BIT_OP) == 0)
-         break;
-
-      /* Delay for 1 Second */
-      MDELAY(IPS_ONE_SEC);
-   }
-
-   if (i >= 240)
-      /* error occurred */
-      return (0);
-
-   /* setup CCCR */
-   writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);
-
-   /* Enable busmastering */
-   writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
-
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      /* fix for anaconda64 */
-      writel(0, ha->mem_ptr + IPS_REG_NDAE);
+ips_init_copperhead_memio(ips_ha_t * ha)
+{
+	uint8_t Isr = 0;
+	uint8_t Cbsp;
+	uint8_t PostByte[IPS_MAX_POST_BYTES];
+	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
+	int i, j;
+
+	METHOD_TRACE("ips_init_copperhead_memio", 1);
+
+	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
+		for (j = 0; j < 45; j++) {
+			Isr = readb(ha->mem_ptr + IPS_REG_HISR);
+			if (Isr & IPS_BIT_GHI)
+				break;
+
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (j >= 45)
+			/* error occurred */
+			return (0);
+
+		PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
+		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
+	}
+
+	if (PostByte[0] < IPS_GOOD_POST_STATUS) {
+		printk(KERN_WARNING
+		       "(%s%d) reset controller fails (post status %x %x).\n",
+		       ips_name, ha->host_num, PostByte[0], PostByte[1]);
+
+		return (0);
+	}
+
+	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
+		for (j = 0; j < 240; j++) {
+			Isr = readb(ha->mem_ptr + IPS_REG_HISR);
+			if (Isr & IPS_BIT_GHI)
+				break;
+
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (j >= 240)
+			/* error occurred */
+			return (0);
+
+		ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
+		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
+	}
+
+	for (i = 0; i < 240; i++) {
+		Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP);
+
+		if ((Cbsp & IPS_BIT_OP) == 0)
+			break;
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+	}
+
+	if (i >= 240)
+		/* error occurred */
+		return (0);
+
+	/* setup CCCR */
+	writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);
+
+	/* Enable busmastering */
+	writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
+
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		/* fix for anaconda64 */
+		writel(0, ha->mem_ptr + IPS_REG_NDAE);
 
-   /* Enable interrupts */
-   writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
+	/* Enable interrupts */
+	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
 
-   /* if we get here then everything went OK */
-   return (1);
+	/* if we get here then everything went OK */
+	return (1);
 }
 
 /****************************************************************************/
@@ -5557,109 +5065,112 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_init_morpheus(ips_ha_t *ha) {
-   uint32_t  Post;
-   uint32_t  Config;
-   uint32_t  Isr;
-   uint32_t  Oimr;
-   int       i;
-
-   METHOD_TRACE("ips_init_morpheus", 1);
-
-   /* Wait up to 45 secs for Post */
-   for (i = 0; i < 45; i++) {
-      Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
-
-      if (Isr & IPS_BIT_I960_MSG0I)
-         break;
-
-      /* Delay for 1 Second */
-      MDELAY(IPS_ONE_SEC);
-   }
-
-   if (i >= 45) {
-      /* error occurred */
-      printk(KERN_WARNING "(%s%d) timeout waiting for post.\n",
-             ips_name, ha->host_num);
-
-      return (0);
-   }
-
-   Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
-
-   if (Post == 0x4F00) {                          /* If Flashing the Battery PIC         */
-       printk(KERN_WARNING "Flashing Battery PIC, Please wait ...\n" );
-
-       /* Clear the interrupt bit */
-       Isr = (uint32_t) IPS_BIT_I960_MSG0I;
-       writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
-
-       for (i = 0; i < 120; i++) {                /*    Wait Up to 2 Min. for Completion */
-          Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
-          if (Post != 0x4F00)
-              break;
-          /* Delay for 1 Second */
-          MDELAY(IPS_ONE_SEC);
-       }
-
-       if (i >= 120) {
-          printk(KERN_WARNING "(%s%d) timeout waiting for Battery PIC Flash\n",
-                 ips_name, ha->host_num);
-          return (0);
-       }
-
-   }
-
-   /* Clear the interrupt bit */
-   Isr = (uint32_t) IPS_BIT_I960_MSG0I;
-   writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
-
-   if (Post < (IPS_GOOD_POST_STATUS << 8)) {
-      printk(KERN_WARNING "(%s%d) reset controller fails (post status %x).\n",
-             ips_name, ha->host_num, Post);
-
-      return (0);
-   }
-
-   /* Wait up to 240 secs for config bytes */
-   for (i = 0; i < 240; i++) {
-      Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
-
-      if (Isr & IPS_BIT_I960_MSG1I)
-         break;
-
-      /* Delay for 1 Second */
-      MDELAY(IPS_ONE_SEC);
-   }
-
-   if (i >= 240) {
-      /* error occurred */
-      printk(KERN_WARNING "(%s%d) timeout waiting for config.\n",
-             ips_name, ha->host_num);
-
-      return (0);
-   }
-
-   Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
-
-   /* Clear interrupt bit */
-   Isr = (uint32_t) IPS_BIT_I960_MSG1I;
-   writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
-
-   /* Turn on the interrupts */
-   Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
-   Oimr &= ~0x8;
-   writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
-
-   /* if we get here then everything went OK */
-
-   /* Since we did a RESET, an EraseStripeLock may be needed */
-   if (Post == 0xEF10) {
-      if ( (Config == 0x000F) || (Config == 0x0009) )
-         ha->requires_esl = 1;
-   }
+ips_init_morpheus(ips_ha_t * ha)
+{
+	uint32_t Post;
+	uint32_t Config;
+	uint32_t Isr;
+	uint32_t Oimr;
+	int i;
+
+	METHOD_TRACE("ips_init_morpheus", 1);
+
+	/* Wait up to 45 secs for Post */
+	for (i = 0; i < 45; i++) {
+		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+		if (Isr & IPS_BIT_I960_MSG0I)
+			break;
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+	}
+
+	if (i >= 45) {
+		/* error occurred */
+		printk(KERN_WARNING "(%s%d) timeout waiting for post.\n",
+		       ips_name, ha->host_num);
+
+		return (0);
+	}
+
+	Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+
+	if (Post == 0x4F00) {	/* If Flashing the Battery PIC         */
+		printk(KERN_WARNING "Flashing Battery PIC, Please wait ...\n");
+
+		/* Clear the interrupt bit */
+		Isr = (uint32_t) IPS_BIT_I960_MSG0I;
+		writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
+
+		for (i = 0; i < 120; i++) {	/*    Wait Up to 2 Min. for Completion */
+			Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+			if (Post != 0x4F00)
+				break;
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (i >= 120) {
+			printk(KERN_WARNING
+			       "(%s%d) timeout waiting for Battery PIC Flash\n",
+			       ips_name, ha->host_num);
+			return (0);
+		}
+
+	}
+
+	/* Clear the interrupt bit */
+	Isr = (uint32_t) IPS_BIT_I960_MSG0I;
+	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
+
+	if (Post < (IPS_GOOD_POST_STATUS << 8)) {
+		printk(KERN_WARNING
+		       "(%s%d) reset controller fails (post status %x).\n",
+		       ips_name, ha->host_num, Post);
+
+		return (0);
+	}
+
+	/* Wait up to 240 secs for config bytes */
+	for (i = 0; i < 240; i++) {
+		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+		if (Isr & IPS_BIT_I960_MSG1I)
+			break;
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+	}
+
+	if (i >= 240) {
+		/* error occurred */
+		printk(KERN_WARNING "(%s%d) timeout waiting for config.\n",
+		       ips_name, ha->host_num);
+
+		return (0);
+	}
+
+	Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
+
+	/* Clear interrupt bit */
+	Isr = (uint32_t) IPS_BIT_I960_MSG1I;
+	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
+
+	/* Turn on the interrupts */
+	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
+	Oimr &= ~0x8;
+	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
+
+	/* if we get here then everything went OK */
+
+	/* Since we did a RESET, an EraseStripeLock may be needed */
+	if (Post == 0xEF10) {
+		if ((Config == 0x000F) || (Config == 0x0009))
+			ha->requires_esl = 1;
+	}
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -5672,38 +5183,39 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_reset_copperhead(ips_ha_t *ha) {
-   int reset_counter;
+ips_reset_copperhead(ips_ha_t * ha)
+{
+	int reset_counter;
 
-   METHOD_TRACE("ips_reset_copperhead", 1);
+	METHOD_TRACE("ips_reset_copperhead", 1);
 
-   DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
-             ips_name, ha->host_num, ha->io_addr, ha->irq);
+	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
+		  ips_name, ha->host_num, ha->io_addr, ha->irq);
 
-   reset_counter = 0;
+	reset_counter = 0;
 
-   while (reset_counter < 2) {
-      reset_counter++;
+	while (reset_counter < 2) {
+		reset_counter++;
 
-      outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
+		outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
 
-      /* Delay for 1 Second */
-      MDELAY(IPS_ONE_SEC);
- 
-      outb(0, ha->io_addr + IPS_REG_SCPR);
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
 
-      /* Delay for 1 Second */
-      MDELAY(IPS_ONE_SEC);
-      
-      if ((*ha->func.init)(ha))
-         break;
-      else if (reset_counter >= 2) {
+		outb(0, ha->io_addr + IPS_REG_SCPR);
 
-         return (0);
-      }
-   }
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
 
-   return (1);
+		if ((*ha->func.init) (ha))
+			break;
+		else if (reset_counter >= 2) {
+
+			return (0);
+		}
+	}
+
+	return (1);
 }
 
 /****************************************************************************/
@@ -5716,38 +5228,39 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_reset_copperhead_memio(ips_ha_t *ha) {
-   int reset_counter;
+ips_reset_copperhead_memio(ips_ha_t * ha)
+{
+	int reset_counter;
 
-   METHOD_TRACE("ips_reset_copperhead_memio", 1);
+	METHOD_TRACE("ips_reset_copperhead_memio", 1);
 
-   DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
-             ips_name, ha->host_num, ha->mem_addr, ha->irq);
+	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
+		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
 
-   reset_counter = 0;
+	reset_counter = 0;
 
-   while (reset_counter < 2) {
-      reset_counter++;
+	while (reset_counter < 2) {
+		reset_counter++;
 
-      writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
+		writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
 
-      /* Delay for 1 Second */
-      MDELAY(IPS_ONE_SEC);
- 
-      writeb(0, ha->mem_ptr + IPS_REG_SCPR);
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
 
-      /* Delay for 1 Second */
-      MDELAY(IPS_ONE_SEC);
- 
-      if ((*ha->func.init)(ha))
-         break;
-      else if (reset_counter >= 2) {
+		writeb(0, ha->mem_ptr + IPS_REG_SCPR);
 
-         return (0);
-      }
-   }
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
 
-   return (1);
+		if ((*ha->func.init) (ha))
+			break;
+		else if (reset_counter >= 2) {
+
+			return (0);
+		}
+	}
+
+	return (1);
 }
 
 /****************************************************************************/
@@ -5760,37 +5273,38 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_reset_morpheus(ips_ha_t *ha) {
-   int           reset_counter;
-   uint8_t       junk;
+ips_reset_morpheus(ips_ha_t * ha)
+{
+	int reset_counter;
+	uint8_t junk;
+
+	METHOD_TRACE("ips_reset_morpheus", 1);
 
-   METHOD_TRACE("ips_reset_morpheus", 1);
+	DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
+		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
 
-   DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
-             ips_name, ha->host_num, ha->mem_addr, ha->irq);
+	reset_counter = 0;
 
-   reset_counter = 0;
+	while (reset_counter < 2) {
+		reset_counter++;
 
-   while (reset_counter < 2) {
-      reset_counter++;
+		writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
 
-      writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
+		/* Delay for 5 Seconds */
+		MDELAY(5 * IPS_ONE_SEC);
 
-      /* Delay for 5 Seconds */
-      MDELAY(5 * IPS_ONE_SEC);
- 
-      /* Do a PCI config read to wait for adapter */
-      pci_read_config_byte(ha->pcidev, 4, &junk);
+		/* Do a PCI config read to wait for adapter */
+		pci_read_config_byte(ha->pcidev, 4, &junk);
 
-      if ((*ha->func.init)(ha))
-         break;
-      else if (reset_counter >= 2) {
+		if ((*ha->func.init) (ha))
+			break;
+		else if (reset_counter >= 2) {
 
-         return (0);
-      }
-   }
+			return (0);
+		}
+	}
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -5803,22 +5317,25 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_statinit(ips_ha_t *ha) {
-   uint32_t phys_status_start;
+ips_statinit(ips_ha_t * ha)
+{
+	uint32_t phys_status_start;
 
-   METHOD_TRACE("ips_statinit", 1);
+	METHOD_TRACE("ips_statinit", 1);
 
-   ha->adapt->p_status_start = ha->adapt->status;
-   ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
-   ha->adapt->p_status_tail = ha->adapt->status;
-
-   phys_status_start = ha->adapt->hw_status_start;
-   outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR);
-   outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE), ha->io_addr + IPS_REG_SQER);
-   outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE), ha->io_addr + IPS_REG_SQHR);
-   outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR);
+	ha->adapt->p_status_start = ha->adapt->status;
+	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
+	ha->adapt->p_status_tail = ha->adapt->status;
+
+	phys_status_start = ha->adapt->hw_status_start;
+	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR);
+	outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE),
+	     ha->io_addr + IPS_REG_SQER);
+	outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE),
+	     ha->io_addr + IPS_REG_SQHR);
+	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR);
 
-   ha->adapt->hw_status_tail = phys_status_start;
+	ha->adapt->hw_status_tail = phys_status_start;
 }
 
 /****************************************************************************/
@@ -5831,22 +5348,24 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_statinit_memio(ips_ha_t *ha) {
-   uint32_t phys_status_start;
+ips_statinit_memio(ips_ha_t * ha)
+{
+	uint32_t phys_status_start;
 
-   METHOD_TRACE("ips_statinit_memio", 1);
+	METHOD_TRACE("ips_statinit_memio", 1);
 
-   ha->adapt->p_status_start = ha->adapt->status;
-   ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
-   ha->adapt->p_status_tail = ha->adapt->status;
-
-   phys_status_start = ha->adapt->hw_status_start;
-   writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);
-   writel(phys_status_start + IPS_STATUS_Q_SIZE, ha->mem_ptr + IPS_REG_SQER);
-   writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);
-   writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);
+	ha->adapt->p_status_start = ha->adapt->status;
+	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
+	ha->adapt->p_status_tail = ha->adapt->status;
+
+	phys_status_start = ha->adapt->hw_status_start;
+	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);
+	writel(phys_status_start + IPS_STATUS_Q_SIZE,
+	       ha->mem_ptr + IPS_REG_SQER);
+	writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);
+	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);
 
-   ha->adapt->hw_status_tail = phys_status_start;
+	ha->adapt->hw_status_tail = phys_status_start;
 }
 
 /****************************************************************************/
@@ -5859,20 +5378,22 @@
 /*                                                                          */
 /****************************************************************************/
 static uint32_t
-ips_statupd_copperhead(ips_ha_t *ha) {
-   METHOD_TRACE("ips_statupd_copperhead", 1);
+ips_statupd_copperhead(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_statupd_copperhead", 1);
 
-   if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
-      ha->adapt->p_status_tail++;
-      ha->adapt->hw_status_tail += sizeof(IPS_STATUS);
-   } else {
-      ha->adapt->p_status_tail = ha->adapt->p_status_start;
-      ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
-   }
+	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
+		ha->adapt->p_status_tail++;
+		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
+	} else {
+		ha->adapt->p_status_tail = ha->adapt->p_status_start;
+		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
+	}
 
-   outl(cpu_to_le32(ha->adapt->hw_status_tail), ha->io_addr + IPS_REG_SQTR);
+	outl(cpu_to_le32(ha->adapt->hw_status_tail),
+	     ha->io_addr + IPS_REG_SQTR);
 
-   return (ha->adapt->p_status_tail->value);
+	return (ha->adapt->p_status_tail->value);
 }
 
 /****************************************************************************/
@@ -5885,20 +5406,21 @@
 /*                                                                          */
 /****************************************************************************/
 static uint32_t
-ips_statupd_copperhead_memio(ips_ha_t *ha) {
-   METHOD_TRACE("ips_statupd_copperhead_memio", 1);
+ips_statupd_copperhead_memio(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_statupd_copperhead_memio", 1);
 
-   if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
-      ha->adapt->p_status_tail++;
-      ha->adapt->hw_status_tail += sizeof(IPS_STATUS);
-   } else {
-      ha->adapt->p_status_tail = ha->adapt->p_status_start;
-      ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
-   }
+	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
+		ha->adapt->p_status_tail++;
+		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
+	} else {
+		ha->adapt->p_status_tail = ha->adapt->p_status_start;
+		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
+	}
 
-   writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);
+	writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);
 
-   return (ha->adapt->p_status_tail->value);
+	return (ha->adapt->p_status_tail->value);
 }
 
 /****************************************************************************/
@@ -5911,14 +5433,15 @@
 /*                                                                          */
 /****************************************************************************/
 static uint32_t
-ips_statupd_morpheus(ips_ha_t *ha) {
-   uint32_t val;
+ips_statupd_morpheus(ips_ha_t * ha)
+{
+	uint32_t val;
 
-   METHOD_TRACE("ips_statupd_morpheus", 1);
+	METHOD_TRACE("ips_statupd_morpheus", 1);
 
-   val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);
+	val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);
 
-   return (val);
+	return (val);
 }
 
 /****************************************************************************/
@@ -5931,50 +5454,49 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_issue_copperhead(ips_ha_t *ha, ips_scb_t *scb) {
-   uint32_t TimeOut;
-   uint32_t val;
-
-   METHOD_TRACE("ips_issue_copperhead", 1);
-
-   if (scb->scsi_cmd) {
-      DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
-                ips_name,
-                ha->host_num,
-                scb->cdb[0],
-                scb->cmd.basic_io.command_id,
-                scb->bus,
-                scb->target_id,
-                scb->lun);
-   } else {
-      DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d",
-                ips_name,
-                ha->host_num,
-                scb->cmd.basic_io.command_id);
-   }
-
-   TimeOut = 0;
-
-   while ((val = le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) {
-      udelay(1000);
-
-      if (++TimeOut >= IPS_SEM_TIMEOUT) {
-         if (!(val & IPS_BIT_START_STOP))
-            break;
-
-         printk(KERN_WARNING "(%s%d) ips_issue val [0x%x].\n",
-                ips_name, ha->host_num, val);
-         printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n",
-                ips_name, ha->host_num);
-
-         return (IPS_FAILURE);
-      } /* end if */
-   } /* end while */
+ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb)
+{
+	uint32_t TimeOut;
+	uint32_t val;
 
-   outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR);
-   outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR);
+	METHOD_TRACE("ips_issue_copperhead", 1);
 
-   return (IPS_SUCCESS);
+	if (scb->scsi_cmd) {
+		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+			  ips_name,
+			  ha->host_num,
+			  scb->cdb[0],
+			  scb->cmd.basic_io.command_id,
+			  scb->bus, scb->target_id, scb->lun);
+	} else {
+		DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d",
+			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
+	}
+
+	TimeOut = 0;
+
+	while ((val = le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) &
+	       IPS_BIT_SEM) {
+		udelay(1000);
+
+		if (++TimeOut >= IPS_SEM_TIMEOUT) {
+			if (!(val & IPS_BIT_START_STOP))
+				break;
+
+			printk(KERN_WARNING "(%s%d) ips_issue val [0x%x].\n",
+			       ips_name, ha->host_num, val);
+			printk(KERN_WARNING
+			       "(%s%d) ips_issue semaphore chk timeout.\n",
+			       ips_name, ha->host_num);
+
+			return (IPS_FAILURE);
+		}		/* end if */
+	}			/* end while */
+
+	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR);
+	outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR);
+
+	return (IPS_SUCCESS);
 }
 
 /****************************************************************************/
@@ -5987,50 +5509,48 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_issue_copperhead_memio(ips_ha_t *ha, ips_scb_t *scb) {
-   uint32_t      TimeOut;
-   uint32_t      val;
-
-   METHOD_TRACE("ips_issue_copperhead_memio", 1);
-
-   if (scb->scsi_cmd) {
-      DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
-                ips_name,
-                ha->host_num,
-                scb->cdb[0],
-                scb->cmd.basic_io.command_id,
-                scb->bus,
-                scb->target_id,
-                scb->lun);
-   } else {
-      DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
-                ips_name,
-                ha->host_num,
-                scb->cmd.basic_io.command_id);
-   }
-
-   TimeOut = 0;
-
-   while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
-      udelay(1000);
-
-      if (++TimeOut >= IPS_SEM_TIMEOUT) {
-         if (!(val & IPS_BIT_START_STOP))
-            break;
-
-         printk(KERN_WARNING "(%s%d) ips_issue val [0x%x].\n",
-                ips_name, ha->host_num, val);
-         printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n",
-                ips_name, ha->host_num);
-
-         return (IPS_FAILURE);
-      } /* end if */
-   } /* end while */
+ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb)
+{
+	uint32_t TimeOut;
+	uint32_t val;
 
-   writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
-   writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
+	METHOD_TRACE("ips_issue_copperhead_memio", 1);
 
-   return (IPS_SUCCESS);
+	if (scb->scsi_cmd) {
+		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+			  ips_name,
+			  ha->host_num,
+			  scb->cdb[0],
+			  scb->cmd.basic_io.command_id,
+			  scb->bus, scb->target_id, scb->lun);
+	} else {
+		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
+			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
+	}
+
+	TimeOut = 0;
+
+	while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
+		udelay(1000);
+
+		if (++TimeOut >= IPS_SEM_TIMEOUT) {
+			if (!(val & IPS_BIT_START_STOP))
+				break;
+
+			printk(KERN_WARNING "(%s%d) ips_issue val [0x%x].\n",
+			       ips_name, ha->host_num, val);
+			printk(KERN_WARNING
+			       "(%s%d) ips_issue semaphore chk timeout.\n",
+			       ips_name, ha->host_num);
+
+			return (IPS_FAILURE);
+		}		/* end if */
+	}			/* end while */
+
+	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
+	writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
+
+	return (IPS_SUCCESS);
 }
 
 /****************************************************************************/
@@ -6043,29 +5563,26 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_issue_i2o(ips_ha_t *ha, ips_scb_t *scb) {
+ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb)
+{
 
-   METHOD_TRACE("ips_issue_i2o", 1);
+	METHOD_TRACE("ips_issue_i2o", 1);
 
-   if (scb->scsi_cmd) {
-      DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
-                ips_name,
-                ha->host_num,
-                scb->cdb[0],
-                scb->cmd.basic_io.command_id,
-                scb->bus,
-                scb->target_id,
-                scb->lun);
-   } else {
-      DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
-                ips_name,
-                ha->host_num,
-                scb->cmd.basic_io.command_id);
-   }
+	if (scb->scsi_cmd) {
+		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+			  ips_name,
+			  ha->host_num,
+			  scb->cdb[0],
+			  scb->cmd.basic_io.command_id,
+			  scb->bus, scb->target_id, scb->lun);
+	} else {
+		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
+			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
+	}
 
-   outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ);
+	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ);
 
-   return (IPS_SUCCESS);
+	return (IPS_SUCCESS);
 }
 
 /****************************************************************************/
@@ -6078,29 +5595,26 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_issue_i2o_memio(ips_ha_t *ha, ips_scb_t *scb) {
+ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb)
+{
 
-   METHOD_TRACE("ips_issue_i2o_memio", 1);
+	METHOD_TRACE("ips_issue_i2o_memio", 1);
 
-   if (scb->scsi_cmd) {
-      DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
-                ips_name,
-                ha->host_num,
-                scb->cdb[0],
-                scb->cmd.basic_io.command_id,
-                scb->bus,
-                scb->target_id,
-                scb->lun);
-   } else {
-      DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
-                ips_name,
-                ha->host_num,
-                scb->cmd.basic_io.command_id);
-   }
+	if (scb->scsi_cmd) {
+		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+			  ips_name,
+			  ha->host_num,
+			  scb->cdb[0],
+			  scb->cmd.basic_io.command_id,
+			  scb->bus, scb->target_id, scb->lun);
+	} else {
+		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
+			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
+	}
 
-   writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
+	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
 
-   return (IPS_SUCCESS);
+	return (IPS_SUCCESS);
 }
 
 /****************************************************************************/
@@ -6113,26 +5627,27 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_isintr_copperhead(ips_ha_t *ha) {
-   uint8_t Isr;
+ips_isintr_copperhead(ips_ha_t * ha)
+{
+	uint8_t Isr;
+
+	METHOD_TRACE("ips_isintr_copperhead", 2);
 
-   METHOD_TRACE("ips_isintr_copperhead", 2);
+	Isr = inb(ha->io_addr + IPS_REG_HISR);
 
-   Isr = inb(ha->io_addr + IPS_REG_HISR);
+	if (Isr == 0xFF)
+		/* ?!?! Nothing really there */
+		return (0);
 
-   if (Isr == 0xFF)
-      /* ?!?! Nothing really there */
-      return (0);
-
-   if (Isr & IPS_BIT_SCE)
-      return (1);
-   else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
-      /* status queue overflow or GHI */
-      /* just clear the interrupt */
-      outb(Isr, ha->io_addr + IPS_REG_HISR);
-   }
+	if (Isr & IPS_BIT_SCE)
+		return (1);
+	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
+		/* status queue overflow or GHI */
+		/* just clear the interrupt */
+		outb(Isr, ha->io_addr + IPS_REG_HISR);
+	}
 
-   return (0);
+	return (0);
 }
 
 /****************************************************************************/
@@ -6145,26 +5660,27 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_isintr_copperhead_memio(ips_ha_t *ha) {
-   uint8_t Isr;
+ips_isintr_copperhead_memio(ips_ha_t * ha)
+{
+	uint8_t Isr;
 
-   METHOD_TRACE("ips_isintr_memio", 2);
+	METHOD_TRACE("ips_isintr_memio", 2);
 
-   Isr = readb(ha->mem_ptr + IPS_REG_HISR);
+	Isr = readb(ha->mem_ptr + IPS_REG_HISR);
 
-   if (Isr == 0xFF)
-      /* ?!?! Nothing really there */
-      return (0);
-
-   if (Isr & IPS_BIT_SCE)
-      return (1);
-   else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
-      /* status queue overflow or GHI */
-      /* just clear the interrupt */
-      writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
-   }
+	if (Isr == 0xFF)
+		/* ?!?! Nothing really there */
+		return (0);
 
-   return (0);
+	if (Isr & IPS_BIT_SCE)
+		return (1);
+	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
+		/* status queue overflow or GHI */
+		/* just clear the interrupt */
+		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
+	}
+
+	return (0);
 }
 
 /****************************************************************************/
@@ -6177,17 +5693,18 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_isintr_morpheus(ips_ha_t *ha) {
-   uint32_t Isr;
+ips_isintr_morpheus(ips_ha_t * ha)
+{
+	uint32_t Isr;
 
-   METHOD_TRACE("ips_isintr_morpheus", 2);
+	METHOD_TRACE("ips_isintr_morpheus", 2);
 
-   Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+	Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
 
-   if (Isr & IPS_BIT_I2O_OPQI)
-      return (1);
-   else
-      return (0);
+	if (Isr & IPS_BIT_I2O_OPQI)
+		return (1);
+	else
+		return (0);
 }
 
 /****************************************************************************/
@@ -6200,51 +5717,52 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_wait(ips_ha_t *ha, int time, int intr) {
-   int   ret;
-   int   done;
-
-   METHOD_TRACE("ips_wait", 1);
-
-   ret = IPS_FAILURE;
-   done = FALSE;
-
-   time *= IPS_ONE_SEC;                       /* convert seconds */
-
-   while ((time > 0) && (!done)) {
-      if (intr == IPS_INTR_ON) {
-         if (ha->waitflag == FALSE) {
-            ret = IPS_SUCCESS;
-            done = TRUE;
-            break;
-         }
-      } else if (intr == IPS_INTR_IORL) {
-         if (ha->waitflag == FALSE) {
-            /*
-             * controller generated an interrupt to
-             * acknowledge completion of the command
-             * and ips_intr() has serviced the interrupt.
-             */
-            ret = IPS_SUCCESS;
-            done = TRUE;
-            break;
-         }
-
-         /*
-          * NOTE: we already have the io_request_lock so
-          * even if we get an interrupt it won't get serviced
-          * until after we finish.
-          */
-
-         (*ha->func.intr)(ha);
-      } 
-
-      /* This looks like a very evil loop, but it only does this during start-up */
-      udelay(1000);        
-      time--;
-   }
+ips_wait(ips_ha_t * ha, int time, int intr)
+{
+	int ret;
+	int done;
+
+	METHOD_TRACE("ips_wait", 1);
 
-   return (ret);
+	ret = IPS_FAILURE;
+	done = FALSE;
+
+	time *= IPS_ONE_SEC;	/* convert seconds */
+
+	while ((time > 0) && (!done)) {
+		if (intr == IPS_INTR_ON) {
+			if (ha->waitflag == FALSE) {
+				ret = IPS_SUCCESS;
+				done = TRUE;
+				break;
+			}
+		} else if (intr == IPS_INTR_IORL) {
+			if (ha->waitflag == FALSE) {
+				/*
+				 * controller generated an interrupt to
+				 * acknowledge completion of the command
+				 * and ips_intr() has serviced the interrupt.
+				 */
+				ret = IPS_SUCCESS;
+				done = TRUE;
+				break;
+			}
+
+			/*
+			 * NOTE: we already have the io_request_lock so
+			 * even if we get an interrupt it won't get serviced
+			 * until after we finish.
+			 */
+
+			(*ha->func.intr) (ha);
+		}
+
+		/* This looks like a very evil loop, but it only does this during start-up */
+		udelay(1000);
+		time--;
+	}
+
+	return (ret);
 }
 
 /****************************************************************************/
@@ -6257,61 +5775,59 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_write_driver_status(ips_ha_t *ha, int intr) {
-   METHOD_TRACE("ips_write_driver_status", 1);
-
-   if (!ips_readwrite_page5(ha, FALSE, intr)) {
-      printk(KERN_WARNING "(%s%d) unable to read NVRAM page 5.\n",
-             ips_name, ha->host_num);
-
-      return (0);
-   }
-
-   /* check to make sure the page has a valid */
-   /* signature */
-   if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) {
-      DEBUG_VAR(1, "(%s%d) NVRAM page 5 has an invalid signature: %X.",
-                ips_name, ha->host_num, ha->nvram->signature);
-      ha->nvram->signature = IPS_NVRAM_P5_SIG;
-   }
-
-   DEBUG_VAR(2, "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.",
-             ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type),
-             ha->nvram->adapter_slot,
-             ha->nvram->bios_high[0], ha->nvram->bios_high[1],
-             ha->nvram->bios_high[2], ha->nvram->bios_high[3],
-             ha->nvram->bios_low[0], ha->nvram->bios_low[1],
-             ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
-
-   ips_get_bios_version(ha, intr);
-
-   /* change values (as needed) */
-   ha->nvram->operating_system = IPS_OS_LINUX;
-   ha->nvram->adapter_type = ha->ad_type;
-   strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4);
-   strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4);
-   strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4);
-   strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);
-
-   ips_version_check(ha, intr);                           /* Check BIOS/FW/Driver Versions */
-
-   /* Save the First Copy of the Adapter Order that BIOS put in Page 5 */
-   if ( (InitState == 0) && (AdapterOrder[0] == 0) ) 
-      strncpy((char *) AdapterOrder, (char *) ha->nvram->adapter_order, sizeof(AdapterOrder) );
-
-   /* now update the page */
-   if (!ips_readwrite_page5(ha, TRUE, intr)) {
-      printk(KERN_WARNING "(%s%d) unable to write NVRAM page 5.\n",
-             ips_name, ha->host_num);
+ips_write_driver_status(ips_ha_t * ha, int intr)
+{
+	METHOD_TRACE("ips_write_driver_status", 1);
 
-      return (0);
-   }
+	if (!ips_readwrite_page5(ha, FALSE, intr)) {
+		printk(KERN_WARNING "(%s%d) unable to read NVRAM page 5.\n",
+		       ips_name, ha->host_num);
+
+		return (0);
+	}
+
+	/* check to make sure the page has a valid */
+	/* signature */
+	if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) {
+		DEBUG_VAR(1,
+			  "(%s%d) NVRAM page 5 has an invalid signature: %X.",
+			  ips_name, ha->host_num, ha->nvram->signature);
+		ha->nvram->signature = IPS_NVRAM_P5_SIG;
+	}
+
+	DEBUG_VAR(2,
+		  "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.",
+		  ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type),
+		  ha->nvram->adapter_slot, ha->nvram->bios_high[0],
+		  ha->nvram->bios_high[1], ha->nvram->bios_high[2],
+		  ha->nvram->bios_high[3], ha->nvram->bios_low[0],
+		  ha->nvram->bios_low[1], ha->nvram->bios_low[2],
+		  ha->nvram->bios_low[3]);
+
+	ips_get_bios_version(ha, intr);
+
+	/* change values (as needed) */
+	ha->nvram->operating_system = IPS_OS_LINUX;
+	ha->nvram->adapter_type = ha->ad_type;
+	strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4);
+	strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4);
+	strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4);
+	strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);
+
+	ips_version_check(ha, intr);	/* Check BIOS/FW/Driver Versions */
+
+	/* now update the page */
+	if (!ips_readwrite_page5(ha, TRUE, intr)) {
+		printk(KERN_WARNING "(%s%d) unable to write NVRAM page 5.\n",
+		       ips_name, ha->host_num);
 
-   /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */
-   ha->slot_num = ha->nvram->adapter_slot;
+		return (0);
+	}
 
+	/* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */
+	ha->slot_num = ha->nvram->adapter_slot;
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -6324,39 +5840,40 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_read_adapter_status(ips_ha_t *ha, int intr) {
-   ips_scb_t *scb;
-   int        ret;
-
-   METHOD_TRACE("ips_read_adapter_status", 1);
-
-   scb = &ha->scbs[ha->max_cmds-1];
-
-   ips_init_scb(ha, scb);
-
-   scb->timeout = ips_cmd_timeout;
-   scb->cdb[0] = IPS_CMD_ENQUIRY;
-
-   scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
-   scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.basic_io.sg_count = 0;
-   scb->cmd.basic_io.lba = 0;
-   scb->cmd.basic_io.sector_count = 0;
-   scb->cmd.basic_io.log_drv = 0;
-   scb->cmd.basic_io.reserved = 0;
-   scb->data_len = sizeof(*ha->enq);
-   scb->data_busaddr = pci_map_single(ha->pcidev, ha->enq, scb->data_len,
-                                      IPS_DMA_DIR(scb));
-   scb->cmd.basic_io.sg_addr = scb->data_busaddr;
-   scb->flags |= IPS_SCB_MAP_SINGLE;
-
-   /* send command */
-   if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
-       (ret == IPS_SUCCESS_IMM) ||
-       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
-      return (0);
+ips_read_adapter_status(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
+
+	METHOD_TRACE("ips_read_adapter_status", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
 
-   return (1);
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_ENQUIRY;
+
+	scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
+	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.basic_io.sg_count = 0;
+	scb->cmd.basic_io.lba = 0;
+	scb->cmd.basic_io.sector_count = 0;
+	scb->cmd.basic_io.log_drv = 0;
+	scb->data_len = sizeof (*ha->enq);
+	scb->data_busaddr = pci_map_single(ha->pcidev, ha->enq, scb->data_len,
+					   IPS_DMA_DIR(scb));
+	scb->cmd.basic_io.sg_addr = scb->data_busaddr;
+	scb->flags |= IPS_SCB_MAP_SINGLE;
+
+	/* send command */
+	if (
+	    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
+	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
+		return (0);
+
+	return (1);
 }
 
 /****************************************************************************/
@@ -6369,39 +5886,40 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_read_subsystem_parameters(ips_ha_t *ha, int intr) {
-   ips_scb_t *scb;
-   int        ret;
-
-   METHOD_TRACE("ips_read_subsystem_parameters", 1);
-
-   scb = &ha->scbs[ha->max_cmds-1];
-
-   ips_init_scb(ha, scb);
-
-   scb->timeout = ips_cmd_timeout;
-   scb->cdb[0] = IPS_CMD_GET_SUBSYS;
-
-   scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS;
-   scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.basic_io.sg_count = 0;
-   scb->cmd.basic_io.lba = 0;
-   scb->cmd.basic_io.sector_count = 0;
-   scb->cmd.basic_io.log_drv = 0;
-   scb->cmd.basic_io.reserved = 0;
-   scb->data_len = sizeof(*ha->subsys);
-   scb->data_busaddr = pci_map_single(ha->pcidev, ha->subsys,
-                                      scb->data_len, IPS_DMA_DIR(scb));
-   scb->cmd.basic_io.sg_addr = scb->data_busaddr;
-   scb->flags |= IPS_SCB_MAP_SINGLE;
-
-   /* send command */
-   if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
-       (ret == IPS_SUCCESS_IMM) ||
-       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
-      return (0);
+ips_read_subsystem_parameters(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
 
-   return (1);
+	METHOD_TRACE("ips_read_subsystem_parameters", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_GET_SUBSYS;
+
+	scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS;
+	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.basic_io.sg_count = 0;
+	scb->cmd.basic_io.lba = 0;
+	scb->cmd.basic_io.sector_count = 0;
+	scb->cmd.basic_io.log_drv = 0;
+	scb->data_len = sizeof (*ha->subsys);
+	scb->data_busaddr = pci_map_single(ha->pcidev, ha->subsys,
+					   scb->data_len, IPS_DMA_DIR(scb));
+	scb->cmd.basic_io.sg_addr = scb->data_busaddr;
+	scb->flags |= IPS_SCB_MAP_SINGLE;
+
+	/* send command */
+	if (
+	    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
+	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
+		return (0);
+
+	return (1);
 }
 
 /****************************************************************************/
@@ -6414,51 +5932,53 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_read_config(ips_ha_t *ha, int intr) {
-   ips_scb_t *scb;
-   int        i;
-   int        ret;
-
-   METHOD_TRACE("ips_read_config", 1);
-
-   /* set defaults for initiator IDs */
-   for (i = 0; i < 4; i++)
-      ha->conf->init_id[i] = 7;
-
-   scb = &ha->scbs[ha->max_cmds-1];
-
-   ips_init_scb(ha, scb);
-
-   scb->timeout = ips_cmd_timeout;
-   scb->cdb[0] = IPS_CMD_READ_CONF;
-
-   scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF;
-   scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->data_len = sizeof(*ha->conf);
-   scb->data_busaddr = pci_map_single(ha->pcidev, ha->conf,
-                                      scb->data_len, IPS_DMA_DIR(scb));
-   scb->cmd.basic_io.sg_addr = scb->data_busaddr;
-   scb->flags |= IPS_SCB_MAP_SINGLE;
-
-   /* send command */
-   if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
-       (ret == IPS_SUCCESS_IMM) ||
-       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
-
-      memset(ha->conf, 0, sizeof(IPS_CONF));
-
-      /* reset initiator IDs */
-      for (i = 0; i < 4; i++)
-         ha->conf->init_id[i] = 7;
-
-      /* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */
-      if ((scb->basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_CMPLT_WERROR)   
-         return (1);                      
-      
-      return (0);
-   }
+ips_read_config(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int i;
+	int ret;
+
+	METHOD_TRACE("ips_read_config", 1);
 
-   return (1);
+	/* set defaults for initiator IDs */
+	for (i = 0; i < 4; i++)
+		ha->conf->init_id[i] = 7;
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_READ_CONF;
+
+	scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF;
+	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->data_len = sizeof (*ha->conf);
+	scb->data_busaddr = pci_map_single(ha->pcidev, ha->conf,
+					   scb->data_len, IPS_DMA_DIR(scb));
+	scb->cmd.basic_io.sg_addr = scb->data_busaddr;
+	scb->flags |= IPS_SCB_MAP_SINGLE;
+
+	/* send command */
+	if (
+	    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
+	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
+
+		memset(ha->conf, 0, sizeof (IPS_CONF));
+
+		/* reset initiator IDs */
+		for (i = 0; i < 4; i++)
+			ha->conf->init_id[i] = 7;
+
+		/* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */
+		if ((scb->basic_status & IPS_GSC_STATUS_MASK) ==
+		    IPS_CMD_CMPLT_WERROR) return (1);
+
+		return (0);
+	}
+
+	return (1);
 }
 
 /****************************************************************************/
@@ -6471,42 +5991,44 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_readwrite_page5(ips_ha_t *ha, int write, int intr) {
-   ips_scb_t *scb;
-   int        ret;
-
-   METHOD_TRACE("ips_readwrite_page5", 1);
-
-   scb = &ha->scbs[ha->max_cmds-1];
-
-   ips_init_scb(ha, scb);
-
-   scb->timeout = ips_cmd_timeout;
-   scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE;
-
-   scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE;
-   scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.nvram.page = 5;
-   scb->cmd.nvram.write = write;
-   scb->cmd.nvram.reserved = 0;
-   scb->cmd.nvram.reserved2 = 0;
-   scb->data_len = sizeof(*ha->nvram);
-   scb->data_busaddr = pci_map_single(ha->pcidev, ha->nvram,
-                                      scb->data_len, IPS_DMA_DIR(scb));
-   scb->cmd.nvram.buffer_addr = scb->data_busaddr;
-   scb->flags |= IPS_SCB_MAP_SINGLE;
-
-   /* issue the command */
-   if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
-       (ret == IPS_SUCCESS_IMM) ||
-       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
+ips_readwrite_page5(ips_ha_t * ha, int write, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
+
+	METHOD_TRACE("ips_readwrite_page5", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
 
-      memset(ha->nvram, 0, sizeof(IPS_NVRAM_P5));
+	ips_init_scb(ha, scb);
 
-      return (0);
-   }
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE;
+
+	scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE;
+	scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.nvram.page = 5;
+	scb->cmd.nvram.write = write;
+	scb->cmd.nvram.reserved = 0;
+	scb->cmd.nvram.reserved2 = 0;
+	scb->data_len = sizeof (*ha->nvram);
+	scb->data_busaddr = pci_map_single(ha->pcidev, ha->nvram,
+					   scb->data_len, IPS_DMA_DIR(scb));
+	scb->cmd.nvram.buffer_addr = scb->data_busaddr;
+	scb->flags |= IPS_SCB_MAP_SINGLE;
+
+	/* issue the command */
+	if (
+	    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
+	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
 
-   return (1);
+		memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5));
+
+		return (0);
+	}
+
+	return (1);
 }
 
 /****************************************************************************/
@@ -6519,54 +6041,57 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_clear_adapter(ips_ha_t *ha, int intr) {
-   ips_scb_t *scb;
-   int        ret;
-
-   METHOD_TRACE("ips_clear_adapter", 1);
-
-   scb = &ha->scbs[ha->max_cmds-1];
-
-   ips_init_scb(ha, scb);
-
-   scb->timeout = ips_reset_timeout;
-   scb->cdb[0] = IPS_CMD_CONFIG_SYNC;
-
-   scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC;
-   scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.config_sync.channel = 0;
-   scb->cmd.config_sync.source_target = IPS_POCL;
-   scb->cmd.config_sync.reserved = 0;
-   scb->cmd.config_sync.reserved2 = 0;
-   scb->cmd.config_sync.reserved3 = 0;
-
-   /* issue command */
-   if (((ret = ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE) ||
-       (ret == IPS_SUCCESS_IMM) ||
-       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
-      return (0);
-
-   /* send unlock stripe command */
-   ips_init_scb(ha, scb);
-
-   scb->cdb[0] = IPS_CMD_ERROR_TABLE;
-   scb->timeout = ips_reset_timeout;
-
-   scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE;
-   scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.unlock_stripe.log_drv = 0;
-   scb->cmd.unlock_stripe.control = IPS_CSL;
-   scb->cmd.unlock_stripe.reserved = 0;
-   scb->cmd.unlock_stripe.reserved2 = 0;
-   scb->cmd.unlock_stripe.reserved3 = 0;
-
-   /* issue command */
-   if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
-       (ret == IPS_SUCCESS_IMM) ||
-       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
-      return (0);
+ips_clear_adapter(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
+
+	METHOD_TRACE("ips_clear_adapter", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_reset_timeout;
+	scb->cdb[0] = IPS_CMD_CONFIG_SYNC;
+
+	scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC;
+	scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.config_sync.channel = 0;
+	scb->cmd.config_sync.source_target = IPS_POCL;
+	scb->cmd.config_sync.reserved = 0;
+	scb->cmd.config_sync.reserved2 = 0;
+	scb->cmd.config_sync.reserved3 = 0;
+
+	/* issue command */
+	if (
+	    ((ret = ips_send_wait(ha, scb, ips_reset_timeout, intr)) ==
+	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
+		return (0);
+
+	/* send unlock stripe command */
+	ips_init_scb(ha, scb);
+
+	scb->cdb[0] = IPS_CMD_ERROR_TABLE;
+	scb->timeout = ips_reset_timeout;
+
+	scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE;
+	scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.unlock_stripe.log_drv = 0;
+	scb->cmd.unlock_stripe.control = IPS_CSL;
+	scb->cmd.unlock_stripe.reserved = 0;
+	scb->cmd.unlock_stripe.reserved2 = 0;
+	scb->cmd.unlock_stripe.reserved3 = 0;
+
+	/* issue command */
+	if (
+	    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
+	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
+		return (0);
 
-   return (1);
+	return (1);
 }
 
 /****************************************************************************/
@@ -6579,27 +6104,28 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_ffdc_reset(ips_ha_t *ha, int intr) {
-   ips_scb_t *scb;
+ips_ffdc_reset(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
 
-   METHOD_TRACE("ips_ffdc_reset", 1);
+	METHOD_TRACE("ips_ffdc_reset", 1);
 
-   scb = &ha->scbs[ha->max_cmds-1];
+	scb = &ha->scbs[ha->max_cmds - 1];
 
-   ips_init_scb(ha, scb);
+	ips_init_scb(ha, scb);
 
-   scb->timeout = ips_cmd_timeout;
-   scb->cdb[0] = IPS_CMD_FFDC;
-   scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
-   scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.ffdc.reset_count = ha->reset_count;
-   scb->cmd.ffdc.reset_type = 0x80;
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_FFDC;
+	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
+	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.ffdc.reset_count = ha->reset_count;
+	scb->cmd.ffdc.reset_type = 0x80;
 
-   /* convert time to what the card wants */
-   ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
+	/* convert time to what the card wants */
+	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
 
-   /* issue command */
-   ips_send_wait(ha, scb, ips_cmd_timeout, intr);
+	/* issue command */
+	ips_send_wait(ha, scb, ips_cmd_timeout, intr);
 }
 
 /****************************************************************************/
@@ -6612,30 +6138,30 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_ffdc_time(ips_ha_t *ha) {
-   ips_scb_t *scb;
+ips_ffdc_time(ips_ha_t * ha)
+{
+	ips_scb_t *scb;
 
-   METHOD_TRACE("ips_ffdc_time", 1);
+	METHOD_TRACE("ips_ffdc_time", 1);
 
-   DEBUG_VAR(1, "(%s%d) Sending time update.",
-             ips_name, ha->host_num);
+	DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num);
 
-   scb = &ha->scbs[ha->max_cmds-1];
+	scb = &ha->scbs[ha->max_cmds - 1];
 
-   ips_init_scb(ha, scb);
+	ips_init_scb(ha, scb);
 
-   scb->timeout = ips_cmd_timeout;
-   scb->cdb[0] = IPS_CMD_FFDC;
-   scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
-   scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.ffdc.reset_count = 0;
-   scb->cmd.ffdc.reset_type = 0x80;
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_FFDC;
+	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
+	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.ffdc.reset_count = 0;
+	scb->cmd.ffdc.reset_type = 0x80;
 
-   /* convert time to what the card wants */
-   ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
+	/* convert time to what the card wants */
+	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
 
-   /* issue command */
-   ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC);
+	/* issue command */
+	ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC);
 }
 
 /****************************************************************************/
@@ -6647,57 +6173,59 @@
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_fix_ffdc_time(ips_ha_t *ha, ips_scb_t *scb, time_t current_time) {
-   long days;
-   long rem;
-   int  i;
-   int  year;
-   int  yleap;
-   int  year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR };
-   int  month_lengths[12][2] = { {31, 31},
-                                 {28, 29},
-                                 {31, 31},
-                                 {30, 30},
-                                 {31, 31},
-                                 {30, 30},
-                                 {31, 31},
-                                 {31, 31},
-                                 {30, 30},
-                                 {31, 31},
-                                 {30, 30},
-                                 {31, 31} };
-
-   METHOD_TRACE("ips_fix_ffdc_time", 1);
-
-   days = current_time / IPS_SECS_DAY;
-   rem = current_time % IPS_SECS_DAY;
-
-   scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR);
-   rem = rem % IPS_SECS_HOUR;
-   scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN);
-   scb->cmd.ffdc.second = (rem % IPS_SECS_MIN);
-
-   year = IPS_EPOCH_YEAR;
-   while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) {
-      int newy;
-
-      newy = year + (days / IPS_DAYS_NORMAL_YEAR);
-      if (days < 0)
-         --newy;
-      days -= (newy - year) * IPS_DAYS_NORMAL_YEAR +
-         IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) -
-         IPS_NUM_LEAP_YEARS_THROUGH(year - 1);
-      year = newy;
-   }
+ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time)
+{
+	long days;
+	long rem;
+	int i;
+	int year;
+	int yleap;
+	int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR };
+	int month_lengths[12][2] = { {31, 31},
+	{28, 29},
+	{31, 31},
+	{30, 30},
+	{31, 31},
+	{30, 30},
+	{31, 31},
+	{31, 31},
+	{30, 30},
+	{31, 31},
+	{30, 30},
+	{31, 31}
+	};
+
+	METHOD_TRACE("ips_fix_ffdc_time", 1);
+
+	days = current_time / IPS_SECS_DAY;
+	rem = current_time % IPS_SECS_DAY;
+
+	scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR);
+	rem = rem % IPS_SECS_HOUR;
+	scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN);
+	scb->cmd.ffdc.second = (rem % IPS_SECS_MIN);
+
+	year = IPS_EPOCH_YEAR;
+	while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) {
+		int newy;
+
+		newy = year + (days / IPS_DAYS_NORMAL_YEAR);
+		if (days < 0)
+			--newy;
+		days -= (newy - year) * IPS_DAYS_NORMAL_YEAR +
+		    IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) -
+		    IPS_NUM_LEAP_YEARS_THROUGH(year - 1);
+		year = newy;
+	}
 
-   scb->cmd.ffdc.yearH = year / 100;
-   scb->cmd.ffdc.yearL = year % 100;
+	scb->cmd.ffdc.yearH = year / 100;
+	scb->cmd.ffdc.yearL = year % 100;
 
-   for (i = 0; days >= month_lengths[i][yleap]; ++i)
-      days -= month_lengths[i][yleap];
+	for (i = 0; days >= month_lengths[i][yleap]; ++i)
+		days -= month_lengths[i][yleap];
 
-   scb->cmd.ffdc.month = i + 1;
-   scb->cmd.ffdc.day = days + 1;
+	scb->cmd.ffdc.month = i + 1;
+	scb->cmd.ffdc.day = days + 1;
 }
 
 /****************************************************************************
@@ -6713,106 +6241,107 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_erase_bios(ips_ha_t *ha) {
-   int      timeout;
-   uint8_t  status=0;
-
-   METHOD_TRACE("ips_erase_bios", 1);
-
-   status = 0;
-
-   /* Clear the status register */
-   outl(0, ha->io_addr + IPS_REG_FLAP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   outb(0x50, ha->io_addr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   /* Erase Setup */
-   outb(0x20, ha->io_addr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   /* Erase Confirm */
-   outb(0xD0, ha->io_addr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   /* Erase Status */
-   outb(0x70, ha->io_addr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   timeout = 80000; /* 80 seconds */
-
-   while (timeout > 0) {
-      if (ha->revision_id == IPS_REVID_TROMBONE64) {
-         outl(0, ha->io_addr + IPS_REG_FLAP);
-         udelay(25); /* 25 us */
-      }
-
-      status = inb(ha->io_addr + IPS_REG_FLDP);
-
-      if (status & 0x80)
-         break;
-
-      MDELAY(1);
-      timeout--;
-   }
-
-   /* check for timeout */
-   if (timeout <= 0) {
-      /* timeout */
-
-      /* try to suspend the erase */
-      outb(0xB0, ha->io_addr + IPS_REG_FLDP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      /* wait for 10 seconds */
-      timeout = 10000;
-      while (timeout > 0) {
-         if (ha->revision_id == IPS_REVID_TROMBONE64) {
-            outl(0, ha->io_addr + IPS_REG_FLAP);
-            udelay(25); /* 25 us */
-         }
-
-         status = inb(ha->io_addr + IPS_REG_FLDP);
-
-         if (status & 0xC0)
-            break;
-
-         MDELAY(1);
-         timeout--;
-      }
-
-      return (1);
-   }
-
-   /* check for valid VPP */
-   if (status & 0x08)
-      /* VPP failure */
-      return (1);
-
-   /* check for succesful flash */
-   if (status & 0x30)
-      /* sequence error */
-      return (1);
-
-   /* Otherwise, we were successful */
-   /* clear status */
-   outb(0x50, ha->io_addr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   /* enable reads */
-   outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
+ips_erase_bios(ips_ha_t * ha)
+{
+	int timeout;
+	uint8_t status = 0;
+
+	METHOD_TRACE("ips_erase_bios", 1);
+
+	status = 0;
 
-   return (0);
+	/* Clear the status register */
+	outl(0, ha->io_addr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	outb(0x50, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Setup */
+	outb(0x20, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Confirm */
+	outb(0xD0, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Status */
+	outb(0x70, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	timeout = 80000;	/* 80 seconds */
+
+	while (timeout > 0) {
+		if (ha->revision_id == IPS_REVID_TROMBONE64) {
+			outl(0, ha->io_addr + IPS_REG_FLAP);
+			udelay(25);	/* 25 us */
+		}
+
+		status = inb(ha->io_addr + IPS_REG_FLDP);
+
+		if (status & 0x80)
+			break;
+
+		MDELAY(1);
+		timeout--;
+	}
+
+	/* check for timeout */
+	if (timeout <= 0) {
+		/* timeout */
+
+		/* try to suspend the erase */
+		outb(0xB0, ha->io_addr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		/* wait for 10 seconds */
+		timeout = 10000;
+		while (timeout > 0) {
+			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+				outl(0, ha->io_addr + IPS_REG_FLAP);
+				udelay(25);	/* 25 us */
+			}
+
+			status = inb(ha->io_addr + IPS_REG_FLDP);
+
+			if (status & 0xC0)
+				break;
+
+			MDELAY(1);
+			timeout--;
+		}
+
+		return (1);
+	}
+
+	/* check for valid VPP */
+	if (status & 0x08)
+		/* VPP failure */
+		return (1);
+
+	/* check for succesful flash */
+	if (status & 0x30)
+		/* sequence error */
+		return (1);
+
+	/* Otherwise, we were successful */
+	/* clear status */
+	outb(0x50, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* enable reads */
+	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	return (0);
 }
 
 /****************************************************************************/
@@ -6824,106 +6353,107 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_erase_bios_memio(ips_ha_t *ha) {
-   int      timeout;
-   uint8_t  status;
-
-   METHOD_TRACE("ips_erase_bios_memio", 1);
-
-   status = 0;
-
-   /* Clear the status register */
-   writel(0, ha->mem_ptr + IPS_REG_FLAP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   /* Erase Setup */
-   writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   /* Erase Confirm */
-   writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   /* Erase Status */
-   writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   timeout = 80000; /* 80 seconds */
-
-   while (timeout > 0) {
-      if (ha->revision_id == IPS_REVID_TROMBONE64) {
-         writel(0, ha->mem_ptr + IPS_REG_FLAP);
-         udelay(25); /* 25 us */
-      }
-
-      status = readb(ha->mem_ptr + IPS_REG_FLDP);
-
-      if (status & 0x80)
-         break;
-
-      MDELAY(1);
-      timeout--;
-   }
-
-   /* check for timeout */
-   if (timeout <= 0) {
-      /* timeout */
-
-      /* try to suspend the erase */
-      writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      /* wait for 10 seconds */
-      timeout = 10000;
-      while (timeout > 0) {
-         if (ha->revision_id == IPS_REVID_TROMBONE64) {
-            writel(0, ha->mem_ptr + IPS_REG_FLAP);
-            udelay(25); /* 25 us */
-         }
-
-         status = readb(ha->mem_ptr + IPS_REG_FLDP);
-
-         if (status & 0xC0)
-            break;
-
-         MDELAY(1);
-         timeout--;
-      }
-
-      return (1);
-   }
-
-   /* check for valid VPP */
-   if (status & 0x08)
-      /* VPP failure */
-      return (1);
-
-   /* check for succesful flash */
-   if (status & 0x30)
-      /* sequence error */
-      return (1);
-
-   /* Otherwise, we were successful */
-   /* clear status */
-   writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   /* enable reads */
-   writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
+ips_erase_bios_memio(ips_ha_t * ha)
+{
+	int timeout;
+	uint8_t status;
+
+	METHOD_TRACE("ips_erase_bios_memio", 1);
+
+	status = 0;
 
-   return (0);
+	/* Clear the status register */
+	writel(0, ha->mem_ptr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Setup */
+	writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Confirm */
+	writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Status */
+	writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	timeout = 80000;	/* 80 seconds */
+
+	while (timeout > 0) {
+		if (ha->revision_id == IPS_REVID_TROMBONE64) {
+			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+			udelay(25);	/* 25 us */
+		}
+
+		status = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+		if (status & 0x80)
+			break;
+
+		MDELAY(1);
+		timeout--;
+	}
+
+	/* check for timeout */
+	if (timeout <= 0) {
+		/* timeout */
+
+		/* try to suspend the erase */
+		writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		/* wait for 10 seconds */
+		timeout = 10000;
+		while (timeout > 0) {
+			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+				writel(0, ha->mem_ptr + IPS_REG_FLAP);
+				udelay(25);	/* 25 us */
+			}
+
+			status = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+			if (status & 0xC0)
+				break;
+
+			MDELAY(1);
+			timeout--;
+		}
+
+		return (1);
+	}
+
+	/* check for valid VPP */
+	if (status & 0x08)
+		/* VPP failure */
+		return (1);
+
+	/* check for succesful flash */
+	if (status & 0x30)
+		/* sequence error */
+		return (1);
+
+	/* Otherwise, we were successful */
+	/* clear status */
+	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* enable reads */
+	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	return (0);
 }
 
 /****************************************************************************/
@@ -6935,84 +6465,86 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_program_bios(ips_ha_t *ha, char *buffer, uint32_t buffersize, uint32_t offset) {
-   int      i;
-   int      timeout;
-   uint8_t  status=0;
-
-   METHOD_TRACE("ips_program_bios", 1);
-
-   status = 0;
-
-   for (i = 0; i < buffersize; i++) {
-      /* write a byte */
-      outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      outb(0x40, ha->io_addr + IPS_REG_FLDP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      /* wait up to one second */
-      timeout = 1000;
-      while (timeout > 0) {
-         if (ha->revision_id == IPS_REVID_TROMBONE64) {
-            outl(0, ha->io_addr + IPS_REG_FLAP);
-            udelay(25); /* 25 us */
-         }
-
-         status = inb(ha->io_addr + IPS_REG_FLDP);
-
-         if (status & 0x80)
-            break;
-
-         MDELAY(1);
-         timeout--;
-      }
-
-      if (timeout == 0) {
-         /* timeout error */
-         outl(0, ha->io_addr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         return (1);
-      }
-
-      /* check the status */
-      if (status & 0x18) {
-         /* programming error */
-         outl(0, ha->io_addr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         return (1);
-      }
-   } /* end for */
-
-   /* Enable reading */
-   outl(0, ha->io_addr + IPS_REG_FLAP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
+ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+		 uint32_t offset)
+{
+	int i;
+	int timeout;
+	uint8_t status = 0;
+
+	METHOD_TRACE("ips_program_bios", 1);
+
+	status = 0;
+
+	for (i = 0; i < buffersize; i++) {
+		/* write a byte */
+		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		outb(0x40, ha->io_addr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		/* wait up to one second */
+		timeout = 1000;
+		while (timeout > 0) {
+			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+				outl(0, ha->io_addr + IPS_REG_FLAP);
+				udelay(25);	/* 25 us */
+			}
+
+			status = inb(ha->io_addr + IPS_REG_FLDP);
+
+			if (status & 0x80)
+				break;
+
+			MDELAY(1);
+			timeout--;
+		}
+
+		if (timeout == 0) {
+			/* timeout error */
+			outl(0, ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			return (1);
+		}
+
+		/* check the status */
+		if (status & 0x18) {
+			/* programming error */
+			outl(0, ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			return (1);
+		}
+	}			/* end for */
+
+	/* Enable reading */
+	outl(0, ha->io_addr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
 
-   return (0);
+	return (0);
 }
 
 /****************************************************************************/
@@ -7024,84 +6556,86 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_program_bios_memio(ips_ha_t *ha, char *buffer, uint32_t buffersize, uint32_t offset) {
-   int      i;
-   int      timeout;
-   uint8_t  status=0;
-
-   METHOD_TRACE("ips_program_bios_memio", 1);
-
-   status = 0;
-
-   for (i = 0; i < buffersize; i++) {
-      /* write a byte */
-      writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      /* wait up to one second */
-      timeout = 1000;
-      while (timeout > 0) {
-         if (ha->revision_id == IPS_REVID_TROMBONE64) {
-            writel(0, ha->mem_ptr + IPS_REG_FLAP);
-            udelay(25); /* 25 us */
-         }
-
-         status = readb(ha->mem_ptr + IPS_REG_FLDP);
-
-         if (status & 0x80)
-            break;
-
-         MDELAY(1);
-         timeout--;
-      }
-
-      if (timeout == 0) {
-         /* timeout error */
-         writel(0, ha->mem_ptr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         return (1);
-      }
-
-      /* check the status */
-      if (status & 0x18) {
-         /* programming error */
-         writel(0, ha->mem_ptr + IPS_REG_FLAP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-         if (ha->revision_id == IPS_REVID_TROMBONE64)
-            udelay(25); /* 25 us */
-
-         return (1);
-      }
-   } /* end for */
-
-   /* Enable reading */
-   writel(0, ha->mem_ptr + IPS_REG_FLAP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
+ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+		       uint32_t offset)
+{
+	int i;
+	int timeout;
+	uint8_t status = 0;
+
+	METHOD_TRACE("ips_program_bios_memio", 1);
+
+	status = 0;
+
+	for (i = 0; i < buffersize; i++) {
+		/* write a byte */
+		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		/* wait up to one second */
+		timeout = 1000;
+		while (timeout > 0) {
+			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+				writel(0, ha->mem_ptr + IPS_REG_FLAP);
+				udelay(25);	/* 25 us */
+			}
+
+			status = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+			if (status & 0x80)
+				break;
+
+			MDELAY(1);
+			timeout--;
+		}
+
+		if (timeout == 0) {
+			/* timeout error */
+			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			return (1);
+		}
+
+		/* check the status */
+		if (status & 0x18) {
+			/* programming error */
+			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			return (1);
+		}
+	}			/* end for */
+
+	/* Enable reading */
+	writel(0, ha->mem_ptr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
 
-   return (0);
+	return (0);
 }
 
 /****************************************************************************/
@@ -7113,42 +6647,44 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_verify_bios(ips_ha_t *ha, char *buffer, uint32_t buffersize, uint32_t offset) {
-   uint8_t  checksum;
-   int      i;
-
-   METHOD_TRACE("ips_verify_bios", 1);
-
-   /* test 1st byte */
-   outl(0, ha->io_addr + IPS_REG_FLAP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
-      return (1);
-
-   outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-   if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
-      return (1);
-
-   checksum = 0xff;
-   for (i = 2; i < buffersize; i++) {
-
-      outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
-   }
-
-   if (checksum != 0)
-      /* failure */
-      return (1);
-   else
-      /* success */
-      return (0);
+ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+		uint32_t offset)
+{
+	uint8_t checksum;
+	int i;
+
+	METHOD_TRACE("ips_verify_bios", 1);
+
+	/* test 1st byte */
+	outl(0, ha->io_addr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
+		return (1);
+
+	outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+	if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
+		return (1);
+
+	checksum = 0xff;
+	for (i = 2; i < buffersize; i++) {
+
+		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
+	}
+
+	if (checksum != 0)
+		/* failure */
+		return (1);
+	else
+		/* success */
+		return (0);
 }
 
 /****************************************************************************/
@@ -7160,42 +6696,45 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_verify_bios_memio(ips_ha_t *ha, char *buffer, uint32_t buffersize, uint32_t offset) {
-   uint8_t  checksum;
-   int      i;
-
-   METHOD_TRACE("ips_verify_bios_memio", 1);
-
-   /* test 1st byte */
-   writel(0, ha->mem_ptr + IPS_REG_FLAP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-
-   if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
-      return (1);
-
-   writel(1, ha->mem_ptr + IPS_REG_FLAP);
-   if (ha->revision_id == IPS_REVID_TROMBONE64)
-      udelay(25); /* 25 us */
-   if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
-      return (1);
-
-   checksum = 0xff;
-   for (i = 2; i < buffersize; i++) {
-
-      writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
-      if (ha->revision_id == IPS_REVID_TROMBONE64)
-         udelay(25); /* 25 us */
-
-      checksum = (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
-   }
-
-   if (checksum != 0)
-      /* failure */
-      return (1);
-   else
-      /* success */
-      return (0);
+ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+		      uint32_t offset)
+{
+	uint8_t checksum;
+	int i;
+
+	METHOD_TRACE("ips_verify_bios_memio", 1);
+
+	/* test 1st byte */
+	writel(0, ha->mem_ptr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
+		return (1);
+
+	writel(1, ha->mem_ptr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
+		return (1);
+
+	checksum = 0xff;
+	for (i = 2; i < buffersize; i++) {
+
+		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		checksum =
+		    (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
+	}
+
+	if (checksum != 0)
+		/* failure */
+		return (1);
+	else
+		/* success */
+		return (0);
 }
 
 /*---------------------------------------------------------------------------*/
@@ -7208,77 +6747,82 @@
 /*     Data is available.                                                    */
 /*                                                                           */
 /*---------------------------------------------------------------------------*/
-static void ips_version_check(ips_ha_t *ha, int intr) {
- IPS_VERSION_DATA VersionInfo;
- uint8_t  FirmwareVersion[ IPS_COMPAT_ID_LENGTH + 1 ];
- uint8_t  BiosVersion[ IPS_COMPAT_ID_LENGTH + 1];
- int      MatchError;
- int      rc;
- char     BiosString[10];
- char     FirmwareString[10];
-
- METHOD_TRACE("ips_version_check", 1);
-
- memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
- memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
-
- /* Get the Compatible BIOS Version from NVRAM Page 5 */
- memcpy(BiosVersion, ha->nvram->BiosCompatibilityID, IPS_COMPAT_ID_LENGTH);
- 
- rc = IPS_FAILURE;
- if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT)  /* If Versioning is Supported */
- {
-     /* Get the Version Info with a Get Version Command */
-     rc = ips_get_version_info(ha, &VersionInfo, intr);
-     if  (rc == IPS_SUCCESS)
-        memcpy(FirmwareVersion, VersionInfo.compatibilityId, IPS_COMPAT_ID_LENGTH);
- }
-
- if  (rc != IPS_SUCCESS)      /* If Data Not Obtainable from a GetVersion Command */
- {
-     /* Get the Firmware Version from Enquiry Data */
-     memcpy(FirmwareVersion, ha->enq->CodeBlkVersion, IPS_COMPAT_ID_LENGTH);
- }
-
- /* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */
- /* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */
- /* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */
- /* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */
-
- MatchError = 0;
-
- if  (strncmp(FirmwareVersion, Compatable[ ha->nvram->adapter_type ], IPS_COMPAT_ID_LENGTH) != 0)
-     MatchError = 1;
-
- if  (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
-     MatchError = 1;
-
- ha->nvram->versioning = 1;          /* Indicate the Driver Supports Versioning */
-
- if  (MatchError)
- {
-     ha->nvram->version_mismatch = 1;
-     if (ips_cd_boot == 0)  
-     {
-       strncpy(&BiosString[0], ha->nvram->bios_high, 4);
-       strncpy(&BiosString[4], ha->nvram->bios_low, 4);
-       BiosString[8] = 0;
-
-       strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);
-       FirmwareString[8] = 0;
-
-       printk(KERN_WARNING "Warning ! ! ! ServeRAID Version Mismatch\n");
-       printk(KERN_WARNING "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
-                            BiosString, FirmwareString, IPS_VERSION_HIGH, IPS_VERSION_LOW );
-       printk(KERN_WARNING "These levels should match to avoid possible compatibility problems.\n" );
-     }
- }
- else
- {
-     ha->nvram->version_mismatch = 0;
- }
+static void
+ips_version_check(ips_ha_t * ha, int intr)
+{
+	IPS_VERSION_DATA VersionInfo;
+	uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1];
+	uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1];
+	int MatchError;
+	int rc;
+	char BiosString[10];
+	char FirmwareString[10];
+
+	METHOD_TRACE("ips_version_check", 1);
+
+	memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
+	memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
+
+	/* Get the Compatible BIOS Version from NVRAM Page 5 */
+	memcpy(BiosVersion, ha->nvram->BiosCompatibilityID,
+	       IPS_COMPAT_ID_LENGTH);
+
+	rc = IPS_FAILURE;
+	if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {	/* If Versioning is Supported */
+		/* Get the Version Info with a Get Version Command */
+		rc = ips_get_version_info(ha, &VersionInfo, intr);
+		if (rc == IPS_SUCCESS)
+			memcpy(FirmwareVersion, VersionInfo.compatibilityId,
+			       IPS_COMPAT_ID_LENGTH);
+	}
+
+	if (rc != IPS_SUCCESS) {	/* If Data Not Obtainable from a GetVersion Command */
+		/* Get the Firmware Version from Enquiry Data */
+		memcpy(FirmwareVersion, ha->enq->CodeBlkVersion,
+		       IPS_COMPAT_ID_LENGTH);
+	}
+
+	/* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */
+	/* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */
+	/* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */
+	/* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */
+
+	MatchError = 0;
+
+	if (strncmp
+	    (FirmwareVersion, Compatable[ha->nvram->adapter_type],
+	     IPS_COMPAT_ID_LENGTH) != 0)
+		MatchError = 1;
+
+	if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
+		MatchError = 1;
+
+	ha->nvram->versioning = 1;	/* Indicate the Driver Supports Versioning */
+
+	if (MatchError) {
+		ha->nvram->version_mismatch = 1;
+		if (ips_cd_boot == 0) {
+			strncpy(&BiosString[0], ha->nvram->bios_high, 4);
+			strncpy(&BiosString[4], ha->nvram->bios_low, 4);
+			BiosString[8] = 0;
+
+			strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);
+			FirmwareString[8] = 0;
+
+			printk(KERN_WARNING
+			       "Warning ! ! ! ServeRAID Version Mismatch\n");
+			printk(KERN_WARNING
+			       "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
+			       BiosString, FirmwareString, IPS_VERSION_HIGH,
+			       IPS_VERSION_LOW);
+			printk(KERN_WARNING
+			       "These levels should match to avoid possible compatibility problems.\n");
+		}
+	} else {
+		ha->nvram->version_mismatch = 0;
+	}
 
- return;
+	return;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -7290,52 +6834,227 @@
 /*   Return Value:                                                           */
 /*     0 if Successful, else non-zero                                        */
 /*---------------------------------------------------------------------------*/
-static int ips_get_version_info(ips_ha_t *ha, IPS_VERSION_DATA *Buffer, int intr ) {
-   ips_scb_t *scb;
-   int        rc;
-
-   METHOD_TRACE("ips_get_version_info", 1);
-
-   memset(Buffer, 0, sizeof(IPS_VERSION_DATA));
-   scb = &ha->scbs[ha->max_cmds-1];
-
-   ips_init_scb(ha, scb);
-
-   scb->timeout = ips_cmd_timeout;
-   scb->cdb[0] = IPS_CMD_GET_VERSION_INFO;
-   scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO;
-   scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.version_info.reserved = 0;
-   scb->cmd.version_info.count = sizeof( IPS_VERSION_DATA);
-   scb->cmd.version_info.reserved2 = 0;
-   scb->data_len = sizeof(*Buffer);
-   scb->data_busaddr = pci_map_single(ha->pcidev, Buffer,
-                                      scb->data_len, IPS_DMA_DIR(scb));
-   scb->cmd.version_info.buffer_addr = scb->data_busaddr;
-   scb->flags |= IPS_SCB_MAP_SINGLE;
-
-   /* issue command */
-   rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
-   return( rc );
-}
-
-  
-
-#if defined (MODULE) || (LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0))
-static Scsi_Host_Template driver_template = IPS;
-#include "scsi_module.c"
-#endif
+static int
+ips_get_version_info(ips_ha_t * ha, IPS_VERSION_DATA * Buffer, int intr)
+{
+	ips_scb_t *scb;
+	int rc;
+
+	METHOD_TRACE("ips_get_version_info", 1);
+
+	memset(Buffer, 0, sizeof (IPS_VERSION_DATA));
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
 
-static int ips_abort_init(ips_ha_t *ha, struct Scsi_Host *sh, int index){
-   ha->active = 0;
-   ips_free(ha);
-   scsi_unregister(sh);
-   ips_ha[index] = 0;
-   ips_sh[index] = 0;
-   return -1;
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_GET_VERSION_INFO;
+	scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO;
+	scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.version_info.reserved = 0;
+	scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA);
+	scb->cmd.version_info.reserved2 = 0;
+	scb->data_len = sizeof (*Buffer);
+	scb->data_busaddr = pci_map_single(ha->pcidev, Buffer,
+					   scb->data_len, IPS_DMA_DIR(scb));
+	scb->cmd.version_info.buffer_addr = scb->data_busaddr;
+	scb->flags |= IPS_SCB_MAP_SINGLE;
+
+	/* issue command */
+	rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
+	return (rc);
 }
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_abort_init                                             */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   cleanup routine for a failed adapter initialization                    */
+/****************************************************************************/
+static int
+ips_abort_init(ips_ha_t * ha, int index)
+{
+	ha->active = 0;
+	ips_free(ha);
+	ips_ha[index] = 0;
+	ips_sh[index] = 0;
+	return -1;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_shift_controllers                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   helper function for ordering adapters                                  */
+/****************************************************************************/
+static void
+ips_shift_controllers(int lowindex, int highindex)
+{
+	ips_ha_t *ha_sav = ips_ha[highindex];
+	struct Scsi_Host *sh_sav = ips_sh[highindex];
+	int i;
+
+	for (i = highindex; i > lowindex; i--) {
+		ips_ha[i] = ips_ha[i - 1];
+		ips_sh[i] = ips_sh[i - 1];
+		ips_ha[i]->host_num = i;
+	}
+	ha_sav->host_num = lowindex;
+	ips_ha[lowindex] = ha_sav;
+	ips_sh[lowindex] = sh_sav;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_order_controllers                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   place controllers is the "proper" boot order                           */
+/****************************************************************************/
+static void
+ips_order_controllers(void)
+{
+	int i, j, tmp, position = 0;
+	IPS_NVRAM_P5 *nvram;
+	if (!ips_ha[0])
+		return;
+	nvram = ips_ha[0]->nvram;
+
+	if (nvram->adapter_order[0]) {
+		for (i = 1; i <= nvram->adapter_order[0]; i++) {
+			for (j = position; j < ips_num_controllers; j++) {
+				switch (ips_ha[j]->ad_type) {
+				case IPS_ADTYPE_SERVERAID6M:
+					if (nvram->adapter_order[i] == 'M') {
+						ips_shift_controllers(position,
+								      j);
+						position++;
+					}
+					break;
+				case IPS_ADTYPE_SERVERAID4L:
+				case IPS_ADTYPE_SERVERAID4M:
+				case IPS_ADTYPE_SERVERAID4MX:
+				case IPS_ADTYPE_SERVERAID4LX:
+					if (nvram->adapter_order[i] == 'N') {
+						ips_shift_controllers(position,
+								      j);
+						position++;
+					}
+					break;
+				case IPS_ADTYPE_SERVERAID6I:
+				case IPS_ADTYPE_SERVERAID5I2:
+				case IPS_ADTYPE_SERVERAID5I1:
+					if (nvram->adapter_order[i] == 'S') {
+						ips_shift_controllers(position,
+								      j);
+						position++;
+					}
+					break;
+				case IPS_ADTYPE_SERVERAID:
+				case IPS_ADTYPE_SERVERAID2:
+				case IPS_ADTYPE_NAVAJO:
+				case IPS_ADTYPE_KIOWA:
+				case IPS_ADTYPE_SERVERAID3L:
+				case IPS_ADTYPE_SERVERAID3:
+				case IPS_ADTYPE_SERVERAID4H:
+					if (nvram->adapter_order[i] == 'A') {
+						ips_shift_controllers(position,
+								      j);
+						position++;
+					}
+					break;
+				default:
+					break;
+				}
+			}
+		}
+		/* if adapter_order[0], then ordering is complete */
+		return;
+	}
+	/* old bios, use older ordering */
+	tmp = 0;
+	for (i = position; i < ips_num_controllers; i++) {
+		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 ||
+		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) {
+			ips_shift_controllers(position, i);
+			position++;
+			tmp = 1;
+		}
+	}
+	/* if there were no 5I cards, then don't do any extra ordering */
+	if (!tmp)
+		return;
+	for (i = position; i < ips_num_controllers; i++) {
+		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L ||
+		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M ||
+		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX ||
+		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) {
+			ips_shift_controllers(position, i);
+			position++;
+		}
+	}
+
+	return;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_register_scsi                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   perform any registration and setup with the scsi layer                 */
+/****************************************************************************/
+static int
+ips_register_scsi(int index)
+{
+	struct Scsi_Host *sh;
+	ips_ha_t *ha, *oldha;
+	sh = scsi_register(&ips_driver_template, sizeof (ips_ha_t));
+	if (!sh) {
+		printk(KERN_WARNING
+		       "Unable to register controller with SCSI subsystem\n");
+		return -1;
+	}
+	oldha = ips_ha[index];
+	ha = IPS_HA(sh);
+	memcpy(ha, oldha, sizeof (ips_ha_t));
+	free_irq(oldha->irq, oldha);
+	/* Install the interrupt handler with the new ha */
+	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+		printk(KERN_WARNING "Unable to install interrupt handler\n");
+		scsi_unregister(sh);
+		return -1;
+	}
+
+	kfree(oldha);
+	ips_sh[index] = sh;
+	ips_ha[index] = ha;
+	scsi_set_pci_device(sh, ha->pcidev);
+
+	/* Store away needed values for later use */
+	sh->io_port = ha->io_addr;
+	sh->n_io_port = ha->io_addr ? 255 : 0;
+	sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;
+	sh->irq = ha->irq;
+	sh->sg_tablesize = sh->hostt->sg_tablesize;
+	sh->can_queue = sh->hostt->can_queue;
+	sh->cmd_per_lun = sh->hostt->cmd_per_lun;
+	sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
+	sh->use_clustering = sh->hostt->use_clustering;
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
+	sh->max_sectors = 128;
+#endif
+
+	sh->max_id = ha->ntargets;
+	sh->max_lun = ha->nlun;
+	sh->max_channel = ha->nbus - 1;
+	sh->can_queue = ha->max_cmds - 1;
+
+	return 0;
+}
 
 /*---------------------------------------------------------------------------*/
 /*   Routine Name: ips_remove_device                                         */
@@ -7343,24 +7062,64 @@
 /*   Routine Description:                                                    */
 /*     Remove one Adapter ( Hot Plugging )                                   */
 /*---------------------------------------------------------------------------*/
-static void ips_remove_device(struct pci_dev *pci_dev)
+static void
+ips_remove_device(struct pci_dev *pci_dev)
 {
-   int    i;
-   struct Scsi_Host *sh;
-   ips_ha_t *ha;                                                                 
-   
-   for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
-      ha = ips_ha[i];
-      if (ha) {
-         if ( (pci_dev->bus->number == ha->pcidev->bus->number) &&
-              (pci_dev->devfn == ha->pcidev->devfn)) {
-            sh = ips_sh[i];
-            ips_release(sh);     
-         }
-      }
-   }
+	int i;
+	struct Scsi_Host *sh;
+	ips_ha_t *ha;
+
+	for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
+		ha = ips_ha[i];
+		if (ha) {
+			if ((pci_dev->bus->number == ha->pcidev->bus->number) &&
+			    (pci_dev->devfn == ha->pcidev->devfn)) {
+				sh = ips_sh[i];
+				ips_release(sh);
+			}
+		}
+	}
 }
 
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_module_init                                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   function called on module load                                         */
+/****************************************************************************/
+static int __init
+ips_module_init(void)
+{
+	if (pci_module_init(&ips_pci_driver) < 0)
+		return -ENODEV;
+	ips_driver_template.module = THIS_MODULE;
+	ips_order_controllers();
+	if (scsi_register_module(MODULE_SCSI_HA, &ips_driver_template)) {
+		pci_unregister_driver(&ips_pci_driver);
+		return -ENODEV;
+	}
+	register_reboot_notifier(&ips_notifier);
+	return 0;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_module_exit                                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   function called on module unload                                       */
+/****************************************************************************/
+static void __exit
+ips_module_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &ips_driver_template);
+	pci_unregister_driver(&ips_pci_driver);
+	unregister_reboot_notifier(&ips_notifier);
+}
+
+module_init(ips_module_init);
+module_exit(ips_module_exit);
 
 /*---------------------------------------------------------------------------*/
 /*   Routine Name: ips_insert_device                                         */
@@ -7371,40 +7130,28 @@
 /*   Return Value:                                                           */
 /*     0 if Successful, else non-zero                                        */
 /*---------------------------------------------------------------------------*/
-static int __devinit ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
+static int __devinit
+ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
 {
-    int  index;
-    int  rc;
+	int index;
+	int rc;
 
-    METHOD_TRACE("ips_insert_device", 1);
+	METHOD_TRACE("ips_insert_device", 1);
 
-    /* If we're still in Init State 0, and we've already found the Adapter */
-    /* Ordering Table, there is no reason to continue.                     */
-    if ( (InitState == 0) && (AdapterOrder[0]) ) 
-        return -1;
-    
-    if (pci_enable_device(pci_dev)) 
+	if (pci_enable_device(pci_dev))
 		return -1;
 
-    rc = ips_init_phase1(pci_dev, &index);
-    if (rc == SUCCESS)
-       rc = ips_init_phase2(index); 
-
-    /* If we're in Init State 0, we're done with the device for now. */
-    /* Release the device and don't count it.                        */
-    if ( InitState == 0 ) {
-        ips_remove_device(pci_dev);
-		return -1;
-    }
+	rc = ips_init_phase1(pci_dev, &index);
+	if (rc == SUCCESS)
+		rc = ips_init_phase2(index);
 
-    if (rc == SUCCESS)
-       ips_num_controllers++;
+	if (rc == SUCCESS)
+		ips_num_controllers++;
 
-    ips_next_controller = ips_num_controllers;
-    return rc;
+	ips_next_controller = ips_num_controllers;
+	return rc;
 }
 
-
 /*---------------------------------------------------------------------------*/
 /*   Routine Name: ips_init_phase1                                           */
 /*                                                                           */
@@ -7414,248 +7161,232 @@
 /*   Return Value:                                                           */
 /*     0 if Successful, else non-zero                                        */
 /*---------------------------------------------------------------------------*/
-static int ips_init_phase1( struct pci_dev *pci_dev, int *indexPtr )
-{         
-   struct Scsi_Host *sh;
-   ips_ha_t         *ha;
-   uint32_t          io_addr;
-   uint32_t          mem_addr;
-   uint32_t          io_len;
-   uint32_t          mem_len;
-   uint8_t           revision_id;
-   uint8_t           bus;
-   uint8_t           func;
-   uint8_t           irq;
-   uint16_t          subdevice_id;
-   int               j;
-   int               index; 
-   uint32_t          count;
-   dma_addr_t        dma_address;
-   char             *ioremap_ptr;
-   char             *mem_ptr;             
-   uint32_t          IsDead
-
-   METHOD_TRACE("ips_init_phase1", 1);
-   index = IPS_MAX_ADAPTERS;
-   for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
-       if (ips_ha[j] ==0) {
-          index = j;
-          break;
-       }
-   }
-
-   if (index >= IPS_MAX_ADAPTERS)
-      return -1;
-   
-   /* stuff that we get in dev */
-    irq  = pci_dev->irq;
-    bus  = pci_dev->bus->number;
-    func = pci_dev->devfn;
-
-    /* Init MEM/IO addresses to 0 */
-    mem_addr = 0;
-    io_addr  = 0;
-    mem_len  = 0;
-    io_len   = 0;
-
-    for (j = 0; j < 2; j++) {
-       if (!pci_resource_start(pci_dev, j))
-          break;
-
-       if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) {
-          io_addr = pci_resource_start(pci_dev, j);
-          io_len = pci_resource_len(pci_dev, j);
-       } else {
-          mem_addr = pci_resource_start(pci_dev, j);
-          mem_len = pci_resource_len(pci_dev, j);
-       }
-    }
-
-    /* setup memory mapped area (if applicable) */
-    if (mem_addr) {
-       uint32_t base;
-       uint32_t offs;
-
-       if (check_mem_region(mem_addr, mem_len)) {
-          printk(KERN_WARNING "Couldn't allocate IO Memory space %x len %d.\n", mem_addr, mem_len);
-          return -1;
-          }
-
-       request_mem_region(mem_addr, mem_len, "ips");
-       base = mem_addr & PAGE_MASK;
-       offs = mem_addr - base;
-       ioremap_ptr = ioremap(base, PAGE_SIZE);
-       mem_ptr = ioremap_ptr + offs;
-    } else {
-       ioremap_ptr = NULL;
-       mem_ptr = NULL;
-    }
-
-    /* setup I/O mapped area (if applicable) */
-    if (io_addr) {
-       if (check_region(io_addr, io_len)) {
-          printk(KERN_WARNING "Couldn't allocate IO space %x len %d.\n", io_addr, io_len);
-          return -1;
-       }
-       request_region(io_addr, io_len, "ips");
-    }
-
-    /* get the revision ID */
-    if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) {
-       printk(KERN_WARNING "Can't get revision id.\n" );
-       return -1;
-    }
-
-    subdevice_id = pci_dev->subsystem_device;
-
-    /* found a controller */
-    sh = scsi_register(&driver_template, sizeof(ips_ha_t));
-#if LINUX_VERSION_CODE > LinuxVersionCode(2,5,0) 
-    pci_set_dma_mask(pci_dev, (u64)0xffffffff);
-    scsi_set_pci_device(sh, pci_dev);
-#endif
-    if (sh == NULL) {
-       printk(KERN_WARNING "Unable to register controller with SCSI subsystem\n" );
-       return -1;
-    }
-
-    ha = IPS_HA(sh);
-    memset(ha, 0, sizeof(ips_ha_t));
-    
-    ips_sh[index] = sh;
-    ips_ha[index] = ha;
-    ha->active = 1;
-
-    ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_KERNEL);
-
-    if (!ha->enq) {
-       printk(KERN_WARNING "Unable to allocate host inquiry structure\n" );
-       return ips_abort_init(ha, sh, index);
-    }
-
-    ha->adapt = pci_alloc_consistent(pci_dev, sizeof(IPS_ADAPTER) +
-                                     sizeof(IPS_IO_CMD), &dma_address);
-    if (!ha->adapt) {
-       printk(KERN_WARNING "Unable to allocate host adapt & dummy structures\n");
-       return ips_abort_init(ha, sh, index);
-    }
-    ha->adapt->hw_status_start = dma_address;
-    ha->dummy = (void *)(ha->adapt + 1);
-
-    ha->conf = kmalloc(sizeof(IPS_CONF), GFP_KERNEL);
-
-    if (!ha->conf) {
-       printk(KERN_WARNING "Unable to allocate host conf structure\n" );
-       return ips_abort_init(ha, sh, index);
-    }
-
-    ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_KERNEL);
-
-    if (!ha->nvram) {
-       printk(KERN_WARNING "Unable to allocate host NVRAM structure\n" );
-       return ips_abort_init(ha, sh, index);
-    }
-
-    ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_KERNEL);
-
-    if (!ha->subsys) {
-       printk(KERN_WARNING "Unable to allocate host subsystem structure\n" );
-       return ips_abort_init(ha, sh, index);
-    }
-
-    for (count = PAGE_SIZE, ha->ioctl_order = 0;
-         count < ips_ioctlsize;
-         ha->ioctl_order++, count <<= 1);
-
-    ha->ioctl_data = (char *) __get_free_pages(GFP_KERNEL, ha->ioctl_order);
-    ha->ioctl_datasize = count;
-
-    if (!ha->ioctl_data) {
-       printk(KERN_WARNING "Unable to allocate IOCTL data\n" );
-       ha->ioctl_data = NULL;
-       ha->ioctl_order = 0;
-       ha->ioctl_datasize = 0;
-    }
-
-    /* Store away needed values for later use */
-    sh->io_port = io_addr;
-    sh->n_io_port = io_addr ? 255 : 0;
-    sh->unique_id = (io_addr) ? io_addr : mem_addr;
-    sh->irq = irq;
-    sh->select_queue_depths = ips_select_queue_depth;
-    sh->sg_tablesize = sh->hostt->sg_tablesize;
-    sh->can_queue = sh->hostt->can_queue;
-    sh->cmd_per_lun = sh->hostt->cmd_per_lun;
-    sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
-    sh->use_clustering = sh->hostt->use_clustering;
+static int
+ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
+{
+	ips_ha_t *ha;
+	uint32_t io_addr;
+	uint32_t mem_addr;
+	uint32_t io_len;
+	uint32_t mem_len;
+	uint8_t revision_id;
+	uint8_t bus;
+	uint8_t func;
+	uint8_t irq;
+	uint16_t subdevice_id;
+	int j;
+	int index;
+	uint32_t count;
+	dma_addr_t dma_address;
+	char *ioremap_ptr;
+	char *mem_ptr;
+	uint32_t IsDead;
+
+	METHOD_TRACE("ips_init_phase1", 1);
+	index = IPS_MAX_ADAPTERS;
+	for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
+		if (ips_ha[j] == 0) {
+			index = j;
+			break;
+		}
+	}
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
-    sh->max_sectors = 128;
-#endif                      
+	if (index >= IPS_MAX_ADAPTERS)
+		return -1;
 
-    /* Store info in HA structure */
-    ha->irq = irq;
-    ha->io_addr = io_addr;
-    ha->io_len = io_len;
-    ha->mem_addr = mem_addr;
-    ha->mem_len = mem_len;
-    ha->mem_ptr = mem_ptr;
-    ha->ioremap_ptr = ioremap_ptr;
-    ha->host_num = ( uint32_t) index;
-    ha->revision_id = revision_id;
-    ha->slot_num = PCI_SLOT(pci_dev->devfn);
-    ha->device_id = pci_dev->device;
-    ha->subdevice_id = subdevice_id;
-    ha->pcidev = pci_dev;
-
-    /*
-     * Setup Functions
-     */
-    ips_setup_funclist(ha);
-
-    if ( ( IPS_IS_MORPHEUS( ha ) ) || ( IPS_IS_MARCO( ha ) ) ) {
-        /* If Morpheus appears dead, reset it */
-        IsDead = readl( ha->mem_ptr + IPS_REG_I960_MSG1 );
-        if ( IsDead == 0xDEADBEEF ) {
-            ips_reset_morpheus( ha );
-        }
-    }
-
-    /*
-     * Initialize the card if it isn't already
-     */
-
-    if (!(*ha->func.isinit)(ha)) {
-       if (!(*ha->func.init)(ha)) {
-          /*
-           * Initialization failed
-           */
-          printk(KERN_WARNING "Unable to initialize controller\n" );
-          return ips_abort_init(ha, sh, index);
-       }
-    }
-
-    /* Install the interrupt handler */
-     if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
-       printk(KERN_WARNING "Unable to install interrupt handler\n" );
-       return ips_abort_init(ha, sh, index);
-    }
-
-    /*
-     * Allocate a temporary SCB for initialization
-     */
-    ha->max_cmds = 1;
-    if (!ips_allocatescbs(ha)) {
-       printk(KERN_WARNING "Unable to allocate a CCB\n" );
-       free_irq(ha->irq, ha);
-       return ips_abort_init(ha, sh, index);
-    }
+	/* stuff that we get in dev */
+	irq = pci_dev->irq;
+	bus = pci_dev->bus->number;
+	func = pci_dev->devfn;
+
+	/* Init MEM/IO addresses to 0 */
+	mem_addr = 0;
+	io_addr = 0;
+	mem_len = 0;
+	io_len = 0;
+
+	for (j = 0; j < 2; j++) {
+		if (!pci_resource_start(pci_dev, j))
+			break;
+
+		if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) {
+			io_addr = pci_resource_start(pci_dev, j);
+			io_len = pci_resource_len(pci_dev, j);
+		} else {
+			mem_addr = pci_resource_start(pci_dev, j);
+			mem_len = pci_resource_len(pci_dev, j);
+		}
+	}
+
+	/* setup memory mapped area (if applicable) */
+	if (mem_addr) {
+		uint32_t base;
+		uint32_t offs;
+
+		if (!request_mem_region(mem_addr, mem_len, "ips")) {
+			printk(KERN_WARNING
+			       "Couldn't allocate IO Memory space %x len %d.\n",
+			       mem_addr, mem_len);
+			return -1;
+		}
+
+		base = mem_addr & PAGE_MASK;
+		offs = mem_addr - base;
+		ioremap_ptr = ioremap(base, PAGE_SIZE);
+		mem_ptr = ioremap_ptr + offs;
+	} else {
+		ioremap_ptr = NULL;
+		mem_ptr = NULL;
+	}
+
+	/* setup I/O mapped area (if applicable) */
+	if (io_addr) {
+		if (!request_region(io_addr, io_len, "ips")) {
+			printk(KERN_WARNING
+			       "Couldn't allocate IO space %x len %d.\n",
+			       io_addr, io_len);
+			return -1;
+		}
+	}
+
+	/* get the revision ID */
+	if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) {
+		printk(KERN_WARNING "Can't get revision id.\n");
+		return -1;
+	}
 
-    *indexPtr = index;
-    return SUCCESS;
-}
+	subdevice_id = pci_dev->subsystem_device;
 
-#endif
+	/* found a controller */
+	ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);
+	if (ha == NULL) {
+		printk(KERN_WARNING "Unable to allocate temporary ha struct\n");
+		return -1;
+	}
+
+	memset(ha, 0, sizeof (ips_ha_t));
+
+	ips_sh[index] = NULL;
+	ips_ha[index] = ha;
+	ha->active = 1;
+
+	/* Store info in HA structure */
+	ha->irq = irq;
+	ha->io_addr = io_addr;
+	ha->io_len = io_len;
+	ha->mem_addr = mem_addr;
+	ha->mem_len = mem_len;
+	ha->mem_ptr = mem_ptr;
+	ha->ioremap_ptr = ioremap_ptr;
+	ha->host_num = (uint32_t) index;
+	ha->revision_id = revision_id;
+	ha->slot_num = PCI_SLOT(pci_dev->devfn);
+	ha->device_id = pci_dev->device;
+	ha->subdevice_id = subdevice_id;
+	ha->pcidev = pci_dev;
+
+	/*
+	 * Set the pci_dev's dma_mask.  Not all adapters support 64bit
+	 * addressing so don't enable it if the adapter can't support
+	 * it!  Also, don't use 64bit addressing if dma addresses
+	 * are guaranteed to be < 4G.
+	 */
+	if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) &&
+	    !pci_set_dma_mask(ha->pcidev, (u64) 0xffffffffffffffff)) {
+		(ha)->flags |= IPS_HA_ENH_SG;
+	} else {
+		if (pci_set_dma_mask(ha->pcidev, (u64) 0xffffffff) != 0) {
+			printk(KERN_WARNING "Unable to set DMA Mask\n");
+			return ips_abort_init(ha, index);
+		}
+	}
+
+	ha->enq = kmalloc(sizeof (IPS_ENQ), IPS_INIT_GFP);
+
+	if (!ha->enq) {
+		printk(KERN_WARNING
+		       "Unable to allocate host inquiry structure\n");
+		return ips_abort_init(ha, index);
+	}
+
+	ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) +
+					 sizeof (IPS_IO_CMD), &dma_address);
+	if (!ha->adapt) {
+		printk(KERN_WARNING
+		       "Unable to allocate host adapt & dummy structures\n");
+		return ips_abort_init(ha, index);
+	}
+	ha->adapt->hw_status_start = dma_address;
+	ha->dummy = (void *) (ha->adapt + 1);
+
+	ha->conf = kmalloc(sizeof (IPS_CONF), IPS_INIT_GFP);
+
+	if (!ha->conf) {
+		printk(KERN_WARNING "Unable to allocate host conf structure\n");
+		return ips_abort_init(ha, index);
+	}
+
+	ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), IPS_INIT_GFP);
+
+	if (!ha->nvram) {
+		printk(KERN_WARNING
+		       "Unable to allocate host NVRAM structure\n");
+		return ips_abort_init(ha, index);
+	}
+
+	ha->subsys = kmalloc(sizeof (IPS_SUBSYS), IPS_INIT_GFP);
+
+	if (!ha->subsys) {
+		printk(KERN_WARNING
+		       "Unable to allocate host subsystem structure\n");
+		return ips_abort_init(ha, index);
+	}
+
+	for (count = PAGE_SIZE, ha->ioctl_order = 0;
+	     count < ips_ioctlsize; ha->ioctl_order++, count <<= 1) ;
+
+	ha->ioctl_data =
+	    (char *) __get_free_pages(IPS_INIT_GFP, ha->ioctl_order);
+	ha->ioctl_datasize = count;
+
+	if (!ha->ioctl_data) {
+		printk(KERN_WARNING "Unable to allocate IOCTL data\n");
+		ha->ioctl_data = NULL;
+		ha->ioctl_order = 0;
+		ha->ioctl_datasize = 0;
+	}
+
+	/*
+	 * Setup Functions
+	 */
+	ips_setup_funclist(ha);
+
+	if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) {
+		/* If Morpheus appears dead, reset it */
+		IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
+		if (IsDead == 0xDEADBEEF) {
+			ips_reset_morpheus(ha);
+		}
+	}
+
+	/*
+	 * Initialize the card if it isn't already
+	 */
+
+	if (!(*ha->func.isinit) (ha)) {
+		if (!(*ha->func.init) (ha)) {
+			/*
+			 * Initialization failed
+			 */
+			printk(KERN_WARNING
+			       "Unable to initialize controller\n");
+			return ips_abort_init(ha, index);
+		}
+	}
+
+	*indexPtr = index;
+	return SUCCESS;
+}
 
 /*---------------------------------------------------------------------------*/
 /*   Routine Name: ips_init_phase2                                           */
@@ -7666,46 +7397,52 @@
 /*   Return Value:                                                           */
 /*     0 if Successful, else non-zero                                        */
 /*---------------------------------------------------------------------------*/
-static int ips_init_phase2( int index )
-{         
-    struct Scsi_Host *sh;
-    ips_ha_t         *ha;
-
-    ha = ips_ha[index];
-    sh = ips_sh[index];
-
-    METHOD_TRACE("ips_init_phase2", 1);
-    if (!ha->active) {
-       scsi_unregister(sh);
-       ips_ha[index] = NULL;
-       ips_sh[index] = NULL;
-       return -1;;
-    }
-
-    if (!ips_hainit(ha)) {
-       printk(KERN_WARNING "Unable to initialize controller\n" );
-       free_irq(ha->irq, ha);
-       return ips_abort_init(ha, sh, index);
-    }
-    /* Free the temporary SCB */
-    ips_deallocatescbs(ha, 1);
-
-    /* allocate CCBs */
-    if (!ips_allocatescbs(ha)) {
-       printk(KERN_WARNING "Unable to allocate CCBs\n" );
-       free_irq(ha->irq, ha);
-       return ips_abort_init(ha, sh, index);
-    }
-
-    /* finish setting values */
-    sh->max_id = ha->ntargets;
-    sh->max_lun = ha->nlun;
-    sh->max_channel = ha->nbus - 1;
-    sh->can_queue = ha->max_cmds-1;
+static int
+ips_init_phase2(int index)
+{
+	ips_ha_t *ha;
 
-    return SUCCESS;
-}
+	ha = ips_ha[index];
+
+	METHOD_TRACE("ips_init_phase2", 1);
+	if (!ha->active) {
+		ips_ha[index] = NULL;
+		return -1;
+	}
+
+	/* Install the interrupt handler */
+	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+		printk(KERN_WARNING "Unable to install interrupt handler\n");
+		return ips_abort_init(ha, index);
+	}
+
+	/*
+	 * Allocate a temporary SCB for initialization
+	 */
+	ha->max_cmds = 1;
+	if (!ips_allocatescbs(ha)) {
+		printk(KERN_WARNING "Unable to allocate a CCB\n");
+		free_irq(ha->irq, ha);
+		return ips_abort_init(ha, index);
+	}
+
+	if (!ips_hainit(ha)) {
+		printk(KERN_WARNING "Unable to initialize controller\n");
+		free_irq(ha->irq, ha);
+		return ips_abort_init(ha, index);
+	}
+	/* Free the temporary SCB */
+	ips_deallocatescbs(ha, 1);
+
+	/* allocate CCBs */
+	if (!ips_allocatescbs(ha)) {
+		printk(KERN_WARNING "Unable to allocate CCBs\n");
+		free_irq(ha->irq, ha);
+		return ips_abort_init(ha, index);
+	}
 
+	return SUCCESS;
+}
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,9)
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/ips.h b/drivers/scsi/ips.h
--- a/drivers/scsi/ips.h	Mon Mar  3 07:41:19 2003
+++ b/drivers/scsi/ips.h	Mon Jun 16 14:04:19 2003
@@ -69,6 +69,13 @@
       #define LinuxVersionCode(x,y,z)  (((x)<<16)+((y)<<8)+(z))
    #endif
 
+   #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,20) || defined CONFIG_HIGHIO
+      #define IPS_HIGHIO
+      #define IPS_HIGHMEM_IO     .highmem_io = 1,
+   #else
+      #define IPS_HIGHMEM_IO
+   #endif
+
    #define IPS_HA(x)                   ((ips_ha_t *) x->hostdata)
    #define IPS_COMMAND_ID(ha, scb)     (int) (scb - ha->scbs)
    #define IPS_IS_TROMBONE(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
@@ -86,10 +93,42 @@
                                          ((IPS_IS_TROMBONE(ha) || IPS_IS_CLARINET(ha)) && \
                                           (ips_force_memio))) ? 1 : 0)
 
+    #define IPS_HAS_ENH_SGLIST(ha)    (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha))
+    #define IPS_USE_ENH_SGLIST(ha)    ((ha)->flags & IPS_HA_ENH_SG)
+    #define IPS_SGLIST_SIZE(ha)       (IPS_USE_ENH_SGLIST(ha) ? \
+                                         sizeof(IPS_ENH_SG_LIST) : sizeof(IPS_STD_SG_LIST))
+
+   #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4)
+      #define pci_set_dma_mask(dev,mask) ( mask > 0xffffffff ? 1:0 )
+      #define scsi_set_pci_device(sh,dev) (0)
+   #endif
+
    #ifndef MDELAY
       #define MDELAY mdelay
    #endif
-   
+
+   #ifndef min
+      #define min(x,y) ((x) < (y) ? x : y)
+   #endif
+
+   #define pci_dma_lo32(a)         (a & 0xffffffff)
+
+   #if (BITS_PER_LONG > 32) || (defined CONFIG_HIGHMEM64G && defined IPS_HIGHIO)
+      #define IPS_ENABLE_DMA64        (1)
+      #define pci_dma_hi32(a)         (a >> 32)
+   #else
+      #define IPS_ENABLE_DMA64        (0)
+      #define pci_dma_hi32(a)         (0)
+   #endif
+
+   #if defined(__ia64__)
+      #define IPS_ATOMIC_GFP	(GFP_DMA | GFP_ATOMIC)
+      #define IPS_INIT_GFP	GFP_DMA
+   #else
+      #define IPS_ATOMIC_GFP    GFP_ATOMIC
+      #define IPS_INIT_GFP	GFP_KERNEL
+   #endif
+
    /*
     * Adapter address map equates
     */
@@ -354,6 +393,12 @@
    #define IPS_SCSI_MP3_AllocateSurface 0x08
 
    /*
+    * HA Flags
+    */
+
+   #define IPS_HA_ENH_SG                0x1
+
+   /*
     * SCB Flags
     */
    #define IPS_SCB_MAP_SG               0x00008
@@ -390,93 +435,45 @@
    /*
     * Scsi_Host Template
     */
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
- #define IPS {                            \
-    next : NULL,                          \
-    module : NULL,                        \
-    proc_info : NULL,                     \
-    proc_dir : NULL,                      \
-    name : NULL,                          \
-    detect : ips_detect,                  \
-    release : ips_release,                \
-    info : ips_info,                      \
-    command : NULL,                       \
-    queuecommand : ips_queue,             \
-    eh_strategy_handler : NULL,           \
-    eh_abort_handler : ips_eh_abort,      \
-    eh_device_reset_handler : NULL,       \
-    eh_bus_reset_handler : NULL,          \
-    eh_host_reset_handler : ips_eh_reset, \
-    abort : NULL,                         \
-    reset : NULL,                         \
-    slave_attach : NULL,                  \
-    bios_param : ips_biosparam,           \
-    can_queue : 0,                        \
-    this_id: -1,                          \
-    sg_tablesize : IPS_MAX_SG,            \
-    cmd_per_lun: 16,                      \
-    present : 0,                          \
-    unchecked_isa_dma : 0,                \
-    use_clustering : ENABLE_CLUSTERING,   \
-    use_new_eh_code : 1                   \
-}
-#elif LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
- #define IPS {                            \
-    next : NULL,                          \
-    module : NULL,                        \
-    proc_info : NULL,                     \
-    name : NULL,                          \
-    detect : ips_detect,                  \
-    release : ips_release,                \
-    info : ips_info,                      \
-    command : NULL,                       \
-    queuecommand : ips_queue,             \
-    eh_strategy_handler : NULL,           \
-    eh_abort_handler : ips_eh_abort,      \
-    eh_device_reset_handler : NULL,       \
-    eh_bus_reset_handler : NULL,          \
-    eh_host_reset_handler : ips_eh_reset, \
-    abort : NULL,                         \
-    reset : NULL,                         \
-    slave_attach : NULL,                  \
-    bios_param : ips_biosparam,           \
-    can_queue : 0,                        \
-    this_id: -1,                          \
-    sg_tablesize : IPS_MAX_SG,            \
-    cmd_per_lun: 16,                      \
-    present : 0,                          \
-    unchecked_isa_dma : 0,                \
-    use_clustering : ENABLE_CLUSTERING,   \
-    use_new_eh_code : 1                   \
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
+   static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
+#define IPS {	\
+	.detect				= ips_detect,	\
+	.release			= ips_release,	\
+	.info				= ips_info,	\
+	.queuecommand			= ips_queue,	\
+	.eh_abort_handler		= ips_eh_abort,	\
+	.eh_host_reset_handler		= ips_eh_reset,	\
+	.bios_param			= ips_biosparam,\
+	.select_queue_depths		= ips_select_queue_depth, \
+	.can_queue			= 0,		\
+	.this_id			= -1,		\
+	.sg_tablesize			= IPS_MAX_SG,	\
+	.cmd_per_lun			= 16,		\
+	.present			= 0,		\
+	.unchecked_isa_dma		= 0,		\
+	.use_clustering			= ENABLE_CLUSTERING,\
+	.use_new_eh_code		= 1, \
+	IPS_HIGHMEM_IO \
 }
 #else
- #define IPS {                            \
-    next : NULL,                          \
-    module : NULL,                        \
-    proc_info : NULL,                     \
-    name : NULL,                          \
-    detect : ips_detect,                  \
-    release : ips_release,                \
-    info : ips_info,                      \
-    command : NULL,                       \
-    queuecommand : ips_queue,             \
-    eh_strategy_handler : NULL,           \
-    eh_abort_handler : ips_eh_abort,      \
-    eh_device_reset_handler : NULL,       \
-    eh_bus_reset_handler : NULL,          \
-    eh_host_reset_handler : ips_eh_reset, \
-    abort : NULL,                         \
-    reset : NULL,                         \
-    slave_attach : NULL,                  \
-    bios_param : ips_biosparam,           \
-    can_queue : 0,                        \
-    this_id: -1,                          \
-    sg_tablesize : IPS_MAX_SG,            \
-    cmd_per_lun: 16,                      \
-    present : 0,                          \
-    unchecked_isa_dma : 0,                \
-    use_clustering : ENABLE_CLUSTERING,   \
-    highmem_io : 1                        \
+#define IPS {	\
+	.detect			= ips_detect,		\
+	.release		= ips_release,		\
+	.info			= ips_info,		\
+	.queuecommand		= ips_queue,		\
+	.eh_abort_handler	= ips_eh_abort,		\
+	.eh_host_reset_handler	= ips_eh_reset,		\
+	.slave_configure	= ips_slave_configure,	\
+	.bios_param		= ips_biosparam,	\
+	.can_queue		= 0,			\
+	.this_id		= -1,			\
+	.sg_tablesize		= IPS_MAX_SG,		\
+	.cmd_per_lun		= 3,			\
+	.present		= 0,			\
+	.unchecked_isa_dma	= 0,			\
+	.use_clustering		= ENABLE_CLUSTERING,	\
+	.highmem_io		= 1 \
 }
 #endif
 
@@ -491,7 +488,8 @@
    uint32_t lba;
    uint32_t sg_addr;
    uint16_t sector_count;
-   uint16_t reserved;
+   uint8_t  segment_4G;
+   uint8_t  enhanced_sg;
    uint32_t ccsar;
    uint32_t cccr;
 } IPS_IO_CMD, *PIPS_IO_CMD;
@@ -542,7 +540,9 @@
    uint16_t reserved;
    uint32_t reserved2;
    uint32_t dcdb_address;
-   uint32_t reserved3;
+   uint16_t reserved3;
+   uint8_t  segment_4G;
+   uint8_t  enhanced_sg;
    uint32_t ccsar;
    uint32_t cccr;
 } IPS_DCDB_CMD, *PIPS_DCDB_CMD;
@@ -986,7 +986,20 @@
 typedef struct ips_sglist {
    uint32_t address;
    uint32_t length;
-} IPS_SG_LIST, *PIPS_SG_LIST;
+} IPS_STD_SG_LIST;
+
+typedef struct ips_enh_sglist {
+   uint32_t address_lo;
+   uint32_t address_hi;
+   uint32_t length;
+   uint32_t reserved;
+} IPS_ENH_SG_LIST;
+
+typedef union {
+   void             *list;
+   IPS_STD_SG_LIST  *std_list;
+   IPS_ENH_SG_LIST  *enh_list;
+} IPS_SG_LIST;
 
 typedef struct _IPS_INFOSTR {
    char *buffer;
@@ -1086,6 +1099,7 @@
    char              *ioctl_data;         /* IOCTL data area            */
    uint32_t           ioctl_datasize;     /* IOCTL data size            */
    uint32_t           cmd_in_progress;    /* Current command in progress*/
+   int                flags;              /*                            */
    uint8_t            waitflag;           /* are we waiting for cmd     */
    uint8_t            active;
    int                ioctl_reset;        /* IOCTL Requested Reset Flag */
@@ -1133,7 +1147,7 @@
    uint32_t          sg_len;
    uint32_t          flags;
    uint32_t          op_code;
-   IPS_SG_LIST      *sg_list;
+   IPS_SG_LIST       sg_list;
    Scsi_Cmnd        *scsi_cmd;
    struct ips_scb   *q_next;
    ips_scb_callback  callback;
@@ -1194,11 +1208,13 @@
 
 #define IPS_VER_MAJOR 6
 #define IPS_VER_MAJOR_STRING "6"
-#define IPS_VER_MINOR 00
-#define IPS_VER_MINOR_STRING "00"
-#define IPS_VER_BUILD 26
-#define IPS_VER_BUILD_STRING "26"
-#define IPS_VER_STRING "6.00.26"
+#define IPS_VER_MINOR 10
+#define IPS_VER_MINOR_STRING "10"
+#define IPS_VER_BUILD 24
+#define IPS_VER_BUILD_STRING "24"
+#define IPS_VER_STRING "6.10.24"
+#define IPS_RELEASE_ID 0x00010000
+#define IPS_BUILD_IDENT 1250
 #define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2003. All Rights Reserved."
 #define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to present. All Rights Reserved."
 #define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2003."
@@ -1207,31 +1223,33 @@
 #define IPS_VER_SERVERAID1 "2.25.01"
 #define IPS_VER_SERVERAID2 "2.88.13"
 #define IPS_VER_NAVAJO "2.88.13"
-#define IPS_VER_SERVERAID3 "6.00.26"
-#define IPS_VER_SERVERAID4H "6.00.26"
-#define IPS_VER_SERVERAID4MLx "6.00.26"
-#define IPS_VER_SARASOTA "6.00.26"
-#define IPS_VER_MARCO "6.00.26"
+#define IPS_VER_SERVERAID3 "6.10.24"
+#define IPS_VER_SERVERAID4H "6.10.24"
+#define IPS_VER_SERVERAID4MLx "6.10.24"
+#define IPS_VER_SARASOTA "6.10.24"
+#define IPS_VER_MARCO "6.10.24"
+#define IPS_VER_SEBRING "6.10.24"
 
 /* Compatability IDs for various adapters */
 #define IPS_COMPAT_UNKNOWN ""
-#define IPS_COMPAT_CURRENT "MR600"
+#define IPS_COMPAT_CURRENT "SB610"
 #define IPS_COMPAT_SERVERAID1 "2.25.01"
 #define IPS_COMPAT_SERVERAID2 "2.88.13"
 #define IPS_COMPAT_NAVAJO  "2.88.13"
 #define IPS_COMPAT_KIOWA "2.88.13"
-#define IPS_COMPAT_SERVERAID3H  "MR600"
-#define IPS_COMPAT_SERVERAID3L  "MR600"
-#define IPS_COMPAT_SERVERAID4H  "MR600"
-#define IPS_COMPAT_SERVERAID4M  "MR600"
-#define IPS_COMPAT_SERVERAID4L  "MR600"
-#define IPS_COMPAT_SERVERAID4Mx "MR600"
-#define IPS_COMPAT_SERVERAID4Lx "MR600"
-#define IPS_COMPAT_SARASOTA     "MR600"
-#define IPS_COMPAT_MARCO        "MR600"
-#define IPS_COMPAT_BIOS "MR600"
+#define IPS_COMPAT_SERVERAID3H  "SB610"
+#define IPS_COMPAT_SERVERAID3L  "SB610"
+#define IPS_COMPAT_SERVERAID4H  "SB610"
+#define IPS_COMPAT_SERVERAID4M  "SB610"
+#define IPS_COMPAT_SERVERAID4L  "SB610"
+#define IPS_COMPAT_SERVERAID4Mx "SB610"
+#define IPS_COMPAT_SERVERAID4Lx "SB610"
+#define IPS_COMPAT_SARASOTA     "SB610"
+#define IPS_COMPAT_MARCO        "SB610"
+#define IPS_COMPAT_SEBRING      "SB610"
+#define IPS_COMPAT_BIOS "SB610"
 
-#define IPS_COMPAT_MAX_ADAPTER_TYPE 15
+#define IPS_COMPAT_MAX_ADAPTER_TYPE 16
 #define IPS_COMPAT_ID_LENGTH 8
 
 #define IPS_DEFINE_COMPAT_TABLE(tablename) \
@@ -1250,7 +1268,8 @@
       IPS_COMPAT_SERVERAID4Lx, \
       IPS_COMPAT_SARASOTA,         /* one-channel variety of SARASOTA */  \
       IPS_COMPAT_SARASOTA,         /* two-channel variety of SARASOTA */  \
-      IPS_COMPAT_MARCO \
+      IPS_COMPAT_MARCO, \
+      IPS_COMPAT_SEBRING \
    }
 
 
diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Sun Jun 29 13:05:10 2003
+++ b/drivers/scsi/scsi_scan.c	Tue Aug 26 10:28:41 2003
@@ -114,7 +114,8 @@
 	{"HP", "C2500A", "", BLIST_NOLUN},			/* scanjet iicx */
 	{"HP", "A6188A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7100 Array */
 	{"HP", "A6189A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7400 Array */
-	{"HP", "A6189B", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7410 Array */
+	{"HP", "A6189B", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7110 Array */
+	{"HP", "A6218A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7410 Array */
 	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
 	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},		/* Locks up if polled for lun != 0  
 								 * extra reset */
diff -Nru a/drivers/sound/Config.in b/drivers/sound/Config.in
--- a/drivers/sound/Config.in	Tue Jul 15 14:31:57 2003
+++ b/drivers/sound/Config.in	Thu Aug 28 09:03:59 2003
@@ -7,6 +7,12 @@
 # Prompt user for primary drivers.
 
 dep_tristate '  ALi5455 audio support' CONFIG_SOUND_ALI5455 $CONFIG_SOUND $CONFIG_PCI
+if [ "$CONFIG_SOUND_ALI5455" = "y" -o "$CONFIG_SOUND_ALI5455" = "m" ]; then
+    bool  '   Enable Codec SPDIF OUT ( Pcm Out Share )' CONFIG_SOUND_ALI5455_CODECSPDIFOUT_PCMOUTSHARE
+    bool  '   Enable Codec SPDIF OUT ( Codec Independent DMA )' CONFIG_SOUND_ALI5455_CODECSPDIFOUT_CODECINDEPENDENTDMA
+    bool  '   Enable Controller SPDIF OUT ( Pcm Out Share )' CONFIG_SOUND_ALI5455_CONTROLLERSPDIFOUT_PCMOUTSHARE
+    bool  '   Enable Controller SPDIF OUT ( Controller Independent DMA )' CONFIG_SOUND_ALI5455_CONTROLLERSPDIFOUT_CONTROLLERINDEPENDENTDMA
+fi
 dep_tristate '  BT878 audio dma' CONFIG_SOUND_BT878 $CONFIG_SOUND $CONFIG_PCI
 dep_tristate '  C-Media PCI (CMI8338/8738)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI
 if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then
@@ -225,6 +231,10 @@
 fi
 
 dep_tristate '  TV card (bt848) mixer support' CONFIG_SOUND_TVMIXER $CONFIG_SOUND $CONFIG_I2C
+
+dep_tristate '  AD1980 front/back switch plugin' CONFIG_SOUND_AD1980 $CONFIG_SOUND 
+
+dep_tristate '  Wolfson Touchscreen/BMON plugin' CONFIG_SOUND_WM97XX $CONFIG_SOUND 
 
 # A cross directory dependence. The sound modules will need gameport.o compiled in,
 # but it resides in the drivers/char/joystick directory. This define_tristate takes
diff -Nru a/drivers/sound/Makefile b/drivers/sound/Makefile
--- a/drivers/sound/Makefile	Fri Jul  4 20:50:41 2003
+++ b/drivers/sound/Makefile	Thu Aug 28 09:04:21 2003
@@ -81,6 +81,8 @@
 obj-$(CONFIG_SOUND_RME96XX)     += rme96xx.o
 obj-$(CONFIG_SOUND_BT878)	+= btaudio.o
 obj-$(CONFIG_SOUND_IT8172)	+= ite8172.o ac97_codec.o
+obj-$(CONFIG_SOUND_AD1980)	+= ac97_plugin_ad1980.o
+obj-$(CONFIG_SOUND_WM97XX)	+= ac97_plugin_wm97xx.o
 
 ifeq ($(CONFIG_MIDI_EMU10K1),y)
   obj-$(CONFIG_SOUND_EMU10K1)	+= sound.o
diff -Nru a/drivers/sound/ac97_plugin_wm97xx.c b/drivers/sound/ac97_plugin_wm97xx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/sound/ac97_plugin_wm97xx.c	Thu Jul 31 06:00:07 2003
@@ -0,0 +1,1408 @@
+/*
+ * ac97_plugin_wm97xx.c  --  Touch screen driver for Wolfson WM9705 and WM9712
+ *                           AC97 Codecs.
+ *
+ * Copyright 2003 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.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.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``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  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.
+ *
+ *  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.
+ *
+ * Notes:
+ *
+ *  Features:
+ *       - supports WM9705, WM9712
+ *       - polling mode
+ *       - coordinate polling
+ *       - adjustable rpu/dpp settings
+ *       - adjustable pressure current
+ *       - adjustable sample settle delay
+ *       - 4 and 5 wire touchscreens (5 wire is WM9712 only)
+ *       - pen down detection
+ *       - battery monitor
+ *       - sample AUX adc's
+ *       - power management
+ *       - direct AC97 IO from userspace (#define WM97XX_TS_DEBUG)
+ *
+ *  TODO:
+ *       - continuous mode
+ *       - adjustable sample rate
+ *       - AUX adc in coordinate / continous modes
+ *	 - Official device identifier or misc device ?
+ *
+ *  Revision history
+ *    7th May 2003   Initial version.
+ *    6th June 2003  Added non module support and AC97 registration.
+ *   18th June 2003  Added AUX adc sampling. 
+ *   23rd June 2003  Did some minimal reformatting, fixed a couple of
+ *		     locking bugs and noted a race to fix.
+ *   24th June 2003  Added power management and fixed race condition.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/pm.h>
+#include <linux/wm97xx.h>       /* WM97xx registers and bits */
+#include <asm/uaccess.h>        /* get_user,copy_to_user */
+#include <asm/io.h>
+
+#define TS_NAME "ac97_plugin_wm97xx"
+#define TS_MINOR 16
+#define WM_TS_VERSION "0.6"
+#define AC97_NUM_REG 64
+
+
+/*
+ * Debug
+ */
+ 
+#define PFX TS_NAME
+#define WM97XX_TS_DEBUG 0
+
+#ifdef WM97XX_TS_DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
+
+/*
+ * Module parameters
+ */
+	
+	
+/*
+ * Set the codec sample mode.
+ *
+ * The WM9712 can sample touchscreen data in 3 different operating
+ * modes. i.e. polling, coordinate and continous.
+ *
+ * Polling:-     The driver polls the codec and issues 3 seperate commands
+ *               over the AC97 link to read X,Y and pressure.
+ * 
+ * Coordinate: - The driver polls the codec and only issues 1 command over
+ *               the AC97 link to read X,Y and pressure. This mode has
+ *               strict timing requirements and may drop samples if 
+ *               interrupted. However, it is less demanding on the AC97
+ *               link. Note: this mode requires a larger delay than polling
+ *               mode.
+ *
+ * Continuous:-  The codec automatically samples X,Y and pressure and then
+ *               sends the data over the AC97 link in slots. This is the
+ *               same method used by the codec when recording audio.
+ *
+ * Set mode = 0 for polling, 1 for coordinate and 2 for continuous.
+ *            
+ */
+MODULE_PARM(mode,"i");
+MODULE_PARM_DESC(mode, "Set WM97XX operation mode");
+static int mode = 0;	
+	
+/*
+ * WM9712 - Set internal pull up for pen detect. 
+ * 
+ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
+ * i.e. pull up resistance = 64k Ohms / rpu.
+ * 
+ * Adjust this value if you are having problems with pen detect not 
+ * detecting any down events.
+ */
+MODULE_PARM(rpu,"i");
+MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
+static int rpu = 0;	
+
+/*
+ * WM9705 - Pen detect comparator threshold. 
+ * 
+ * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
+ * i.e. 1 =  Vmid/15 threshold
+ *      15 =  Vmid/1 threshold
+ * 
+ * Adjust this value if you are having problems with pen detect not 
+ * detecting any down events.
+ */
+MODULE_PARM(pdd,"i");
+MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold");
+static int pdd = 0;	
+	
+/*
+ * Set current used for pressure measurement.
+ *
+ * Set pil = 2 to use 400uA 
+ *     pil = 1 to use 200uA and
+ *     pil = 0 to disable pressure measurement.
+ *
+ * This is used to increase the range of values returned by the adc
+ * when measureing touchpanel pressure. 
+ */
+MODULE_PARM(pil,"i");
+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
+static int pil = 0;
+
+/*
+ * WM9712 - Set five_wire = 1 to use a 5 wire touchscreen.
+ * 
+ * NOTE: Five wire mode does not allow for readback of pressure.
+ */
+MODULE_PARM(five_wire,"i");
+MODULE_PARM_DESC(five_wire, "Set 5 wire touchscreen.");
+static int five_wire = 0;	
+
+/*
+ * Set adc sample delay.
+ * 
+ * For accurate touchpanel measurements, some settling time may be
+ * required between the switch matrix applying a voltage across the
+ * touchpanel plate and the ADC sampling the signal.
+ *
+ * This delay can be set by setting delay = n, where n is the array
+ * position of the delay in the array delay_table below.
+ * Long delays > 1ms are supported for completeness, but are not
+ * recommended.
+ */
+MODULE_PARM(delay,"i");
+MODULE_PARM_DESC(delay, "Set adc sample delay.");
+static int delay = 4;	
+
+
+/* +++++++++++++ Lifted from include/linux/h3600_ts.h ++++++++++++++*/
+typedef struct {
+	unsigned short pressure;  // touch pressure
+	unsigned short x;         // calibrated X
+	unsigned short y;         // calibrated Y
+	unsigned short millisecs; // timestamp of this event
+} TS_EVENT;
+
+typedef struct {
+	int xscale;
+	int xtrans;
+	int yscale;
+	int ytrans;
+	int xyswap;
+} TS_CAL;
+
+/* Use 'f' as magic number */
+#define IOC_MAGIC  'f'
+
+#define TS_GET_RATE             _IO(IOC_MAGIC, 8)
+#define TS_SET_RATE             _IO(IOC_MAGIC, 9)
+#define TS_GET_CAL              _IOR(IOC_MAGIC, 10, TS_CAL)
+#define TS_SET_CAL              _IOW(IOC_MAGIC, 11, TS_CAL)
+
+/* +++++++++++++ Done lifted from include/linux/h3600_ts.h +++++++++*/
+
+#define TS_GET_COMP1			_IOR(IOC_MAGIC, 12, short)
+#define TS_GET_COMP2			_IOR(IOC_MAGIC, 13, short)
+#define TS_GET_BMON			_IOR(IOC_MAGIC, 14, short)
+#define TS_GET_WIPER			_IOR(IOC_MAGIC, 15, short)
+
+#ifdef WM97XX_TS_DEBUG
+/* debug get/set ac97 codec register ioctl's */
+#define TS_GET_AC97_REG			_IOR(IOC_MAGIC, 20, short)
+#define TS_SET_AC97_REG			_IOW(IOC_MAGIC, 21, short)
+#define TS_SET_AC97_INDEX		_IOW(IOC_MAGIC, 22, short)
+#endif
+
+#define EVENT_BUFSIZE 128
+
+typedef struct {
+	TS_CAL cal;                       /* Calibration values */
+	TS_EVENT event_buf[EVENT_BUFSIZE];/* The event queue */
+	int nextIn, nextOut;
+	int event_count;
+	int is_wm9712:1;                  /* are we a WM912 or a WM9705 */
+	int is_registered:1;              /* Is the driver AC97 registered */
+	int line_pgal:5;
+	int line_pgar:5;
+	int phone_pga:5;
+	int mic_pgal:5;
+	int mic_pgar:5;
+	int overruns;                     /* event buffer overruns */
+	int adc_errs;                     /* sample read back errors */
+#ifdef WM97XX_TS_DEBUG
+	short ac97_index;
+#endif
+	struct fasync_struct *fasync;     /* asynch notification */
+	struct timer_list acq_timer;      /* Timer for triggering acquisitions */
+	wait_queue_head_t wait;           /* read wait queue */
+	spinlock_t lock;
+	struct ac97_codec *codec;
+	struct proc_dir_entry *wm97xx_ts_ps;
+#ifdef WM97XX_TS_DEBUG
+	struct proc_dir_entry *wm97xx_debug_ts_ps;
+#endif
+	struct pm_dev * pm;
+} wm97xx_ts_t;
+
+static inline void poll_delay (void);
+static int __init wm97xx_ts_init_module(void);
+static int wm97xx_poll_read_adc (wm97xx_ts_t* ts, u16 adcsel, u16* sample);
+static int wm97xx_coord_read_adc (wm97xx_ts_t* ts, u16* x, u16* y, 
+                                  u16* pressure);
+static inline int pendown (wm97xx_ts_t *ts);
+static void wm97xx_acq_timer(unsigned long data);
+static int wm97xx_fasync(int fd, struct file *filp, int mode);
+static int wm97xx_ioctl(struct inode * inode, struct file *filp,
+	                    unsigned int cmd, unsigned long arg);
+static unsigned int wm97xx_poll(struct file * filp, poll_table * wait);
+static ssize_t wm97xx_read(struct file * filp, char * buf, size_t count, 
+	                       loff_t * l);
+static int wm97xx_open(struct inode * inode, struct file * filp);
+static int wm97xx_release(struct inode * inode, struct file * filp);
+static void init_wm97xx_phy(void);
+static int adc_get (wm97xx_ts_t *ts, unsigned short *value, int id);
+static int wm97xx_probe(struct ac97_codec *codec, struct ac97_driver *driver);
+static void wm97xx_remove(struct ac97_codec *codec,  struct ac97_driver *driver);
+static void wm97xx_ts_cleanup_module(void);
+static int wm97xx_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);
+static void wm97xx_suspend(void);
+static void wm97xx_resume(void);
+static void wm9712_pga_save(wm97xx_ts_t* ts);
+static void wm9712_pga_restore(wm97xx_ts_t* ts);
+
+/* AC97 registration info */
+static struct ac97_driver wm9705_driver = {
+	codec_id: 0x574D4C05,
+	codec_mask: 0xFFFFFFFF,
+	name: "Wolfson WM9705 Touchscreen/BMON",
+	probe:	wm97xx_probe,
+	remove: __devexit_p(wm97xx_remove),
+};
+
+static struct ac97_driver wm9712_driver = {
+	codec_id: 0x574D4C12,
+	codec_mask: 0xFFFFFFFF,
+	name: "Wolfson WM9712 Touchscreen/BMON",
+	probe:	wm97xx_probe,
+	remove: __devexit_p(wm97xx_remove),
+};
+
+/* we only support a single touchscreen */
+static wm97xx_ts_t wm97xx_ts;
+
+/*
+ * ADC sample delay times in uS
+ */
+static const int delay_table[16] = {
+	21,		// 1 AC97 Link frames
+	42,		// 2
+	84,		// 4
+	167,		// 8
+	333,		// 16
+	667,		// 32
+	1000,		// 48
+	1333,		// 64
+	2000,		// 96
+	2667,		// 128
+	3333,		// 160
+	4000,		// 192
+	4667,		// 224
+	5333,		// 256
+	6000,		// 288
+	0 		// No delay, switch matrix always on
+};
+
+/*
+ * Delay after issuing a POLL command.
+ *
+ * The delay is 3 AC97 link frames + the touchpanel settling delay
+ */
+
+static inline void poll_delay(void)
+{ 
+	int pdelay = 3 * AC97_LINK_FRAME + delay_table[delay];
+	udelay (pdelay);
+}
+
+
+/*
+ * sample the auxillary ADC's 
+ */
+
+static int adc_get(wm97xx_ts_t* ts, unsigned short * value, int id)
+{
+	short adcsel = 0;
+	
+	/* first find out our adcsel flag */
+	if (ts->is_wm9712) {
+		switch (id) {
+			case TS_COMP1:
+				adcsel = WM9712_ADCSEL_COMP1;
+				break;
+			case TS_COMP2:
+				adcsel = WM9712_ADCSEL_COMP2;
+				break;
+			case TS_BMON:
+				adcsel = WM9712_ADCSEL_BMON;
+				break;
+			case TS_WIPER:
+				adcsel = WM9712_ADCSEL_WIPER;
+				break;
+		}
+	} else {
+		switch (id) {
+			case TS_COMP1:
+				adcsel = WM9705_ADCSEL_PCBEEP;
+				break;
+			case TS_COMP2:
+				adcsel = WM9705_ADCSEL_PHONE;
+				break;
+			case TS_BMON:
+				adcsel = WM9705_ADCSEL_BMON;
+				break;
+			case TS_WIPER:
+				adcsel = WM9705_ADCSEL_AUX;
+				break;
+		}
+	}
+	
+	/* now sample the adc */
+	if (mode == 1) {
+		/* coordinate mode - not currently available (TODO) */
+			return 0;
+	}
+	else
+	{
+		/* polling mode */
+		if (!wm97xx_poll_read_adc(ts, adcsel, value))
+			return 0;	
+	}
+	
+	return 1;
+}
+
+
+/*
+ * Read a sample from the adc in polling mode.
+ */
+static int wm97xx_poll_read_adc (wm97xx_ts_t* ts, u16 adcsel, u16* sample)
+{
+	u16 dig1;
+	int timeout = 5 * delay;
+
+	/* set up digitiser */
+	dig1 = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1); 
+	dig1&=0x0fff;
+	ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER1, dig1 | adcsel |
+		WM97XX_POLL); 
+
+	/* wait 3 AC97 time slots + delay for conversion */
+	poll_delay();
+
+	/* wait for POLL to go low */
+	while ((ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) { 
+		udelay(AC97_LINK_FRAME);
+		timeout--;	
+	}
+	if (timeout > 0)
+		*sample = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
+	else {
+		ts->adc_errs++;
+		err ("adc sample timeout");
+		return 0;
+	}
+	
+	/* check we have correct sample */
+	if ((*sample & 0x7000) != adcsel ) { 
+		err ("adc wrong sample, read %x got %x", adcsel, *sample & 0x7000);
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * Read a sample from the adc in coordinate mode.
+ */
+static int wm97xx_coord_read_adc(wm97xx_ts_t* ts, u16* x, u16* y, u16* pressure)
+{
+	u16 dig1;
+	int timeout = 5 * delay;
+
+	/* set up digitiser */
+	dig1 = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1); 
+	dig1&=0x0fff;
+	ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER1, dig1 | WM97XX_ADCSEL_PRES |
+		WM97XX_POLL); 
+
+	/* wait 3 AC97 time slots + delay for conversion */
+	poll_delay();
+	
+	/* read X then wait for 1 AC97 link frame + settling delay */
+	*x = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
+	udelay (AC97_LINK_FRAME + delay_table[delay]);
+
+	/* read Y */
+	*y = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
+	
+	/* wait for POLL to go low and then read pressure */
+	while ((ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)&& timeout) {
+			udelay(AC97_LINK_FRAME);
+			timeout--;
+	}
+	if (timeout > 0)		
+		*pressure = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
+	else {
+		ts->adc_errs++;
+		err ("adc sample timeout");
+		return 0;
+	}
+	
+	/* check we have correct samples */
+	if (((*x & 0x7000) == 0x1000) && ((*y & 0x7000) == 0x2000) && 
+		((*pressure & 0x7000) == 0x3000)) { 
+		return 1;
+	} else {
+		ts->adc_errs++;
+		err ("adc got wrong samples, got x 0x%x y 0x%x pressure 0x%x", *x, *y, *pressure);
+		return 0;
+	}
+}
+
+/*
+ * Is the pen down ?
+ */
+static inline int pendown (wm97xx_ts_t *ts)
+{
+	return ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD) & WM97XX_PEN_DOWN;
+}
+
+/*
+ * X,Y coordinates and pressure aquisition function.
+ * This function is run by a kernel timer and it's frequency between
+ * calls is the touchscreen polling rate;
+ */
+ 
+static void wm97xx_acq_timer(unsigned long data)
+{
+	wm97xx_ts_t* ts = (wm97xx_ts_t*)data;
+	unsigned long flags;
+	long x,y;
+	TS_EVENT event;
+	
+	spin_lock_irqsave(&ts->lock, flags);
+
+	/* are we still registered ? */
+	if (!ts->is_registered) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return; /* we better stop then */
+	}
+	
+	/* read coordinates if pen is down */
+	if (!pendown(ts))
+		goto acq_exit;
+	
+	if (mode == 1) {
+		/* coordinate mode */
+		if (!wm97xx_coord_read_adc(ts, (u16*)&x, (u16*)&y, &event.pressure))
+			goto acq_exit;
+	} else
+	{
+		/* polling mode */
+		if (!wm97xx_poll_read_adc(ts, WM97XX_ADCSEL_X, (u16*)&x))
+			goto acq_exit;
+		if (!wm97xx_poll_read_adc(ts, WM97XX_ADCSEL_Y, (u16*)&y))
+			goto acq_exit;
+		
+		/* only read pressure if we have to */
+		if (!five_wire && pil) {
+			if (!wm97xx_poll_read_adc(ts, WM97XX_ADCSEL_PRES, &event.pressure))
+				goto acq_exit;
+		}
+		else
+			event.pressure = 0;
+	}
+	/* timestamp this new event. */
+	event.millisecs = jiffies;
+
+	/* calibrate and remove unwanted bits from samples */
+	event.pressure &= 0x0fff;
+	
+	x &= 0x00000fff;
+	x = ((ts->cal.xscale * x) >> 8) + ts->cal.xtrans;
+	event.x = (u16)x;
+	
+	y &= 0x00000fff;
+	y = ((ts->cal.yscale * y) >> 8) + ts->cal.ytrans;
+	event.y = (u16)y;
+	
+	/* add this event to the event queue */
+	ts->event_buf[ts->nextIn++] = event;
+	if (ts->nextIn == EVENT_BUFSIZE)
+		ts->nextIn = 0;
+	if (ts->event_count < EVENT_BUFSIZE) {
+		ts->event_count++;
+	} else {
+		/* throw out the oldest event */
+		if (++ts->nextOut == EVENT_BUFSIZE) {
+			ts->nextOut = 0;
+			ts->overruns++;
+		}
+	}
+
+	/* async notify */
+	if (ts->fasync)
+		kill_fasync(&ts->fasync, SIGIO, POLL_IN);
+	/* wake up any read call */
+	if (waitqueue_active(&ts->wait))
+		wake_up_interruptible(&ts->wait);
+
+	/* schedule next acquire */
+acq_exit:
+	ts->acq_timer.expires = jiffies + HZ / 100;
+	add_timer(&ts->acq_timer);
+
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+	
+	
+/* +++++++++++++ File operations ++++++++++++++*/
+
+static int wm97xx_fasync(int fd, struct file *filp, int mode)
+{
+	wm97xx_ts_t* ts = (wm97xx_ts_t*)filp->private_data;
+	return fasync_helper(fd, filp, mode, &ts->fasync);
+}
+
+static int wm97xx_ioctl(struct inode * inode, struct file *filp,
+	     unsigned int cmd, unsigned long arg)
+{
+	unsigned short adc_value;
+#ifdef WM97XX_TS_DEBUG
+	short data;
+#endif	
+	wm97xx_ts_t* ts = (wm97xx_ts_t*)filp->private_data;
+
+	switch(cmd) {
+	case TS_GET_RATE:       /* TODO: what is this? */
+		break;
+	case TS_SET_RATE:       /* TODO: what is this? */
+		break;
+	case TS_GET_CAL:
+		if(copy_to_user((char *)arg, (char *)&ts->cal, sizeof(TS_CAL)))
+			return -EFAULT;
+		break;
+	case TS_SET_CAL:
+		if(copy_from_user((char *)&ts->cal, (char *)arg, sizeof(TS_CAL)))
+			return -EFAULT;
+		break;
+	case TS_GET_COMP1:
+		if (adc_get(ts, &adc_value, TS_COMP1)) {
+			if(copy_to_user((char *)arg, (char *)&adc_value, sizeof(adc_value)))
+				return -EFAULT;
+		}
+		else
+			return -EIO;
+		break;
+	case TS_GET_COMP2:
+		if (adc_get(ts, &adc_value, TS_COMP2)) {
+			if(copy_to_user((char *)arg, (char *)&adc_value, sizeof(adc_value)))
+				return -EFAULT;
+		}
+		else
+			return -EIO;
+		break;
+	case TS_GET_BMON:
+		if (adc_get(ts, &adc_value, TS_BMON)) {
+			if(copy_to_user((char *)arg, (char *)&adc_value, sizeof(adc_value)))
+				return -EFAULT;
+		}
+		else
+			return -EIO;
+		break;
+	case TS_GET_WIPER:
+		if (adc_get(ts, &adc_value, TS_WIPER)) {
+			if(copy_to_user((char *)arg, (char *)&adc_value, sizeof(adc_value)))
+				return -EFAULT;
+		}
+		else
+			return -EIO;
+		break;
+#ifdef WM97XX_TS_DEBUG
+		/* debug get/set ac97 codec register ioctl's 
+		 *
+		 * This is direct IO to the codec registers - BE CAREFULL
+		 */
+	case TS_GET_AC97_REG: /* read from ac97 reg (index) */
+		data = ts->codec->codec_read(ts->codec, ts->ac97_index);
+		if(copy_to_user((char *)arg, (char *)&data, sizeof(data)))
+			return -EFAULT;
+		break;
+	case TS_SET_AC97_REG: /* write to ac97 reg (index) */
+		if(copy_from_user((char *)&data, (char *)arg, sizeof(data)))
+			return -EFAULT;
+		ts->codec->codec_write(ts->codec, ts->ac97_index, data);
+		break;
+	case TS_SET_AC97_INDEX: /* set ac97 reg index */
+		if(copy_from_user((char *)&ts->ac97_index, (char *)arg, sizeof(ts->ac97_index)))
+			return -EFAULT;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned int wm97xx_poll(struct file * filp, poll_table * wait)
+{
+	wm97xx_ts_t *ts = (wm97xx_ts_t *)filp->private_data;
+	poll_wait(filp, &ts->wait, wait);
+	if (ts->event_count)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static ssize_t wm97xx_read(struct file *filp, char *buf, size_t count, loff_t *l)
+{
+	wm97xx_ts_t* ts = (wm97xx_ts_t*)filp->private_data;
+	unsigned long flags;
+	TS_EVENT event;
+	int i;
+
+	/* are we still registered with AC97 layer ? */
+	spin_lock_irqsave(&ts->lock, flags);
+	if (!ts->is_registered) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return -ENXIO;
+	}
+	
+	if (ts->event_count == 0) {
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		spin_unlock_irqrestore(&ts->lock, flags);
+
+		wait_event_interruptible(ts->wait, ts->event_count != 0);
+		
+		/* are we still registered after sleep ? */
+		spin_lock_irqsave(&ts->lock, flags);
+		if (!ts->is_registered) {
+			spin_unlock_irqrestore(&ts->lock, flags);
+			return -ENXIO;
+		}
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+	
+	for (i = count; i >= sizeof(TS_EVENT);
+	    i -= sizeof(TS_EVENT), buf += sizeof(TS_EVENT)) {
+		if (ts->event_count == 0)
+			break;
+		spin_lock_irqsave(&ts->lock, flags);
+		event = ts->event_buf[ts->nextOut++];
+		if (ts->nextOut == EVENT_BUFSIZE)
+			ts->nextOut = 0;
+		if (ts->event_count)
+			ts->event_count--;
+		spin_unlock_irqrestore(&ts->lock, flags);
+		if(copy_to_user(buf, &event, sizeof(TS_EVENT)))
+			return i != count  ? count - i : -EFAULT;
+	}
+	return count - i;
+}
+
+
+static int wm97xx_open(struct inode * inode, struct file * filp)
+{
+	wm97xx_ts_t* ts;
+	unsigned long flags;
+	u16 val;
+	int minor = MINOR(inode->i_rdev);
+	
+	if (minor != TS_MINOR)
+		return -ENODEV;
+	
+	filp->private_data = ts = &wm97xx_ts;
+
+	spin_lock_irqsave(&ts->lock, flags);
+	
+	/* are we registered with AC97 layer ? */
+	if (!ts->is_registered) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return -ENXIO;
+	}
+	
+	/* start digitiser */
+	val = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER2);
+	ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER2, 
+		val | WM97XX_PRP_DET_DIG);
+	
+	/* flush event queue */
+	ts->nextIn = ts->nextOut = ts->event_count = 0;
+	
+	/* Set up timer. */
+	init_timer(&ts->acq_timer);
+	ts->acq_timer.function = wm97xx_acq_timer;
+	ts->acq_timer.data = (unsigned long)ts;
+	ts->acq_timer.expires = jiffies + HZ / 100;
+	add_timer(&ts->acq_timer);
+
+	spin_unlock_irqrestore(&ts->lock, flags);
+	return 0;
+}
+
+static int wm97xx_release(struct inode * inode, struct file * filp)
+{
+	wm97xx_ts_t* ts = (wm97xx_ts_t*)filp->private_data;
+	unsigned long flags;
+	u16 val;
+	
+	wm97xx_fasync(-1, filp, 0);
+	del_timer_sync(&ts->acq_timer);
+
+	spin_lock_irqsave(&ts->lock, flags);
+	
+	/* stop digitiser */
+	val = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER2);
+	ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER2, 
+		val & ~WM97XX_PRP_DET_DIG);
+	
+	spin_unlock_irqrestore(&ts->lock, flags);
+	return 0;
+}
+
+static struct file_operations ts_fops = {
+	owner:		THIS_MODULE,
+	read:           wm97xx_read,
+	poll:           wm97xx_poll,
+	ioctl:		wm97xx_ioctl,
+	fasync:         wm97xx_fasync,
+	open:		wm97xx_open,
+	release:	wm97xx_release,
+};
+
+/* +++++++++++++ End File operations ++++++++++++++*/
+
+#ifdef CONFIG_PROC_FS
+static int wm97xx_read_proc (char *page, char **start, off_t off,
+		    int count, int *eof, void *data)
+{
+	int len = 0, prpu;
+	u16 dig1, dig2, digrd, adcsel, adcsrc, slt, prp, rev;
+	unsigned long flags;
+	char srev = ' ';
+	
+	wm97xx_ts_t* ts;
+
+	if ((ts = data) == NULL)
+		return -ENODEV;
+	
+	spin_lock_irqsave(&ts->lock, flags);
+	if (!ts->is_registered) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		len += sprintf (page+len, "No device registered\n");
+		return len;
+	}
+
+	dig1 = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1);
+	dig2 = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER2);
+	digrd = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
+	rev = (ts->codec->codec_read(ts->codec, AC97_WM9712_REV) & 0x000c) >> 2;
+
+	spin_unlock_irqrestore(&ts->lock, flags);
+	
+	adcsel = dig1 & 0x7000;
+	adcsrc = digrd & 0x7000;
+	slt = (dig1 & 0x7) + 5;
+	prp = dig2 & 0xc000;
+	prpu = dig2 & 0x003f;
+
+	/* driver version */
+	len += sprintf (page+len, "Wolfson WM97xx Version %s\n", WM_TS_VERSION);
+	
+	/* what we are using */
+	len += sprintf (page+len, "Using %s", ts->is_wm9712 ? "WM9712" : "WM9705");
+	if (ts->is_wm9712) {
+		switch (rev) {
+			case 0x0:
+				srev = 'A';
+			break;
+			case 0x1:
+				srev = 'B';
+			break;
+			case 0x2:
+				srev = 'D';
+			break;
+			case 0x3:
+				srev = 'E';
+			break;
+		}
+		len += sprintf (page+len, " silicon rev %c\n",srev);
+	} else
+		len += sprintf (page+len, "\n");
+		
+	/* WM97xx settings */
+	len += sprintf (page+len, "Settings     :\n%s%s%s%s",
+			dig1 & WM97XX_POLL ? " -sampling adc data(poll)\n" : "",
+			adcsel ==  WM97XX_ADCSEL_X ? " -adc set to X coordinate\n" : "",
+			adcsel ==  WM97XX_ADCSEL_Y ? " -adc set to Y coordinate\n" : "",
+			adcsel ==  WM97XX_ADCSEL_PRES ? " -adc set to pressure\n" : "");
+	if (ts->is_wm9712) {
+		len += sprintf (page+len, "%s%s%s%s", 
+			adcsel ==  WM9712_ADCSEL_COMP1 ? " -adc set to COMP1/AUX1\n" : "",
+			adcsel ==  WM9712_ADCSEL_COMP2 ? " -adc set to COMP2/AUX2\n" : "",
+			adcsel ==  WM9712_ADCSEL_BMON ? " -adc set to BMON\n" : "",
+			adcsel ==  WM9712_ADCSEL_WIPER ? " -adc set to WIPER\n" : "");
+		} else {
+		len += sprintf (page+len, "%s%s%s%s",
+			adcsel ==  WM9705_ADCSEL_PCBEEP ? " -adc set to PCBEEP\n" : "",
+			adcsel ==  WM9705_ADCSEL_PHONE ? " -adc set to PHONE\n" : "",
+			adcsel ==  WM9705_ADCSEL_BMON ? " -adc set to BMON\n" : "",
+			adcsel ==  WM9705_ADCSEL_AUX ? " -adc set to AUX\n" : "");
+		}
+		
+	len += sprintf (page+len, "%s%s%s%s%s%s",
+			dig1 & WM97XX_COO ? " -coordinate sampling\n" : " -individual sampling\n",
+			dig1 & WM97XX_CTC ? " -continuous mode\n" : " -polling mode\n",
+			prp == WM97XX_PRP_DET ? " -pen detect enabled, no wake up\n" : "",
+			prp == WM97XX_PRP_DETW ? " -pen detect enabled, wake up\n" : "",
+			prp == WM97XX_PRP_DET_DIG ? " -pen digitiser and pen detect enabled\n" : "",
+			dig1 & WM97XX_SLEN ? " -read back using slot " : " -read back using AC97\n");
+	
+	if ((dig1 & WM97XX_SLEN) && slt !=12)	
+		len += sprintf(page+len, "%d\n", slt);
+	len += sprintf (page+len, " -adc sample delay %d uSecs\n", delay_table[(dig1 & 0x00f0) >> 4]);
+	
+	if (ts->is_wm9712) {
+		if (prpu)
+			len += sprintf (page+len, " -rpu %d Ohms\n", 64000/ prpu);
+		len += sprintf (page+len, " -pressure current %s uA\n", dig2 & WM9712_PIL ? "400" : "200");
+		len += sprintf (page+len, " -using %s wire touchscreen mode", dig2 & WM9712_45W ? "5" : "4");
+	} else {
+		len += sprintf (page+len, " -pressure current %s uA\n", dig2 & WM9705_PIL ? "400" : "200");
+		len += sprintf (page+len, " -%s impedance for PHONE and PCBEEP\n", dig2 & WM9705_PHIZ ? "high" : "low");
+	}
+	
+	/* WM97xx digitiser read */
+	len += sprintf(page+len, "\nADC data:\n%s%d\n%s%s\n",
+		" -adc value (decimal) : ", digrd & 0x0fff,
+		" -pen ", digrd & 0x8000 ? "Down" : "Up");
+	if (ts->is_wm9712) {
+		len += sprintf (page+len, "%s%s%s%s", 
+			adcsrc ==  WM9712_ADCSEL_COMP1 ? " -adc value is COMP1/AUX1\n" : "",
+			adcsrc ==  WM9712_ADCSEL_COMP2 ? " -adc value is COMP2/AUX2\n" : "",
+			adcsrc ==  WM9712_ADCSEL_BMON ? " -adc value is BMON\n" : "",
+			adcsrc ==  WM9712_ADCSEL_WIPER ? " -adc value is WIPER\n" : "");
+		} else {
+		len += sprintf (page+len, "%s%s%s%s",
+			adcsrc ==  WM9705_ADCSEL_PCBEEP ? " -adc value is PCBEEP\n" : "",
+			adcsrc ==  WM9705_ADCSEL_PHONE ? " -adc value is PHONE\n" : "",
+			adcsrc ==  WM9705_ADCSEL_BMON ? " -adc value is BMON\n" : "",
+			adcsrc ==  WM9705_ADCSEL_AUX ? " -adc value is AUX\n" : "");
+		}
+		
+	/* register dump */
+	len += sprintf(page+len, "\nRegisters:\n%s%x\n%s%x\n%s%x\n",
+		" -digitiser 1    (0x76) : 0x", dig1,
+		" -digitiser 2    (0x78) : 0x", dig2,
+		" -digitiser read (0x7a) : 0x", digrd);
+		
+	/* errors */
+	len += sprintf(page+len, "\nErrors:\n%s%d\n%s%d\n",
+		" -buffer overruns ", ts->overruns,
+		" -coordinate errors ", ts->adc_errs);
+		
+	return len;
+}
+
+#ifdef WM97XX_TS_DEBUG
+/* dump all the AC97 register space */
+static int wm_debug_read_proc (char *page, char **start, off_t off,
+		    int count, int *eof, void *data)
+{
+	int len = 0, i;
+	unsigned long flags;
+	wm97xx_ts_t* ts;
+	u16 reg[AC97_NUM_REG];
+
+	if ((ts = data) == NULL)
+		return -ENODEV;
+
+	spin_lock_irqsave(&ts->lock, flags);
+	if (!ts->is_registered) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		len += sprintf (page+len, "Not registered\n");
+		return len;
+	}
+	
+	for (i=0; i < AC97_NUM_REG; i++) {
+		reg[i] = ts->codec->codec_read(ts->codec, i * 2);
+	}
+	spin_unlock_irqrestore(&ts->lock, flags);
+	
+	for (i=0; i < AC97_NUM_REG; i++) {
+		len += sprintf (page+len, "0x%2.2x : 0x%4.4x\n",i * 2, reg[i]);
+	}
+		
+	return len;
+}
+#endif
+
+#endif
+
+#ifdef CONFIG_PM
+/* WM97xx Power Management
+ * The WM9712 has extra powerdown states that are controlled in 
+ * seperate registers from the AC97 power management.
+ * We will only power down into the extra WM9712 states and leave 
+ * the AC97 power management to the sound driver.
+ */
+static int wm97xx_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	switch(rqst) {
+		case PM_SUSPEND:
+			wm97xx_suspend();
+			break;
+		case PM_RESUME:
+			wm97xx_resume();
+			break;
+	}
+	return 0;
+}
+
+/*
+ * Power down the codec
+ */
+static void wm97xx_suspend(void)
+{
+	wm97xx_ts_t* ts = &wm97xx_ts;
+	u16 reg;
+	unsigned long flags;
+	
+	/* are we registered */
+	spin_lock_irqsave(&ts->lock, flags);
+	if (!ts->is_registered) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return;
+	}
+	
+	/* wm9705 does not have extra PM */
+	if (!ts->is_wm9712) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return;
+	}
+	
+	/* save and mute the PGA's */
+	wm9712_pga_save(ts);
+	
+	reg = ts->codec->codec_read(ts->codec, AC97_PHONE_VOL);
+	ts->codec->codec_write(ts->codec, AC97_PHONE_VOL, reg | 0x001f);
+	
+	reg = ts->codec->codec_read(ts->codec, AC97_MIC_VOL);
+	ts->codec->codec_write(ts->codec, AC97_MIC_VOL, reg | 0x1f1f);
+	
+	reg = ts->codec->codec_read(ts->codec, AC97_LINEIN_VOL);
+	ts->codec->codec_write(ts->codec, AC97_LINEIN_VOL, reg | 0x1f1f);
+	
+	/* power down, dont disable the AC link */
+	ts->codec->codec_write(ts->codec, AC97_WM9712_POWER, WM9712_PD(14) | WM9712_PD(13) |
+							WM9712_PD(12) | WM9712_PD(11) | WM9712_PD(10) |                    
+							WM9712_PD(9) | WM9712_PD(8) | WM9712_PD(7) |
+							WM9712_PD(6) | WM9712_PD(5) | WM9712_PD(4) |
+							WM9712_PD(3) | WM9712_PD(2) | WM9712_PD(1) |
+							WM9712_PD(0));
+	
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+/*
+ * Power up the Codec
+ */
+static void wm97xx_resume(void)
+{
+	wm97xx_ts_t* ts = &wm97xx_ts;
+	unsigned long flags;
+	
+	/* are we registered */
+	spin_lock_irqsave(&ts->lock, flags);
+	if (!ts->is_registered) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return;
+	}
+	
+	/* wm9705 does not have extra PM */
+	if (!ts->is_wm9712) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return;
+	}
+
+	/* power up */
+	ts->codec->codec_write(ts->codec, AC97_WM9712_POWER, 0x0);
+	
+	/* restore PGA state */
+	wm9712_pga_restore(ts);
+	
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+
+/* save state of wm9712 PGA's */
+static void wm9712_pga_save(wm97xx_ts_t* ts)
+{
+	ts->phone_pga = ts->codec->codec_read(ts->codec, AC97_PHONE_VOL) & 0x001f;
+	ts->line_pgal = ts->codec->codec_read(ts->codec, AC97_LINEIN_VOL) & 0x1f00;
+	ts->line_pgar = ts->codec->codec_read(ts->codec, AC97_LINEIN_VOL) & 0x001f;
+	ts->mic_pgal = ts->codec->codec_read(ts->codec, AC97_MIC_VOL) & 0x1f00;
+	ts->mic_pgar = ts->codec->codec_read(ts->codec, AC97_MIC_VOL) & 0x001f;
+}
+
+/* restore state of wm9712 PGA's */
+static void wm9712_pga_restore(wm97xx_ts_t* ts)
+{
+	u16 reg;
+	
+	reg = ts->codec->codec_read(ts->codec, AC97_PHONE_VOL);
+	ts->codec->codec_write(ts->codec, AC97_PHONE_VOL, reg | ts->phone_pga);
+	
+	reg = ts->codec->codec_read(ts->codec, AC97_LINEIN_VOL);
+	ts->codec->codec_write(ts->codec, AC97_LINEIN_VOL, reg | ts->line_pgar | (ts->line_pgal << 8));
+
+	reg = ts->codec->codec_read(ts->codec, AC97_MIC_VOL);
+	ts->codec->codec_write(ts->codec, AC97_MIC_VOL, reg | ts->mic_pgar | (ts->mic_pgal << 8));
+}
+
+#endif
+
+/*
+ * set up the physical settings of the device 
+ */
+
+static void init_wm97xx_phy(void)
+{
+	u16 dig1, dig2, aux, vid;
+	wm97xx_ts_t *ts = &wm97xx_ts;
+
+	/* default values */
+	dig1 = WM97XX_DELAY(4) | WM97XX_SLT(6);
+	if (ts->is_wm9712)
+		dig2 = WM9712_RPU(1);
+	else {
+		dig2 = 0x0;
+		
+		/* 
+		 * mute VIDEO and AUX as they share X and Y touchscreen 
+		 * inputs on the WM9705 
+		 */
+		aux = ts->codec->codec_read(ts->codec, AC97_AUX_VOL);
+		if (!(aux & 0x8000)) {
+			info("muting AUX mixer as it shares X touchscreen coordinate");
+			ts->codec->codec_write(ts->codec, AC97_AUX_VOL, 0x8000 | aux);
+		}
+		
+		vid = ts->codec->codec_read(ts->codec, AC97_VIDEO_VOL);
+		if (!(vid & 0x8000)) {
+			info("muting VIDEO mixer as it shares Y touchscreen coordinate");
+			ts->codec->codec_write(ts->codec, AC97_VIDEO_VOL, 0x8000 | vid);
+		}
+	}
+	
+	/* WM9712 rpu */
+	if (ts->is_wm9712 && rpu) {
+		dig2 &= 0xffc0;
+		dig2 |= WM9712_RPU(rpu);
+		info("setting pen detect pull-up to %d Ohms",64000 / rpu);
+	}
+	
+	/* touchpanel pressure */
+	if  (pil == 2) {
+		if (ts->is_wm9712)
+			dig2 |= WM9712_PIL;
+		else
+			dig2 |= WM9705_PIL;
+		info("setting pressure measurement current to 400uA.");
+	} else if (pil) 
+		info ("setting pressure measurement current to 200uA.");
+	
+	/* WM9712 five wire */
+	if (ts->is_wm9712 && five_wire) {
+		dig2 |= WM9712_45W;
+		info("setting 5-wire touchscreen mode.");
+	}		
+	
+	/* sample settling delay */
+	if (delay!=4) {
+		if (delay < 0 || delay > 15) {
+			info ("supplied delay out of range.");
+			delay = 4;
+		}
+		dig1 &= 0xff0f;
+		dig1 |= WM97XX_DELAY(delay);
+		info("setting adc sample delay to %d u Secs.", delay_table[delay]);
+	}
+	
+	/* coordinate mode */
+	if (mode == 1) {
+		dig1 |= WM97XX_COO;
+		info("using coordinate mode");
+	}		
+	
+	/* WM9705 pdd */
+	if (pdd && !ts->is_wm9712) {
+		dig2 |= (pdd & 0x000f);
+		info("setting pdd to Vmid/%d", 1 - (pdd & 0x000f));
+	}
+	
+	ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER1, dig1);
+	ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER2, dig2); 
+}
+
+
+/*
+ * Called by the audio codec initialisation to register
+ * the touchscreen driver.
+ */
+
+static int wm97xx_probe(struct ac97_codec *codec, struct ac97_driver *driver)
+{
+	 unsigned long flags;
+	u16 id1, id2;
+	wm97xx_ts_t *ts = &wm97xx_ts;
+		
+	spin_lock_irqsave(&ts->lock, flags);
+	
+	/* we only support 1 touchscreen at the moment */
+	if (ts->is_registered) {
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return -1;
+	}
+	
+	/* 
+	 * We can only use a WM9705 or WM9712 that has been *first* initialised
+	 * by the AC97 audio driver. This is because we have to use the audio 
+	 * drivers codec read() and write() functions to sample the touchscreen	
+	 *	
+	 * If an initialsed WM97xx is found then get the codec read and write 
+	 * functions.		 
+	 */
+	
+	/* test for a WM9712 or a WM9705 */
+	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
+	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
+	if (id1 == WM97XX_ID1 && id2 == WM9712_ID2) {
+		ts->is_wm9712 = 1;
+		info("registered a WM9712");
+	} else if (id1 == WM97XX_ID1 && id2 == WM9705_ID2) {
+		    ts->is_wm9712 = 0;
+		    info("registered a WM9705");
+	} else {
+		err("could not find a WM97xx codec. Found a 0x%4x:0x%4x instead",
+		    id1, id2);
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return -1;
+	}
+	
+	/* set up AC97 codec interface */
+	ts->codec = codec;
+	codec->driver_private = (void*)&ts;
+	codec->codec_unregister = 0;
+	
+	/* set up physical characteristics */
+	init_wm97xx_phy();
+		
+	ts->is_registered = 1;
+	spin_unlock_irqrestore(&ts->lock, flags);
+	return 0;
+}
+
+/* this is called by the audio driver when ac97_codec is unloaded */
+
+static void wm97xx_remove(struct ac97_codec *codec, struct ac97_driver *driver)
+{
+	unsigned long flags;
+	u16 dig1, dig2;
+	wm97xx_ts_t *ts = codec->driver_private;
+	
+	spin_lock_irqsave(&ts->lock, flags);
+			
+	/* check that are registered */
+	if (!ts->is_registered) {
+		err("double unregister");
+		spin_unlock_irqrestore(&ts->lock, flags);
+		return;
+	}
+	
+	ts->is_registered = 0;
+	wake_up_interruptible(&ts->wait); /* So we see its gone */
+	
+	/* restore default digitiser values */
+	dig1 = WM97XX_DELAY(4) | WM97XX_SLT(6);
+	if (ts->is_wm9712)
+		dig2 = WM9712_RPU(1);
+	else 
+		dig2 = 0x0;
+		
+	codec->codec_write(codec, AC97_WM97XX_DIGITISER1, dig1);
+	codec->codec_write(codec, AC97_WM97XX_DIGITISER2, dig2); 
+	ts->codec = NULL;
+		
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static struct miscdevice wm97xx_misc = { 
+	minor:	TS_MINOR,
+	name:	"touchscreen/wm97xx",
+	fops:	&ts_fops,
+};
+
+static int __init wm97xx_ts_init_module(void)
+{
+	wm97xx_ts_t* ts = &wm97xx_ts;
+	int ret;
+	char proc_str[64];
+	
+	info("Wolfson WM9705/WM9712 Touchscreen Controller");
+	info("Version %s  liam.girdwood@wolfsonmicro.com", WM_TS_VERSION);
+	
+	memset(ts, 0, sizeof(wm97xx_ts_t));
+	
+	/* register our misc device */
+	if ((ret = misc_register(&wm97xx_misc)) < 0) {
+		err("can't register misc device");
+		return ret;
+	}
+	
+	init_waitqueue_head(&ts->wait);
+	spin_lock_init(&ts->lock);
+	
+	// initial calibration values
+	ts->cal.xscale = 256;
+	ts->cal.xtrans = 0;
+	ts->cal.yscale = 256;
+	ts->cal.ytrans = 0;
+	
+	/* reset error counters */
+	ts->overruns = 0;
+	ts->adc_errs = 0;
+	
+	/* register with the AC97 layer */
+	ac97_register_driver(&wm9705_driver);
+	ac97_register_driver(&wm9712_driver);
+	
+#ifdef CONFIG_PROC_FS
+	/* register proc interface */
+	sprintf(proc_str, "driver/%s", TS_NAME);
+	if ((ts->wm97xx_ts_ps = create_proc_read_entry (proc_str, 0, NULL,
+					     wm97xx_read_proc, ts)) == 0)
+		err("could not register proc interface /proc/%s", proc_str);
+#ifdef WM97XX_TS_DEBUG
+	if ((ts->wm97xx_debug_ts_ps = create_proc_read_entry ("driver/ac97_registers",
+		0, NULL,wm_debug_read_proc, ts)) == 0)
+		err("could not register proc interface /proc/driver/ac97_registers");
+#endif
+#endif
+#ifdef CONFIG_PM
+	if ((ts->pm = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, wm97xx_pm_event)) == 0)
+		err("could not register with power management");
+#endif
+	return 0;
+}
+
+static void wm97xx_ts_cleanup_module(void)
+{
+	wm97xx_ts_t* ts = &wm97xx_ts;
+
+#ifdef CONFIG_PM
+	pm_unregister (ts->pm);
+#endif
+	ac97_unregister_driver(&wm9705_driver);
+	ac97_unregister_driver(&wm9712_driver);
+	misc_deregister(&wm97xx_misc);
+}
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("WM9705/WM9712 Touch Screen / BMON Driver");
+MODULE_LICENSE("GPL");
+
+module_init(wm97xx_ts_init_module);
+module_exit(wm97xx_ts_cleanup_module);
+
+#ifndef MODULE
+
+static int __init wm97xx_ts_setup(char *options)
+{
+	char *this_opt = options;
+
+	if (!options || !*options)
+		return 0;
+
+	/* parse the options and check for out of range values */
+	for(this_opt=strtok(options, ",");
+	    this_opt; this_opt=strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "pil:", 4)) {
+			this_opt+=4;
+			pil = simple_strtol(this_opt, NULL, 0);
+			if (pil < 0 || pil > 2)
+				pil = 0;
+			continue;
+		}
+		if (!strncmp(this_opt, "rpu:", 4)) {
+			this_opt+=4;
+			rpu = simple_strtol(this_opt, NULL, 0);
+			if (rpu < 0 || rpu > 31)
+				rpu = 0;
+			continue;
+		}
+		if (!strncmp(this_opt, "pdd:", 4)) {
+			this_opt+=4;
+			pdd = simple_strtol(this_opt, NULL, 0);
+			if (pdd < 0 || pdd > 15)
+				pdd = 0;
+			continue;
+		}
+		if (!strncmp(this_opt, "delay:", 6)) {
+			this_opt+=6;
+			delay = simple_strtol(this_opt, NULL, 0);
+			if (delay < 0 || delay > 15)
+				delay = 4;
+			continue;
+		}
+		if (!strncmp(this_opt, "five_wire:", 10)) {
+			this_opt+=10;
+			five_wire = simple_strtol(this_opt, NULL, 0);
+			if (five_wire < 0 || five_wire > 1)
+				five_wire = 0;
+			continue;
+		}
+		if (!strncmp(this_opt, "mode:", 5)) {
+			this_opt+=5;
+			mode = simple_strtol(this_opt, NULL, 0);
+			if (mode < 0 || mode > 2)
+				mode = 0;
+			continue;
+		}
+	}
+	return 1;
+}
+
+__setup("wm97xx_ts=", wm97xx_ts_setup);
+
+#endif /* MODULE */
diff -Nru a/drivers/sound/ad1889.c b/drivers/sound/ad1889.c
--- a/drivers/sound/ad1889.c	Sun Jun 29 08:10:12 2003
+++ b/drivers/sound/ad1889.c	Wed Aug 13 06:43:27 2003
@@ -236,16 +236,24 @@
 
 	for (i = 0; i < AD_MAX_STATES; i++) {
 		dmabuf = &dev->state[i].dmabuf;
-		if ((dmabuf->rawbuf = kmalloc(DMA_SIZE, GFP_KERNEL|GFP_DMA)) == NULL)
-			return NULL;
+		dmabuf->rawbuf = kmalloc(DMA_SIZE, GFP_KERNEL|GFP_DMA);
+		if (!dmabuf->rawbuf)
+			goto err_free_dmabuf;
 		dmabuf->rawbuf_size = DMA_SIZE;
 		dmabuf->dma_handle = 0;
 		dmabuf->rd_ptr = dmabuf->wr_ptr = dmabuf->dma_len = 0UL;
 		dmabuf->ready = 0;
 		dmabuf->rate = 44100;
 	}
-
+out:
 	return dev;
+
+err_free_dmabuf:
+	while (--i >= 0)
+		kfree(dev->state[i].dmabuf.rawbuf);
+	kfree(dev);
+	dev = NULL;
+	goto out;
 }
 
 static void ad1889_free_dev(ad1889_dev_t *dev)
diff -Nru a/drivers/sound/ali5455.c b/drivers/sound/ali5455.c
--- a/drivers/sound/ali5455.c	Sun Jun 29 08:10:12 2003
+++ b/drivers/sound/ali5455.c	Tue Jul 29 09:55:34 2003
@@ -1,5 +1,5 @@
 /*
- *	ALI  ali5455 and friends ICH driver for Linux
+ *	Driver for ALI 5455  Audio PCI soundcard
  *	LEI HU <Lei_Hu@ali.com.tw>
  *
  *  Built from:
@@ -23,10 +23,7 @@
  *	along with this program; if not, write to the Free Software
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *
- *	ALi 5455 theory of operation
- *
- *	The chipset provides three DMA channels that talk to an AC97
+ *	The chipset provides five DMA channels that talk to an AC97
  *	CODEC (AC97 is a digital/analog mixer standard). At its simplest
  *	you get 48Khz audio with basic volume and mixer controls. At the
  *	best you get rate adaption in the codec. We set the card up so
@@ -42,6 +39,13 @@
  *	esd working you need to use esd -r 48000 as it won't probe 48KHz
  *	by default. mpg123 can't handle 48Khz only audio so use xmms.
  *
+ *
+ *	Not everyone uses 48KHz. We know of no way to detect this reliably
+ *	and certainly not to get the right data. If your ali audio sounds
+ *	stupid you may need to investigate other speeds. According to Analog
+ *	they tend to use a 14.318MHz clock which gives you a base rate of
+ *	41194Hz.
+ *
  *	If you need to force a specific rate set the clocking= option
  *
  */
@@ -78,31 +82,45 @@
 
 static int strict_clocking = 0;
 static unsigned int clocking = 0;
-static unsigned int codec_pcmout_share_spdif_locked = 0;
-static unsigned int codec_independent_spdif_locked = 0;
+#ifdef CONFIG_SOUND_ALI5455_CODECSPDIFOUT_PCMOUTSHARE
+static unsigned int codec_pcmout_share_spdif_locked = 48000;
+#else
+ static unsigned int codec_pcmout_share_spdif_locked = 0;
+#endif
+#ifdef CONFIG_SOUND_ALI5455_CODECSPDIFOUT_CODECINDEPENDENTDMA
+static unsigned int codec_independent_spdif_locked = 48000;
+#else
+static unsigned int codec_independent_spdif_locked = 0;   
+#endif
+#ifdef CONFIG_SOUND_ALI5455_CONTROLLERSPDIFOUT_PCMOUTSHARE
+static unsigned int controller_pcmout_share_spdif_locked = 48000;
+#else
 static unsigned int controller_pcmout_share_spdif_locked = 0;
+#endif
+#ifdef CONFIG_SOUND_ALI5455_CONTROLLERSPDIFOUT_CONTROLLERINDEPENDENTDMA
+static unsigned int controller_independent_spdif_locked = 48000;
+#else
 static unsigned int controller_independent_spdif_locked = 0;
-static unsigned int globel = 0;
-
-#define ADC_RUNNING	1
-#define DAC_RUNNING	2
-#define CODEC_SPDIFOUT_RUNNING 8
-#define CONTROLLER_SPDIFOUT_RUNNING 4
-
-#define SPDIF_ENABLE_OUTPUT	4	/* bits 0,1 are PCM */
-
-#define ALI5455_FMT_16BIT	1
-#define ALI5455_FMT_STEREO	2
-#define ALI5455_FMT_MASK	3
+#endif
 
-#define SPDIF_ON	0x0004
-#define SURR_ON		0x0010
-#define CENTER_LFE_ON	0x0020
-#define VOL_MUTED	0x8000
+#define ADC_RUNNING			1
+#define DAC_RUNNING			2
+#define CONTROLLER_SPDIFOUT_RUNNING 	4
+#define CODEC_SPDIFOUT_RUNNING		8
+
+#define ALI5455_FMT_16BIT		1
+#define ALI5455_FMT_STEREO		2
+#define ALI5455_FMT_MASK		3
+
+#define SPDIF_ON			0x0004
+#define SURR_ON				0x0010
+#define CENTER_LFE_ON			0x0020
+#define VOL_MUTED			0x8000
 
+#define SPDIF_ENABLE_OUTPUT 		0x00000004
 
-#define ALI_SPDIF_OUT_CH_STATUS 0xbf
-/* the 810's array of pointers to data buffers */
+#define ALI_SPDIF_OUT_CH_STATUS		0xbf
+/* the ali5455 's array of pointers to data buffers */
 
 struct sg_item {
 #define BUSADDR_MASK	0xFFFFFFFE
@@ -113,20 +131,21 @@
 	u32 control;
 };
 
-/* an instance of the ali channel */
+/* An instance of the ali 5455 channel */
 #define SG_LEN 32
 struct ali_channel {
 	/* these sg guys should probably be allocated
 	   seperately as nocache. Must be 8 byte aligned */
 	struct sg_item sg[SG_LEN];	/* 32*8 */
-	u32 offset;		/* 4 */
-	u32 port;		/* 4 */
+	u32 offset;			/* 4 */
+	u32 port;			/* 4 */
 	u32 used;
 	u32 num;
 };
 
 /*
- * we have 3 seperate dma engines.  pcm in, pcm out, and mic.
+ * we have 5 seperate dma engines.  pcm in, pcm out, mc in, 
+ * codec independant DMA, and controller independant DMA
  * each dma engine has controlling registers.  These goofy
  * names are from the datasheet, but make it easy to write
  * code while leafing through it.
@@ -142,11 +161,11 @@
 	PRE##_CR =	0x##DIG##b		/* Control Register */				\
 }
 
-ENUM_ENGINE(OFF, 0);		/* Offsets */
-ENUM_ENGINE(PI, 4);		/* PCM In */
-ENUM_ENGINE(PO, 5);		/* PCM Out */
-ENUM_ENGINE(MC, 6);		/* Mic In */
-ENUM_ENGINE(CODECSPDIFOUT, 7);	/* CODEC SPDIF OUT  */
+ENUM_ENGINE(OFF, 0);			/* Offsets */
+ENUM_ENGINE(PI, 4);			/* PCM In */
+ENUM_ENGINE(PO, 5);			/* PCM Out */
+ENUM_ENGINE(MC, 6);			/* Mic In */
+ENUM_ENGINE(CODECSPDIFOUT, 7);		/* CODEC SPDIF OUT  */
 ENUM_ENGINE(CONTROLLERSPDIFIN, A);	/* CONTROLLER SPDIF In */
 ENUM_ENGINE(CONTROLLERSPDIFOUT, B);	/* CONTROLLER SPDIF OUT */
 
@@ -171,7 +190,7 @@
 	ALI_SPDIFICS = 0xfc	/* spdif interface control/status  */
 };
 
-// x-status register(x:pcm in ,pcm out, mic in,)
+/* x-status register(x:pcm in ,pcm out, mic in,codec independent DMA.controller independent DMA) */
 /* interrupts for a dma engine */
 #define DMA_INT_FIFO		(1<<4)	/* fifo under/over flow */
 #define DMA_INT_COMPLETE	(1<<3)	/* buffer read/write complete and ioc set */
@@ -180,8 +199,7 @@
 #define DMA_INT_DCH		(1)	/* DMA Controller Halted (happens on LVI interrupts) */	//not eqult intel
 #define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
 
-/* interrupts for the whole chip */// by interrupt status register finish
-
+/* interrupts for the whole chip */ 
 #define INT_SPDIFOUT   (1<<23)	/* controller spdif out INTERRUPT */
 #define INT_SPDIFIN   (1<<22)
 #define INT_CODECSPDIFOUT   (1<<19)
@@ -193,13 +211,14 @@
 #define INT_GPIO    (1<<1)
 #define INT_MASK   (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)
 
-#define DRIVER_VERSION "0.02ac"
+#define DRIVER_VERSION "0.03-ac"
 
 /* magic numbers to protect our data structures */
 #define ALI5455_CARD_MAGIC		0x5072696E	/* "Prin" */
 #define ALI5455_STATE_MAGIC		0x63657373	/* "cess" */
 #define ALI5455_DMA_MASK		0xffffffff	/* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH			5	//I think 5 channel
+
+#define NR_HW_CH			5		/* I think 5 channel */
 
 /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
 #define NR_AC97		2
@@ -216,7 +235,7 @@
 	"ALI 5455"
 };
 
-static struct pci_device_id ali_pci_tbl[] __initdata = {
+static struct pci_device_id ali_pci_tbl[] __devinitdata = {
 	{PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},
 	{0,}
@@ -267,12 +286,12 @@
 		unsigned fragshift;
 
 		/* 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 consumed or been generated by dma machine */
+		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 consumed or been generated by dma machine */
 		unsigned total_bytes;	/* total bytes dmaed by hardware */
 
-		unsigned error;	/* number of over/underruns */
+		unsigned error;		/* number of over/underruns */
 		wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */
 
 		/* redundant, but makes calculations easier */
@@ -399,7 +418,11 @@
 }
 
 
-//add support  codec spdif out 
+/*
+ *	we use ALC650 which only support  48k sample rate, so we test firstly
+ *	spdifout 's sample rate validity 
+ */
+ 
 static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate)
 {
 	unsigned long id = 0L;
@@ -428,16 +451,13 @@
 
 /* ali_set_spdif_output
  * 
- *  Configure the S/PDIF output transmitter. When we turn on
- *  S/PDIF, we turn off the analog output. This may not be
- *  the right thing to do.
+ *  Configure the S/PDIF output transmitter.
  *
  *  Assumptions:
  *     The DSP sample rate must already be set to a supported
  *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
  */
-static void ali_set_spdif_output(struct ali_state *state, int slots,
-				 int rate)
+static void ali_set_spdif_output(struct ali_state *state, int slots, int rate)
 {
 	int vol;
 	int aud_reg;
@@ -453,8 +473,7 @@
 			/* If the volume wasn't muted before we turned on S/PDIF, unmute it */
 			if (!(state->card->ac97_status & VOL_MUTED)) {
 				aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
-				ali_ac97_set(codec, AC97_MASTER_VOL_STEREO,
-					     (aud_reg & ~VOL_MUTED));
+				ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));
 			}
 			state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
 			return;
@@ -486,7 +505,7 @@
 		ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
 
 		aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
-		aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF;
+		aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF; /* ALC650 don't support VRA */
 		ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
 
 		aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL);
@@ -508,8 +527,6 @@
 			aud_reg = ali_ac97_get(codec, 0x6a);
 			ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff));
 		}
-		/* Mute the analog output */
-		/* Should this only mute the PCM volume??? */
 	}
 }
 
@@ -517,13 +534,6 @@
  *
  *  Configure the codec's multi-channel DACs
  *
- *  The logic is backwards. Setting the bit to 1 turns off the DAC. 
- *
- *  What about the ICH? We currently configure it using the
- *  SNDCTL_DSP_CHANNELS ioctl.  If we're turnning on the DAC, 
- *  does that imply that we want the ICH set to support
- *  these channels?
- *  
  *  TODO:
  *    vailidate that the codec really supports these DACs
  *    before turning them on. 
@@ -556,8 +566,7 @@
 }
 
 /* set playback sample rate */
-static unsigned int ali_set_dac_rate(struct ali_state *state,
-				     unsigned int rate)
+static unsigned int ali_set_dac_rate(struct ali_state *state, unsigned int rate)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	u32 new_rate;
@@ -594,8 +603,7 @@
 }
 
 /* set recording sample rate */
-static unsigned int ali_set_adc_rate(struct ali_state *state,
-				     unsigned int rate)
+static unsigned int ali_set_adc_rate(struct ali_state *state, unsigned int rate)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	u32 new_rate;
@@ -632,11 +640,10 @@
 }
 
 /* set codec independent spdifout sample rate */
-static unsigned int ali_set_codecspdifout_rate(struct ali_state *state,
-					       unsigned int rate)
+static unsigned int ali_set_codecspdifout_rate(struct ali_state *state, unsigned int rate)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-
+	
 	if (!(state->card->ac97_features & 0x0001)) {
 		dmabuf->rate = clocking;
 		return clocking;
@@ -652,8 +659,7 @@
 }
 
 /* set  controller independent spdif out function sample rate */
-static void ali_set_spdifout_rate(struct ali_state *state,
-				  unsigned int rate)
+static void ali_set_spdifout_rate(struct ali_state *state, unsigned int rate)
 {
 	unsigned char ch_st_sel;
 	unsigned short status_rate;
@@ -729,7 +735,9 @@
 	data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize;
 	if (inw(port_picb) == 0)
 		data -= 2048;
-
+	/* It is  hardware  bug  when read port 's PICB ==0 */
+	if ( inw(port_picb) == 0 )
+		data -= 2048;  
 	return data;
 }
 
@@ -745,6 +753,8 @@
 	udelay(1);
 
 	outb(0, card->iobase + PI_CR);
+ 
+	// wait for the card to acknowledge shutdown
 	while (inb(card->iobase + PI_CR) != 0);
 
 	// now clear any latent interrupt bits (like the halt bit)
@@ -771,10 +781,8 @@
 		outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR);
 		if (state->card->channel[0].used == 1)
 			outl(1, state->card->iobase + ALI_DMACR);	// DMA CONTROL REGISTRER
-		udelay(100);
 		if (state->card->channel[2].used == 1)
 			outl((1 << 2), state->card->iobase + ALI_DMACR);	//DMA CONTROL REGISTER
-		udelay(100);
 	}
 }
 
@@ -965,7 +973,7 @@
 static int prog_dmabuf(struct ali_state *state, unsigned rec)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	struct ali_channel *c = NULL;
+	struct ali_channel *c = NULL ;
 	struct sg_item *sg;
 	unsigned long flags;
 	int ret;
@@ -1248,9 +1256,7 @@
 	}
 }
 
-static inline int ali_get_free_write_space(struct
-					   ali_state
-					   *state)
+static inline int ali_get_free_write_space(struct ali_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	int free;
@@ -1267,9 +1273,7 @@
 	return (free);
 }
 
-static inline int ali_get_available_read_data(struct
-					      ali_state
-					      *state)
+static inline int ali_get_available_read_data(struct ali_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	int avail;
@@ -1288,12 +1292,12 @@
 
 static int drain_dac(struct ali_state *state, int signals_allowed)
 {
-
 	DECLARE_WAITQUEUE(wait, current);
 	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long flags;
 	unsigned long tmo;
 	int count;
+
 	if (!dmabuf->ready)
 		return 0;
 	if (dmabuf->mapped) {
@@ -1302,11 +1306,11 @@
 	}
 	add_wait_queue(&dmabuf->wait, &wait);
 	for (;;) {
-
 		spin_lock_irqsave(&state->card->lock, flags);
 		ali_update_ptr(state);
 		count = dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
+
 		if (count <= 0)
 			break;
 		/* 
@@ -1355,7 +1359,6 @@
 
 static int drain_spdifout(struct ali_state *state, int signals_allowed)
 {
-
 	DECLARE_WAITQUEUE(wait, current);
 	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long flags;
@@ -1548,7 +1551,6 @@
 {
 	struct ali_card *card = (struct ali_card *) dev_id;
 	u32 status;
-	u16 status2;
 
 	spin_lock(&card->lock);
 	status = inl(card->iobase + ALI_INTERRUPTSR);
@@ -1557,19 +1559,8 @@
 		return;		/* not for us */
 	}
 
-	if (codec_independent_spdif_locked > 0) {
-		if (globel == 0) {
-			globel += 1;
-			status2 = inw(card->iobase + 0x76);
-			outw(status2 | 0x000c, card->iobase + 0x76);
-		} else {
-			if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
-				ali_channel_interrupt(card);
-		}
-	} else {
-		if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
-			ali_channel_interrupt(card);
-	}
+	if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
+		ali_channel_interrupt(card);
 
 	/* clear 'em */
 	outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR);
@@ -1580,8 +1571,7 @@
    waiting to be copied to the user's buffer.  It is filled by the dma
    machine and drained by this loop. */
 
-static ssize_t ali_read(struct file *file, char *buffer,
-			size_t count, loff_t * ppos)
+static ssize_t ali_read(struct file *file, char *buffer, size_t count, loff_t * ppos)
 {
 	struct ali_state *state = (struct ali_state *) file->private_data;
 	struct ali_card *card = state ? state->card : 0;
@@ -1721,8 +1711,7 @@
 
 /* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
    the soundcard.  it is drained by the dma machine and filled by this loop. */
-static ssize_t ali_write(struct file *file,
-			 const char *buffer, size_t count, loff_t * ppos)
+static ssize_t ali_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
 {
 	struct ali_state *state = (struct ali_state *) file->private_data;
 	struct ali_card *card = state ? state->card : 0;
@@ -1908,8 +1897,7 @@
 }
 
 /* No kernel lock - we have our own spinlock */
-static unsigned int ali_poll(struct file *file, struct poll_table_struct
-			     *wait)
+static unsigned int ali_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct ali_state *state = (struct ali_state *) file->private_data;
 	struct dmabuf *dmabuf = &state->dmabuf;
@@ -2014,8 +2002,7 @@
 		}
 		if (c != NULL) {
 			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);
+			outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);
 			outb(0, state->card->iobase + c->port + OFF_CIV);
 			outb(0, state->card->iobase + c->port + OFF_LVI);
 		}
@@ -2990,7 +2977,6 @@
 {
 	struct ali_card *card = dev->private_data;
 	int count1 = 100;
-	unsigned long flags;
 	char val;
 	unsigned short int count;
 
@@ -3660,12 +3646,17 @@
 MODULE_PARM(codec_independent_spdif_locked, "i");
 MODULE_PARM(controller_pcmout_share_spdif_locked, "i");
 MODULE_PARM(controller_independent_spdif_locked, "i");
+
 #define ALI5455_MODULE_NAME "ali5455"
+
 static struct pci_driver ali_pci_driver = {
-	name:ALI5455_MODULE_NAME, id_table:ali_pci_tbl, probe:ali_probe,
-	    remove:__devexit_p(ali_remove),
+	name:			ALI5455_MODULE_NAME, 
+	id_table:		ali_pci_tbl, 
+	probe:			ali_probe,
+	remove:			__devexit_p(ali_remove),
 #ifdef CONFIG_PM
-	suspend:ali_pm_suspend, resume:ali_pm_resume,
+	suspend:		ali_pm_suspend, 
+	resume:			ali_pm_resume,
 #endif				/* CONFIG_PM */
 };
 
diff -Nru a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c
--- a/drivers/sound/cmpci.c	Sun Jun 29 08:10:11 2003
+++ b/drivers/sound/cmpci.c	Tue Jul 29 09:56:03 2003
@@ -98,15 +98,16 @@
 #include <linux/slab.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
-#include <linux/wrapper.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
+#include <linux/wrapper.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
+#include <linux/gameport.h>
 #include <linux/bitops.h>
 
 #include "dm.h"
@@ -178,26 +179,143 @@
 #define DSP_MIX_TREBLEIDX_R		((unsigned char)(0x45))
 #define DSP_MIX_BASSIDX_L		((unsigned char)(0x46))
 #define DSP_MIX_BASSIDX_R		((unsigned char)(0x47))
+#define DSP_MIX_EXTENSION		((unsigned char)(0xf0))
+// pseudo register for AUX
+#define	DSP_MIX_AUXVOL_L		((unsigned char)(0x50))
+#define	DSP_MIX_AUXVOL_R		((unsigned char)(0x51))
+
+// I/O length
+#define CM_EXTENT_CODEC	  0x100
+#define CM_EXTENT_MIDI	  0x2
+#define CM_EXTENT_SYNTH	  0x4
+#define CM_EXTENT_GAME	  0x8
+
+// Function Control Register 0 (00h)
+#define CHADC0    	0x01
+#define CHADC1    	0x02
+#define PAUSE0	  	0x04
+#define PAUSE1	  	0x08
+ 
+// Function Control Register 0+2 (02h)
+#define CHEN0     	0x01
+#define CHEN1     	0x02
+#define RST_CH0	  	0x04
+#define RST_CH1	  	0x08
+ 
+// Function Control Register 1 (04h)
+#define JYSTK_EN	0x02
+#define UART_EN		0x04
+#define	SPDO2DAC	0x40
+#define	SPDFLOOP	0x80
+ 
+// Function Control Register 1+1 (05h)
+#define	SPDF_0		0x01
+#define	SPDF_1		0x02
+#define	ASFC		0xe0
+#define	DSFC		0x1c
+#define	SPDIF2DAC	(SPDF_0 << 8 | SPDO2DAC)
+
+// Channel Format Register (08h)
+#define CM_CFMT_STEREO	0x01
+#define CM_CFMT_16BIT	0x02
+#define CM_CFMT_MASK	0x03
+#define	POLVALID	0x20
+#define	INVSPDIFI	0x80
+
+// Channel Format Register+2 (0ah)
+#define SPD24SEL	0x20
+
+// Channel Format Register+3 (0bh)
+#define CHB3D		0x20
+#define CHB3D5C		0x80
+
+// Interrupt Hold/Clear Register+2 (0eh)
+#define	CH0_INT_EN	0x01
+#define	CH1_INT_EN	0x02
+
+// Interrupt Register (10h)
+#define CHINT0		0x01
+#define CHINT1		0x02
+#define	CH0BUSY		0x04
+#define	CH1BUSY		0x08
+
+// Legacy Control/Status Register+1 (15h)
+#define	EXBASEN		0x10
+#define	BASE2LIN	0x20
+#define	CENTR2LIN	0x40
+#define	CB2LIN		(BASE2LIN|CENTR2LIN)
+#define	CHB3D6C		0x80
+
+// Legacy Control/Status Register+2 (16h)
+#define	DAC2SPDO	0x20
+#define	SPDCOPYRHT	0x40
+#define	ENSPDOUT	0x80
+
+// Legacy Control/Status Register+3 (17h)
+#define	FMSEL		0x03
+#define	VSBSEL		0x0c
+#define	VMPU		0x60
+#define	NXCHG		0x80
+ 
+// Miscellaneous Control Register (18h)
+#define	REAR2LIN	0x20
+#define	MUTECH1		0x40
+#define	ENCENTER	0x80
+ 
+// Miscellaneous Control Register+1 (19h)
+#define	SELSPDIFI2	0x01
+#define	SPDF_AC97	0x80
+ 
+// Miscellaneous Control Register+2 (1ah)
+#define	AC3_EN		0x04
+#define	FM_EN		0x08
+#define	SPD32SEL	0x20
+#define	XCHGDAC		0x40
+#define	ENDBDAC		0x80
+ 
+// Miscellaneous Control Register+3 (1bh)
+#define	SPDIFI48K	0x01
+#define	SPDO5V		0x02
+#define	N4SPK3D		0x04
+#define	RESET		0x40
+#define	PWD		0x80
+#define	SPDIF48K	(SPDIFI48K << 24 | SPDF_AC97 << 8)
+ 
+// Mixer1 (24h)
+#define	CDPLAY		0x01
+#define	X3DEN		0x02
+#define	REAR2FRONT	0x10
+#define	SPK4		0x20
+#define	WSMUTE		0x40
+ 
+// Miscellaneous Register (27h)
+#define	SPDVALID	0x02
+#define	CENTR2MIC	0x04
+
+#define CM_CFMT_DACSHIFT   0
+#define CM_CFMT_ADCSHIFT   2
+#define CM_FREQ_DACSHIFT   2
+#define CM_FREQ_ADCSHIFT   5
+#define	RSTDAC		RST_CH0
+#define	RSTADC		RST_CH1
+#define	ENDAC		CHEN0
+#define	ENADC		CHEN1
+#define	PAUSEDAC	PAUSE0
+#define	PAUSEADC	PAUSE1
+#define CODEC_CMI_DAC_FRAME1	CODEC_CMI_CH0_FRAME1
+#define CODEC_CMI_DAC_FRAME2	CODEC_CMI_CH0_FRAME2
+#define CODEC_CMI_ADC_FRAME1	CODEC_CMI_CH1_FRAME1
+#define CODEC_CMI_ADC_FRAME2	CODEC_CMI_CH1_FRAME2
+#define	DACINT		CHINT0
+#define	ADCINT		CHINT1
+#define	DACBUSY		CH0BUSY
+#define	ADCBUSY		CH1BUSY
+#define	ENDACINT	CH0_INT_EN
+#define	ENADCINT	CH1_INT_EN
 
-#define CM_CH0_RESET			0x04
-#define CM_CH1_RESET			0x08
-#define CM_EXTENT_CODEC			0x100
-#define CM_EXTENT_MIDI			0x2
-#define CM_EXTENT_SYNTH			0x4
-#define CM_INT_CH0			1
-#define CM_INT_CH1			2
-
-#define CM_CFMT_STEREO			0x01
-#define CM_CFMT_16BIT			0x02
-#define CM_CFMT_MASK			0x03
-#define CM_CFMT_DACSHIFT		2
-#define CM_CFMT_ADCSHIFT		0
-
+static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[]	= { 0, 1, 1, 2 };
 
-#define CM_ENABLE_CH1      0x2
-#define CM_ENABLE_CH0      0x1
-
 /* MIDI buffer sizes **************************/
 
 #define MIDIINBUF  256
@@ -213,11 +331,19 @@
 
 #define NR_DEVICE 3		/* maximum number of devices */
 
-/*********************************************/
+static unsigned int devindex = 0;
+
+//*********************************************/
 
 struct cm_state {
-	unsigned int magic;		/* magic */
-	struct cm_state *next;		/* we keep cm cards in a linked list */
+	/* magic */
+	unsigned int magic;
+
+	/* list of cmedia devices */
+	struct list_head devs;
+
+	/* the corresponding pci_dev structure */
+	struct pci_dev *dev;
 
 	int dev_audio;			/* soundcore stuff */
 	int dev_mixer;
@@ -275,7 +401,9 @@
 		unsigned char ibuf[MIDIINBUF];
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
-	
+
+	struct gameport gameport;
+
 	int	chip_version;		
 	int	max_channels;
 	int	curr_channels;		
@@ -312,8 +440,7 @@
 #define	DO_SPDIF_IN		0x00000200
 #define	DO_SPDIF_LOOP		0x00000400
 
-static struct cm_state *devs;
-static unsigned long wavetable_mem;
+static LIST_HEAD(devs);
 
 /* --------------------------------------------------------------------- */
 
@@ -356,55 +483,55 @@
 static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count)
 {
 	if (addr)
-	    outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
-	outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~1, 0);
+	    outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
+	outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, 0);
 }
 
 static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
 {
-	outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
-	outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 1);
+	outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
+	outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, CHADC1);
 }
 
 static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
 {
-	outl(addr, s->iobase + CODEC_CMI_CH1_FRAME1);
-	outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 0);
+	outl(addr, s->iobase + CODEC_CMI_DAC_FRAME1);
+	outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC0, 0);
 	if (s->status & DO_DUAL_DAC)
 		set_dmadac1(s, 0, count);
 }
 
 static void set_countadc(struct cm_state *s, unsigned count)
 {
-	outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+	outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2 + 2);
 }
 
 static void set_countdac(struct cm_state *s, unsigned count)
 {
-	outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+	outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2 + 2);
 	if (s->status & DO_DUAL_DAC)
 	    set_countadc(s, count);
 }
 
-static inline unsigned get_dmadac(struct cm_state *s)
+static unsigned get_dmadac(struct cm_state *s)
 {
 	unsigned int curr_addr;
 
-	curr_addr = inw(s->iobase + CODEC_CMI_CH1_FRAME2) + 1;
+	curr_addr = inw(s->iobase + CODEC_CMI_DAC_FRAME2) + 1;
 	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
 	curr_addr = s->dma_dac.dmasize - curr_addr;
 
 	return curr_addr;
 }
 
-static inline unsigned get_dmaadc(struct cm_state *s)
+static unsigned get_dmaadc(struct cm_state *s)
 {
 	unsigned int curr_addr;
 
-	curr_addr = inw(s->iobase + CODEC_CMI_CH0_FRAME2) + 1;
+	curr_addr = inw(s->iobase + CODEC_CMI_ADC_FRAME2) + 1;
 	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];
 	curr_addr = s->dma_adc.dmasize - curr_addr;
 
@@ -413,23 +540,79 @@
 
 static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data)
 {
+	unsigned char regval, pseudo;
+
+	// pseudo register
+	if (idx == DSP_MIX_AUXVOL_L) {
+		data >>= 4;
+		data &= 0x0f;
+		regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0x0f;
+		outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
+		return;
+	}
+	if (idx == DSP_MIX_AUXVOL_R) {
+		data &= 0xf0;
+		regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0xf0;
+		outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
+		return;
+	}
 	outb(idx, s->iobase + CODEC_SB16_ADDR);
 	udelay(10);
+	// pseudo bits
+	if (idx == DSP_MIX_OUTMIXIDX) {
+		pseudo = data & ~0x1f;
+		pseudo >>= 1;	
+		regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x30;
+		outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
+	}
+	if (idx == DSP_MIX_ADCMIXIDX_L) {
+		pseudo = data & 0x80;
+		pseudo >>= 1;
+		regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x40;
+		outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
+	}
+	if (idx == DSP_MIX_ADCMIXIDX_R) {
+		pseudo = data & 0x80;
+		regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x80;
+		outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
+	}
 	outb(data, s->iobase + CODEC_SB16_DATA);
 	udelay(10);
 }
 
 static unsigned char rdmixer(struct cm_state *s, unsigned char idx)
 {
-	unsigned char v;
-	unsigned long flags;
+	unsigned char v, pseudo;
 	
-	spin_lock_irqsave(&s->lock, flags);
+	// pseudo register
+	if (idx == DSP_MIX_AUXVOL_L) {
+		v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0x0f;
+		v <<= 4;
+		return v;
+	}
+	if (idx == DSP_MIX_AUXVOL_L) {
+		v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0xf0;
+		return v;
+	}
 	outb(idx, s->iobase + CODEC_SB16_ADDR);
 	udelay(10);
 	v = inb(s->iobase + CODEC_SB16_DATA);
 	udelay(10);
-	spin_unlock_irqrestore(&s->lock, flags);
+	// pseudo bits
+	if (idx == DSP_MIX_OUTMIXIDX) {
+		pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x30;
+		pseudo <<= 1;
+		v |= pseudo;
+	}
+	if (idx == DSP_MIX_ADCMIXIDX_L) {
+		pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x40;
+		pseudo <<= 1;
+		v |= pseudo;
+	}
+	if (idx == DSP_MIX_ADCMIXIDX_R) {
+		pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x80;
+		v |= pseudo;
+	}
 	return v;
 }
 
@@ -479,24 +662,88 @@
 	{ 48000,	(44100 + 48000) / 2,	48000,			7 }
 };
 
+static void set_spdif_copyright(struct cm_state *s, int spdif_copyright)
+{
+	/* enable SPDIF-in Copyright */
+	maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~SPDCOPYRHT, spdif_copyright ? SPDCOPYRHT : 0);
+}
+
+static void set_spdif_loop(struct cm_state *s, int spdif_loop)
+{
+	/* enable SPDIF loop */
+	if (spdif_loop) {
+		s->status |= DO_SPDIF_LOOP;
+		/* turn on spdif-in to spdif-out */
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, SPDFLOOP);
+	} else {
+		s->status &= ~DO_SPDIF_LOOP;
+		/* turn off spdif-in to spdif-out */
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDFLOOP, 0);
+	}
+}
+
+static void set_spdif_monitor(struct cm_state *s, int channel)
+{
+	// SPDO2DAC
+	maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDO2DAC, channel == 2 ? SPDO2DAC : 0);
+	// CDPLAY
+	if (s->chip_version >= 39)
+		maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, channel ? CDPLAY : 0);
+}
+
+static void set_spdifout_level(struct cm_state *s, int level5v)
+{
+	/* SPDO5V */
+	maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~SPDO5V, level5v ? SPDO5V : 0);
+}
+
+static void set_spdifin_inverse(struct cm_state *s, int spdif_inverse)
+{
+	if (spdif_inverse) {
+		/* turn on spdif-in inverse */
+		if (s->chip_version >= 39)
+			maskb(s->iobase + CODEC_CMI_CHFORMAT, ~0, INVSPDIFI);
+		else
+			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);
+	} else {
+		/* turn off spdif-ininverse */
+		if (s->chip_version >= 39) 
+			maskb(s->iobase + CODEC_CMI_CHFORMAT, ~INVSPDIFI, 0);
+		else
+			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);
+	}
+}
+
+static void set_spdifin_channel2(struct cm_state *s, int channel2)
+{
+	/* SELSPDIFI2 */
+	if (s->chip_version >= 39)
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 1, ~SELSPDIFI2, channel2 ? SELSPDIFI2 : 0);
+}
+
+static void set_spdifin_valid(struct cm_state *s, int valid)
+{
+	/* SPDVALID */
+	maskb(s->iobase + CODEC_CMI_MISC, ~SPDVALID, valid ? SPDVALID : 0);
+}
+
 static void set_spdifout_unlocked(struct cm_state *s, unsigned rate)
 {
 	if (rate == 48000 || rate == 44100) {
+		// SPDF_0
+		maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0, SPDF_0);
 		// SPDIFI48K SPDF_ACc97
-		maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~0x01008000, rate == 48000 ? 0x01008000 : 0);
+		maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
 		// ENSPDOUT
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, 0x80);
-		// SPDF_1 SPD2DAC
-		maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x240);
-		// CDPLAY
-		if (s->chip_version >= 39)
-			maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 1);
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, ENSPDOUT);
+		// monitor SPDIF out
+		set_spdif_monitor(s, 2);
 		s->status |= DO_SPDIF_OUT;
 	} else {
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0x80, 0);
-		maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0x240, 0);
-		if (s->chip_version >= 39)
-			maskb(s->iobase + CODEC_CMI_MIXER1, ~1, 0);
+		maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDF_0, 0);
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~ENSPDOUT, 0);
+		// monitor none
+		set_spdif_monitor(s, 0);
 		s->status &= ~DO_SPDIF_OUT;
 	}
 }
@@ -510,7 +757,30 @@
 	spin_unlock_irqrestore(&s->lock, flags);
 }
 
-/* find parity for bit 4~30 */
+static void set_spdifin_unlocked(struct cm_state *s, unsigned rate)
+{
+	if (rate == 48000 || rate == 44100) {
+		// SPDF_1
+		maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0, SPDF_1);
+		// SPDIFI48K SPDF_AC97
+		maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
+		s->status |= DO_SPDIF_IN;
+	} else {
+		maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDF_1, 0);
+		s->status &= ~DO_SPDIF_IN;
+	}
+}
+
+static void set_spdifin(struct cm_state *s, unsigned rate)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->lock, flags);
+	set_spdifin_unlocked(s,rate);
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+//* find parity for bit 4~30 */
 static unsigned parity(unsigned data)
 {
 	unsigned parity = 0;
@@ -531,21 +801,26 @@
 	/* enable AC3 */
 	if (rate == 48000 || rate == 44100) {
 		// mute DAC
-		maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 0x40);
-		// AC3EN for 037, 0x10
-		maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);
+		maskb(s->iobase + CODEC_CMI_MIXER1, ~0, WSMUTE);
 		// AC3EN for 039, 0x04
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0x04);
+		if (s->chip_version >= 39)
+			maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, AC3_EN);
+		// AC3EN for 037, 0x10
+		else if (s->chip_version == 37)
+			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);
 		if (s->capability & CAN_AC3_HW) {
-			// SPD24SEL for 037, 0x02
 			// SPD24SEL for 039, 0x20, but cannot be set
-			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);
+			if (s->chip_version >= 39)
+				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, SPD24SEL);
+			// SPD24SEL for 037, 0x02
+			else if (s->chip_version == 37)
+				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);
 			s->status |= DO_AC3_HW;
 			if (s->chip_version >= 39)
-				maskb(s->iobase + CODEC_CMI_MIXER1, ~1, 0);
+				maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, 0);
 		 } else {
 			// SPD32SEL for 037 & 039, 0x20
-			maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0x20);
+			maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, SPD32SEL);
 			// set 176K sample rate to fix 033 HW bug
 			if (s->chip_version == 33) {
 				if (rate == 48000)
@@ -556,18 +831,16 @@
 			s->status |= DO_AC3_SW;
 		}
 	} else {
-		maskb(s->iobase + CODEC_CMI_MIXER1, ~0x40, 0);
+		maskb(s->iobase + CODEC_CMI_MIXER1, ~WSMUTE, 0);
 		maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0x32, 0);
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0x24, 0);
-		maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~(SPD32SEL|AC3_EN), 0);
 		if (s->chip_version == 33)
 			maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
 		if (s->chip_version >= 39)
-			maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 1);
+			maskb(s->iobase + CODEC_CMI_MIXER1, ~0, CDPLAY);
 		s->status &= ~DO_AC3;
 	}
 	s->spdif_counter = 0;
-
 }
 
 static void set_ac3(struct cm_state *s, unsigned rate)
@@ -629,9 +902,9 @@
 	    	}
 	}
 	s->rateadc = rate;
-	freq <<= 2;
+	freq <<= CM_FREQ_ADCSHIFT;
 
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
 }
 
 static void set_adc_rate(struct cm_state *s, unsigned rate)
@@ -652,10 +925,10 @@
 	    	}
 	}
 	s->rateadc = rate;
-	freq <<= 2;
+	freq <<= CM_FREQ_ADCSHIFT;
 
 	spin_lock_irqsave(&s->lock, flags);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
 	spin_unlock_irqrestore(&s->lock, flags);
 }
 
@@ -677,46 +950,45 @@
 	    	}
 	}
 	s->ratedac = rate;
-	freq <<= 5;
+	freq <<= CM_FREQ_DACSHIFT;
 
 	spin_lock_irqsave(&s->lock, flags);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0xe0, freq);
-
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~DSFC, freq);
+	spin_unlock_irqrestore(&s->lock, flags);
 
 	if (s->curr_channels <=  2)
-		set_spdifout_unlocked(s, rate);
+		set_spdifout(s, rate);
 	if (s->status & DO_DUAL_DAC)
-		set_adc_rate_unlocked(s, rate);
-
-	spin_unlock_irqrestore(&s->lock, flags);
+		set_adc_rate(s, rate);
 }
 
 /* --------------------------------------------------------------------- */
 static inline void reset_adc(struct cm_state *s)
 {
 	/* reset bus master */
-	outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	outb(s->enable | RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 	udelay(10);
-	outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	outb(s->enable & ~RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 }
 
 static inline void reset_dac(struct cm_state *s)
 {
 	/* reset bus master */
-	outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	outb(s->enable | RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	udelay(10);
+	outb(s->enable & ~RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 	if (s->status & DO_DUAL_DAC)
 		reset_adc(s);
 }
 
 static inline void pause_adc(struct cm_state *s)
 {
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 4);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEADC);
 }
 
 static inline void pause_dac(struct cm_state *s)
 {
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 8);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEDAC);
 	if (s->status & DO_DUAL_DAC)
 		pause_adc(s);
 }
@@ -724,7 +996,7 @@
 static inline void disable_adc(struct cm_state *s)
 {
 	/* disable channel */
-	s->enable &= ~CM_ENABLE_CH0;
+	s->enable &= ~ENADC;
 	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 	reset_adc(s);
 }
@@ -732,7 +1004,7 @@
 static inline void disable_dac(struct cm_state *s)
 {
 	/* disable channel */
-	s->enable &= ~CM_ENABLE_CH1;
+	s->enable &= ~ENDAC;
 	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 	reset_dac(s);
 	if (s->status & DO_DUAL_DAC)
@@ -741,22 +1013,22 @@
 
 static inline void enable_adc(struct cm_state *s)
 {
-	if (!(s->enable & CM_ENABLE_CH0)) {
+	if (!(s->enable & ENADC)) {
 		/* enable channel */
-		s->enable |= CM_ENABLE_CH0;
+		s->enable |= ENADC;
 		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 	}
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~4, 0);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEADC, 0);
 }
 
 static inline void enable_dac_unlocked(struct cm_state *s)
 {
-	if (!(s->enable & CM_ENABLE_CH1)) {
+	if (!(s->enable & ENDAC)) {
 		/* enable channel */
-		s->enable |= CM_ENABLE_CH1;
+		s->enable |= ENDAC;
 		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
 	}
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~8, 0);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEDAC, 0);
 
 	if (s->status & DO_DUAL_DAC)
 		enable_adc(s);
@@ -773,9 +1045,9 @@
 
 static inline void stop_adc_unlocked(struct cm_state *s)
 {
-	if (s->enable & CM_ENABLE_CH0) {
+	if (s->enable & ENADC) {
 		/* disable interrupt */
-		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~1, 0);
+		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENADCINT, 0);
 		disable_adc(s);
 	}
 }
@@ -792,9 +1064,9 @@
 
 static inline void stop_dac_unlocked(struct cm_state *s)
 {
-	if (s->enable & CM_ENABLE_CH1) {
+	if (s->enable & ENDAC) {
 		/* disable interrupt */
-		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~2, 0);
+		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENDACINT, 0);
 		disable_dac(s);
 	}
 	if (s->status & DO_DUAL_DAC)
@@ -810,12 +1082,12 @@
 	spin_unlock_irqrestore(&s->lock, flags);
 }
 
-static void start_adc_unlocked(struct cm_state *s)
+static inline void start_adc_unlocked(struct cm_state *s)
 {
 	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
 	    && s->dma_adc.ready) {
 		/* enable interrupt */
-		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1);
+		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
 		enable_adc(s);
 	}
 }
@@ -833,7 +1105,7 @@
 {
 	if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) {
 		/* enable interrupt */
-//		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1);
+		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
  		enable_dac_unlocked(s);
 	}
 }
@@ -842,11 +1114,11 @@
 {
 	if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
 		/* enable interrupt */
-		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 2);
+		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENDACINT);
 		enable_dac_unlocked(s);
 	}
-		if (s->status & DO_DUAL_DAC)
-			start_dac1_unlocked(s);
+	if (s->status & DO_DUAL_DAC)
+		start_dac1_unlocked(s);
 }
 
 static void start_dac(struct cm_state *s)
@@ -870,13 +1142,13 @@
 	    set_spdifout_unlocked(s, 0);
 	    if (s->capability & CAN_MULTI_CH_HW) {
 		// NXCHG
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, 0x80);
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, NXCHG);
 		// CHB3D or CHB3D5C
-	       	maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~0xa0, channels > 4 ? 0x80 : 0x20);
+	       	maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), channels > 4 ? CHB3D5C : CHB3D);
 		// CHB3D6C
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x80, channels == 6 ? 0x80 : 0);
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, channels == 6 ? CHB3D6C : 0);
 		// ENCENTER 
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0x80, channels == 6 ? 0x80 : 0);
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~ENCENTER, channels == 6 ? ENCENTER : 0);
 		s->status |= DO_MULTI_CH_HW;
 	    } else if (s->capability & CAN_DUAL_DAC) {
 		unsigned char fmtm = ~0, fmts = 0;
@@ -884,7 +1156,7 @@
 
 		// ENDBDAC, turn on double DAC mode
 		// XCHGDAC, CH0 -> back, CH1->front
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0xC0);
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, ENDBDAC|XCHGDAC);
 		s->status |= DO_DUAL_DAC;
 		// prepare secondary buffer
 
@@ -907,20 +1179,21 @@
 
 	    }
 
+	    // N4SPK3D, disable 4 speaker mode (analog duplicate)
 	    if (s->speakers > 2)
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0x04, 0);
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~N4SPK3D, 0);
 	    s->curr_channels = channels;
 	} else {
 	    if (s->status & DO_MULTI_CH_HW) {
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x80, 0);
-		maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~0xa0, 0);
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x80, 0);
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~NXCHG, 0);
+		maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), 0);
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, 0);
 	    } else if (s->status & DO_DUAL_DAC) {
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0x80, 0);
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~ENDBDAC, 0);
 	    }
 	    // N4SPK3D, enable 4 speaker mode (analog duplicate)
 	    if (s->speakers > 2)
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, 0x04);
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, N4SPK3D);
 	    s->status &= ~DO_MULTI_CH;
 	    s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
 	}
@@ -1173,10 +1446,10 @@
 	spin_lock(&s->lock);
 	intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
 	/* acknowledge interrupt */
-	if (intsrc & CM_INT_CH0)
-		mask |= 1;
-	if (intsrc & CM_INT_CH1)
-		mask |= 2;
+	if (intsrc & ADCINT)
+		mask |= ENADCINT;
+	if (intsrc & DACINT)
+		mask |= ENDACINT;
 	outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
 	outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
 	cm_update_ptr(s);
@@ -1237,6 +1510,7 @@
 	[SOUND_MIXER_SYNTH]  = { DSP_MIX_FMVOLIDX_L,  	 DSP_MIX_FMVOLIDX_R,     MT_5MUTE,     0x40, 0x00 },
 	[SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE,     0x00, 0x00 },
 	[SOUND_MIXER_PCM]    = { DSP_MIX_VOICEVOLIDX_L,  DSP_MIX_VOICEVOLIDX_R,  MT_5MUTE,     0x00, 0x00 },
+	[SOUND_MIXER_LINE1]  = { DSP_MIX_AUXVOL_L,       DSP_MIX_AUXVOL_R,       MT_5MUTE,     0x80, 0x20 },
 	[SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX,	 DSP_MIX_SPKRVOLIDX,	 MT_5MUTEMONO, 0x01, 0x01 }
 };
 
@@ -1248,15 +1522,32 @@
 	[SOUND_MIXER_SYNTH]  = 4,
 	[SOUND_MIXER_VOLUME] = 5,
 	[SOUND_MIXER_PCM]    = 6,
-	[SOUND_MIXER_SPEAKER]= 7
+	[SOUND_MIXER_LINE1]  = 7,
+	[SOUND_MIXER_SPEAKER]= 8
 };
 
+static unsigned mixer_outmask(struct cm_state *s)
+{
+	unsigned long flags;
+	int i, j, k;
+
+	spin_lock_irqsave(&s->lock, flags);
+	j = rdmixer(s, DSP_MIX_OUTMIXIDX);
+	spin_unlock_irqrestore(&s->lock, flags);
+	for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+		if (j & mixtable[i].play)
+			k |= 1 << i;
+	return k;
+}
+
 static unsigned mixer_recmask(struct cm_state *s)
 {
+	unsigned long flags;
 	int i, j, k;
 
+	spin_lock_irqsave(&s->lock, flags);
 	j = rdmixer(s, DSP_MIX_ADCMIXIDX_L);
-	j &= 0x7f;
+	spin_unlock_irqrestore(&s->lock, flags);
 	for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 		if (j & mixtable[i].rec)
 			k |= 1 << i;
@@ -1297,7 +1588,7 @@
 			return put_user(mixer_recmask(s), (int *)arg);
 			
                 case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */
-			return put_user(mixer_recmask(s), (int *)arg);//need fix
+			return put_user(mixer_outmask(s), (int *)arg);
 			
                 case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
 			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
@@ -1354,7 +1645,7 @@
 		}
 		spin_lock_irqsave(&s->lock, flags);
 		wrmixer(s, DSP_MIX_ADCMIXIDX_L, j);
-		wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1));
+		wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1) | (j & 0x80));
 		spin_unlock_irqrestore(&s->lock, flags);
 		return 0;
 
@@ -1371,11 +1662,11 @@
 			j |= mixtable[i].play;
 		}
 		spin_lock_irqsave(&s->lock, flags);
-		frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, j);
+		wrmixer(s, DSP_MIX_OUTMIXIDX, j);
 		spin_unlock_irqrestore(&s->lock, flags);
 		return 0;
 
-		default:
+	default:
 		i = _IOC_NR(cmd);
 		if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
 			return -EINVAL;
@@ -1402,15 +1693,28 @@
 			rl = (l < 4 ? 0 : (l - 5) / 3) & 31;
 			rr = (rl >> 2) & 7;
 			wrmixer(s, mixtable[i].left, rl<<3);
-			maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
+			if (i == SOUND_MIXER_MIC)
+				maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
 			break;
 			
 		case MT_5MUTEMONO:
 			r = l;
 			rl = l < 4 ? 0 : (l - 5) / 3;
-			rr = rl >> 2;
  			wrmixer(s, mixtable[i].left, rl<<3);
-			maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
+			l = rdmixer(s, DSP_MIX_OUTMIXIDX) & ~mixtable[i].play;
+			rr = rl ? mixtable[i].play : 0;
+			wrmixer(s, DSP_MIX_OUTMIXIDX, l | rr);
+			/* for recording */
+			if (i == SOUND_MIXER_MIC) {
+				if (s->chip_version >= 39) {
+					rr = rl >> 1;
+					maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr&0x07);
+					frobindir(s, DSP_MIX_EXTENSION, 0x01, rr>>3);
+				} else {
+					rr = rl >> 2;
+					maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
+				}
+			}
 			break;
 				
 		case MT_5MUTE:
@@ -1418,6 +1722,10 @@
 			rr = r < 4 ? 0 : (r - 5) / 3;
  			wrmixer(s, mixtable[i].left, rl<<3);
 			wrmixer(s, mixtable[i].right, rr<<3);
+			l = rdmixer(s, DSP_MIX_OUTMIXIDX);
+			l &= ~mixtable[i].play;
+			r = (rl|rr) ? mixtable[i].play : 0;
+			wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);
 			break;
 
 		case MT_6MUTE:
@@ -1447,12 +1755,16 @@
 static int cm_open_mixdev(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct cm_state *s = devs;
+	struct list_head *list;
+	struct cm_state *s;
 
-	while (s && s->dev_mixer != minor)
-		s = s->next;
-	if (!s)
-		return -ENODEV;
+	for (list = devs.next; ; list = list->next) {
+		if (list == &devs)
+			return -ENODEV;
+		s = list_entry(list, struct cm_state, devs);
+		if (s->dev_mixer == minor)
+			break;
+	}
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	return 0;
@@ -1490,9 +1802,9 @@
 
 	if (s->dma_dac.mapped || !s->dma_dac.ready)
 		return 0;
-        set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
+        	__set_current_state(TASK_INTERRUPTIBLE);
                 spin_lock_irqsave(&s->lock, flags);
 		count = s->dma_dac.count;
                 spin_unlock_irqrestore(&s->lock, flags);
@@ -1522,6 +1834,7 @@
 static ssize_t cm_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct cm_state *s = (struct cm_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned swptr;
@@ -1538,12 +1851,15 @@
 		return -EFAULT;
 	ret = 0;
 
+        add_wait_queue(&s->dma_adc.wait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		swptr = s->dma_adc.swptr;
 		cnt = s->dma_adc.dmasize-swptr;
 		if (s->dma_adc.count < cnt)
 			cnt = s->dma_adc.count;
+		if (cnt <= 0)
+			__set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(&s->lock, flags);
 		if (cnt > count)
 			cnt = count;
@@ -1551,7 +1867,7 @@
 			start_adc(s);
 			if (file->f_flags & O_NONBLOCK)
 				return ret ? ret : -EAGAIN;
-			if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
+			if (!schedule_timeout(HZ)) {
 				printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
 				       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
 				       s->dma_adc.hwptr, s->dma_adc.swptr);
@@ -1579,12 +1895,15 @@
 		start_adc_unlocked(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+        remove_wait_queue(&s->dma_adc.wait, &wait);
+	set_current_state(TASK_RUNNING);
 	return ret;
 }
 
 static ssize_t cm_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct cm_state *s = (struct cm_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned swptr;
@@ -1609,6 +1928,7 @@
 		return -EFAULT;
 	ret = 0;
 
+        add_wait_queue(&s->dma_dac.wait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		if (s->dma_dac.count < 0) {
@@ -1629,6 +1949,8 @@
 			if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
 				cnt = s->dma_dac.dmasize - s->dma_dac.count;
 		}
+		if (cnt <= 0)
+			__set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(&s->lock, flags);
 		if (cnt > count)
 			cnt = count;
@@ -1638,7 +1960,7 @@
 			start_dac(s);
 			if (file->f_flags & O_NONBLOCK)
 				return ret ? ret : -EAGAIN;
-			if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
+			if (!schedule_timeout(HZ)) {
 				printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
 				       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
 				       s->dma_dac.hwptr, s->dma_dac.swptr);
@@ -1704,6 +2026,8 @@
 		}
 		start_dac(s);
 	}
+        remove_wait_queue(&s->dma_dac.wait, &wait);
+	set_current_state(TASK_RUNNING);
 	return ret;
 }
 
@@ -1772,6 +2096,16 @@
 	return ret;
 }
 
+#define SNDCTL_SPDIF_COPYRIGHT	_SIOW('S',  0, int)       // set/reset S/PDIF copy protection
+#define SNDCTL_SPDIF_LOOP	_SIOW('S',  1, int)       // set/reset S/PDIF loop
+#define SNDCTL_SPDIF_MONITOR	_SIOW('S',  2, int)       // set S/PDIF monitor
+#define SNDCTL_SPDIF_LEVEL	_SIOW('S',  3, int)       // set/reset S/PDIF out level
+#define SNDCTL_SPDIF_INV	_SIOW('S',  4, int)       // set/reset S/PDIF in inverse
+#define SNDCTL_SPDIF_SEL2	_SIOW('S',  5, int)       // set S/PDIF in #2
+#define SNDCTL_SPDIF_VALID	_SIOW('S',  6, int)       // set S/PDIF valid
+#define SNDCTL_SPDIFOUT		_SIOW('S',  7, int)       // set S/PDIF out
+#define SNDCTL_SPDIFIN		_SIOW('S',  8, int)       // set S/PDIF out
+
 static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct cm_state *s = (struct cm_state *)file->private_data;
@@ -1955,14 +2289,14 @@
 		val = 0;
 		if (s->status & DO_DUAL_DAC) {
 			if (file->f_mode & FMODE_WRITE &&
-			 (s->enable & CM_ENABLE_CH1) &&
-			 (s->enable & CM_ENABLE_CH0))
+			 (s->enable & ENDAC) &&
+			 (s->enable & ENADC))
 				val |= PCM_ENABLE_OUTPUT;
 			return put_user(val, (int *)arg);
 		}
-		if (file->f_mode & FMODE_READ && s->enable & CM_ENABLE_CH0) 
+		if (file->f_mode & FMODE_READ && s->enable & ENADC) 
 			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && s->enable & CM_ENABLE_CH1) 
+		if (file->f_mode & FMODE_WRITE && s->enable & ENDAC) 
 			val |= PCM_ENABLE_OUTPUT;
 		return put_user(val, (int *)arg);
 
@@ -1994,7 +2328,7 @@
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!(s->enable & CM_ENABLE_CH1) && (val = prog_dmabuf(s, 0)) != 0)
+		if (!(s->enable & ENDAC) && (val = prog_dmabuf(s, 0)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		cm_update_ptr(s);
@@ -2008,7 +2342,7 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!(s->enable & CM_ENABLE_CH0) && (val = prog_dmabuf(s, 1)) != 0)
+		if (!(s->enable & ENADC) && (val = prog_dmabuf(s, 1)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		cm_update_ptr(s);
@@ -2155,6 +2489,11 @@
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(s);
 				s->dma_adc.ready = 0;
+				if (val & DSP_BIND_SPDIF) {
+					set_spdifin(s, s->rateadc);
+					if (!(s->status & DO_SPDIF_OUT))
+						val &= ~DSP_BIND_SPDIF;
+				}
 			}
 			if (file->f_mode & FMODE_WRITE) {
 				stop_dac(s);
@@ -2194,7 +2533,51 @@
 	case SNDCTL_DSP_MAPOUTBUF:
         case SNDCTL_DSP_SETSYNCRO:
                 return -EINVAL;
-		
+	case SNDCTL_SPDIF_COPYRIGHT:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		set_spdif_copyright(s, val);
+                return 0;
+	case SNDCTL_SPDIF_LOOP:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		set_spdif_loop(s, val);
+                return 0;
+	case SNDCTL_SPDIF_MONITOR:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		set_spdif_monitor(s, val);
+                return 0;
+	case SNDCTL_SPDIF_LEVEL:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		set_spdifout_level(s, val);
+                return 0;
+	case SNDCTL_SPDIF_INV:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		set_spdifin_inverse(s, val);
+                return 0;
+	case SNDCTL_SPDIF_SEL2:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		set_spdifin_channel2(s, val);
+                return 0;
+	case SNDCTL_SPDIF_VALID:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		set_spdifin_valid(s, val);
+                return 0;
+	case SNDCTL_SPDIFOUT:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		set_spdifout(s, val ? s->ratedac : 0);
+                return 0;
+	case SNDCTL_SPDIFIN:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		set_spdifin(s, val ? s->rateadc : 0);
+                return 0;
 	}
 	return mixer_ioctl(s, cmd, arg);
 }
@@ -2202,13 +2585,18 @@
 static int cm_open(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct cm_state *s = devs;
+	DECLARE_WAITQUEUE(wait, current);
 	unsigned char fmtm = ~0, fmts = 0;
+	struct list_head *list;
+	struct cm_state *s;
 
-	while (s && ((s->dev_audio ^ minor) & ~0xf))
-		s = s->next;
-	if (!s)
-		return -ENODEV;
+	for (list = devs.next; ; list = list->next) {
+		if (list == &devs)
+			return -ENODEV;
+		s = list_entry(list, struct cm_state, devs);
+		if (!((s->dev_audio ^ minor) & ~0xf))
+			break;
+	}
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
@@ -2218,8 +2606,12 @@
 			up(&s->open_sem);
 			return -EBUSY;
 		}
+		add_wait_queue(&s->open_wait, &wait);
+		__set_current_state(TASK_INTERRUPTIBLE);
 		up(&s->open_sem);
-		interruptible_sleep_on(&s->open_wait);
+		schedule();
+		remove_wait_queue(&s->open_wait, &wait);
+		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
 		down(&s->open_sem);
@@ -2230,6 +2622,8 @@
 			fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
 		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
 		set_adc_rate(s, 8000);
+		// spdif-in is turnned off by default
+		set_spdifin(s, 0);
 	}
 	if (file->f_mode & FMODE_WRITE) {
 		fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
@@ -2321,6 +2715,8 @@
 		cnt = MIDIINBUF - ptr;
 		if (s->midi.icnt < cnt)
 			cnt = s->midi.icnt;
+		if (cnt <= 0)
+			__set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(&s->lock, flags);
 		if (cnt > count)
 			cnt = count;
@@ -2331,7 +2727,6 @@
 					ret = -EAGAIN;
 				break;
 			}
-			__set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 			if (signal_pending(current))
 			{
@@ -2386,8 +2781,10 @@
 		cnt = MIDIOUTBUF - ptr;
 		if (s->midi.ocnt + cnt > MIDIOUTBUF)
 			cnt = MIDIOUTBUF - s->midi.ocnt;
-		if (cnt <= 0)
+		if (cnt <= 0) {
+			__set_current_state(TASK_INTERRUPTIBLE);
 			cm_handle_midi(s);
+		}
 		spin_unlock_irqrestore(&s->lock, flags);
 		if (cnt > count)
 			cnt = count;
@@ -2398,7 +2795,6 @@
 					ret = -EAGAIN;
 				break;
 			}
-			__set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 			if (signal_pending(current)) {
 				if (!ret)
@@ -2457,13 +2853,18 @@
 static int cm_midi_open(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct cm_state *s = devs;
+	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
+	struct list_head *list;
+	struct cm_state *s;
 
-	while (s && s->dev_midi != minor)
-		s = s->next;
-	if (!s)
-		return -ENODEV;
+	for (list = devs.next; ; list = list->next) {
+		if (list == &devs)
+			return -ENODEV;
+		s = list_entry(list, struct cm_state, devs);
+		if (s->dev_midi == minor)
+			break;
+	}
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
@@ -2473,8 +2874,12 @@
 			up(&s->open_sem);
 			return -EBUSY;
 		}
+ 		add_wait_queue(&s->open_wait, &wait);
+ 		__set_current_state(TASK_INTERRUPTIBLE);
 		up(&s->open_sem);
-		interruptible_sleep_on(&s->open_wait);
+ 		schedule();
+ 		remove_wait_queue(&s->open_wait, &wait);
+ 		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
 		down(&s->open_sem);
@@ -2484,7 +2889,7 @@
 		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
 		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
 		/* enable MPU-401 */
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 4);
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, UART_EN);
 		outb(0xff, s->iomidi+1); /* reset command */
 		if (!(inb(s->iomidi+1) & 0x80))
 			inb(s->iomidi);
@@ -2554,7 +2959,7 @@
 		if (!(inb(s->iomidi+1) & 0x80))
 			inb(s->iomidi);
 		/* disable MPU-401 */
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~4, 0);
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~UART_EN, 0);
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
 	up(&s->open_sem);
@@ -2675,12 +3080,17 @@
 static int cm_dmfm_open(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct cm_state *s = devs;
+	DECLARE_WAITQUEUE(wait, current);
+	struct list_head *list;
+	struct cm_state *s;
 
-	while (s && s->dev_dmfm != minor)
-		s = s->next;
-	if (!s)
-		return -ENODEV;
+	for (list = devs.next; ; list = list->next) {
+		if (list == &devs)
+			return -ENODEV;
+		s = list_entry(list, struct cm_state, devs);
+		if (s->dev_dmfm == minor)
+			break;
+	}
        	VALIDATE_STATE(s);
 	file->private_data = s;
 	/* wait for device to become free */
@@ -2690,8 +3100,12 @@
 			up(&s->open_sem);
 			return -EBUSY;
 		}
+		add_wait_queue(&s->open_wait, &wait);
+		__set_current_state(TASK_INTERRUPTIBLE);
 		up(&s->open_sem);
-		interruptible_sleep_on(&s->open_wait);
+		schedule();
+		remove_wait_queue(&s->open_wait, &wait);
+		set_current_state(TASK_RUNNING);
 		if (signal_pending(current))
 			return -ERESTARTSYS;
 		down(&s->open_sem);
@@ -2836,11 +3250,17 @@
 #else
 static	int	use_line_as_bass;
 #endif
+#ifdef CONFIG_SOUND_CMPCI_MIC_BASS
+static	int	use_mic_as_bass = 1;
+#else
+static	int	use_mic_as_bass = 0;
+#endif
 #ifdef CONFIG_SOUND_CMPCI_JOYSTICK
 static	int	joystick = 1;
 #else
 static	int	joystick;
 #endif
+static	int	mic_boost = 0;
 MODULE_PARM(mpuio, "i");
 MODULE_PARM(fmio, "i");
 MODULE_PARM(spdif_inverse, "i");
@@ -2848,7 +3268,9 @@
 MODULE_PARM(speakers, "i");
 MODULE_PARM(use_line_as_rear, "i");
 MODULE_PARM(use_line_as_bass, "i");
+MODULE_PARM(use_mic_as_bass, "i");
 MODULE_PARM(joystick, "i");
+MODULE_PARM(mic_boost, "i");
 MODULE_PARM_DESC(mpuio, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable");
 MODULE_PARM_DESC(fmio, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable");
 MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal");
@@ -2856,24 +3278,15 @@
 MODULE_PARM_DESC(speakers, "(2-6) Number of speakers you connect");
 MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out");
 MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center");
+MODULE_PARM_DESC(use_mic_as_bass, "(1/0) Use mic-in jack as bass/center");
 MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver");
+MODULE_PARM_DESC(mic_boost, "(1/0) Enable microphone boost");
 
-static struct pci_device_id cmpci_pci_tbl[] = {
-	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, 
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- 	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, 
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, 
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ 0 }
-};
-MODULE_DEVICE_TABLE(pci, cmpci_pci_tbl);
-
-void initialize_chip(struct pci_dev *pcidev)
+static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
 {
 	struct cm_state *s;
 	mm_segment_t fs;
-	int i, val;
+	int i, val, ret;
 	unsigned char reg_mask = 0;
 	struct {
 		unsigned short	deviceid;
@@ -2886,277 +3299,276 @@
 		{ PCI_DEVICE_ID_CMEDIA_CM8738B, "CM8738B" },
 	};
 	char	*devicename = "unknown";
-	{
-		if (pci_enable_device(pcidev))
-			return;
-		if (pcidev->irq == 0)
-			return;
-		s = kmalloc(sizeof(*s), GFP_KERNEL);
-		if (!s) {
-			printk(KERN_WARNING "cmpci: out of memory\n");
-			return;
-		}
-		/* search device name */
-		for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) {
-			if (devicetable[i].deviceid == pcidev->device)
-			{
-				devicename = devicetable[i].devicename;
-				break;
-			}
-		}
-		memset(s, 0, sizeof(struct cm_state));
-		init_waitqueue_head(&s->dma_adc.wait);
-		init_waitqueue_head(&s->dma_dac.wait);
-		init_waitqueue_head(&s->open_wait);
-		init_waitqueue_head(&s->midi.iwait);
-		init_waitqueue_head(&s->midi.owait);
-		init_MUTEX(&s->open_sem);
-		spin_lock_init(&s->lock);
-		s->magic = CM_MAGIC;
-		s->iobase = pci_resource_start(pcidev, 0);
-		s->iosynth = fmio;
-		s->iomidi = mpuio;
-		s->status = 0;
-		/* range check */
-		if (speakers < 2)
-			speakers = 2;
-		else if (speakers > 6)
-			speakers = 6;
-		s->speakers = speakers;
-		if (s->iobase == 0)
-			return;
-		s->irq = pcidev->irq;
-
-		if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) {
-			printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
-			goto err_region5;
+	if ((ret = pci_enable_device(pcidev)))
+		return ret;
+	if (pcidev->irq == 0)
+		return -ENODEV;
+	s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (!s) {
+		printk(KERN_WARNING "cmpci: out of memory\n");
+		return -ENOMEM;
+	}
+	/* search device name */
+	for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) {
+		if (devicetable[i].deviceid == pcidev->device)
+		{
+			devicename = devicetable[i].devicename;
+			break;
 		}
+	}
+	memset(s, 0, sizeof(struct cm_state));
+	init_waitqueue_head(&s->dma_adc.wait);
+	init_waitqueue_head(&s->dma_dac.wait);
+	init_waitqueue_head(&s->open_wait);
+	init_waitqueue_head(&s->midi.iwait);
+	init_waitqueue_head(&s->midi.owait);
+	init_MUTEX(&s->open_sem);
+	spin_lock_init(&s->lock);
+	s->magic = CM_MAGIC;
+	s->iobase = pci_resource_start(pcidev, 0);
+#ifdef CONFIG_IA64
+	/* The IA64 quirk handler didn't fix us up */
+	if (s->iobase == 0xff00)
+	{
+		kfree(s);
+		return -ENODEV;
+	}
+#endif
+	s->iosynth = fmio;
+	s->iomidi = mpuio;
+	s->gameport.io = 0x200;
+	s->status = 0;
+	/* range check */
+	if (speakers < 2)
+		speakers = 2;
+	else if (speakers > 6)
+		speakers = 6;
+	s->speakers = speakers;
+	if (s->iobase == 0)
+	{
+		kfree(s);
+		return -ENODEV;
+	}
+	s->irq = pcidev->irq;
+
+	if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) {
+		printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
+		goto err_region5;
+	}
 #ifdef CONFIG_SOUND_CMPCI_MIDI
-		/* disable MPU-401 */
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
-		if (s->iomidi) {
-		    if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) {
-			printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
+	/* disable MPU-401 */
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
+	if (s->iomidi) {
+	    if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) {
+		printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
+		s->iomidi = 0;
+	    } else {
+		/* set IO based at 0x330 */
+		switch (s->iomidi) {
+		    case 0x330:
+			reg_mask = 0;
+			break;
+		    case 0x320:
+			reg_mask = 0x20;
+			break;
+		    case 0x310:
+			reg_mask = 0x40;
+			break;
+		    case 0x300:
+			reg_mask = 0x60;
+			break;
+		    default:
 			s->iomidi = 0;
-		    } else {
-		        /* set IO based at 0x330 */
-		        switch (s->iomidi) {
-		 	    case 0x330:
-				reg_mask = 0;
-				break;
-			    case 0x320:
-				reg_mask = 0x20;
-				break;
-			    case 0x310:
-				reg_mask = 0x40;
-				break;
-			    case 0x300:
-				reg_mask = 0x60;
-				break;
-			    default:
-				s->iomidi = 0;
-				break;
-		        }
-		        outb((inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60) | reg_mask, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
-			/* enable MPU-401 */
-			if (s->iomidi) {
-			    maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
-			}
-		    }
+			break;
 		}
+		outb((inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60) | reg_mask, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
+		/* enable MPU-401 */
+		if (s->iomidi) {
+		    maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
+		}
+	    }
+	}
 #endif
 #ifdef CONFIG_SOUND_CMPCI_FM
-		/* disable FM */
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
-		if (s->iosynth) {
-		    if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) {
-			printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
+	/* disable FM */
+	maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
+	if (s->iosynth) {
+	    if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) {
+		printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
+		s->iosynth = 0;
+	    } else {
+		/* set IO based at 0x388 */
+		switch (s->iosynth) {
+		    case 0x388:
+			reg_mask = 0;
+			break;
+		    case 0x3C8:
+			reg_mask = 0x01;
+			break;
+		    case 0x3E0:
+			reg_mask = 0x02;
+			break;
+		    case 0x3E8:
+			reg_mask = 0x03;
+			break;
+		    default:
 			s->iosynth = 0;
-		    } else {
-		        /* set IO based at 0x388 */
-		        switch (s->iosynth) {
-		 	    case 0x388:
-				reg_mask = 0;
-				break;
-			    case 0x3C8:
-				reg_mask = 0x01;
-				break;
-			    case 0x3E0:
-				reg_mask = 0x02;
-				break;
-			    case 0x3E8:
-				reg_mask = 0x03;
-				break;
-			    default:
-				s->iosynth = 0;
-				break;
-		        }
-		        maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask);
-		        /* enable FM */
-			if (s->iosynth) {
-		            maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8);
-			}
-		    }
+			break;
 		}
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask);
+		/* enable FM */
+		if (s->iosynth) {
+		    maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8);
+		}
+	    }
+	}
 #endif
-		/* enable joystick */
-		if (joystick)
+	/* enable joystick */
+	if (joystick) {
+		if (s->gameport.io && !request_region(s->gameport.io, CM_EXTENT_GAME, "cmpci GAME")) {
+			printk(KERN_ERR "cmpci: gameport io ports in use\n");
+			s->gameport.io = 0;
+	       	} else
 			maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
-		else
-			maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
-		/* initialize codec registers */
-		outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
-		outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
-		/* reset mixer */
-		wrmixer(s, DSP_MIX_DATARESETIDX, 0);
-
-		/* request irq */
-		if (request_irq(s->irq, cm_interrupt, SA_SHIRQ, "cmpci", s)) {
-			printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
-			goto err_irq;
-		}
-		printk(KERN_INFO "cmpci: found %s adapter at io %#06x irq %u\n",
-		       devicename, s->iobase, s->irq);
-		/* register devices */
-		if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0)
-			goto err_dev1;
-		if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0)
-			goto err_dev2;
+	} else {
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
+		s->gameport.io = 0;
+	}
+	/* initialize codec registers */
+	outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
+	outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
+	/* reset mixer */
+	wrmixer(s, DSP_MIX_DATARESETIDX, 0);
+
+	/* request irq */
+	if (request_irq(s->irq, cm_interrupt, SA_SHIRQ, "cmpci", s)) {
+		printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
+		goto err_irq;
+	}
+	printk(KERN_INFO "cmpci: found %s adapter at io %#x irq %u\n",
+	       devicename, s->iobase, s->irq);
+	/* register devices */
+	if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0) {
+		ret = s->dev_audio;
+		goto err_dev1;
+	}
+	if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0) {
+		ret = s->dev_mixer;
+		goto err_dev2;
+	}
 #ifdef CONFIG_SOUND_CMPCI_MIDI
-		if ((s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
-			goto err_dev3;
+	if ((s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0) {
+		ret = s->dev_midi;
+		goto err_dev3;
+	}
 #endif
 #ifdef CONFIG_SOUND_CMPCI_FM
-		if ((s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
-			goto err_dev4;
-#endif
-		pci_set_master(pcidev);	/* enable bus mastering */
-		/* initialize the chips */
-		fs = get_fs();
-		set_fs(KERNEL_DS);
-		/* set mixer output */
-		frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, 0x1f);
-		/* set mixer input */
-		val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD|SOUND_MASK_MIC;
-		mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
-		for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
-			val = initvol[i].vol;
-			mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
-		}
-		/* use channel 0 for record, channel 1 for play */
-		maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 1);
-		s->deviceid = pcidev->device;
-
-		if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738) {
-
-			/* chip version and hw capability check */
-			s->chip_version = query_chip(s);
-			printk(KERN_INFO "cmpci: chip version = 0%d\n", s->chip_version);
-
-			/* seet SPDIF-in inverse before enable SPDIF loop */
-			if (spdif_inverse) {
-				/* turn on spdif-in inverse */
-				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);
-				printk(KERN_INFO "cmpci: Inverse SPDIF-in\n");
-			} else {
-				/* turn off spdif-ininverse */
-				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);
-			}
-
-			/* enable SPDIF loop */
-			if (spdif_loop) {
-				s->status |= DO_SPDIF_LOOP;
-				/* turn on spdif-in to spdif-out */
-				maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x80);
-				printk(KERN_INFO "cmpci: Enable SPDIF loop\n");
-			} else {
-				s->status &= ~DO_SPDIF_LOOP;
-				/* turn off spdif-in to spdif-out */
-				maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x80, 0);
-			}
-			if (use_line_as_rear) {
-				s->capability |= CAN_LINE_AS_REAR;
-				s->status |= DO_LINE_AS_REAR;
-				maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 0x20);
+	if ((s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0) {
+		ret = s->dev_dmfm;
+		goto err_dev4;
+	}
+#endif
+	pci_set_master(pcidev);	/* enable bus mastering */
+	/* initialize the chips */
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	/* set mixer output */
+	frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, 0x1f);
+	/* set mixer input */
+	val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD|SOUND_MASK_MIC;
+	mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+	for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+		val = initvol[i].vol;
+		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+	}
+	/* use channel 1 for record, channel 0 for play */
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, CHADC1);
+	/* turn off VMIC3 - mic boost */
+	if (mic_boost)
+		maskb(s->iobase + CODEC_CMI_MIXER2, ~1, 0);
+	else
+		maskb(s->iobase + CODEC_CMI_MIXER2, ~0, 1);
+	s->deviceid = pcidev->device;
+
+	if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738) {
+
+		/* chip version and hw capability check */
+		s->chip_version = query_chip(s);
+		printk(KERN_INFO "cmpci: chip version = 0%d\n", s->chip_version);
+
+		/* seet SPDIF-in inverse before enable SPDIF loop */
+		set_spdifin_inverse(s, spdif_inverse);
+
+		/* enable SPDIF loop */
+		set_spdif_loop(s, spdif_loop);
+
+		/* use SPDIF in #1 */
+		set_spdifin_channel2(s, 0);
+
+		if (use_line_as_rear) {
+			s->capability |= CAN_LINE_AS_REAR;
+			s->status |= DO_LINE_AS_REAR;
+			maskb(s->iobase + CODEC_CMI_MIXER1, ~0, SPK4);
+		} else
+			maskb(s->iobase + CODEC_CMI_MIXER1, ~SPK4, 0);
+		if (s->chip_version >= 39) {
+			if (use_line_as_bass) {
+				s->capability |= CAN_LINE_AS_BASS;
+				s->status |= DO_LINE_AS_BASS;
+				maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, CB2LIN);
 			} else
-				maskb(s->iobase + CODEC_CMI_MIXER1, ~0x20, 0);
-			if (s->chip_version >= 39) {
-				if (use_line_as_bass) {
-					s->capability |= CAN_LINE_AS_BASS;
-					s->status |= DO_LINE_AS_BASS;
-					maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, 0x60);
-				} else
-					maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x60, 0);
-			}
-		} else {
-			/* 8338 will fall here */
-			s->max_channels = 2;
+				maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CB2LIN, 0);
+			if (use_mic_as_bass) {
+				s->capability |= CAN_MIC_AS_BASS;
+				s->status |= DO_MIC_AS_BASS;
+				maskb(s->iobase + CODEC_CMI_MISC, ~0, 0x04);
+			} else
+				maskb(s->iobase + CODEC_CMI_MISC, ~0x04, 0);
 		}
-		/* queue it for later freeing */
-		s->next = devs;
-		devs = s;
-		return;
+	} else {
+		s->chip_version = 0;
+		/* 8338 will fall here */
+		s->max_channels = 2;
+	}
+	/* register gameport */
+	if (joystick)
+		gameport_register_port(&s->gameport);
+	/* store it in the driver field */
+	pci_set_drvdata(pcidev, s);
+	/* put it into driver list */
+	list_add_tail(&s->devs, &devs);
+	/* increment devindex */
+	if (devindex < NR_DEVICE-1)
+		devindex++;
+	return 0;
 
 #ifdef CONFIG_SOUND_CMPCI_FM
-		unregister_sound_special(s->dev_dmfm);
-	err_dev4:
+	unregister_sound_special(s->dev_dmfm);
+err_dev4:
 #endif
 #ifdef CONFIG_SOUND_CMPCI_MIDI
-		unregister_sound_midi(s->dev_midi);
-	err_dev3:
+	unregister_sound_midi(s->dev_midi);
+err_dev3:
 #endif
-		unregister_sound_mixer(s->dev_mixer);
-	err_dev2:
-		unregister_sound_dsp(s->dev_audio);
-	err_dev1:
-		printk(KERN_ERR "cmpci: cannot register misc device\n");
-		free_irq(s->irq, s);
-	err_irq:
+	unregister_sound_mixer(s->dev_mixer);
+err_dev2:
+	unregister_sound_dsp(s->dev_audio);
+err_dev1:
+	printk(KERN_ERR "cmpci: cannot register misc device\n");
+	free_irq(s->irq, s);
+err_irq:
+	if (s->gameport.io)
+		release_region(s->gameport.io, CM_EXTENT_GAME);
 #ifdef CONFIG_SOUND_CMPCI_FM
-		if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
+	if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
 #endif
 #ifdef CONFIG_SOUND_CMPCI_MIDI
-		if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
+	if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
 #endif
-		release_region(s->iobase, CM_EXTENT_CODEC);
-	err_region5:
-		kfree(s);
-	}
-	if (!devs) {
-		if (wavetable_mem)
-			free_pages(wavetable_mem, 20-PAGE_SHIFT);
-		return;
-	}
-	return;
-}
-
-static int __init init_cmpci(void)
-{
-	struct pci_dev *pcidev = NULL;
-	int index = 0;
-
-#ifdef CONFIG_PCI
-	if (!pci_present())   /* No PCI bus in this machine! */
-#endif
-		return -ENODEV;
-	printk(KERN_INFO "cmpci: version $Revision: 5.64 $ time " __TIME__ " " __DATE__ "\n");
-
-	while (index < NR_DEVICE && (
-	       (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, pcidev)))) { 
-		initialize_chip(pcidev);
-		index++;
-	}
-	while (index < NR_DEVICE && (
- 	       (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)))) {
-		initialize_chip(pcidev);
-		index++;
-	}
-	while (index < NR_DEVICE && (
-	       (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, pcidev)))) {
-		initialize_chip(pcidev);
-		index++;
-	}
-	return 0;
+	release_region(s->iobase, CM_EXTENT_CODEC);
+err_region5:
+	kfree(s);
+	return ret;
 }
 
 /* --------------------------------------------------------------------- */
@@ -3165,42 +3577,74 @@
 MODULE_DESCRIPTION("CM8x38 Audio Driver");
 MODULE_LICENSE("GPL");
 
-
-static void __exit cleanup_cmpci(void)
+static void __devinit cm_remove(struct pci_dev *dev)
 {
-	struct cm_state *s;
-
-	while ((s = devs)) {
-		devs = devs->next;
-		outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
-		synchronize_irq();
-		outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
-		free_irq(s->irq, s);
+	struct cm_state *s = pci_get_drvdata(dev);
 
-		/* reset mixer */
-		wrmixer(s, DSP_MIX_DATARESETIDX, 0);
-
-		release_region(s->iobase, CM_EXTENT_CODEC);
+	if (!s)
+		return;
+	list_del(&s->devs);
+	outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
+	synchronize_irq();
+	outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
+	free_irq(s->irq, s);
+
+	/* reset mixer */
+	wrmixer(s, DSP_MIX_DATARESETIDX, 0);
+
+	if (s->gameport.io) {
+		gameport_unregister_port(&s->gameport);
+		release_region(s->gameport.io, CM_EXTENT_GAME);
+	}
+	release_region(s->iobase, CM_EXTENT_CODEC);
 #ifdef CONFIG_SOUND_CMPCI_MIDI
-		if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
+	if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
 #endif
 #ifdef CONFIG_SOUND_CMPCI_FM
-		if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
+	if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
 #endif
-		unregister_sound_dsp(s->dev_audio);
-		unregister_sound_mixer(s->dev_mixer);
+	unregister_sound_dsp(s->dev_audio);
+	unregister_sound_mixer(s->dev_mixer);
 #ifdef CONFIG_SOUND_CMPCI_MIDI
-		unregister_sound_midi(s->dev_midi);
+	unregister_sound_midi(s->dev_midi);
 #endif
 #ifdef CONFIG_SOUND_CMPCI_FM
-		unregister_sound_special(s->dev_dmfm);
+	unregister_sound_special(s->dev_dmfm);
 #endif
-		kfree(s);
-	}
-	if (wavetable_mem)
-		free_pages(wavetable_mem, 20-PAGE_SHIFT);
+	kfree(s);
+	pci_set_drvdata(dev, NULL);
+}
+
+static struct pci_device_id id_table[] __devinitdata = {
+	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+ 	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, id_table);
+
+static struct pci_driver cm_driver = {
+       name: "cmpci",
+       id_table: id_table,
+       probe: cm_probe,
+       remove: cm_remove
+};
+ 
+static int __init init_cmpci(void)
+{
+	if (!pci_present())   /* No PCI bus in this machine! */
+		return -ENODEV;
+	printk(KERN_INFO "cmpci: version $Revision: 6.16 $ time " __TIME__ " " __DATE__ "\n");
+	return pci_module_init(&cm_driver);
+}
+
+static void __exit cleanup_cmpci(void)
+{
 	printk(KERN_INFO "cmpci: unloading\n");
+	pci_unregister_driver(&cm_driver);
 }
 
 module_init(init_cmpci);
 module_exit(cleanup_cmpci);
+
diff -Nru a/drivers/sound/dmasound/dmasound_core.c b/drivers/sound/dmasound/dmasound_core.c
--- a/drivers/sound/dmasound/dmasound_core.c	Sun Dec 15 22:22:18 2002
+++ b/drivers/sound/dmasound/dmasound_core.c	Wed Aug 27 11:46:28 2003
@@ -374,7 +374,7 @@
 	release:	mixer_release,
 };
 
-static void __init mixer_init(void)
+static void mixer_init(void)
 {
 #ifndef MODULE
 	int mixer_unit;
@@ -1211,6 +1211,8 @@
 			shared_resources_initialised = 0 ;
 		return result ;
 		break ;
+	case SOUND_PCM_READ_RATE:
+		return IOCTL_OUT(arg, dmasound.soft.speed);
 	case SNDCTL_DSP_SPEED:
 		/* Changing this on the fly will have weird effects on the sound.
 		   Where there are rate conversions implemented in soft form - it
@@ -1337,7 +1339,7 @@
 #endif
 };
 
-static int __init sq_init(void)
+static int sq_init(void)
 {
 #ifndef MODULE
 	int sq_unit;
@@ -1554,7 +1556,7 @@
 	release:	state_release,
 };
 
-static int __init state_init(void)
+static int state_init(void)
 {
 #ifndef MODULE
 	int state_unit;
@@ -1573,7 +1575,7 @@
      *  This function is called by _one_ chipset-specific driver
      */
 
-int __init dmasound_init(void)
+int dmasound_init(void)
 {
 	int res ;
 #ifdef MODULE
@@ -1644,7 +1646,7 @@
 
 #else /* !MODULE */
 
-static int __init dmasound_setup(char *str)
+static int dmasound_setup(char *str)
 {
 	int ints[6], size;
 
@@ -1660,13 +1662,13 @@
 #ifdef HAS_RECORD
         case 5:
                 if ((ints[5] < 0) || (ints[5] > MAX_CATCH_RADIUS))
-                        printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+                        printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
                 else
                         catchRadius = ints[5];
                 /* fall through */
         case 4:
                 if (ints[4] < MIN_BUFFERS)
-                        printk("dmasound_setup: illegal number of read buffers, using default = %d\n",
+                        printk("dmasound_setup: invalid number of read buffers, using default = %d\n",
                                  numReadBufs);
                 else
                         numReadBufs = ints[4];
@@ -1675,21 +1677,21 @@
 		if ((size = ints[3]) < 256)  /* check for small buffer specs */
 			size <<= 10 ;
                 if (size < MIN_BUFSIZE || size > MAX_BUFSIZE)
-                        printk("dmasound_setup: illegal read buffer size, using default = %d\n", readBufSize);
+                        printk("dmasound_setup: invalid read buffer size, using default = %d\n", readBufSize);
                 else
                         readBufSize = size;
                 /* fall through */
 #else
 	case 3:
 		if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
-			printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+			printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
 		else
 			catchRadius = ints[3];
 		/* fall through */
 #endif
 	case 2:
 		if (ints[1] < MIN_BUFFERS)
-			printk("dmasound_setup: illegal number of buffers, using default = %d\n", numWriteBufs);
+			printk("dmasound_setup: invalid number of buffers, using default = %d\n", numWriteBufs);
 		else
 			numWriteBufs = ints[1];
 		/* fall through */
@@ -1697,13 +1699,13 @@
 		if ((size = ints[2]) < 256) /* check for small buffer specs */
 			size <<= 10 ;
                 if (size < MIN_BUFSIZE || size > MAX_BUFSIZE)
-                        printk("dmasound_setup: illegal write buffer size, using default = %d\n", writeBufSize);
+                        printk("dmasound_setup: invalid write buffer size, using default = %d\n", writeBufSize);
                 else
                         writeBufSize = size;
 	case 0:
 		break;
 	default:
-		printk("dmasound_setup: illegal number of arguments\n");
+		printk("dmasound_setup: invalid number of arguments\n");
 		return 0;
 	}
 	return 1;
diff -Nru a/drivers/sound/i810_audio.c b/drivers/sound/i810_audio.c
--- a/drivers/sound/i810_audio.c	Fri Aug  8 12:30:44 2003
+++ b/drivers/sound/i810_audio.c	Sat Aug  9 08:07:52 2003
@@ -3266,6 +3266,8 @@
 	free_irq(card->irq, devs);
 	release_region(card->iobase, 64);
 	release_region(card->ac97base, 256);
+	pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
+			    card->channel, card->chandma);
 	if (card->use_mmio) {
 		iounmap(card->ac97base_mmio);
 		iounmap(card->iobase_mmio);
diff -Nru a/drivers/usb/acm.c b/drivers/usb/acm.c
--- a/drivers/usb/acm.c	Thu Mar 20 10:22:12 2003
+++ b/drivers/usb/acm.c	Fri Aug  1 01:18:57 2003
@@ -512,7 +512,7 @@
 	struct usb_config_descriptor *cfacm;
 	struct usb_interface_descriptor *ifcom, *ifdata;
 	struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
-	int readsize, ctrlsize, minor, i;
+	int readsize, ctrlsize, minor, i, j;
 	unsigned char *buf;
 
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
@@ -521,93 +521,98 @@
 
 		dbg("probing config %d", cfacm->bConfigurationValue);
 
-		if (cfacm->bNumInterfaces != 2 ||
-		    usb_interface_claimed(cfacm->interface + 0) ||
-		    usb_interface_claimed(cfacm->interface + 1))
-			continue;
-
-		ifcom = cfacm->interface[0].altsetting + 0;
-		ifdata = cfacm->interface[1].altsetting + 0;
-
-		if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
-			ifcom = cfacm->interface[1].altsetting + 0;
-			ifdata = cfacm->interface[0].altsetting + 0;
-			if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
-				continue;
-		}
-
-		if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
-		    ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints < 1)
-			continue;
-
-		epctrl = ifcom->endpoint + 0;
-		epread = ifdata->endpoint + 0;
-		epwrite = ifdata->endpoint + 1;
-
-		if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
-		   (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
-		   ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
-			continue;
-
-		if ((epread->bEndpointAddress & 0x80) != 0x80) {
-			epread = ifdata->endpoint + 1;
-			epwrite = ifdata->endpoint + 0;
-		}
+		for (j = 0; j < cfacm->bNumInterfaces - 1; j++) {
 
-		usb_set_configuration(dev, cfacm->bConfigurationValue);
-
-		for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
-		if (acm_table[minor]) {
-			err("no more free acm devices");
-			return NULL;
-		}
-
-		if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
-			err("out of memory");
-			return NULL;
-		}
-		memset(acm, 0, sizeof(struct acm));
-
-		ctrlsize = epctrl->wMaxPacketSize;
-		readsize = epread->wMaxPacketSize;
-		acm->writesize = epwrite->wMaxPacketSize;
-		acm->iface = cfacm->interface;
-		acm->minor = minor;
-		acm->dev = dev;
-
-		acm->tqueue.routine = acm_softint;
-		acm->tqueue.data = acm;
-
-		if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
-			err("out of memory");
-			kfree(acm);
-			return NULL;
-		}
-
-		FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
-			buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+			if (usb_interface_claimed(cfacm->interface + j) ||
+			    usb_interface_claimed(cfacm->interface + j + 1))
+				continue;
 
-		FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
-			buf += ctrlsize, readsize, acm_read_bulk, acm);
-		acm->readurb.transfer_flags |= USB_NO_FSBR;
+			ifcom = cfacm->interface[j].altsetting + 0;
+			ifdata = cfacm->interface[j + 1].altsetting + 0;
 
-		FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
-			buf += readsize, acm->writesize, acm_write_bulk, acm);
-		acm->writeurb.transfer_flags |= USB_NO_FSBR;
+			if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
+				ifcom = cfacm->interface[j + 1].altsetting + 0;
+				ifdata = cfacm->interface[j].altsetting + 0;
+				if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
+					continue;
+			}
+
+			if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
+			    ifcom->bInterfaceProtocol < 1 || ifcom->bInterfaceProtocol > 6 ||
+			    ifcom->bNumEndpoints < 1)
+				continue;
 
-		printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+			epctrl = ifcom->endpoint + 0;
+			epread = ifdata->endpoint + 0;
+			epwrite = ifdata->endpoint + 1;
+
+			if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
+			    (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
+			    ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
+				continue;
 
-		acm_set_control(acm, acm->ctrlout);
+			dbg("using interface %d\n", j);
 
-		acm->line.speed = cpu_to_le32(9600);
-		acm->line.databits = 8;
-		acm_set_line(acm, &acm->line);
+			if ((epread->bEndpointAddress & 0x80) != 0x80) {
+				epread = ifdata->endpoint + 1;
+				epwrite = ifdata->endpoint + 0;
+			}
+
+			usb_set_configuration(dev, cfacm->bConfigurationValue);
+
+			for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
+			if (acm_table[minor]) {
+				err("no more free acm devices");
+				return NULL;
+			}
+
+			if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
+				err("out of memory");
+				return NULL;
+			}
+			memset(acm, 0, sizeof(struct acm));
+
+			ctrlsize = epctrl->wMaxPacketSize;
+			readsize = epread->wMaxPacketSize;
+			acm->writesize = epwrite->wMaxPacketSize;
+			acm->iface = cfacm->interface + j;
+			acm->minor = minor;
+			acm->dev = dev;
+
+			acm->tqueue.routine = acm_softint;
+			acm->tqueue.data = acm;
+
+			if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
+				err("out of memory");
+				kfree(acm);
+				return NULL;
+			}
+
+			FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
+				     buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+
+			FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+				      buf += ctrlsize, readsize, acm_read_bulk, acm);
+			acm->readurb.transfer_flags |= USB_NO_FSBR;
+
+			FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+				      buf += readsize, acm->writesize, acm_write_bulk, acm);
+			acm->writeurb.transfer_flags |= USB_NO_FSBR;
+
+			printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+
+			acm_set_control(acm, acm->ctrlout);
+
+			acm->line.speed = cpu_to_le32(9600);
+			acm->line.databits = 8;
+			acm_set_line(acm, &acm->line);
 
-		usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
-		usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+			usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
+			usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
 
-		tty_register_devfs(&acm_tty_driver, 0, minor);
-		return acm_table[minor] = acm;
+			tty_register_devfs(&acm_tty_driver, 0, minor);
+			return acm_table[minor] = acm;
+		}
 	}
 
 	return NULL;
diff -Nru a/drivers/usb/audio.c b/drivers/usb/audio.c
--- a/drivers/usb/audio.c	Mon Dec 30 09:34:32 2002
+++ b/drivers/usb/audio.c	Thu Jul 31 06:45:45 2003
@@ -105,6 +105,8 @@
  *              functionality. Tested and used in production with the emagic emi 2|6 
  *              on PPC and Intel. Also fixed a few logic 'crash and burn' corner 
  *              cases.
+ * 2003-06-30:  Thomas Sailer
+ *              Fix SETTRIGGER non OSS API conformity
  */
 
 /*
@@ -279,23 +281,24 @@
 	unsigned int srate;
 	/* physical buffer */
 	unsigned char *sgbuf[NRSGBUF];
-	unsigned bufsize;
-	unsigned numfrag;
-	unsigned fragshift;
-	unsigned wrptr, rdptr;
-	unsigned total_bytes;
+	unsigned int bufsize;
+	unsigned int numfrag;
+	unsigned int fragshift;
+	unsigned int wrptr, rdptr;
+	unsigned int total_bytes;
 	int count;
-	unsigned error; /* over/underrun */
+	unsigned int error; /* over/underrun */
 	wait_queue_head_t wait;
 	/* redundant, but makes calculations easier */
-	unsigned fragsize;
-	unsigned dmasize;
+	unsigned int fragsize;
+	unsigned int dmasize;
 	/* OSS stuff */
-	unsigned mapped:1;
-	unsigned ready:1;
-	unsigned ossfragshift;
+	unsigned int mapped:1;
+	unsigned int ready:1;
+	unsigned int enabled:1;
+	unsigned int ossfragshift;
 	int ossmaxfrags;
-	unsigned subdivision;
+	unsigned int subdivision;
 };
 
 struct usb_audio_state;
@@ -562,6 +565,7 @@
 			break;
 	}
 	db->bufsize = nr << PAGE_SHIFT;
+	db->enabled = 1;
 	db->ready = 1;
 	dprintk((KERN_DEBUG "usbaudio: dmabuf_init bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
 	         "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x srate %d\n",
@@ -2299,7 +2303,7 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (usbin_start(as)) {
+			if (as->usbin.dma.enabled && usbin_start(as)) {
 				if (!ret)
 					ret = -ENODEV;
 				break;
@@ -2332,6 +2336,11 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		if (as->usbin.dma.enabled && usbin_start(as)) {
+			if (!ret)
+				ret = -ENODEV;
+			break;
+		}
 	}
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&as->usbin.dma.wait, &wait);
@@ -2378,7 +2387,7 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (usbout_start(as)) {
+			if (as->usbout.dma.enabled && usbout_start(as)) {
 				if (!ret)
 					ret = -ENODEV;
 				break;
@@ -2411,7 +2420,7 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		if (as->usbout.dma.count >= start_thr && usbout_start(as)) {
+		if (as->usbout.dma.enabled && as->usbout.dma.count >= start_thr && usbout_start(as)) {
 			if (!ret)
 				ret = -ENODEV;
 			break;
@@ -2616,19 +2625,25 @@
 			if (val & PCM_ENABLE_INPUT) {
 				if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
 					return ret;
+				as->usbin.dma.enabled = 1;
 				if (usbin_start(as))
 					return -ENODEV;
-			} else
+			} else {
+				as->usbin.dma.enabled = 0;
 				usbin_stop(as);
+			}
 		}
 		if (file->f_mode & FMODE_WRITE) {
 			if (val & PCM_ENABLE_OUTPUT) {
 				if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
 					return ret;
+				as->usbout.dma.enabled = 1;
 				if (usbout_start(as))
 					return -ENODEV;
-			} else
+			} else {
+				as->usbout.dma.enabled = 0;
 				usbout_stop(as);
+			}
 		}
 		return 0;
 
@@ -2827,10 +2842,14 @@
 		if (signal_pending(current))
 			return -ERESTARTSYS;
 	}
-	if (file->f_mode & FMODE_READ)
+	if (file->f_mode & FMODE_READ) {
 		as->usbin.dma.ossfragshift = as->usbin.dma.ossmaxfrags = as->usbin.dma.subdivision = 0;
-	if (file->f_mode & FMODE_WRITE)
+		as->usbin.dma.enabled = 1;
+	}
+	if (file->f_mode & FMODE_WRITE) {
 		as->usbout.dma.ossfragshift = as->usbout.dma.ossmaxfrags = as->usbout.dma.subdivision = 0;
+		as->usbout.dma.enabled = 1;
+	}
 	if (set_format(as, file->f_mode, ((minor & 0xf) == SND_DEV_DSP16) ? AFMT_S16_LE : AFMT_U8 /* AFMT_ULAW */, 8000)) {
 		up(&open_sem);
 		return -EIO;
diff -Nru a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c
--- a/drivers/usb/bluetooth.c	Thu Aug 29 10:40:53 2002
+++ b/drivers/usb/bluetooth.c	Thu Aug 28 04:13:49 2003
@@ -1,8 +1,8 @@
 /*
  * bluetooth.c   Version 0.12
  *
- * Copyright (c) 2000, 2001 Greg Kroah-Hartman	<greg@kroah.com>
- * Copyright (c) 2000 Mark Douglas Corner	<mcorner@umich.edu>
+ * Copyright (C) 2000, 2001 Greg Kroah-Hartman	<greg@kroah.com>
+ * Copyright (C) 2000 Mark Douglas Corner	<mcorner@umich.edu>
  *
  * USB Bluetooth TTY driver, based on the Bluetooth Spec version 1.0B
  * 
diff -Nru a/drivers/usb/devio.c b/drivers/usb/devio.c
--- a/drivers/usb/devio.c	Thu Dec  5 06:04:11 2002
+++ b/drivers/usb/devio.c	Mon Aug 19 09:49:38 2002
@@ -1078,6 +1078,8 @@
 	int			size;
 	void			*buf = 0;
 	int			retval = 0;
+       struct usb_interface    *ifp = 0;
+       struct usb_driver       *driver = 0;
 
 	/* get input parameters and alloc buffer */
 	if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl)))
@@ -1095,32 +1097,41 @@
 		}
 	}
 
-	/* ioctl to device */
-	if (ctrl.ifno < 0) {
-		switch (ctrl.ioctl_code) {
-		/* access/release token for issuing control messages
-		 * ask a particular driver to bind/unbind, ... etc
-		 */
-		}
-		retval = -ENOSYS;
+       if (!ps->dev)
+               retval = -ENODEV;
+       else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+               retval = -EINVAL;
+       else switch (ctrl.ioctl_code) {
+
+       /* disconnect kernel driver from interface, leaving it unbound.  */
+       case USBDEVFS_DISCONNECT:
+               driver = ifp->driver;
+               if (driver) {
+                       down (&driver->serialize);
+                       dbg ("disconnect '%s' from dev %d interface %d",
+                               driver->name, ps->dev->devnum, ctrl.ifno);
+                       driver->disconnect (ps->dev, ifp->private_data);
+                       usb_driver_release_interface (driver, ifp);
+                       up (&driver->serialize);
+               } else
+                       return -ENODATA;
+               break;
 
-	/* ioctl to the driver which has claimed a given interface */
-	} else {
-		struct usb_interface	*ifp = 0;
-		if (!ps->dev)
-			retval = -ENODEV;
-		else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces)
-			retval = -EINVAL;
+       /* let kernel drivers try to (re)bind to the interface */
+       case USBDEVFS_CONNECT:
+               usb_find_interface_driver_for_ifnum (ps->dev, ctrl.ifno);
+               break;
+
+       /* talk directly to the interface's driver */
+       default:
+               driver = ifp->driver;
+               if (driver == 0 || driver->ioctl == 0)
+                       retval = -ENOSYS;
 		else {
-			if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
-				retval = -EINVAL;
-			else if (ifp->driver == 0 || ifp->driver->ioctl == 0)
-				retval = -ENOSYS;
-		}
-		if (retval == 0)
 			/* ifno might usefully be passed ... */
-			retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
+                       retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
 			/* size = min_t(int, size, retval)? */
+               }
 	}
 
 	/* cleanup and return */
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Thu Jun 19 06:54:16 2003
+++ b/drivers/usb/host/ehci-hcd.c	Thu Jul 17 04:39:00 2003
@@ -333,7 +333,8 @@
 	spin_lock_init (&ehci->lock);
 
 	ehci->caps = (struct ehci_caps *) hcd->regs;
-	ehci->regs = (struct ehci_regs *) (hcd->regs + ehci->caps->length);
+	ehci->regs = (struct ehci_regs *) (hcd->regs +
+				readb (&ehci->caps->length));
 	dbg_hcs_params (ehci, "ehci_start");
 	dbg_hcc_params (ehci, "ehci_start");
 
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Thu Jun 19 06:51:52 2003
+++ b/drivers/usb/host/ehci-q.c	Wed Aug 13 02:58:53 2003
@@ -832,6 +832,10 @@
 					qh->hw_info1 = cpu_to_le32 (info);
 				}
 			}
+
+                        /* usb_reset_device() briefly reverts to address 0 */
+                        if (usb_pipedevice (urb->pipe) == 0)
+                                qh->hw_info1 &= cpu_to_le32(~0x7f);
 		}
 
 		/* NOTE:  changing config or interface setting is not
diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c	Wed Mar  5 14:30:19 2003
+++ b/drivers/usb/host/ehci-sched.c	Wed Jul 30 03:05:59 2003
@@ -397,7 +397,7 @@
 				if (status == 0)
 					break;
 			}
-		} while (status && --frame);
+		} while (status && frame--);
 		if (status)
 			goto done;
 		qh->start = frame;
diff -Nru a/drivers/usb/pwc-ctrl.c b/drivers/usb/pwc-ctrl.c
--- a/drivers/usb/pwc-ctrl.c	Sun Dec 15 16:02:02 2002
+++ b/drivers/usb/pwc-ctrl.c	Sat Jul 26 18:49:10 2003
@@ -1,7 +1,7 @@
 /* Driver for Philips webcam
    Functions that send various control messages to the webcam, including
    video modes.
-   (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
+   (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
@@ -452,7 +452,7 @@
 	pdev->view.x = width;
 	pdev->view.y = height;
 	pwc_set_image_buffer_size(pdev);
-	Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d, palette = %d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y, pdev->vpalette);
+	Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
 	return 0;
 }
 
@@ -461,38 +461,9 @@
 {
 	int factor, i, filler = 0;
 
-	switch(pdev->vpalette) {
-	case VIDEO_PALETTE_RGB32 | 0x80:
-	case VIDEO_PALETTE_RGB32:
-		factor = 16;
-		filler = 0;
-		break;
-	case VIDEO_PALETTE_RGB24 | 0x80:
-	case VIDEO_PALETTE_RGB24:
-		factor = 12;
-		filler = 0;
-		break;
-	case VIDEO_PALETTE_YUYV:
-	case VIDEO_PALETTE_YUV422:
-		factor = 8;
-		filler = 128;
-		break;
-	case VIDEO_PALETTE_YUV420:
-	case VIDEO_PALETTE_YUV420P:
-		factor = 6;
-		filler = 128;
-		break;
-#if PWC_DEBUG		
-	case VIDEO_PALETTE_RAW:
-		pdev->image.size = pdev->frame_size;
-		pdev->view.size = pdev->frame_size;
-		return;
-		break;
-#endif	
-	default:
-		factor = 0;
-		break;
-	}
+	/* for PALETTE_YUV420P */
+	factor = 6;
+	filler = 128;
 
 	/* Set sizes in bytes */
 	pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
@@ -1358,7 +1329,7 @@
 	{
 		struct pwc_probe probe;
 		
-		strcpy(probe.name, pdev->vdev->name);
+		strcpy(probe.name, pdev->vdev.name);
 		probe.type = pdev->type;
 		if (copy_to_user(arg, &probe, sizeof(probe)))
 			ret = -EFAULT;
diff -Nru a/drivers/usb/pwc-if.c b/drivers/usb/pwc-if.c
--- a/drivers/usb/pwc-if.c	Mon Dec 16 11:24:30 2002
+++ b/drivers/usb/pwc-if.c	Sat Jul 26 18:47:26 2003
@@ -1,6 +1,6 @@
-/* Linux driver for Philips webcam 
+/* Linux driver for Philips webcam
    USB and Video4Linux interface part.
-   (C) 1999-2002 Nemosoft Unv.
+   (C) 1999-2003 Nemosoft Unv.
 
    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
@@ -75,14 +75,21 @@
 	{ USB_DEVICE(0x0471, 0x0310) },
 	{ USB_DEVICE(0x0471, 0x0311) },
 	{ USB_DEVICE(0x0471, 0x0312) },
+	{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
 	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
-	{ USB_DEVICE(0x046D, 0x08b0) }, /* Logitech QuickCam Pro 3000 */
-	{ USB_DEVICE(0x046D, 0x08b1) }, /* Logitech QuickCam Notebook Pro */
-	{ USB_DEVICE(0x046d, 0x08b2) }, /* Logitech QuickCam Pro 4000 */
-	{ USB_DEVICE(0x046d, 0x08b3) }, /* Logitech QuickCam Zoom */
+	{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
+	{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
+	{ USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
+	{ USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom */
+	{ USB_DEVICE(0x046D, 0x08B4) }, /* Logitech (reserved) */
+	{ USB_DEVICE(0x046D, 0x08B5) }, /* Logitech (reserved) */
+	{ USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
+	{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
+	{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
 	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
 	{ USB_DEVICE(0x055D, 0x9001) },
 	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
+	{ USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
 	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
 	{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
 	{ USB_DEVICE(0x0d81, 0x1900) },
@@ -101,11 +108,11 @@
 	disconnect:		usb_pwc_disconnect,	/* disconnect() */
 };
 
-#define MAX_DEV_HINTS 10
+#define MAX_DEV_HINTS	20
+#define MAX_ISOC_ERRORS	20
 
 static int default_size = PSZ_QCIF;
 static int default_fps = 10;
-static int default_palette = VIDEO_PALETTE_YUV420P; /* This format is understood by most tools */
 static int default_fbufs = 3;   /* Default number of frame buffers */
 static int default_mbufs = 2;	/* Default number of mmap() buffers */
        int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
@@ -119,9 +126,6 @@
 	struct pwc_device *pdev;
 } device_hint[MAX_DEV_HINTS];
 
-static struct semaphore mem_lock;
-static void *mem_leak = NULL; /* For delayed kfree()s. See below */
-
 /***/
 
 static int  pwc_video_open(struct video_device *vdev, int mode);
@@ -383,50 +387,50 @@
    the user program. The first scheme involves the ISO buffers (called thus
    since they transport ISO data from the USB controller), and not really
    interesting. Suffices to say the data from this buffer is quickly 
-   gathered in an interrupt handler (pwc_isoc_handler) and placed into the 
+   gathered in an interrupt handler (pwc_isoc_handler) and placed into the
    frame buffer.
-   
+
    The frame buffer is the second scheme, and is the central element here.
    It collects the data from a single frame from the camera (hence, the
    name). Frames are delimited by the USB camera with a short USB packet,
    so that's easy to detect. The frame buffers form a list that is filled
-   by the camera+USB controller and drained by the user process through 
+   by the camera+USB controller and drained by the user process through
    either read() or mmap().
-   
+
    The image buffer is the third scheme, in which frames are decompressed
-   and possibly converted into planar format. For mmap() there is more than
+   and converted into planar format. For mmap() there is more than
    one image buffer available.
 
-   The frame buffers provide the image buffering, in case the user process
-   is a bit slow. This introduces lag and some undesired side-effects.
-   The problem arises when the frame buffer is full. I used to drop the last 
-   frame, which makes the data in the queue stale very quickly. But dropping 
+   The frame buffers provide the image buffering. In case the user process
+   is a bit slow, this introduces lag and some undesired side-effects.
+   The problem arises when the frame buffer is full. I used to drop the last
+   frame, which makes the data in the queue stale very quickly. But dropping
    the frame at the head of the queue proved to be a litte bit more difficult.
    I tried a circular linked scheme, but this introduced more problems than
    it solved.
 
    Because filling and draining are completely asynchronous processes, this
    requires some fiddling with pointers and mutexes.
-   
+
    Eventually, I came up with a system with 2 lists: an 'empty' frame list
    and a 'full' frame list:
      * Initially, all frame buffers but one are on the 'empty' list; the one
        remaining buffer is our initial fill frame.
-     * If a frame is needed for filling, we take it from the 'empty' list, 
-       unless that list is empty, in which case we take the buffer at the 
-       head of the 'full' list.
-     * When our fill buffer has been filled, it is appended to the 'full' 
+     * If a frame is needed for filling, we try to take it from the 'empty' 
+       list, unless that list is empty, in which case we take the buffer at 
+       the head of the 'full' list.
+     * When our fill buffer has been filled, it is appended to the 'full'
        list.
-     * If a frame is needed by read() or mmap(), it is taken from the head of 
+     * If a frame is needed by read() or mmap(), it is taken from the head of
        the 'full' list, handled, and then appended to the 'empty' list. If no
        buffer is present on the 'full' list, we wait.
    The advantage is that the buffer that is currently being decompressed/
-   converted, is on neither list, and thus not in our way (any other scheme 
+   converted, is on neither list, and thus not in our way (any other scheme
    I tried had the problem of old data lingering in the queue).
 
    Whatever strategy you choose, it always remains a tradeoff: with more
    frame buffers the chances of a missed frame are reduced. On the other
-   hand, on slower machines it introduces lag because the queue will 
+   hand, on slower machines it introduces lag because the queue will
    always be full.
  */
 
@@ -437,7 +441,7 @@
 {
 	int ret;
 	unsigned long flags;
-	
+
 	ret = 0;
 	spin_lock_irqsave(&pdev->ptrlock, flags);
 	if (pdev->fill_frame != NULL) {
@@ -454,11 +458,11 @@
 	if (pdev->empty_frames != NULL) {
 		/* We have empty frames available. That's easy */
 		pdev->fill_frame = pdev->empty_frames;
-		pdev->empty_frames = pdev->empty_frames->next;	
+		pdev->empty_frames = pdev->empty_frames->next;
 	}
 	else {
 		/* Hmm. Take it from the full list */
-#if PWC_DEBUG		
+#if PWC_DEBUG
 		/* sanity check */
 		if (pdev->full_frames == NULL) {
 			Err("Neither empty or full frames available!\n");
@@ -478,11 +482,11 @@
 	spin_unlock_irqrestore(&pdev->ptrlock, flags);
 	return ret;
 }
- 
+
 
 /**
-  \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. 
-  
+  \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
+
   If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
  */
 static void pwc_reset_buffers(struct pwc_device *pdev)
@@ -519,7 +523,7 @@
 {
 	int ret = 0;
 	unsigned long flags;
-	
+
 	spin_lock_irqsave(&pdev->ptrlock, flags);
 	/* First grab our read_frame; this is removed from all lists, so
 	   we can release the lock after this without problems */
@@ -542,7 +546,7 @@
 			Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
 #endif
 			/* Decompression is a lenghty process, so it's outside of the lock.
-			   This gives the isoc_handler the opportunity to fill more frames 
+			   This gives the isoc_handler the opportunity to fill more frames
 			   in the mean time.
 			*/
 			spin_unlock_irqrestore(&pdev->ptrlock, flags);
@@ -566,7 +570,7 @@
 }
 
 /**
-  \brief Advance pointers of image buffer (after each user request) 
+  \brief Advance pointers of image buffer (after each user request)
 */
 static inline void pwc_next_image(struct pwc_device *pdev)
 {
@@ -574,22 +578,6 @@
 	pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
 }
 
-/* 2001-10-14: YUV420P is the only palette remaining. */
-static int pwc_set_palette(struct pwc_device *pdev, int pal)
-{
-	if (   pal == VIDEO_PALETTE_YUV420P
-#if PWC_DEBUG
-            || pal == VIDEO_PALETTE_RAW
-#endif
-	) {
-		pdev->vpalette = pal;
-		pwc_set_image_buffer_size(pdev);
-		return 0;
-	}
-	Trace(TRACE_READ, "Palette %d not supported.\n", pal);
-	return -1;
-}
-
 
 
 /* This gets called for the Isochronous pipe (video). This is done in
@@ -601,14 +589,15 @@
 	int i, fst, flen;
 	int awake;
 	struct pwc_frame_buf *fbuf;
-	unsigned char *fillptr, *iso_buf;
+	unsigned char *fillptr = 0, *iso_buf = 0;
 
+	awake = 0;
 	pdev = (struct pwc_device *)urb->context;
 	if (pdev == NULL) {
 		Err("isoc_handler() called with NULL device?!\n");
 		return;
 	}
-#ifdef PWC_MAGIC	
+#ifdef PWC_MAGIC
 	if (pdev->magic != PWC_MAGIC) {
 		Err("isoc_handler() called with bad magic!\n");
 		return;
@@ -619,33 +608,51 @@
 		return;
 	}
 	if (urb->status != -EINPROGRESS && urb->status != 0) {
-		char *errmsg;
-		
+		const char *errmsg;
+
 		errmsg = "Unknown";
 		switch(urb->status) {
 			case -ENOSR:		errmsg = "Buffer error (overrun)"; break;
 			case -EPIPE:		errmsg = "Stalled (device not responding)"; break;
 			case -EOVERFLOW:	errmsg = "Babble (bad cable?)"; break;
 			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break;
-			case -EILSEQ:		errmsg = "CRC/Timeout"; break;
+			case -EILSEQ:		errmsg = "CRC/Timeout (could be anything)"; break;
 			case -ETIMEDOUT:	errmsg = "NAK (device does not respond)"; break;
 		}
 		Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
-		return;
+		/* Give up after a number of contiguous errors on the USB bus. 
+		   Appearantly something is wrong so we simulate an unplug event.
+		 */
+		if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
+		{
+			Info("Too many ISOC errors, bailing out.\n");
+			pdev->error_status = EIO;
+			awake = 1;
+		}
+		else
+			return; // better luck next time
 	}
 
 	fbuf = pdev->fill_frame;
 	if (fbuf == NULL) {
 		Err("pwc_isoc_handler without valid fill frame.\n");
+		awake = 1;
+	}
+	else {
+		fillptr = fbuf->data + fbuf->filled;
+	}
+	/* Premature wakeup */
+	if (awake) {
 		wake_up_interruptible(&pdev->frameq);
 		return;
 	}
-	fillptr = fbuf->data + fbuf->filled;
-	awake = 0;
+
+	/* Reset ISOC error counter. We did get here, after all. */
+	pdev->visoc_errors = 0;
 
 	/* vsync: 0 = don't copy data
 	          1 = sync-hunt
-	          2 = synched 
+	          2 = synched
 	 */
 	/* Compact data */
 	for (i = 0; i < urb->number_of_packets; i++) {
@@ -674,7 +681,7 @@
 			if (flen < pdev->vlast_packet_size) {
 				/* Shorter packet... We probably have the end of an image-frame; 
 				   wake up read() process and let select()/poll() do something.
-				   Decompression is done in user time over there. 
+				   Decompression is done in user time over there.
 				 */
 				if (pdev->vsync == 2) {
 					/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus 
@@ -731,7 +738,7 @@
 						else {
 							/* Send only once per EOF */
 							awake = 1; /* delay wake_ups */
-							
+
 							/* Find our next frame to fill. This will always succeed, since we
 							 * nick a frame from either empty or full list, but if we had to
 							 * take it from the full list, it means a frame got dropped.
@@ -764,7 +771,7 @@
 			if (iso_error < 20)
 				Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
 		}
-#endif			
+#endif
 	}
 	if (awake)
 		wake_up_interruptible(&pdev->frameq);
@@ -893,8 +900,10 @@
 		}
 	}
 
-	/* Stop camera, but only if we are sure the camera is still there */
-	if (!pdev->unplugged) {
+	/* Stop camera, but only if we are sure the camera is still there (unplug
+	   is signalled by EPIPE) 
+	 */
+	if (pdev->error_status && pdev->error_status != EPIPE) {
 		Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
 		usb_set_interface(pdev->udev, 0, 0);
 	}
@@ -922,28 +931,6 @@
 }
 
 
-static inline void set_mem_leak(void *ptr)
-{
-	down(&mem_lock);
-	if (mem_leak != NULL)
-		Err("Memleak: overwriting mem_leak pointer!\n");
-	Trace(TRACE_MEMORY, "Setting mem_leak to 0x%p.\n", ptr);
-	mem_leak = ptr;
-	up(&mem_lock);
-}
-
-static inline void free_mem_leak(void)
-{
-	down(&mem_lock);
-	if (mem_leak != NULL) {
-		Trace(TRACE_MEMORY, "Freeing mem_leak ptr 0x%p.\n", mem_leak);
-		kfree(mem_leak);
-		mem_leak = NULL;
-	}
-	up(&mem_lock);
-}
-
-
 /***************************************************************************/
 /* Video4Linux functions */
 
@@ -967,8 +954,8 @@
 		Trace(TRACE_OPEN, "Doing first time initialization.\n");
 		pdev->usb_init = 1;
 		
-		if (pwc_trace & TRACE_OPEN) {
-			/* Query CMOS sensor type */
+		{
+			/* Query sensor type */
 			const char *sensor_type = NULL;
 
 			i = pwc_get_cmos_sensor(pdev);
@@ -987,7 +974,7 @@
 			default:    sensor_type = "unknown type of sensor"; break;
 			}
 			if (sensor_type != NULL)
-				Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+				Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev.name, sensor_type, i);
 		}
 	}
 
@@ -1022,24 +1009,20 @@
 	pdev->vframe_count = 0;
 	pdev->vframes_dumped = 0;
 	pdev->vframes_error = 0;
-	pdev->vpalette = default_palette;
-#if PWC_DEBUG	
+	pdev->visoc_errors = 0;
+	pdev->error_status = 0;
+#if PWC_DEBUG
 	pdev->sequence = 0;
 #endif
 
 	/* Set some defaults */
 	pdev->vsnapshot = 0;
-	if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
-		pdev->vsize = PSZ_QSIF;
-	else
-		pdev->vsize = PSZ_QCIF;
-	pdev->vframes = 10;
-
-	/* Start iso pipe for video; first try user-supplied size/fps, if
-	   that fails try QCIF/10 or QSIF/10 (a reasonable default), 
-	   then give up 
+
+	/* Start iso pipe for video; first try the last used video size
+	   (or the default one); if that fails try QCIF/10 or QSIF/10;
+	   it that fails too, give up.
 	 */
-	i = pwc_set_video_mode(pdev, pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y, default_fps, pdev->vcompression, 0);
+	i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
 	if (i)	{
 		Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
 		if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
@@ -1091,46 +1074,41 @@
 	if (pdev->vframe_count > 20)
 		Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
 
-	/* Free isoc URBs, stop camera */
+	if (pdev->decompressor != NULL) {
+		pdev->decompressor->exit();
+		pdev->decompressor->unlock();
+		pdev->decompressor = NULL;
+	}
+
 	pwc_isoc_cleanup(pdev);
+	pwc_free_buffers(pdev);
 
-	if (!pdev->unplugged) {
-		/* Turn LEDs off */
+	/* Turn off LEDS and power down camera, but only when not unplugged */
+	if (pdev->error_status != EPIPE) {
 		if (pwc_set_leds(pdev, 0, 0) < 0)
 			Info("Failed to set LED on/off time.\n");
-		/* Power down camera to save energy */
 		if (power_save) {
 			i = pwc_camera_power(pdev, 0);
 			if (i < 0) 
 				Err("Failed to power down camera (%d)\n", i);
 		}
 	}
-
 	pdev->vopen = 0;
-	if (pdev->decompressor != NULL) {
-		pdev->decompressor->exit();
-		pdev->decompressor->unlock();
-	}
-	pwc_free_buffers(pdev);
-
-	/* wake up _disconnect() routine */
-	if (pdev->unplugged)
-		wake_up(&pdev->remove_ok);
 	Trace(TRACE_OPEN, "<< video_close()\n");
 }
 
 /*
  *	FIXME: what about two parallel reads ????
  *      ANSWER: Not supported. You can't open the device more than once,
-                despite what the V4L1 interface says. First, I don't see 
-                the need, second there's no mechanism of alerting the 
+                despite what the V4L1 interface says. First, I don't see
+                the need, second there's no mechanism of alerting the
                 2nd/3rd/... process of events like changing image size.
-                And I don't see the point of blocking that for the 
+                And I don't see the point of blocking that for the
                 2nd/3rd/... process.
                 In multi-threaded environments reading parallel from any
                 device is tricky anyhow.
  */
- 
+
 static long pwc_video_read(struct video_device *vdev, char *buf, unsigned long count, int noblock)
 {
 	struct pwc_device *pdev;
@@ -1142,17 +1120,20 @@
 	pdev = vdev->priv;
 	if (pdev == NULL)
 		return -EFAULT;
-	if (pdev->unplugged) {
-		Info("pwc_video_read: Device got unplugged (1).\n");
-		return -EPIPE; /* unplugged device! */
-	}
+	if (pdev->error_status)
+		return -pdev->error_status; /* Something happened, report what. */
 
 	/* In case we're doing partial reads, we don't have to wait for a frame */
 	if (pdev->image_read_pos == 0) {
 		/* Do wait queueing according to the (doc)book */
 		add_wait_queue(&pdev->frameq, &wait);
-	        set_current_state(TASK_INTERRUPTIBLE);
 		while (pdev->full_frames == NULL) {
+			/* Check for unplugged/etc. here */
+			if (pdev->error_status) {
+				remove_wait_queue(&pdev->frameq, &wait);
+				set_current_state(TASK_RUNNING);
+				return -pdev->error_status ;
+			}
 	                if (noblock) {
 	                	remove_wait_queue(&pdev->frameq, &wait);
 	                	set_current_state(TASK_RUNNING);
@@ -1168,8 +1149,8 @@
 		}
 		remove_wait_queue(&pdev->frameq, &wait);
 		set_current_state(TASK_RUNNING);
-	                                                                                                                                                                                
-		/* Decompress [, convert] and release frame */
+
+		/* Decompress and release frame */
 		if (pwc_handle_frame(pdev))
 			return -EFAULT;
 	}
@@ -1191,35 +1172,33 @@
 
 static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock)
 {
-	return -EINVAL;   
+	return -EINVAL;
 }
 
 static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait)
 {
 	struct pwc_device *pdev;
-	
+
 	if (vdev == NULL)
 		return -EFAULT;
 	pdev = vdev->priv;
 	if (pdev == NULL)
 		return -EFAULT;
-	
+
 	poll_wait(file, &pdev->frameq, wait);
-	if (pdev->unplugged) {
-		Info("pwc_video_poll: Device got unplugged.\n");
+	if (pdev->error_status)
 		return POLLERR;
-	}		
 	if (pdev->full_frames != NULL) /* we have frames waiting */
 		return (POLLIN | POLLRDNORM);
 
 	return 0;
 }
-        
+
 static int pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 {
 	struct pwc_device *pdev;
 	DECLARE_WAITQUEUE(wait, current);
-	
+
 	if (vdev == NULL)
 		return -EFAULT;
 	pdev = vdev->priv;
@@ -1228,7 +1207,7 @@
 
 	switch (cmd) {
 		/* Query cabapilities */
-		case VIDIOCGCAP: 
+		case VIDIOCGCAP:
 		{
 			struct video_capability caps;
 
@@ -1314,7 +1293,7 @@
 			else
 				p.colour = 0xffff;
 			p.depth = 24;
-			p.palette = pdev->vpalette;
+			p.palette = VIDEO_PALETTE_YUV420P;
 			p.hue = 0xFFFF; /* N/A */
 
 			if (copy_to_user(arg, &p, sizeof(p)))
@@ -1341,9 +1320,8 @@
 			pwc_set_contrast(pdev, p.contrast);
 			pwc_set_gamma(pdev, p.whiteness);
 			pwc_set_saturation(pdev, p.colour);
-			if (p.palette && p.palette != pdev->vpalette) {
-				if (pwc_set_palette(pdev, p.palette) < 0)
-					return -EINVAL;
+			if (p.palette && p.palette != VIDEO_PALETTE_YUV420P) {
+				return -EINVAL;
 			}
 			break;
 		}
@@ -1436,9 +1414,8 @@
 			   various palettes... The driver doesn't support
 			   such small images, so I'm working around it.
 			 */
-			if (vm.format && vm.format != pdev->vpalette)
-				if (pwc_set_palette(pdev, vm.format) < 0)
-					return -EINVAL;
+			if (vm.format && vm.format != VIDEO_PALETTE_YUV420P)
+				return -EINVAL;
 			 
 			if ((vm.width != pdev->view.x || vm.height != pdev->view.y) &&
 			    (vm.width >= pdev->view_min.x && vm.height >= pdev->view_min.y)) {
@@ -1458,7 +1435,7 @@
 			/* Okay, we're done here. In the SYNC call we wait until a 
 			   frame comes available, then expand image into the given 
 			   buffer.
-			   In contrast to the CPiA cam the Philips cams deliver a 
+			   In contrast to the CPiA cam the Philips cams deliver a
 			   constant stream, almost like a grabber card. Also,
 			   we have separate buffers for the rawdata and the image,
 			   meaning we can nearly always expand into the requested buffer.
@@ -1498,27 +1475,26 @@
 				return -EINVAL;
 
 			/* Add ourselves to the frame wait-queue.
-			   
+			   In the loop, check for error conditions and signals.
+
 			   FIXME: needs auditing for safety.
-			   QUSTION: In what respect? I think that using the
-			            frameq is safe now.
+			   QUESTION: In what respect? I think that using the
+			             frameq is safe now.
 			 */
 			add_wait_queue(&pdev->frameq, &wait);
-		        set_current_state(TASK_INTERRUPTIBLE);
 			while (pdev->full_frames == NULL) {
-				if (pdev->unplugged) {
+				if (pdev->error_status) {
 					remove_wait_queue(&pdev->frameq, &wait);
 					set_current_state(TASK_RUNNING);
-					return -ENODEV;
+					return -pdev->error_status;
 				}
-			
 	                	if (signal_pending(current)) {
 	                		remove_wait_queue(&pdev->frameq, &wait);
 		                	set_current_state(TASK_RUNNING);
 		                	return -ERESTARTSYS;
 	        	        }
-		                set_current_state(TASK_INTERRUPTIBLE);
 	                	schedule();
+		                set_current_state(TASK_INTERRUPTIBLE);
 			}
 			remove_wait_queue(&pdev->frameq, &wait);
 			set_current_state(TASK_RUNNING);
@@ -1572,7 +1548,7 @@
 		{
 			struct video_unit vu;
 			
-			vu.video = pdev->vdev->minor & 0x3F;
+			vu.video = pdev->vdev.minor & 0x3F;
 			vu.audio = -1; /* not known yet */
 			vu.vbi = -1;
 			vu.radio = -1;
@@ -1623,14 +1599,11 @@
 static void *usb_pwc_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
 {
 	struct pwc_device *pdev = NULL;
-	struct video_device *vdev;
 	int vendor_id, product_id, type_id;
 	int i, hint;
 	int video_nr = -1; /* default: use next available device */
 	char serial_number[30], *name;
 
-	free_mem_leak();
-	
 	/* Check if we can handle this device */
 	Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", udev->descriptor.idVendor, udev->descriptor.idProduct, ifnum);
 
@@ -1691,6 +1664,11 @@
 			name = "Philips 750 webcam";
 			type_id = 750;
 			break;
+		case 0x0313:
+			Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+			name = "Philips 720 webcam";
+			type_id = 720;
+			break;
 		default:
 			return NULL;
 			break;
@@ -1713,12 +1691,12 @@
 		case 0x08b0:
 			Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
 			name = "Logitech QuickCam Pro 3000";
-			type_id = 730;
+			type_id = 740; /* CCD sensor */
 			break;
 		case 0x08b1:
 			Info("Logitech QuickCam for Notebook Pro USB webcam detected.\n");
 			name = "Logitech QuickCam Notebook Pro";
-			type_id = 740; /* ?? unknown sensor */
+			type_id = 740; /* CCD sensor */
 			break;
 		case 0x08b2:
 			Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
@@ -1730,6 +1708,15 @@
 			name = "Logitech QuickCam Zoom";
 			type_id = 740; /* CCD sensor */
 			break;
+		case 0x08b4:
+		case 0x08b5:
+		case 0x08b6:
+		case 0x08b7:
+		case 0x08b8:
+			Info("Logitech QuickCam detected (reserved ID).\n");
+			name = "Logitech QuickCam (res.)";
+			type_id = 730; /* Assuming CMOS */
+			break;
         	default:
         		return NULL;
         		break;
@@ -1763,6 +1750,11 @@
 			name = "Creative Labs Webcam 5";
 			type_id = 730;
 			break;
+		case 0x4011:
+			Info("Creative Labs Webcam Pro Ex detected.\n");
+			name = "Creative Labs Webcam Pro Ex";
+			type_id = 740;
+			break;
 		default:
 			return NULL;
 			break;
@@ -1816,26 +1808,20 @@
 	memset(pdev, 0, sizeof(struct pwc_device));
 	pdev->type = type_id;
 	pwc_construct(pdev);
+	pdev->vsize = default_size;
+	pdev->vframes = default_fps;
 
 	init_MUTEX(&pdev->modlock);
 	pdev->ptrlock = SPIN_LOCK_UNLOCKED;
 
 	pdev->udev = udev;
 	init_waitqueue_head(&pdev->frameq);
-	init_waitqueue_head(&pdev->remove_ok);
 	pdev->vcompression = pwc_preferred_compression;
 
-	/* Now hook it up to the video subsystem */
-	vdev = kmalloc(sizeof(struct video_device), GFP_KERNEL);
-	if (vdev == NULL) {
-		Err("Oops, could not allocate memory for video_device.\n");
-		return NULL;
-	}
-	memcpy(vdev, &pwc_template, sizeof(pwc_template));
-	strcpy(vdev->name, name);
-	SET_MODULE_OWNER(vdev);
-	pdev->vdev = vdev;
-	vdev->priv = pdev;
+	memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
+	strcpy(pdev->vdev.name, name);
+	SET_MODULE_OWNER(&pdev->vdev);
+	pdev->vdev.priv = pdev;
 
 	pdev->release = udev->descriptor.bcdDevice;
 	Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
@@ -1854,14 +1840,14 @@
 		}
 	}
 
-	i = video_register_device(vdev, VFL_TYPE_GRABBER, video_nr);
+	i = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
 	if (i < 0) {
 		Err("Failed to register as video device (%d).\n", i);
+		kfree(pdev); /* Oops, no memory leaks please */
 		return NULL;
 	}
 	else {
-		Trace(TRACE_PROBE, "Registered video struct at 0x%p.\n", vdev);
-		Info("Registered as /dev/video%d.\n", vdev->minor & 0x3F);
+		Info("Registered as /dev/video%d.\n", pdev->vdev.minor & 0x3F);
 	}
 	/* occupy slot */
 	if (hint < MAX_DEV_HINTS) 
@@ -1876,75 +1862,56 @@
 {
 	struct pwc_device *pdev;
 	int hint;
-	DECLARE_WAITQUEUE(wait, current);
 
 	lock_kernel();
-	free_mem_leak();
-
 	pdev = (struct pwc_device *)ptr;
 	if (pdev == NULL) {
 		Err("pwc_disconnect() Called without private pointer.\n");
+		unlock_kernel();
 		return;
 	}
 	if (pdev->udev == NULL) {
 		Err("pwc_disconnect() already called for %p\n", pdev);
+		unlock_kernel();
 		return;
 	}
 	if (pdev->udev != udev) {
 		Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
+		unlock_kernel();
 		return;
 	}
-#ifdef PWC_MAGIC	
+#ifdef PWC_MAGIC
 	if (pdev->magic != PWC_MAGIC) {
 		Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
+		unlock_kernel();
 		return;
 	}
 #endif	
-	
-	pdev->unplugged = 1;
-	if (pdev->vdev != NULL) {
-		add_wait_queue(&pdev->remove_ok, &wait);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		Trace(TRACE_PROBE, "Unregistering video device.\n");
-		video_unregister_device(pdev->vdev); 
-		if (pdev->vopen) {
-			Info("Disconnected while device/video is open!\n");
-			
-			/* Wake up any processes that might be waiting for
-			   a frame, let them return an error condition
-			 */
-			wake_up(&pdev->frameq);
-			
-			/* Wait until we get a 'go' from _close(). This used
-			   to have a gigantic race condition, since we kfree()
-			   stuff here, but we have to wait until close() 
-			   is finished. 
-			 */
-			   
-			Trace(TRACE_PROBE, "Sleeping on remove_ok.\n");
-			/* ... wait ... */
-			schedule();
-			Trace(TRACE_PROBE, "Done sleeping.\n");
-			set_mem_leak(pdev->vdev);
-			pdev->vdev = NULL;
-		}
-		else {
-			/* Normal disconnect; remove from available devices */
-			kfree(pdev->vdev);
-			pdev->vdev = NULL;
-		}
-		remove_wait_queue(&pdev->remove_ok, &wait);
-		set_current_state(TASK_RUNNING);
+
+	/* We got unplugged; this is signalled by an EPIPE error code */
+	if (pdev->vopen) {
+		Info("Disconnected while webcam is in use!\n");
+		pdev->error_status = EPIPE;
 	}
+	
+	/* Alert waiting processes */
+	wake_up_interruptible(&pdev->frameq);
+	/* Wait until device is closed */
+	while (pdev->vopen)
+		schedule();
+	/* Device is now closed, so we can safely unregister it */
+	Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+	video_unregister_device(&pdev->vdev); 
+
+	/* Free memory (don't set pdev to 0 just yet) */
+	kfree(pdev);
 
 	/* search device_hint[] table if we occupy a slot, by any chance */
 	for (hint = 0; hint < MAX_DEV_HINTS; hint++)
 		if (device_hint[hint].pdev == pdev)
 			device_hint[hint].pdev = NULL;
 
-	pdev->udev = NULL;
 	unlock_kernel();
-	kfree(pdev);
 }
 
 
@@ -1973,7 +1940,7 @@
 static int trace = -1;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
-static char *dev_hint[10] = { };
+static char *dev_hint[MAX_DEV_HINTS] = { };
 
 MODULE_PARM(size, "s");
 MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
@@ -1991,7 +1958,7 @@
 MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
 MODULE_PARM(leds, "2i");
 MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-MODULE_PARM(dev_hint, "0-10s");
+MODULE_PARM(dev_hint, "0-20s");
 MODULE_PARM_DESC(dev_hint, "Device node hints");
 
 MODULE_DESCRIPTION("Philips USB & OEM webcam driver");
@@ -2133,14 +2100,12 @@
 			device_hint[i].type = 0; /* not filled */
 	} /* ..for MAX_DEV_HINTS */
 
-	init_MUTEX(&mem_lock);
  	Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
 	return usb_register(&pwc_driver);
 }
 
 static void __exit usb_pwc_exit(void)
 {
-	free_mem_leak();
 	Trace(TRACE_MODULE, "Deregistering driver.\n");
 	usb_deregister(&pwc_driver);
 	Info("Philips webcam module removed.\n");
diff -Nru a/drivers/usb/pwc-ioctl.h b/drivers/usb/pwc-ioctl.h
--- a/drivers/usb/pwc-ioctl.h	Sun Dec 15 16:22:40 2002
+++ b/drivers/usb/pwc-ioctl.h	Fri Jul 25 17:00:23 2003
@@ -1,7 +1,7 @@
 #ifndef PWC_IOCTL_H
 #define PWC_IOCTL_H
 
-/* (C) 2001-2002 Nemosoft Unv.    webcam@smcc.demon.nl
+/* (C) 2001-2003 Nemosoft Unv.    webcam@smcc.demon.nl
    
    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
diff -Nru a/drivers/usb/pwc-misc.c b/drivers/usb/pwc-misc.c
--- a/drivers/usb/pwc-misc.c	Fri Mar 22 14:49:45 2002
+++ b/drivers/usb/pwc-misc.c	Fri Jul 25 17:01:03 2003
@@ -1,6 +1,6 @@
 /* Linux driver for Philips webcam 
    Various miscellaneous functions and tables.
-   (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
+   (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
@@ -51,7 +51,6 @@
 	}
 	return find;
 }
-
 /* initialize variables depending on type */
 void pwc_construct(struct pwc_device *pdev)
 {
@@ -81,6 +80,7 @@
 		pdev->frame_header_size = 0;
 		pdev->frame_trailer_size = 0;
 		break;
+	case 720:
 	case 730:
 	case 740:
 	case 750:
diff -Nru a/drivers/usb/pwc-uncompress.c b/drivers/usb/pwc-uncompress.c
--- a/drivers/usb/pwc-uncompress.c	Sat Oct  5 15:35:01 2002
+++ b/drivers/usb/pwc-uncompress.c	Sat Jul 26 18:51:14 2003
@@ -1,6 +1,6 @@
 /* Linux driver for Philips webcam 
    Decompression frontend.
-   (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
+   (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
@@ -32,7 +32,7 @@
 
 /* Should the pwc_decompress structure ever change, we increase the 
    version number so that we don't get nasty surprises, or can 
-   dynamicly adjust our structure.
+   dynamically adjust our structure.
  */
 const int pwc_decompressor_version = PWC_MAJOR;
 
@@ -98,14 +98,6 @@
 	if (!image)
 		return -EFAULT;
 	
-#if PWC_DEBUG
-	/* This is a quickie */
-	if (pdev->vpalette == VIDEO_PALETTE_RAW) {
-		memcpy(image, fbuf->data, pdev->frame_size);
-		return 0;
-	}
-#endif
-
 	yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
 	if (pdev->vbandlength == 0) { 
 		/* Uncompressed mode. We copy the data into the output buffer,
@@ -113,8 +105,6 @@
 		   size). Unfortunately we have to do a bit of byte stuffing
 		   to get the desired output format/size.
 		 */
-		switch (pdev->vpalette) {
-		case VIDEO_PALETTE_YUV420P:
 			/* 
 			 * We do some byte shuffling here to go from the 
 			 * native format to YUV420P.
@@ -149,11 +139,6 @@
 				else
 					dstu += (stride >> 1);
 			}
-			break;
-		default:
-			Err("Unsupported palette!");
-			break;
-		}
 	}
 	else { 
 		/* Compressed; the decompressor routines will write the data 
diff -Nru a/drivers/usb/pwc-uncompress.h b/drivers/usb/pwc-uncompress.h
--- a/drivers/usb/pwc-uncompress.h	Fri Mar 22 14:49:45 2002
+++ b/drivers/usb/pwc-uncompress.h	Sat Jul 26 18:49:38 2003
@@ -1,4 +1,4 @@
-/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
+/* (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
diff -Nru a/drivers/usb/pwc.h b/drivers/usb/pwc.h
--- a/drivers/usb/pwc.h	Sun Dec 15 15:05:19 2002
+++ b/drivers/usb/pwc.h	Sat Jul 26 18:51:14 2003
@@ -1,4 +1,4 @@
-/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl)
+/* (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl)
 
    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
@@ -60,8 +60,8 @@
 
 /* Version block */
 #define PWC_MAJOR	8
-#define PWC_MINOR	10
-#define PWC_VERSION 	"8.10"
+#define PWC_MINOR	11
+#define PWC_VERSION 	"8.11"
 #define PWC_NAME 	"pwc"
 
 /* Turn certain features on/off */
@@ -82,7 +82,7 @@
 #define PWC_FRAME_SIZE 		(460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)
 
 /* Absolute maximum number of buffers available for mmap() */
-#define MAX_IMAGES 		4
+#define MAX_IMAGES 		10
 
 struct pwc_coord
 {
@@ -112,6 +112,7 @@
 
 struct pwc_device
 {
+   struct video_device vdev;
 #ifdef PWC_MAGIC
    int magic;
 #endif
@@ -120,22 +121,21 @@
    
    int type;                    /* type of cam (645, 646, 675, 680, 690) */
    int release;			/* release number */
-   int unplugged;		/* set when the plug is pulled */
+   int error_status;		/* set when something goes wrong with the cam (unplugged, USB errors) */
    int usb_init;		/* set when the cam has been initialized over USB */
 
    /*** Video data ***/
    int vopen;			/* flag */
-   struct video_device *vdev;
    int vendpoint;		/* video isoc endpoint */
    int vcinterface;		/* video control interface */
    int valternate;		/* alternate interface needed */
    int vframes, vsize;		/* frames-per-second & size (see PSZ_*) */
-   int vpalette;		/* YUV */
    int vframe_count;		/* received frames */
    int vframes_dumped; 		/* counter for dumped frames */
    int vframes_error;		/* frames received in error */
    int vmax_packet_size;	/* USB maxpacket size */
    int vlast_packet_size;	/* for frame synchronisation */
+   int visoc_errors;		/* number of contiguous ISOC errors */
    int vcompression;		/* desired compression factor */
    int vbandlength;		/* compressed band length; 0 is uncompressed */
    char vsnapshot;		/* snapshot mode */
@@ -147,15 +147,15 @@
       2. data is synchronized and packed into a frame buffer
       3a. in case data is compressed, decompress it directly into image buffer
       3b. in case data is uncompressed, copy into image buffer with viewport
-      4. data is transfered to the user process
+      4. data is transferred to the user process
 
-      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... 
+      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES....
       We have in effect a back-to-back-double-buffer system.
     */
    /* 1: isoc */
    struct pwc_iso_buf sbuf[MAX_ISO_BUFS];
    char iso_init;
-   
+
    /* 2: frame */
    struct pwc_frame_buf *fbuf;	/* all frames */
    struct pwc_frame_buf *empty_frames, *empty_frames_tail;	/* all empty frames */
@@ -168,7 +168,7 @@
 #if PWC_DEBUG
    int sequence;			/* Debugging aid */
 #endif
-   
+
    /* 3: decompression */
    struct pwc_decompressor *decompressor;	/* function block with decompression routines */
    void *decompress_data;		/* private data for decompression engine */
@@ -176,7 +176,7 @@
    /* 4: image */
    /* We have an 'image' and a 'view', where 'image' is the fixed-size image
       as delivered by the camera, and 'view' is the size requested by the
-      program. The camera image is centered in this viewport, laced with 
+      program. The camera image is centered in this viewport, laced with
       a gray or black border. view_min <= image <= view <= view_max;
     */
    int image_mask;			/* bitmask of supported sizes */
@@ -196,10 +196,9 @@
 
    /*** Misc. data ***/
    wait_queue_head_t frameq;		/* When waiting for a frame to finish... */
-   wait_queue_head_t remove_ok;		/* When we got hot unplugged, we have to avoid a few race conditions */
 #if PWC_INT_PIPE
    void *usb_int_handler;		/* for the interrupt endpoint */
-#endif   
+#endif
 };
 
 /* Enumeration of image sizes */
diff -Nru a/drivers/usb/scanner.c b/drivers/usb/scanner.c
--- a/drivers/usb/scanner.c	Sat Jun 14 04:33:19 2003
+++ b/drivers/usb/scanner.c	Thu Jul 17 08:56:41 2003
@@ -367,6 +367,17 @@
  *      Mustek, Pacific Image Electronics, Plustek, and Visioneer scanners.
  *      Fixed names of some other scanners.
  *
+ * 0.4.14  2003-07-15
+ *    - Added vendor/product ids for Avision, Canon, HP, Microtek and Relisys
+ *      scanners.
+ *    - When checking if all minors are used don't read beyond p_scn_table
+ *      (Sergey Vlasov).
+ *    - Kfree the scn structure only after disconnect AND close have occured and
+ *      check for scn->present.  This avoids crashing when someone writes (reads) to 
+ *      the device while it's already disconnected but still open. Patch from
+ *      Sergey Vlasov.
+ *    - Clean up irq urb when not enough memory is available (Sergey Vlasov).
+ *
  * TODO
  *    - Performance
  *    - Select/poll methods
@@ -411,6 +422,8 @@
  */ 
 #include "scanner.h"
 
+static void purge_scanner(struct scn_usb_data *scn);
+
 static void
 irq_scanner(struct urb *urb)
 {
@@ -501,28 +514,20 @@
 static int
 close_scanner(struct inode * inode, struct file * file)
 {
-	struct scn_usb_data *scn;
-
-	kdev_t scn_minor;
-
-	scn_minor = USB_SCN_MINOR (inode);
-
-	dbg("close_scanner: scn_minor:%d", scn_minor);
-
-	if (!p_scn_table[scn_minor]) {
-		err("close_scanner(%d): invalid scn_minor", scn_minor);
-		return -ENODEV;
-	}
-
-	down(&scn_mutex);
+	struct scn_usb_data *scn = file->private_data;
 
-	scn = p_scn_table[scn_minor];
 	down(&(scn->sem));
 	scn->isopen = 0;
 
 	file->private_data = NULL;
 
-	up(&scn_mutex);
+	if (!scn->present) {
+		/* The device was unplugged while open - need to clean up */
+		up(&(scn->sem));
+		purge_scanner(scn);
+		return 0;
+	}
+
 	up(&(scn->sem));
 
 	return 0;
@@ -550,6 +555,12 @@
 
 	down(&(scn->sem));
 
+	if (!scn->present) {
+		/* The device was unplugged while open */
+		up(&(scn->sem));
+		return -ENODEV;
+	}
+
 	if (!scn->bulk_out_ep) {
 		/* This scanner does not have a bulk-out endpoint */
 		up(&(scn->sem));
@@ -644,6 +655,12 @@
 
 	down(&(scn->sem));
 
+	if (!scn->present) {
+		/* The device was unplugged while open */
+		up(&(scn->sem));
+		return -ENODEV;
+	}
+
 	scn_minor = scn->scn_minor;
 
 	ibuf = scn->ibuf;
@@ -751,6 +768,12 @@
 	scn = file->private_data;
 	down(&(scn->sem));
 
+	if (!scn->present) {
+		/* The device was unplugged while open */
+		up(&(scn->sem));
+		return -ENODEV;
+	}
+
 	dev = scn->scn_dev;
 
 	switch (cmd)
@@ -978,7 +1001,7 @@
 	}
 
 /* Check to make sure that the last slot isn't already taken */
-	if (p_scn_table[scn_minor]) {
+	if (scn_minor >= SCN_MAX_MNR) {
 		err("probe_scanner: No more minor devices remaining.");
 		up(&scn_mutex);
 		return NULL;
@@ -1018,6 +1041,8 @@
 /* Ok, now initialize all the relevant values */
 	if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
 		err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);
+		if (have_intr)
+			usb_unlink_urb(&scn->scn_irq);
 		kfree(scn);
 		up(&scn_mutex);
 		return NULL;
@@ -1026,6 +1051,8 @@
 
 	if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
 		err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);
+		if (have_intr)
+			usb_unlink_urb(&scn->scn_irq);
 		kfree(scn->obuf);
 		kfree(scn);
 		up(&scn_mutex);
@@ -1080,6 +1107,14 @@
 }
 
 static void
+purge_scanner(struct scn_usb_data *scn)
+{
+	kfree(scn->ibuf);
+	kfree(scn->obuf);
+	kfree(scn);
+}
+
+static void
 disconnect_scanner(struct usb_device *dev, void *ptr)
 {
 	struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
@@ -1094,15 +1129,22 @@
         usb_driver_release_interface(&scanner_driver,
                 &scn->scn_dev->actconfig->interface[scn->ifnum]);
 
-	kfree(scn->ibuf);
-	kfree(scn->obuf);
-
 	dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
 	devfs_unregister(scn->devfs);
 	p_scn_table[scn->scn_minor] = NULL;
+
+	if (scn->isopen) {
+		/* The device is still open - cleanup must be delayed */
+		scn->present = 0;
+		up(&(scn->sem));
+		up(&scn_mutex);
+		return;
+	}
+
 	up (&(scn->sem));
-	kfree (scn);
 	up (&scn_mutex);
+
+	purge_scanner(scn);
 }
 
 static struct
diff -Nru a/drivers/usb/scanner.h b/drivers/usb/scanner.h
--- a/drivers/usb/scanner.h	Sat Jun 14 04:41:25 2003
+++ b/drivers/usb/scanner.h	Tue Jul 15 03:00:15 2003
@@ -44,7 +44,7 @@
 
 // #define DEBUG
 
-#define DRIVER_VERSION "0.4.13"
+#define DRIVER_VERSION "0.4.14"
 #define DRIVER_DESC "USB Scanner Driver"
 
 #include <linux/usb.h>
@@ -104,6 +104,7 @@
 	/* Avision */
 	{ USB_DEVICE(0x0638, 0x0268) }, /* iVina 1200U */
 	{ USB_DEVICE(0x0638, 0x0a10) },	/* iVina FB1600 (=Umax Astra 4500) */
+	{ USB_DEVICE(0x0638, 0x0a20) }, /* iVina FB1800 (=Umax Astra 4700) */
 	/* Benq: see Acer */
 	/* Brother */
 	{ USB_DEVICE(0x04f9, 0x010f) },	/* MFC 5100C */
@@ -116,10 +117,12 @@
 	{ USB_DEVICE(0x04a9, 0x2206) }, /* CanoScan N650U/N656U */
 	{ USB_DEVICE(0x04a9, 0x2207) }, /* CanoScan N1220U */
 	{ USB_DEVICE(0x04a9, 0x2208) }, /* CanoScan D660U */ 
+	{ USB_DEVICE(0x04a9, 0x220a) },	/* CanoScan D2400UF */
 	{ USB_DEVICE(0x04a9, 0x220b) }, /* CanoScan D646U */
 	{ USB_DEVICE(0x04a9, 0x220c) },	/* CanoScan D1250U2 */
 	{ USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */
 	{ USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */
+	{ USB_DEVICE(0x04a9, 0x220f) },	/* CanoScan 8000F */
 	{ USB_DEVICE(0x04a9, 0x2213) },	/* LIDE 50 */
 	{ USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */
 	/* Colorado -- See Primax/Colorado below */
@@ -159,6 +162,7 @@
 	{ USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */
 	{ USB_DEVICE(0x03F0, 0x1005) },	/* ScanJet 5400C */
 	{ USB_DEVICE(0x03F0, 0x1105) },	/* ScanJet 5470C */
+	{ USB_DEVICE(0x03f0, 0x1205) }, /* ScanJet 5550C */
 	{ USB_DEVICE(0x03f0, 0x1305) },	/* Scanjet 4570c */
 	{ USB_DEVICE(0x03f0, 0x1411) }, /* PSC 750 */
 	{ USB_DEVICE(0x03f0, 0x2005) },	/* ScanJet 3570c */
@@ -174,6 +178,7 @@
 	/* Memorex */
 	{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
 	/* Microtek */
+	{ USB_DEVICE(0x05da, 0x20c9) }, /* ScanMaker 6700 */
 	{ USB_DEVICE(0x05da, 0x30ce) },	/* ScanMaker 3800 */
 	{ USB_DEVICE(0x05da, 0x30cf) },	/* ScanMaker 4800 */
 	{ USB_DEVICE(0x04a7, 0x0224) },	/* Scanport 3000 (actually Visioneer?)*/
@@ -251,6 +256,7 @@
 	{ USB_DEVICE(0x06dc, 0x0014) }, /* Winscan Pro 2448U */
 	/* Relisis */
 	// { USB_DEVICE(0x0475, 0x0103) },	/* Episode - undetected endpoint */
+	{ USB_DEVICE(0x0475, 0x0210) }, /* Scorpio Ultra 3 */
 	/* Seiko/Epson Corp. */
 	{ USB_DEVICE(0x04b8, 0x0101) },	/* Perfection 636U and 636Photo */
 	{ USB_DEVICE(0x04b8, 0x0102) }, /* GT-2200 */
diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c	Thu Jul 10 05:14:03 2003
+++ b/drivers/usb/serial/ftdi_sio.c	Wed Aug 20 03:59:43 2003
@@ -17,6 +17,20 @@
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *	and extra documentation
  *
+ * (19/Aug/2003) Ian Abbott
+ *      Omitted some paranoid checks in write bulk callback that don't matter.
+ *
+ * (05/Aug/2003) Ian Abbott
+ *      Added VID/PID for ID TECH IDT1221U USB to RS-232 adapter.
+ *      VID/PID provided by Steve Briggs.
+ *
+ * (23/Jul/2003) Ian Abbott
+ *      Added PIDs for CrystalFontz 547, 633, 631, 635, 640 and 640 from
+ *      Wayne Wylupski.
+ *
+ * (10/Jul/2003) David Glance
+ *      Added PID for DSS-20 SyncStation cradle for Sony-Ericsson P800.
+ *
  * (23/Jun/2003) Ian Abbott
  *      Reduced flip buffer pushes and corrected a data length test in
  *      ftdi_read_bulk_callback.
@@ -247,8 +261,14 @@
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) },
-	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0, 0x3ff) },
@@ -304,6 +324,7 @@
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0, 0x3ff) },
 	{ }						/* Terminating entry */
 };
 
@@ -312,8 +333,14 @@
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) },
-	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
@@ -369,6 +396,7 @@
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0x400, 0xffff) },
 	{ }						/* Terminating entry */
 };
 
@@ -389,8 +417,14 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
-	{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_XF_633_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_XF_631_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_XF_635_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
 	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
@@ -447,6 +481,7 @@
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
+	{ USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) },
 	{ USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
 	{ }						/* Terminating entry */
@@ -1419,33 +1454,21 @@
 static void ftdi_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
-
-	dbg("%s", __FUNCTION__);
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
+	dbg("%s - port %d", __FUNCTION__, port->number);
+	
 	if (urb->status) {
 		dbg("nonzero write bulk status received: %d", urb->status);
 		return;
 	}
 
-	serial = get_usb_serial (port, __FUNCTION__);
-	if (!serial) {
-		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
-		return;
-	}
-
-	/* Have to check for validity of queueing up the tasks */
-	dbg("%s - port->open_count = %d", __FUNCTION__, port->open_count);
-
  	if (port->open_count > 0){
 		queue_task(&port->tqueue, &tq_immediate);
 		mark_bh(IMMEDIATE_BH);
-	} 
-
-	return;
+	}
 } /* ftdi_write_bulk_callback */
 
 
diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
--- a/drivers/usb/serial/ftdi_sio.h	Thu Jul 10 05:11:54 2003
+++ b/drivers/usb/serial/ftdi_sio.h	Thu Aug  7 04:51:09 2003
@@ -32,8 +32,14 @@
 
 /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
 /* they use the ftdi chipset for the USB interface and the vendor id is the same */
-#define FTDI_XF_634_PID  0xFC09	/* Four line device */
-#define FTDI_XF_632_PID  0xFC08	/* Two line device */
+#define FTDI_XF_632_PID 0xFC08	/* 632: 16x2 Character Display */
+#define FTDI_XF_634_PID 0xFC09	/* 634: 20x4 Character Display */
+#define FTDI_XF_547_PID 0xFC0A	/* 547: Two line Display */
+#define FTDI_XF_633_PID 0xFC0B	/* 633: 16x2 Character Display with Keys */
+#define FTDI_XF_631_PID 0xFC0C	/* 631: 20x2 Character Display */
+#define FTDI_XF_635_PID 0xFC0D	/* 635: 20x4 Character Display */
+#define FTDI_XF_640_PID 0xFC0E	/* 640: Two line Display */
+#define FTDI_XF_642_PID 0xFC0F	/* 642: Two line Display */
 
 /* Video Networks Limited / Homechoice in the UK use an ftdi-based device for their 1Mb */
 /* broadband internet service.  The following PID is exhibited by the usb device supplied */
@@ -120,6 +126,12 @@
 /* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */
 /* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
 #define FTDI_USB_UIRT_PID	0xF850	/* Product Id */
+
+/*
+ * Definitions for ID TECH (www.idt-net.com) devices
+ */
+#define IDTECH_VID		0x0ACD	/* ID TECH Vendor ID */
+#define IDTECH_IDT1221U_PID	0x0300	/* IDT1221U USB to RS-232 adapter */
 
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
diff -Nru a/drivers/usb/serial/io_16654.h b/drivers/usb/serial/io_16654.h
--- a/drivers/usb/serial/io_16654.h	Thu Dec  5 06:07:15 2002
+++ b/drivers/usb/serial/io_16654.h	Thu Aug 28 04:13:49 2003
@@ -2,7 +2,7 @@
  *
  *	16654.H		Definitions for 16C654 UART used on EdgePorts
  *
- *	Copyright (c) 1998 Inside Out Networks, Inc.
+ *	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
diff -Nru a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
--- a/drivers/usb/serial/io_edgeport.c	Tue Jun 24 07:30:06 2003
+++ b/drivers/usb/serial/io_edgeport.c	Thu Aug 28 04:13:49 2003
@@ -1,8 +1,8 @@
 /*
  * Edgeport USB Serial Converter driver
  *
- * Copyright(c) 2000 Inside Out Networks, All rights reserved.
- * Copyright(c) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2000 Inside Out Networks, All rights reserved.
+ * Copyright (C) 2001-2002 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
diff -Nru a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h
--- a/drivers/usb/serial/io_edgeport.h	Thu Aug 29 10:53:13 2002
+++ b/drivers/usb/serial/io_edgeport.h	Thu Aug 28 04:13:49 2003
@@ -2,7 +2,7 @@
  *
  *	io_edgeport.h	Edgeport Linux Interface definitions
  *
- *	Copyright (c) 2000 Inside Out Networks, Inc.
+ *	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
diff -Nru a/drivers/usb/serial/io_fw_boot.h b/drivers/usb/serial/io_fw_boot.h
--- a/drivers/usb/serial/io_fw_boot.h	Thu Aug 29 10:53:13 2002
+++ b/drivers/usb/serial/io_fw_boot.h	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 //**************************************************************
 //* Edgeport/4 Binary Image
 //* Generated by HEX2C v1.06
-//* Copyright(c) 1998 Inside Out Networks, All rights reserved.
+//* 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
diff -Nru a/drivers/usb/serial/io_fw_boot2.h b/drivers/usb/serial/io_fw_boot2.h
--- a/drivers/usb/serial/io_fw_boot2.h	Thu Aug 29 10:53:13 2002
+++ b/drivers/usb/serial/io_fw_boot2.h	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 //**************************************************************
 //* Edgeport/4 Binary Image
 //* Generated by HEX2C v1.06
-//* Copyright(c) 1998 Inside Out Networks, All rights reserved.
+//* 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
diff -Nru a/drivers/usb/serial/io_fw_down.h b/drivers/usb/serial/io_fw_down.h
--- a/drivers/usb/serial/io_fw_down.h	Thu Aug 29 10:53:13 2002
+++ b/drivers/usb/serial/io_fw_down.h	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 //**************************************************************
 //* Edgeport/4 Binary Image
 //* Generated by HEX2C v1.06
-//* Copyright(c) 1998 Inside Out Networks, All rights reserved.
+//* 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
diff -Nru a/drivers/usb/serial/io_fw_down2.h b/drivers/usb/serial/io_fw_down2.h
--- a/drivers/usb/serial/io_fw_down2.h	Thu Aug 29 10:53:13 2002
+++ b/drivers/usb/serial/io_fw_down2.h	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 //**************************************************************
 //* Edgeport/4 Binary Image
 //* Generated by HEX2C v1.06
-//* Copyright(c) 1998 Inside Out Networks, All rights reserved.
+//* 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
diff -Nru a/drivers/usb/serial/io_fw_down3.h b/drivers/usb/serial/io_fw_down3.h
--- a/drivers/usb/serial/io_fw_down3.h	Thu Aug 29 10:53:14 2002
+++ b/drivers/usb/serial/io_fw_down3.h	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 //**************************************************************
 //* Edgeport Binary Image (for TI based products)
 //* Generated by TIBin2C v1.00
-//* Copyright(c) 2001 Inside Out Networks, All rights reserved.
+//* Copyright (C) 2001 Inside Out Networks, All rights reserved.
 //**************************************************************
 
 
diff -Nru a/drivers/usb/serial/io_ionsp.h b/drivers/usb/serial/io_ionsp.h
--- a/drivers/usb/serial/io_ionsp.h	Thu Aug 29 10:53:14 2002
+++ b/drivers/usb/serial/io_ionsp.h	Thu Aug 28 04:13:49 2003
@@ -2,7 +2,7 @@
  *
  *	IONSP.H		Definitions for I/O Networks Serial Protocol
  *
- *	Copyright (c) 1997-1998 Inside Out Networks, Inc.
+ *	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
diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
--- a/drivers/usb/serial/io_ti.c	Fri Mar 14 04:03:18 2003
+++ b/drivers/usb/serial/io_ti.c	Thu Aug 28 04:13:49 2003
@@ -1,8 +1,8 @@
 /*
  * Edgeport USB Serial Converter driver
  *
- * Copyright(c) 2000-2002 Inside Out Networks, All rights reserved.
- * Copyright(c) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2000-2002 Inside Out Networks, All rights reserved.
+ * Copyright (C) 2001-2002 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
@@ -126,6 +126,7 @@
 
 static struct usb_device_id edgeport_2port_id_table [] = {
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) },
@@ -144,6 +145,7 @@
 static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) },
diff -Nru a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h
--- a/drivers/usb/serial/io_ti.h	Thu Aug 29 10:53:44 2002
+++ b/drivers/usb/serial/io_ti.h	Thu Aug 28 04:13:49 2003
@@ -1,6 +1,6 @@
 /*****************************************************************************  
  *
- *	Copyright (c) 1997-2002 Inside Out Networks, Inc.
+ *	Copyright (C) 1997-2002 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
diff -Nru a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
--- a/drivers/usb/serial/io_usbvend.h	Thu Aug 29 10:53:14 2002
+++ b/drivers/usb/serial/io_usbvend.h	Thu Aug 28 04:13:49 2003
@@ -7,7 +7,7 @@
  *
  ************************************************************************
  *
- *	Copyright (c) 1998 Inside Out Networks, Inc.
+ *	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
@@ -118,6 +118,7 @@
 #define ION_DEVICE_ID_TI_EDGEPORT_1		0x0215	/* Edgeport/1 RS232 */
 #define ION_DEVICE_ID_TI_EDGEPORT_42		0x0217	/* Edgeport/42 4 hub 2 RS232 */
 #define ION_DEVICE_ID_TI_EDGEPORT_22		0x021A	/* Edgeport/22  Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 */
+#define ION_DEVICE_ID_TI_EDGEPORT_2C		0x021B	/* Edgeport/2c RS232 */
 
 #define ION_DEVICE_ID_TI_EDGEPORT_421_BOOT	0x0240	/* Edgeport/421 in boot mode */
 #define ION_DEVICE_ID_TI_EDGEPORT_421_DOWN	0x0241	/* Edgeport/421 in download mode first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */
diff -Nru a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
--- a/drivers/usb/serial/keyspan_pda.c	Thu Aug 29 10:55:14 2002
+++ b/drivers/usb/serial/keyspan_pda.c	Thu Aug 28 04:13:49 2003
@@ -1,9 +1,9 @@
 /*
  * USB Keyspan PDA / Xircom / Entregra Converter driver
  *
- * Copyright (c) 1999 - 2001 Greg Kroah-Hartman	<greg@kroah.com>
- * Copyright (c) 1999, 2000 Brian Warner	<warner@lothar.com>
- * Copyright (c) 2000 Al Borchers		<borchers@steinerpoint.com>
+ * Copyright (C) 1999 - 2001 Greg Kroah-Hartman	<greg@kroah.com>
+ * Copyright (C) 1999, 2000 Brian Warner	<warner@lothar.com>
+ * Copyright (C) 2000 Al Borchers		<borchers@steinerpoint.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
diff -Nru a/drivers/usb/serial/keyspan_pda_fw.h b/drivers/usb/serial/keyspan_pda_fw.h
--- a/drivers/usb/serial/keyspan_pda_fw.h	Mon Feb  4 23:40:21 2002
+++ b/drivers/usb/serial/keyspan_pda_fw.h	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 /*
  * USB Keyspan PDA Firmware
  *
- * Copyright (c) 1999, 2000 Brian Warner	<warner@lothar.com>
+ * Copyright (C) 1999, 2000 Brian Warner	<warner@lothar.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
diff -Nru a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h
--- a/drivers/usb/serial/keyspan_usa26msg.h	Thu Aug 29 10:56:43 2002
+++ b/drivers/usb/serial/keyspan_usa26msg.h	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 /*
 	usa26msg.h
 
-	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+	Copyright (C) 1998-2000 InnoSys Incorporated.  All Rights Reserved
 	This file is available under a BSD-style copyright
 
 	Keyspan USB Async Firmware to run on Anchor EZ-USB
@@ -15,7 +15,7 @@
    	disclaimer.  The following copyright notice must appear immediately at
    	the beginning of all source files:
 
-        	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+        	Copyright (C) 1998-2000 InnoSys Incorporated.  All Rights Reserved
 
         	This file is available under a BSD-style copyright
 
diff -Nru a/drivers/usb/serial/keyspan_usa28msg.h b/drivers/usb/serial/keyspan_usa28msg.h
--- a/drivers/usb/serial/keyspan_usa28msg.h	Thu Aug 29 10:56:43 2002
+++ b/drivers/usb/serial/keyspan_usa28msg.h	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 /*
 	usa28msg.h
 
-	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+	Copyright (C) 1998-2000 InnoSys Incorporated.  All Rights Reserved
 	This file is available under a BSD-style copyright
 
 	Keyspan USB Async Firmware to run on Anchor EZ-USB
@@ -15,7 +15,7 @@
    	disclaimer.  The following copyright notice must appear immediately at
    	the beginning of all source files:
 
-        	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+        	Copyright (C) 1998-2000 InnoSys Incorporated.  All Rights Reserved
 
         	This file is available under a BSD-style copyright
 
diff -Nru a/drivers/usb/serial/keyspan_usa49msg.h b/drivers/usb/serial/keyspan_usa49msg.h
--- a/drivers/usb/serial/keyspan_usa49msg.h	Thu Aug 29 10:56:43 2002
+++ b/drivers/usb/serial/keyspan_usa49msg.h	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 /*
 	usa49msg.h
 
-	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+	Copyright (C) 1998-2000 InnoSys Incorporated.  All Rights Reserved
 	This file is available under a BSD-style copyright
 
 	Keyspan USB Async Firmware to run on Anchor EZ-USB
@@ -15,7 +15,7 @@
    	disclaimer.  The following copyright notice must appear immediately at
    	the beginning of all source files:
 
-        	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+        	Copyright (C) 1998-2000 InnoSys Incorporated.  All Rights Reserved
 
         	This file is available under a BSD-style copyright
 
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c	Tue Jun 24 07:56:11 2003
+++ b/drivers/usb/serial/pl2303.c	Tue Aug  5 08:27:19 2003
@@ -59,7 +59,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.9"
+#define DRIVER_VERSION "v0.10"
 #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
 
@@ -266,12 +266,6 @@
 	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
 
-	i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
-			     VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
-			     0, 1, NULL, 0, 100);
-
-	dbg ("0x40:1:0:1  %d", i);
-
 	if (cflag & CSIZE) {
 		switch (cflag & CSIZE) {
 			case CS5:	buf[6] = 5;	break;
@@ -405,9 +399,6 @@
 	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
 	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
 	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0xc0);
-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
 
 	/* Setup termios */
 	if (port->tty) {
@@ -531,7 +522,9 @@
 	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
 		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
 		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
-		  | ((status & UART_DSR)	? TIOCM_DSR : 0);
+		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
+		  | ((status & UART_RING)	? TIOCM_RI  : 0)
+		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
 
 	dbg("%s - result = %x", __FUNCTION__, result);
 
@@ -618,7 +611,7 @@
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-	if (urb->actual_length > UART_STATE)
+	if (urb->actual_length < UART_STATE)
 		return;
 
 	/* Save off the uart status for others to look at */
diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c	Wed Jun 18 09:43:24 2003
+++ b/drivers/usb/serial/usbserial.c	Thu Aug 28 04:13:49 2003
@@ -2,8 +2,8 @@
  * USB Serial Converter driver
  *
  * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2000 Peter Berger (pberger@brimson.com)
- * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com)
+ * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
+ * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License version
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Fri Jun 27 09:58:20 2003
+++ b/drivers/usb/serial/visor.c	Thu Aug 28 08:22:11 2003
@@ -211,6 +211,7 @@
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
+	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -239,6 +240,7 @@
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
+	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h	Tue Mar 11 09:44:58 2003
+++ b/drivers/usb/serial/visor.h	Thu Aug 28 08:21:32 2003
@@ -44,6 +44,9 @@
 #define SAMSUNG_VENDOR_ID		0x04E8
 #define SAMSUNG_SCH_I330_ID		0x8001
 
+#define GARMIN_VENDOR_ID		0x091E
+#define GARMIN_IQUE_3600_ID		0x0004
+
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
  * A big thank you to Handspring for providing the following information.
diff -Nru a/drivers/usb/serial/xircom_pgs_fw.h b/drivers/usb/serial/xircom_pgs_fw.h
--- a/drivers/usb/serial/xircom_pgs_fw.h	Mon Feb  4 23:49:26 2002
+++ b/drivers/usb/serial/xircom_pgs_fw.h	Thu Aug 28 04:13:49 2003
@@ -1,8 +1,8 @@
 /*
  * USB Xircom PGS Firmware
  *
- * Copyright (c) 1999, 2000 Brian Warner        <warner@lothar.com>
- * Copyright (c) 2001 Cristian M. Craciunescu	<cristi@dnt.ro>
+ * Copyright (C) 1999, 2000 Brian Warner        <warner@lothar.com>
+ * Copyright (C) 2001 Cristian M. Craciunescu	<cristi@dnt.ro>
  *
  *      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
diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h	Wed Jul  2 05:27:36 2003
+++ b/drivers/usb/storage/unusual_devs.h	Wed Aug 27 03:03:51 2003
@@ -119,7 +119,7 @@
 UNUSUAL_DEV(  0x04cb, 0x0100, 0x0000, 0x2210,
 		"Fujifilm",
 		"FinePix 1400Zoom",
-		US_SC_8070, US_PR_CBI, NULL, US_FL_FIX_INQUIRY),
+		US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
 
 /* Reported by Peter Wächtler <pwaechtler@loewe-komp.de>
  * The device needs the flags only.
@@ -236,7 +236,7 @@
 UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0450, 
 		"Sony",
 		"DSC-S30/S70/S75/505V/F505/F707/F717/P8", 
-		US_SC_SCSI, US_PR_CB, NULL,
+		US_SC_SCSI, US_PR_DEVICE, NULL,
 		US_FL_SINGLE_LUN | US_FL_MODE_XLATE ),
 
 /* Reported by wim@geeks.nl */
@@ -264,7 +264,7 @@
 UNUSUAL_DEV(  0x054c, 0x002e, 0x0106, 0x0310, 
 		"Sony",
 		"Handycam",
-		US_SC_SCSI, US_PR_CB, NULL,
+		US_SC_SCSI, US_PR_DEVICE, NULL,
 		US_FL_SINGLE_LUN | US_FL_MODE_XLATE),
 
 UNUSUAL_DEV(  0x054c, 0x0032, 0x0000, 0x9999,
@@ -388,6 +388,12 @@
 		US_FL_SINGLE_LUN ),
 #endif
 
+/* Submitted by Benny Sjostrand <benny@hostmobility.com> */
+UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
+		"Minolta",
+		"Dimage F300",
+		US_SC_SCSI, US_PR_BULK, NULL, 0 ),
+
 UNUSUAL_DEV(  0x0693, 0x0002, 0x0100, 0x0100, 
 		"Hagiwara",
 		"FlashGate SmartMedia",
@@ -407,7 +413,7 @@
 UNUSUAL_DEV(  0x0781, 0x0002, 0x0009, 0x0009, 
 		"Sandisk",
 		"ImageMate SDDR-31",
-		US_SC_SCSI, US_PR_BULK, NULL,
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_SER ),
 
 UNUSUAL_DEV(  0x0781, 0x0100, 0x0100, 0x0100,
@@ -555,7 +561,7 @@
 UNUSUAL_DEV(  0x08ca, 0x2011, 0x0000, 0x9999,
 		"AIPTEK",
 		"PocketCAM 3Mega",
-		US_SC_SCSI, US_PR_BULK, NULL,
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_MODE_XLATE ),
 
 /* aeb */
@@ -604,6 +610,13 @@
 		US_SC_ISD200, US_PR_BULK, isd200_Initialization,
 		0 ),
 #endif
+
+/* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
+UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
+		"USB",
+		"Solid state disk",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
 
 /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
  * Tested on hardware version 1.10.
diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
--- a/drivers/usb/usb-skeleton.c	Thu Jan  9 13:03:34 2003
+++ b/drivers/usb/usb-skeleton.c	Thu Aug 28 04:13:49 2003
@@ -1,7 +1,7 @@
 /*
  * USB Skeleton driver - 0.7
  *
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * 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
diff -Nru a/drivers/usb/usb.c b/drivers/usb/usb.c
--- a/drivers/usb/usb.c	Mon Jul  7 08:23:35 2003
+++ b/drivers/usb/usb.c	Mon Aug 19 09:49:38 2002
@@ -195,6 +195,17 @@
 	up (&usb_bus_list_lock);
 }
 
+int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum)
+{
+	int i;
+
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+		if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum)
+			return i;
+
+	return -EINVAL;
+}
+
 struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
 {
 	int i;
@@ -759,6 +770,23 @@
 	return -1;
 }
 
+/*
+ * This simply converts the interface _number_ (as in interface.bInterfaceNumber) and
+ * converts it to the interface _position_ (as in dev->actconfig->interface + position)
+ * and calls usb_find_interface_driver().
+ *
+ * Note that the number is the same as the position for all interfaces _except_
+ * devices with interfaces not sequentially numbered (e.g., 0, 2, 3, etc).
+ */
+int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned ifnum)
+{
+	int ifpos = usb_ifnum_to_ifpos(dev, ifnum);
+
+	if (0 > ifpos)
+		return -EINVAL;
+
+	return usb_find_interface_driver(dev, ifpos);
+}
 
 #ifdef	CONFIG_HOTPLUG
 
@@ -2384,6 +2412,7 @@
  * into the kernel, and other device drivers are built as modules,
  * then these symbols need to be exported for the modules to use.
  */
+EXPORT_SYMBOL(usb_ifnum_to_ifpos);
 EXPORT_SYMBOL(usb_ifnum_to_if);
 EXPORT_SYMBOL(usb_epnum_to_ep_desc);
 
@@ -2398,6 +2427,7 @@
 EXPORT_SYMBOL(usb_free_dev);
 EXPORT_SYMBOL(usb_inc_dev_use);
 
+EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum);
 EXPORT_SYMBOL(usb_driver_claim_interface);
 EXPORT_SYMBOL(usb_interface_claimed);
 EXPORT_SYMBOL(usb_driver_release_interface);
diff -Nru a/drivers/usb/usbnet.c b/drivers/usb/usbnet.c
--- a/drivers/usb/usbnet.c	Mon Jul  7 11:20:41 2003
+++ b/drivers/usb/usbnet.c	Mon Jul 28 15:48:09 2003
@@ -1391,27 +1391,8 @@
 };
 
 /* PXA-2xx based */
-static const struct driver_info	zaurus_sla300_info = {
-	.description =	"Sharp Zaurus SL-A300",
-	.flags =	FLAG_FRAMING_Z,
-	.check_connect = always_connected,
-	.tx_fixup = 	zaurus_tx_fixup,
-
-	.in = 1, .out = 2,
-	.epsize = 64,
-};
-static const struct driver_info	zaurus_slb500_info = {
-	/* Japanese B500 ~= US SL-5600 */
-	.description =	"Sharp Zaurus SL-B500",
-	.flags =	FLAG_FRAMING_Z,
-	.check_connect = always_connected,
-	.tx_fixup = 	zaurus_tx_fixup,
-
-	.in = 1, .out = 2,
-	.epsize = 64,
-};
-static const struct driver_info	zaurus_slc700_info = {
-	.description =	"Sharp Zaurus SL-C700",
+static const struct driver_info zaurus_pxa_info = {
+	.description =	"Sharp Zaurus, PXA-2xx based",
 	.flags =	FLAG_FRAMING_Z,
 	.check_connect = always_connected,
 	.tx_fixup = 	zaurus_tx_fixup,
@@ -2388,29 +2369,38 @@
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE, 
 	.idVendor		= 0x04DD,
-	.idProduct		= 0x8005,
+	.idProduct		= 0x8005, /* A-300 */
 	.bInterfaceClass	= 0x02,
 	.bInterfaceSubClass	= 0x0a,
 	.bInterfaceProtocol	= 0x00,
-	.driver_info =  (unsigned long) &zaurus_sla300_info,
+	.driver_info =  (unsigned long) &zaurus_pxa_info,
 }, {
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE, 
 	.idVendor		= 0x04DD,
-	.idProduct		= 0x8006,
+	.idProduct		= 0x8006, /* B-500/SL-5600 */
 	.bInterfaceClass	= 0x02,
 	.bInterfaceSubClass	= 0x0a,
 	.bInterfaceProtocol	= 0x00,
-	.driver_info =  (unsigned long) &zaurus_slb500_info,
+	.driver_info =  (unsigned long) &zaurus_pxa_info,
 }, {
 	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
 			  | USB_DEVICE_ID_MATCH_DEVICE, 
 	.idVendor		= 0x04DD,
-	.idProduct		= 0x8007,
+	.idProduct		= 0x8007, /* C-700 */
+	.bInterfaceClass	= 0x02,
+	.bInterfaceSubClass	= 0x0a,
+	.bInterfaceProtocol	= 0x00,
+	.driver_info =  (unsigned long) &zaurus_pxa_info,
+}, {
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x9031, /* C-750 C-760 */
 	.bInterfaceClass	= 0x02,
 	.bInterfaceSubClass	= 0x0a,
 	.bInterfaceProtocol	= 0x00,
-	.driver_info =  (unsigned long) &zaurus_slc700_info,
+	.driver_info =	(unsigned long) &zaurus_pxa_info,
 },
 #endif
 
diff -Nru a/drivers/video/Config.in b/drivers/video/Config.in
--- a/drivers/video/Config.in	Fri Jul  4 20:50:50 2003
+++ b/drivers/video/Config.in	Fri Aug 29 04:10:45 2003
@@ -96,6 +96,9 @@
       tristate '  Hercules mono graphics console (EXPERIMENTAL)' CONFIG_FB_HGA
       define_bool CONFIG_VIDEO_SELECT y
    fi
+   if [ "$CONFIG_IA64" = "y" ]; then
+      tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
+   fi
    if [ "$CONFIG_VISWS" = "y" ]; then
       tristate '  SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
       define_bool CONFIG_BUS_I2C y
@@ -148,10 +151,10 @@
  	 tristate '  ATI Radeon display support (EXPERIMENTAL)' CONFIG_FB_RADEON
 	 tristate '  ATI Rage128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
 	 tristate '  Intel 830M/845G/852GM/855GM/865G display support (EXPERIMENTAL)' CONFIG_FB_INTEL 
-	 tristate '  SIS acceleration (EXPERIMENTAL)' CONFIG_FB_SIS
+	 tristate '  SIS display support (EXPERIMENTAL)' CONFIG_FB_SIS
 	 if [ "$CONFIG_FB_SIS" != "n" ]; then
-	    bool '    SIS 630/540/730 support' CONFIG_FB_SIS_300
-	    bool '    SIS 315H/315 support' CONFIG_FB_SIS_315
+	    bool '    SIS 300 series support' CONFIG_FB_SIS_300
+	    bool '    SIS 315/330 series support' CONFIG_FB_SIS_315
 	 fi
 	 tristate '  NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
 	 tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
diff -Nru a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
--- a/drivers/video/fbcmap.c	Mon Feb  4 23:38:15 2002
+++ b/drivers/video/fbcmap.c	Mon Mar 17 09:39:59 2003
@@ -271,7 +271,7 @@
 	    hred = *red;
 	    hgreen = *green;
 	    hblue = *blue;
-	    htransp = transp ? *transp : 0;
+	    htransp = transp ? *transp : 0xffff;
 	} else {
 	    get_user(hred, red);
 	    get_user(hgreen, green);
@@ -279,7 +279,7 @@
 	    if (transp)
 		get_user(htransp, transp);
 	    else
-		htransp = 0;
+		htransp = 0xffff;
 	}
 	red++;
 	green++;
diff -Nru a/drivers/video/sis/300vtbl.h b/drivers/video/sis/300vtbl.h
--- a/drivers/video/sis/300vtbl.h	Sun Jun 29 08:10:19 2003
+++ b/drivers/video/sis/300vtbl.h	Fri Jul 11 09:57:14 2003
@@ -29,6 +29,8 @@
  *
  * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
  *
+ * Based on code by Silicon Intergrated Systems
+ *
  */
 
 typedef struct _SiS300_StStruct
@@ -242,10 +244,10 @@
 	{0x0047,0x3e,0x34,0x06,0x29,1152, 864}, /* 36 1152x864-75Hz */
 	{0x0047,0x44,0x3a,0x06,0x29,1152, 864}, /* 37 1152x864-85Hz */
 	{0x00c7,0x3f,0x28,0x00,0x39, 848, 480}, /* 38 848x480-38Hzi */
-	{0xc047,0x40,0x3d,0x00,0x39, 848, 480}, /* 39 848x480-60Hz  */
+	{0xc067,0x40,0x3d,0x0b,0x39, 848, 480}, /* 39 848x480-60Hz  */
 	{0x00c7,0x41,0x28,0x00,0x3f, 856, 480}, /* 3a 856x480-38Hzi */
 	{0xc047,0x42,0x28,0x00,0x3f, 856, 480}, /* 3b 856x480-60Hz  */
-	{0x0047,0x43,0x3e,0x00,0x48,1360, 768}, /* 3c 1360x768-60Hz */
+	{0x0067,0x43,0x3e,0x0c,0x48,1360, 768}, /* 3c 1360x768-60Hz */
 	{0x0077,0x46,0x3f,0x08,0x55,1280, 768}, /* 3d 1280x768-60Hz */
 	{0x000f,0x47,0x03,0x06,0x5f, 768, 576}, /* 3e 768x576 */
 	{0x0027,0x48,0x13,0x08,0x67,1360,1024}, /* 3f 1360x1024-59Hz (BARCO1366 only) */
@@ -690,19 +692,19 @@
 	{ 0x31,0xc2, 39}, /* 0x27 */
 	{ 0xbf,0xc8, 35}, /* 0x28 */  /* 856x480 */
 	{ 0x60,0x36, 30}, /* 0x29 */  /* CH/UNTSC TEXT | LVDS_2(CH) - 730, A901(301B), Mitac(CH): 0xe0, 0xb6, 30 */
-	{ 0x40,0x4a, 28}, /* 0x2a */
-	{ 0x9f,0x46, 44}, /* 0x2b */
-	{ 0x97,0x2c, 26}, /* 0x2c */
-	{ 0x44,0xe4, 25}, /* 0x2d */
-	{ 0x7e,0x32, 47}, /* 0x2e */
+	{ 0x40,0x4a, 28}, /* 0x2a */  /* CH-TV */
+	{ 0x9f,0x46, 44}, /* 0x2b */  /* CH-TV */
+	{ 0x97,0x2c, 26}, /* 0x2c */  /* CH-TV */
+	{ 0x44,0xe4, 25}, /* 0x2d */  /* CH-TV */
+	{ 0x7e,0x32, 47}, /* 0x2e */  /* CH-TV */
 	{ 0x8a,0x24, 31}, /* 0x2f */  /* CH/PAL TEXT | LVDS_2(CH), Mitac(CH) -  730, A901(301B): 0x57, 0xe4, 31 */
-	{ 0x97,0x2c, 26}, /* 0x30 */
-	{ 0xce,0x3c, 39}, /* 0x31 */
+	{ 0x97,0x2c, 26}, /* 0x30 */  /* CH-TV */
+	{ 0xce,0x3c, 39}, /* 0x31 */  /* CH-TV */
 	{ 0x52,0x4a, 36}, /* 0x32 */  /* CH/PAL 800x600 5/6 */
 	{ 0x34,0x61, 95}, /* 0x33 */
 	{ 0x78,0x27,108}, /* 0x34 */  /* Replacement for index 0x14 for 630 (?) */
 	{ 0xce,0x25,189}, /* 0x35 */  /* Replacement for index 0x1b for 730 (and 540?) */
-	{ 0x45,0x6b, 21}, /* 0x36 */
+	{ 0x45,0x6b, 21}, /* 0x36 */  /* Chrontel SuperOverscan */
 	{ 0x52,0xe2, 49}, /* 0x37 */  /* 16:9 modes  */
 	{ 0x2b,0x61, 78}, /* 0x38 */  /* 16:9 modes  */
 	{ 0x70,0x44,108}, /* 0x39 */  /* 16:9 modes  */
@@ -2078,7 +2080,7 @@
 
 static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_SOPAL[] =
 {
-	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 5/4 */
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */
 	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
 	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
 	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
diff -Nru a/drivers/video/sis/310vtbl.h b/drivers/video/sis/310vtbl.h
--- a/drivers/video/sis/310vtbl.h	Sun Jun 29 08:10:19 2003
+++ b/drivers/video/sis/310vtbl.h	Wed Aug  6 10:22:32 2003
@@ -29,6 +29,8 @@
  *
  * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
  *
+ * Based on code by Silicon Intergrated Systems
+ *
  */
 
 typedef struct _SiS310_StStruct
@@ -117,8 +119,8 @@
 	{0x5a,0x021b,0x0014,0x0138,SIS_RI_320x240,  0x00,0x00,0x04,0x3f}, /* 320x240x8  fstn */
 	{0x5b,0x0a1d,0x0014,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x3f}, /* 320x240x16 fstn */
 	{0x5c,0xba1f,0x0204,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x28}, /* 512x384x32 */
-	{0x5d,0x0a1d,0x0305,0x0139,SIS_RI_640x400,  0x00,0x00,0x07,0x10},
-	{0x5e,0x0a1f,0x0305,0x0000,SIS_RI_640x400,  0x00,0x00,0x07,0x10}, /* 640x400x32 */
+	{0x5d,0x0a1d,0x0305,0x0139,SIS_RI_640x400,  0x00,0x00,0x05,0x10},
+	{0x5e,0x0a1f,0x0305,0x0000,SIS_RI_640x400,  0x00,0x00,0x05,0x10}, /* 640x400x32 */
 	{0x62,0x0a3f,0x0306,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x08}, /* 640x480x32 */
 	{0x63,0x2a3f,0x0407,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x00}, /* 800x600x32 */
 	{0x64,0x0a7f,0x0508,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x13}, /* 1024x768x32 */
@@ -163,9 +165,9 @@
 	{0x4f,0x9a1f,0x0000,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x25}, /* 320x200x32 */
 	{0x53,0x9a1f,0x0001,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x26}, /* 320x240x32 */
 	{0x54,0xba1f,0x0103,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x27}, /* 400x300x32 */
-	{0x5f,0x2a1b,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x4a}, /* 768x576x8 */
-	{0x60,0x2a1d,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x4a}, /* 768x576x16 */
-	{0x61,0x2a1f,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x4a}, /* 768x576x32 */
+	{0x5f,0x2a1b,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x4a}, /* 768x576x8 */
+	{0x60,0x2a1d,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x4a}, /* 768x576x16 */
+	{0x61,0x2a1f,0x0f0e,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x4a}, /* 768x576x32 */
 	{0xff,0x0000,0x0000,0x0000,0x00,            0x00,0x00,0x00,0x00}
 };
 
@@ -252,10 +254,10 @@
 	{0x0047,0x44,0x19,0x00,0x29,1152, 864}, /* 0x43 TW: Non-BIOS, new */
 	{0x0047,0x4a,0x1e,0x00,0x29,1152, 864}, /* 0x44 TW: Non-BIOS, new */
 	{0x00c7,0x45,0x57,0x00,0x39, 848, 480}, /* 0x45 TW: 848x480-38Hzi - Non-BIOS, new */
-	{0xc047,0x46,0x55,0x00,0x39, 848, 480}, /* 0x46 TW: 848x480-60Hz  - Non-BIOS, new */
+	{0xc067,0x46,0x55,0x0b,0x39, 848, 480}, /* 0x46 TW: 848x480-60Hz  - Non-BIOS, new */
 	{0x00c7,0x47,0x57,0x00,0x3f, 856, 480}, /* 0x47 TW: 856x480-38Hzi - Non-BIOS, new */
 	{0xc047,0x48,0x57,0x00,0x3f, 856, 480}, /* 0x48 TW: 856x480-60Hz  - Non-BIOS, new */
-	{0x0047,0x49,0x58,0x00,0x48,1360, 768}, /* 0x49 TW: 1360x768-60Hz - Non-BIOS, new */
+	{0x0067,0x49,0x58,0x0c,0x48,1360, 768}, /* 0x49 TW: 1360x768-60Hz - Non-BIOS, new */
 	{0x000f,0x4d,0x03,0x06,0x5f, 768, 576}, /* 0x4a TW: 768x576 */
 	{0xffff,0x00,0x00,0x00,0x00,   0,   0}
 };
@@ -925,7 +927,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-static const SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[] = 
+static const SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[] =
 {
 	{  211,  60,1024, 501,1688,1066},
 	{  211,  60,1024, 508,1688,1066},
@@ -962,7 +964,7 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-static const SiS310_LCDDataStruct  SiS310_NoScaleData1280x1024[] =  
+static const SiS310_LCDDataStruct  SiS310_NoScaleData1280x1024[] =
 {
         {    1,   1,1688,1066,1688,1066},
 	{    1,   1,1688,1066,1688,1066},
@@ -975,6 +977,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
+
 typedef struct _SiS310_PanelDelayTblStruct
 {
  	UCHAR timer[2];
@@ -1591,16 +1594,17 @@
 };
 
 static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_1[] =
-{	/* TW: Temporary data, invalid */
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+{
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}
 };
 
 static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_2[] =
@@ -1611,8 +1615,8 @@
  {{0x2c,0x12,0x38,0x55,0x2f,0xc1,0x35,0xb1,0x47,0xe9,0x71,0x33}},
  {{0x2d,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
  {{0x29,0x12,0xb5,0xd2,0xac,0xe9,0x35,0xd9,0x47,0x11,0x99,0x33}},
- {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},  /* old  */
-/* 0x36,0x13,0x02,0x25,0xff,0x03,0x45,0x09,0x07,0xf9,0x00,0x24        new? */
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},  /* others  */
+/* 0x36,0x13,0x02,0x25,0xff,0x03,0x45,0x09,0x07,0xf9,0x00,0x24        my      */
  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
 };
@@ -1644,22 +1648,23 @@
 };
 
 static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_2[] =
-{	/* TW: Temporary data, invalid */
- {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x33,0x13,0x01,0x0d,0xfd,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x3f,0x1b,0x3d,0x49,0x39,0x54,0x23,0xc0,0x27,0x66,0x30,0x42}},
- {{0x33,0x1b,0x91,0x9d,0x8d,0x8c,0x23,0xf8,0x27,0x9e,0x68,0x42}},
- {{0x43,0x24,0x11,0x1d,0x0d,0xcc,0x23,0x38,0x37,0xde,0xa8,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+{
+ {{0x32,0x1B,0x2C,0x52,0x20,0x80,0x20,0x52,0x30,0xA3,0x3A,0x02}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x32,0x1B,0x2C,0x52,0x20,0x80,0x20,0x52,0x30,0xA3,0x3A,0x02}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x3A,0x1B,0x54,0x7A,0x48,0x80,0x24,0x52,0x30,0xA3,0x3A,0x02}},
+ {{0x36,0x1B,0x90,0xB6,0x84,0xA8,0x24,0x7A,0x30,0xCB,0x62,0x02}},
+ {{0x3A,0x1C,0xE4,0x0A,0xD8,0xE0,0x24,0xB2,0x30,0x03,0x9A,0x02}},
+ {{0x4A,0x24,0x64,0x8A,0x58,0x20,0x34,0xF2,0x30,0x43,0xDA,0x52}},
+ {{0x47,0x24,0x71,0x97,0x65,0x3E,0x34,0x10,0x40,0x61,0xF8,0x02}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}
 };
 
 
 static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_3[] =
-{	/* TW: Data from 650/301LVx 1.10.6s */
-#if 0
+{
+#if 1   /* Data from 650/301LVx 1.10.6s and others */
  {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
  {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
  {{0x25,0x13,0xc9,0x24,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
@@ -1669,8 +1674,9 @@
  {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
  {{0x25,0x13,0xc9,0x25,0xff,0xf9,0x45,0x09,0x07,0xf9,0x09,0x24}}
-#endif	/* Data from my 301LV */
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},   /* @@@@@ TEST */
+#endif
+#if 0    /* Data from my 301LV */
+ {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},   /* TEST */
  {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
  {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
  {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
@@ -1679,6 +1685,7 @@
  {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
  {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
  {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}
+#endif
 };
 
 /*   1     2    4    5    6   1c   1d   1f   20   21   23   25   */
@@ -1708,16 +1715,17 @@
 };
 
 static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_3[] =
-{	/* TW: Temporary data, invalid */
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
+{
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
+ {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}
 };
 
 typedef struct _SiS310_LCDACRT1DataStruct
diff -Nru a/drivers/video/sis/init.c b/drivers/video/sis/init.c
--- a/drivers/video/sis/init.c	Sun Jun 29 08:10:19 2003
+++ b/drivers/video/sis/init.c	Thu Aug 28 16:19:27 2003
@@ -1,6 +1,7 @@
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init.c,v 1.3 2002/24/04 01:16:16 dawes Exp $ */
 /*
- * Mode switching code (CRT1 section) for SiS 300/540/630/730/315/550/650/740/330/660
+ * Mode switching code (CRT1 section) for
+ * SiS 300/540/630/730/315/550/650/M650/651/M652/740/330/660/M660/760
  * (Universal module for Linux kernel framebuffer and XFree86 4.x)
  *
  * Assembler-To-C translation
@@ -62,10 +63,6 @@
 #endif /* dual head */
 #endif /* linux_xf86 */
 
-#ifdef LINUXBIOS
-BOOLEAN SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
-#endif
-
 #ifdef LINUX_XF86
 BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
                    ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch);
@@ -74,14 +71,16 @@
                    USHORT ModeNo);
 #endif
 
+#ifndef LINUX_XF86
+static ULONG GetDRAMSize(SiS_Private *SiS_Pr,
+                         PSIS_HW_DEVICE_INFO HwDeviceExtension);
+#endif
+
 #if defined(ALLOC_PRAGMA)
 #pragma alloc_text(PAGE,SiSSetMode)
 #pragma alloc_text(PAGE,SiSInit)
 #endif
 
-static ULONG GetDRAMSize(SiS_Private *SiS_Pr,
-                         PSIS_HW_DEVICE_INFO HwDeviceExtension);
-
 static void
 InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
@@ -219,6 +218,8 @@
    SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS_LVDSBARCO1366Data_2;
    SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS_LVDSBARCO1024Data_1;
    SiS_Pr->SiS_LVDSBARCO1024Data_2 = SiS_LVDSBARCO1024Data_2;
+   SiS_Pr->SiS_LVDS848x480Data_1   = SiS_LVDS848x480Data_1;
+   SiS_Pr->SiS_LVDS848x480Data_2   = SiS_LVDS848x480Data_2;
 
    SiS_Pr->SiS_LCDA1400x1050Data_1 = SiS_LCDA1400x1050Data_1;
    SiS_Pr->SiS_LCDA1400x1050Data_2 = SiS_LCDA1400x1050Data_2;
@@ -463,8 +464,8 @@
    SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS310_CRT1Table;
    /* TW: MCLK is different */
 #ifdef LINUXBIOS
-   if(HwDeviceExtension->jChipType == SIS_660) {
-      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_660;  /* 660 */
+   if(HwDeviceExtension->jChipType >= SIS_660) {
+      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_660;  /* 660/760 */
    } else if(HwDeviceExtension->jChipType == SIS_330) {
 #endif
       SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_330;  /* 330 */
@@ -665,1227 +666,6 @@
 }
 #endif
 
-#ifdef LINUXBIOS
-/* -------------- SiSInit -----------------*/
-/* TW: I degraded this for LINUXBIOS only, because we
- *     don't need this otherwise. Under normal
- *     circumstances, the video BIOS has initialized
- *     the adapter for us. BTW, this code is incomplete
- *     and very possibly not working on newer chipsets.
- */
-BOOLEAN
-SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
-   ULONG   FBAddr   = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
-   USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
-   UCHAR   i, temp=0;
-   UCHAR   SR11;
-#ifdef LINUX_KERNEL
-   UCHAR   temp1;
-   ULONG   base;
-#endif
-   UCHAR   SR13=0, SR14=0, SR16=0
-   UCHAR   SR17=0, SR19=0, SR1A=0;
-#ifdef SIS300
-   UCHAR   SR18=0, SR12=0;
-#endif
-#ifdef SIS315H
-   UCHAR   CR37=0, CR38=0, CR79=0,
-   UCHAR   CR7A=0, CR7B=0, CR7C=0;
-   UCHAR   SR1B=0, SR15=0;
-   PSIS_DSReg pSR;
-   ULONG   Temp;
-#endif
-   UCHAR   VBIOSVersion[5];
-
-   if(FBAddr==0)    return (FALSE);
-   if(BaseAddr==0)  return (FALSE);
-
-   SiS_SetReg3((USHORT)(BaseAddr+0x12),  0x67);  /* Misc */
-
-#ifdef SIS315H
-   if(HwDeviceExtension->jChipType > SIS_315PRO) {
-     if(!HwDeviceExtension->bIntegratedMMEnabled)
-     	return (FALSE);
-   }
-#endif
-
-   SiS_MemoryCopy(VBIOSVersion,HwDeviceExtension->szVBIOSVer,4);
-   VBIOSVersion[4]= 0x00;
-
-   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
-
-   /* TW: Init pointers */
-#ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H) ||
-      (HwDeviceExtension->jChipType == SIS_315) ||
-      (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_550) ||
-      (HwDeviceExtension->jChipType == SIS_650) ||
-      (HwDeviceExtension->jChipType == SIS_740) ||
-      (HwDeviceExtension->jChipType == SIS_330) ||
-      (HwDeviceExtension->jChipType == SIS_660))
-     InitTo310Pointer(SiS_Pr, HwDeviceExtension);
-#endif
-
-#ifdef SIS300
-   if((HwDeviceExtension->jChipType == SIS_540) ||
-      (HwDeviceExtension->jChipType == SIS_630) ||
-      (HwDeviceExtension->jChipType == SIS_730) ||
-      (HwDeviceExtension->jChipType == SIS_300))
-     InitTo300Pointer(SiS_Pr, HwDeviceExtension);
-#endif
-
-   /* TW: Set SiS Register definitions */
-   SiSRegInit(SiS_Pr, BaseAddr);
-
-   /* TW: Determine LVDS/CH70xx/TRUMPION */
-   SiS_Set_LVDS_TRUMPION(SiS_Pr, HwDeviceExtension);
-
-   /* TW: Unlock registers */
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
-
-#ifdef LINUX_KERNEL
-
-#ifdef SIS300                                         	/* Set SR14 */
-   if((HwDeviceExtension->jChipType==SIS_540) ||
-      (HwDeviceExtension->jChipType==SIS_630) ||
-      (HwDeviceExtension->jChipType==SIS_730)) {
-     base=0x80000060;
-     OutPortLong(base,0xcf8);
-     temp1 = InPortLong(0xcfc);
-     temp1 >>= (16+8+4);
-     temp1 &= 0x07;
-     temp1++;
-     temp1 = 1 << temp1;
-     SR14 = temp1 - 1;
-     base = 0x80000064;
-     OutPortLong(base,0xcf8);
-     temp1 = InPortLong(0xcfc);
-     temp1 &= 0x00000020;
-     if(temp1) 	SR14 |= 0x80;
-     else      	SR14 |= 0x40;
-   }
-#endif
-
-#ifdef SIS315H                                          /* Set SR14 */
-   if(HwDeviceExtension->jChipType == SIS_550) {
-     base = 0x80000060;
-     OutPortLong(base,0xcf8);
-     temp1 = InPortLong(0xcfc);
-     temp1 >>= (16+8+4);
-     temp1 &= 0x07;
-     temp1++;
-     temp1 = 1 << temp1;
-     SR14 = temp1 - 1;
-     base = 0x80000064;
-     OutPortLong(base,0xcf8);
-     temp1 = InPortLong(0xcfc);
-     temp1 &= 0x00000020;
-     if(temp1)  SR14 |= 0x80;
-     else       SR14 |= 0x40;
-   }
-
-   if((HwDeviceExtension->jChipType == SIS_740) ||     /* Set SR14 */
-      (HwDeviceExtension->jChipType == SIS_650))  {
-     base = 0x80000064;
-     OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1 >>= 4;
-     temp1 &= 0x07;
-     if(temp1 > 2) {
-       temp = temp1;
-       switch(temp) {
-        case 3: temp1 = 0x07;  break;
-        case 4: temp1 = 0x0F;  break;
-        case 5: temp1 = 0x1F;  break;
-        case 6: temp1 = 0x05;  break;
-        case 7: temp1 = 0x17;  break;
-        case 8: break;
-        case 9: break;
-       }
-     }
-     SR14 = temp1;
-     base = 0x8000007C;
-     OutPortLong(base,0xcf8);
-     temp1 = InPortLong(0xcfc);
-     temp1 &= 0x00000020;
-     if(temp1)  SR14 |= 0x80;
-   }
-#endif
-
-#endif  /* Linux kernel */
-
-#ifdef SIS300
-   if((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
-      (HwDeviceExtension->jChipType == SIS_730)) {
-     SR12 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x12);
-     SR13 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13);
-     SR14 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-     SR16 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
-     SR17 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17);
-     SR18 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
-     SR19 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x19);
-     SR1A = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
-   } else if(HwDeviceExtension->jChipType == SIS_300){
-     SR13 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13);
-     SR14 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-   }
-#endif
-#ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_550) ||
-      (HwDeviceExtension->jChipType == SIS_740) ||
-      (HwDeviceExtension->jChipType == SIS_650)) {
-     SR19 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x19);
-     SR19 = (SR19)||0x01;  /* TW: ??? || ??? */
-     if(SR19==0x00) {
-     	SR13 = 0x22;
-     	SR14 = 0x00;
-    	SR15 = 0x01;
-     	SR16 = 0x00;
-     	SR17 = 0x00;
-     	SR1A = 0x00;
-     	SR1B = 0x00;
-     	CR37 = 0x00;
-     	CR38 = 0x00;
-     	CR79 = 0x00;
-     	CR7A = 0x00;
-     	CR7B = 0x00;
-     	CR7C = 0x00;
-     } else {
-     	SR13 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13);
-     	SR14 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-     	SR15 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15);
-     	SR16 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
-     	SR17 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17);
-     	SR1A = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
-     	SR1B = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1B);
-     	CR37 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);  /* TW: Was 0x02 - why? */
-     	CR38 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
-     	CR79 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x79);
-     	CR7A = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x7A);
-     	CR7B = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x7B);
-     	CR7C = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x7C);
-     }
-   }
-#endif
-
-   /* Reset extended registers */
-
-   for(i=0x06; i< 0x20; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
-   for(i=0x21; i<=0x27; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
-   for(i=0x31; i<=0x3D; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
-
-#ifdef SIS300
-   if((HwDeviceExtension->jChipType == SIS_540) ||
-      (HwDeviceExtension->jChipType == SIS_630) ||
-      (HwDeviceExtension->jChipType == SIS_730) ||
-      (HwDeviceExtension->jChipType == SIS_300)) {
-     	for(i=0x38; i<=0x3F; i++) SiS_SetReg1(SiS_Pr->SiS_P3d4,i,0);
-   }
-#endif
-
-#ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H) ||
-      (HwDeviceExtension->jChipType == SIS_315) ||
-      (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_550) ||
-      (HwDeviceExtension->jChipType == SIS_650) ||
-      (HwDeviceExtension->jChipType == SIS_740) ||
-      (HwDeviceExtension->jChipType == SIS_330) ||
-      (HwDeviceExtension->jChipType == SIS_660)) {
-   	for(i=0x12; i<=0x1B; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
-   	for(i=0x79; i<=0x7C; i++) SiS_SetReg1(SiS_Pr->SiS_P3d4,i,0);
-   }
-#endif
-
-   /* Restore Extended Registers */
-
-#ifdef SIS300
-   if((HwDeviceExtension->jChipType == SIS_540) ||
-      (HwDeviceExtension->jChipType == SIS_630) ||
-      (HwDeviceExtension->jChipType == SIS_730)) {
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x12,SR12);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x18,SR18);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);
-   }
-#endif
-
-#ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_550) ||
-      (HwDeviceExtension->jChipType == SIS_740) ||
-      (HwDeviceExtension->jChipType == SIS_650)) {
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x15,SR15);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1B,SR1B);
-     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,CR37);
-     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x38,CR38);
-     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x79,CR79);
-     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x7A,CR7A);
-     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x7B,CR7B);
-     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x7C,CR7C);
-   }
-#endif
-
-#ifdef SIS300
-   if((HwDeviceExtension->jChipType==SIS_540) ||
-      (HwDeviceExtension->jChipType==SIS_630) ||
-      (HwDeviceExtension->jChipType==SIS_730)) {
-     	temp = (UCHAR)SR1A & 0x03;
-   } else if(HwDeviceExtension->jChipType == SIS_300) {
-        /* TW: Nothing */
-   }
-#endif
-#ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H)   ||
-      (HwDeviceExtension->jChipType == SIS_315)    ||
-      (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_330)) {
-      	if((*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) == 0) {
-          	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A) & 0x03;
-        }
-   }
-   if((HwDeviceExtension->jChipType == SIS_550) ||
-      (HwDeviceExtension->jChipType == SIS_740) ||
-      (HwDeviceExtension->jChipType == SIS_650) ||
-      (HwDeviceExtension->jChipType == SIS_660)) {
-        if((*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) == 0) {
-          	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x07;
-        }
-   }
-#endif
-
-   SiS_Pr->SiS_RAMType = temp;
-   SiS_SetMemoryClock(SiS_Pr, ROMAddr, HwDeviceExtension);
-
-   /* Set default register contents */
-
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x07,*SiS_Pr->pSiS_SR07); 		/* DAC speed */
-
-   if((HwDeviceExtension->jChipType != SIS_540) &&
-      (HwDeviceExtension->jChipType != SIS_630) &&
-      (HwDeviceExtension->jChipType != SIS_730)){
-     	for(i=0x15; i<0x1C; i++) {
-       	    SiS_SetReg1(SiS_Pr->SiS_P3c4,i,SiS_Pr->SiS_SR15[i-0x15][SiS_Pr->SiS_RAMType]);
-     	}
-   }
-
-#ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H) ||
-      (HwDeviceExtension->jChipType == SIS_315)  ||
-      (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_330)) {
-     	for(i=0x40;i<=0x44;i++) {
-       	    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,SiS_Pr->SiS_CR40[i-0x40][SiS_Pr->SiS_RAMType]);
-     	}
-     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x48,0x23);
-     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x49,SiS_Pr->SiS_CR49[0]);
-    /*  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x25,SiS_Pr->SiS_SR25[0]);  */
-   }
-#endif
-
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1F,*SiS_Pr->pSiS_SR1F); 	/* DAC pedestal */
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xA0);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x23,*SiS_Pr->pSiS_SR23);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x24,*SiS_Pr->pSiS_SR24);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x25,SiS_Pr->SiS_SR25[0]);
-
-#ifdef SIS300
-   if(HwDeviceExtension->jChipType == SIS_300) {
-     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,0x84);
-     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x22,0x00);
-   }
-#endif
-
-   SR11 = 0x0F;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x11,SR11);		/* Power Management & DDC port */
-
-   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
-   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,0x00);
-   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,*SiS_Pr->pSiS_CRT2Data_1_2);
-
-#ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H) ||
-      (HwDeviceExtension->jChipType == SIS_315) ||
-      (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_550) ||
-      (HwDeviceExtension->jChipType == SIS_650) ||
-      (HwDeviceExtension->jChipType == SIS_740) ||
-      (HwDeviceExtension->jChipType == SIS_330) ||
-      (HwDeviceExtension->jChipType == SIS_660))
-     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2E,0x08);    /* use VB */
-#endif
-
-   temp = *SiS_Pr->pSiS_SR32;
-   if(SiS_BridgeIsOn(SiS_Pr, BaseAddr)) {
-     	temp &= 0xEF;
-   }
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
-
-#ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H)   ||
-      (HwDeviceExtension->jChipType == SIS_315)    ||
-      (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_330)) {
-     HwDeviceExtension->pQueryVGAConfigSpace(HwDeviceExtension,0x50,0,&Temp);
-     Temp >>= 20;
-     Temp &= 0xF;
-     if (Temp != 1) {
-     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x25,SiS_Pr->SiS_SR25[1]);
-     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x49,SiS_Pr->SiS_CR49[1]);
-     }
-
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x27,0x1F);
-
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,*SiS_Pr->pSiS_SR31);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,*SiS_Pr->pSiS_SR32);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x33,*SiS_Pr->pSiS_SR33);
-   }
-#endif
-
-   if (SiS_BridgeIsOn(SiS_Pr, BaseAddr) == 0) {
-     	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
-       		SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,0x1C);
-       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0D,*SiS_Pr->pSiS_CRT2Data_4_D);
-       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0E,*SiS_Pr->pSiS_CRT2Data_4_E);
-       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x10,*SiS_Pr->pSiS_CRT2Data_4_10);
-       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0F,0x3F);
-     	}
-     	SiS_LockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
-   }
-   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x83,0x00);
-
-#ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H)   ||
-      (HwDeviceExtension->jChipType == SIS_315)    ||
-      (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_330)) {
-       	if(HwDeviceExtension->bSkipDramSizing==TRUE) {
-         	SiS_SetDRAMModeRegister(SiS_Pr, ROMAddr,HwDeviceExtension);
-         	pSR = HwDeviceExtension->pSR;
-         	if(pSR != NULL) {
-           		while(pSR->jIdx != 0xFF) {
-             			SiS_SetReg1(SiS_Pr->SiS_P3c4,pSR->jIdx,pSR->jVal);
-             			pSR++;
-           		}
-         	}
-       } else SiS_SetDRAMSize_310(SiS_Pr, HwDeviceExtension);
-   }
-#endif
-
-#ifdef SIS315H
-   if(HwDeviceExtension->jChipType == SIS_550) {
-       /* SetDRAMConfig begin */
-/*     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x12,SR12);
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x18,SR18);
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);   */
-       /* SetDRAMConfig end */
-   }
-#endif
-
-#ifdef SIS300
-   if(HwDeviceExtension->jChipType == SIS_300) {
-       	if (HwDeviceExtension->bSkipDramSizing == TRUE) {
-/*       	SiS_SetDRAMModeRegister(ROMAddr,HwDeviceExtension);
-         	temp = (HwDeviceExtension->pSR)->jVal;
-         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,temp);
-         	temp = (HwDeviceExtension->pSR)->jVal;
-         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,temp);   */
-       } else {
-#ifdef TC
-         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
-         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
-         	SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x15,0xFF,0x04);
-#else
-         	SiS_SetDRAMSize_300(SiS_Pr, HwDeviceExtension);
-         	SiS_SetDRAMSize_300(SiS_Pr, HwDeviceExtension);
-#endif
-       }
-   }
-   if((HwDeviceExtension->jChipType==SIS_540)||
-      (HwDeviceExtension->jChipType==SIS_630)||
-      (HwDeviceExtension->jChipType==SIS_730)) {
-#if 0
-     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x12,SR12);
-       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
-       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
-       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
-       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
-       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x18,SR18);
-       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
-       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);
-#endif
-   }
-/* SetDRAMSize end */
-#endif /* SIS300 */
-
-   /* Set default Ext2Regs */
-#if 0
-   AGP=1;
-   temp=(UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
-   temp &= 0x30;
-   if(temp == 0x30) AGP=0;
-   if(AGP == 0) *SiS_Pr->pSiS_SR21 &= 0xEF;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,*SiS_Pr->pSiS_SR21);
-   if(AGP == 1) *SiS_Pr->pSiS_SR22 &= 0x20;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x22,*SiS_Pr->pSiS_SR22);
-#endif
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,*SiS_Pr->pSiS_SR21);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x22,*SiS_Pr->pSiS_SR22);
-
-#if 0
-   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
-   SiS_ClearDAC(SiS_Pr, SiS_Pr->SiS_P3c8);
-#endif
-
-#ifdef LINUXBIOS   /* TW: This is not needed for our purposes */
-   SiS_DetectMonitor(SiS_Pr, HwDeviceExtension,BaseAddr);    /* Sense CRT1 */
-   SiS_GetSenseStatus(SiS_Pr, HwDeviceExtension,ROMAddr);    /* Sense CRT2 */
-#endif
-
-   return(TRUE);
-}
-
-void
-SiS_Set_LVDS_TRUMPION(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  USHORT temp = 0;
-
-#ifdef SiS300
-  if((HwDeviceExtension->jChipType == SIS_540) ||
-     (HwDeviceExtension->jChipType == SIS_630) ||
-     (HwDeviceExtension->jChipType == SIS_730)) {
-        /* TW: Read POWER_ON_TRAP and copy to CR37 */
-    	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
-    	temp = (temp & 0xE0) >> 4;
-   	SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0xF1,temp);
-  }
-#endif
-#ifdef SIS315H
-  if((HwDeviceExtension->jChipType == SIS_650) ||
-     (HwDeviceExtension->jChipType == SIS_740) ||
-     (HwDeviceExtension->jChipType == SIS_330) ||
-     (HwDeviceExtension->jChipType == SIS_660)) {
-#if 0 /* TW: This is not required */
-        /* TW: Read POWER_ON_TRAP and copy to CR37 */
-    	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
-    	temp = (temp & 0xE0) >> 4;
-   	SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0xF1,temp);
-#endif
-  }
-#endif
-
-   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, 0);
-}
-
-/* ===============  SiS 300 dram sizing begin  =============== */
-#ifdef SIS300
-void
-SiS_SetDRAMSize_300(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-   ULONG   FBAddr = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
-   USHORT  SR13, SR14=0, buswidth, Done;
-   SHORT   i, j, k;
-   USHORT  data, TotalCapacity, PhysicalAdrOtherPage=0;
-   ULONG   Addr;
-   UCHAR   temp;
-   int     PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
-   int     RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
-   int     PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage;
-
-   SiSSetMode(SiS_Pr, HwDeviceExtension, 0x2e);
-
-   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20);        /* Turn OFF Display  */
-
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,0x00);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0xBF);
-
-   buswidth = SiS_ChkBUSWidth_300(SiS_Pr, FBAddr);
-
-   MB2Bank = 16;
-   Done = 0;
-   for(i=6; i>=0; i--) {
-      if(Done == 1) break;
-      PseudoRankCapacity = 1 << i;
-      for(j=4; j>=1; j--) {
-         if(Done == 1) break;
-         PseudoTotalCapacity = PseudoRankCapacity * j;
-         PseudoAdrPinCount = 15 - j;
-         if(PseudoTotalCapacity <= 64) {
-            for(k=0; k<=16; k++) {
-               if(Done == 1) break;
-               RankCapacity = buswidth * SiS_DRAMType[k][3];
-               AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
-               if(RankCapacity == PseudoRankCapacity)
-                 if(AdrPinCount <= PseudoAdrPinCount) {
-                    if(j == 3) {             /* Rank No */
-                       BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
-                       BankNumMid = RankCapacity * MB2Bank * 1 - 1;
-                    } else {
-                       BankNumHigh = RankCapacity * MB2Bank * j - 1;
-                       BankNumMid = RankCapacity * MB2Bank * j / 2 - 1;
-                    }
-                    PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
-                    PhysicalAdrHigh = BankNumHigh;
-                    PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
-                    PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
-                    /* Write data */
-                    /*Test*/
-                    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x15,0xFB);
-                    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x15,0x04);
-                    /*/Test*/
-                    TotalCapacity = SiS_DRAMType[k][3] * buswidth;
-                    SR13 = SiS_DRAMType[k][4];
-                    if(buswidth == 4) SR14 = (TotalCapacity - 1) | 0x80;
-                    if(buswidth == 2) SR14 = (TotalCapacity - 1) | 0x40;
-                    if(buswidth == 1) SR14 = (TotalCapacity - 1) | 0x00;
-                    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
-                    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
-
-                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrHigh;
-                    *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh;
-                    Addr = FBAddr + (BankNumMid) * 64 * 1024 + PhysicalAdrHigh;
-                    *((USHORT *)(Addr)) = (USHORT)BankNumMid;
-                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrHalfPage;
-                    *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage;
-                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrOtherPage;
-                    *((USHORT *)(Addr)) = PhysicalAdrOtherPage;
-
-                    /* Read data */
-                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrHigh;
-                    data = *((USHORT *)(Addr));
-                    if(data == PhysicalAdrHigh) Done = 1;
-                 }  /* if struct */
-            }  /* for loop (k) */
-         }  /* if struct */
-      }  /* for loop (j) */
-   }  /* for loop (i) */
-}
-
-USHORT
-SiS_ChkBUSWidth_300(SiS_Private *SiS_Pr, ULONG FBAddress)
-{
-   PULONG  pVideoMemory;
-
-   pVideoMemory = (PULONG)FBAddress;
-
-   pVideoMemory[0] = 0x01234567L;
-   pVideoMemory[1] = 0x456789ABL;
-   pVideoMemory[2] = 0x89ABCDEFL;
-   pVideoMemory[3] = 0xCDEF0123L;
-   if (pVideoMemory[3]==0xCDEF0123L) {  /* Channel A 128bit */
-     return(4);
-   }
-   if (pVideoMemory[1]==0x456789ABL) {  /* Channel B 64bit */
-     return(2);
-   }
-   return(1);
-}
-#endif
-/* ===============  SiS 300 dram sizing end    =============== */
-
-/* ============  SiS 315 dram sizing begin  ============== */
-#ifdef SIS315H
-
-/* TW: Moved Get310DRAMType further down */
-
-void
-SiS_Delay15us(SiS_Private *SiS_Pr, ULONG ulMicrsoSec)
-{
-}
-
-void
-SiS_SDR_MRS(SiS_Private *SiS_Pr, )
-{
-   USHORT  data;
-
-   data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
-   data &= 0x3F;          		        /* SR16 D7=0, D6=0 */
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);   	/* enable mode register set(MRS) low */
-   SiS_Delay15us(SiS_Pr, 0x100);
-   data |= 0x80;          		        /* SR16 D7=1, D6=0 */
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);   	/* enable mode register set(MRS) high */
-   SiS_Delay15us(SiS_Pr, 0x100);
-}
-
-void
-SiS_DDR_MRS(SiS_Private *SiS_Pr)
-{
-   USHORT  data;
-
-   /* SR16 <- 1F,DF,2F,AF */
-
-   /* enable DLL of DDR SD/SGRAM , SR16 D4=1 */
-   data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
-   data &= 0x0F;
-   data |= 0x10;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
-
-   if (!(SiS_Pr->SiS_SR15[1][SiS_Pr->SiS_RAMType] & 0x10))
-     data &= 0x0F;
-
-   /* SR16 D7=1,D6=1 */
-   data |= 0xC0;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
-   
-   /* SR16 D7=1,D6=0,D5=1,D4=0 */
-   data &= 0x0F;
-   data |= 0x20;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
-   if (!(SiS_Pr->SiS_SR15[1][SiS_Pr->SiS_RAMType] & 0x10))
-     data &= 0x0F;
-
-   /* SR16 D7=1 */
-   data |= 0x80;
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
-}
-
-void
-SiS_SetDRAMModeRegister(SiS_Private *SiS_Pr, UCHAR *ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-    if (SiS_Get310DRAMType(ROMAddr,HwDeviceExtension) < 2)
-        SiS_SDR_MRS(SiS_Pr);
-    else
-        /* SR16 <- 0F,CF,0F,8F */
-        SiS_DDR_MRS(SiS_Pr);
-}
-
-void
-SiS_DisableRefresh(SiS_Private *SiS_Pr)
-{
-   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x17,0xF8);
-   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x19,0x03);
-}
-
-void
-SiS_EnableRefresh(SiS_Private *SiS_Pr, UCHAR *ROMAddr)
-{
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SiS_Pr->SiS_SR15[2][SiS_Pr->SiS_RAMType]);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SiS_Pr->SiS_SR15[4][SiS_Pr->SiS_RAMType]);
-}
-
-void
-SiS_DisableChannelInterleaving(SiS_Private *SiS_Pr, int index,
-                               USHORT SiS_DDRDRAM_TYPE[][5])
-{
-   USHORT  data;
-
-   data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15);
-   data &= 0x1F;
-   switch (SiS_DDRDRAM_TYPE[index][3])
-   {
-     case 64: data |= 0; 	break;
-     case 32: data |= 0x20;	break;
-     case 16: data |= 0x40;     break;
-     case 4:  data |= 0x60;     break;
-   }
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x15,data);
-}
-
-void
-SiS_SetDRAMSizingType(SiS_Private *SiS_Pr, int index, USHORT DRAMTYPE_TABLE[][5])
-{
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,DRAMTYPE_TABLE[index][4]);
-   /* should delay 50 ns */
-}
-
-void
-SiS_CheckBusWidth_310(SiS_Private *SiS_Pr, UCHAR *ROMAddress,ULONG FBAddress,
-                      PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-   USHORT  data, temp;
-   PULONG  volatile pVideoMemory;
-
-   pVideoMemory = (PULONG)FBAddress;
-
-   if(HwDeviceExtension->jChipType == SIS_330) temp = 1;
-   else temp = 2;
-
-   if(SiS_Get310DRAMType(ROMAddress,HwDeviceExtension) < temp) {
-
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,0x00);
-     if(HwDeviceExtension->jChipType != SIS_330) {
-        SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x12);
-     } else {
-        SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x02);
-     }
-     /* should delay */
-     SiS_SDR_MRS(SiS_Pr);
-
-     SiS_Pr->SiS_ChannelAB = 0;
-     SiS_Pr->SiS_DataBusWidth = 128;
-     pVideoMemory[0] = 0x01234567L;
-     pVideoMemory[1] = 0x456789ABL;
-     pVideoMemory[2] = 0x89ABCDEFL;
-     pVideoMemory[3] = 0xCDEF0123L;
-     pVideoMemory[4] = 0x55555555L;
-     pVideoMemory[5] = 0x55555555L;
-     pVideoMemory[6] = 0xFFFFFFFFL;
-     pVideoMemory[7] = 0xFFFFFFFFL;
-     if((pVideoMemory[3] != 0xCDEF0123L) || (pVideoMemory[2] != 0x89ABCDEFL)) {
-       /* Channel A 64Bit */
-       SiS_Pr->SiS_DataBusWidth = 64;
-       SiS_Pr->SiS_ChannelAB = 0;
-       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x14, 0xFD);
-     }
-     if((pVideoMemory[1] != 0x456789ABL) || (pVideoMemory[0] != 0x01234567L)) {
-       /* Channel B 64Bit */
-       SiS_Pr->SiS_DataBusWidth = 64;
-       SiS_Pr->SiS_ChannelAB = 1;
-       SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x14,0xfd,0x01);
-     }
-     return;
-
-   } else {
-
-     /* DDR Dual channel */
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,0x00);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x02); /* Channel A, 64bit */
-     /* should delay */
-     SiS_DDR_MRS(SiS_Pr);
-
-     SiS_Pr->SiS_ChannelAB = 0;
-     SiS_Pr->SiS_DataBusWidth = 64;
-     pVideoMemory[0] = 0x01234567L;
-     pVideoMemory[1] = 0x456789ABL;
-     pVideoMemory[2] = 0x89ABCDEFL;
-     pVideoMemory[3] = 0xCDEF0123L;
-     pVideoMemory[4] = 0x55555555L;
-     pVideoMemory[5] = 0x55555555L;
-     pVideoMemory[6] = 0xAAAAAAAAL;
-     pVideoMemory[7] = 0xAAAAAAAAL;
-
-     if (pVideoMemory[1] == 0x456789ABL) {
-       if (pVideoMemory[0] == 0x01234567L) {
-         /* Channel A 64bit */
-         return;
-       }
-     } else {
-       if (pVideoMemory[0] == 0x01234567L) {
-         /* Channel A 32bit */
-         SiS_Pr->SiS_DataBusWidth = 32;
-         SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x00);
-         return;
-       }
-     }
-
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x03); /* Channel B, 64bit */
-     SiS_DDR_MRS(SiS_Pr);
-
-     SiS_Pr->SiS_ChannelAB = 1;
-     SiS_Pr->SiS_DataBusWidth = 64;
-     pVideoMemory[0] = 0x01234567L;
-     pVideoMemory[1] = 0x456789ABL;
-     pVideoMemory[2] = 0x89ABCDEFL;
-     pVideoMemory[3] = 0xCDEF0123L;
-     pVideoMemory[4] = 0x55555555L;
-     pVideoMemory[5] = 0x55555555L;
-     pVideoMemory[6] = 0xAAAAAAAAL;
-     pVideoMemory[7] = 0xAAAAAAAAL;
-     if(pVideoMemory[1] == 0x456789ABL) {
-       /* Channel B 64 */
-       if(pVideoMemory[0] == 0x01234567L) {
-         /* Channel B 64bit */
-         return;
-       } else {
-         /* error */
-       }
-     } else {
-       if(pVideoMemory[0] == 0x01234567L) {
-         /* Channel B 32 */
-         SiS_Pr->SiS_DataBusWidth = 32;
-         SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x01);
-       } else {
-         /* error */
-       }
-     }
-   }
-}
-
-int
-SiS_SetRank(SiS_Private *SiS_Pr, int index,UCHAR RankNo,USHORT DRAMTYPE_TABLE[][5])
-{
-  USHORT  data;
-  int RankSize;
-
-  if ((RankNo==2)&&(DRAMTYPE_TABLE[index][0]==2))
-         return 0;
-
-  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_Pr->SiS_DataBusWidth / 32;
-
-  if (RankNo * RankSize <= 128) {
-    data = 0;
-    while((RankSize >>= 1) > 0) {
-      data += 0x10;
-    }
-    data |= (RankNo - 1) << 2;
-    data |= (SiS_Pr->SiS_DataBusWidth / 64) & 2;
-    data |= SiS_Pr->SiS_ChannelAB;
-    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,data);
-    /* should delay */
-    SiS_SDR_MRS(SiS_Pr);
-    return 1;
-  } else
-    return 0;
-}
-
-int
-SiS_SetDDRChannel(SiS_Private *SiS_Pr, int index,UCHAR ChannelNo,
-                  USHORT DRAMTYPE_TABLE[][5])
-{
-  USHORT  data;
-  int RankSize;
-
-  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_Pr->SiS_DataBusWidth / 32;
-  /* RankSize = DRAMTYPE_TABLE[index][3]; */
-  if (ChannelNo * RankSize <= 128) {
-    data = 0;
-    while((RankSize >>= 1) > 0) {
-      data += 0x10;
-    }
-    if(ChannelNo == 2) data |= 0x0C;
-    data |= (SiS_Pr->SiS_DataBusWidth / 32) & 2;
-    data |= SiS_Pr->SiS_ChannelAB;
-    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,data);
-    /* should delay */
-    SiS_DDR_MRS(SiS_Pr);
-    return 1;
-  } else
-    return 0;
-}
-
-int
-SiS_CheckColumn(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
-{
-  int i;
-  ULONG Increment,Position;
-
-  /*Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiS_Pr->SiS_DataBusWidth / 64 + 1); */
-  Increment = 1 << (10 + SiS_Pr->SiS_DataBusWidth / 64);
-
-  for (i=0,Position=0;i<2;i++) {
-         *((PULONG)(FBAddress + Position)) = Position;
-         Position += Increment;
-  }
-
-  for (i=0,Position=0;i<2;i++) {
-/*    if (FBAddress[Position]!=Position) */
-         if((*(PULONG)(FBAddress + Position)) != Position)
-                return 0;
-         Position += Increment;
-  }
-  return 1;
-}
-
-int
-SiS_CheckBanks(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
-{
-  int i;
-  ULONG Increment,Position;
-  Increment = 1 << (DRAMTYPE_TABLE[index][2] + SiS_Pr->SiS_DataBusWidth / 64 + 2);
-
-  for (i=0,Position=0;i<4;i++) {
-/*    FBAddress[Position]=Position; */
-    *((PULONG)(FBAddress + Position)) = Position;
-    Position += Increment;
-  }
-
-  for (i=0,Position=0;i<4;i++) {
-/*    if (FBAddress[Position]!=Position) */
-    if((*(PULONG)(FBAddress + Position)) != Position)
-      return 0;
-    Position += Increment;
-  }
-  return 1;
-}
-
-int
-SiS_CheckRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
-{
-  int i;
-  ULONG Increment,Position;
-  Increment = 1<<(DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] +
-                  DRAMTYPE_TABLE[index][0] + SiS_Pr->SiS_DataBusWidth / 64 + RankNo);
-
-  for (i=0,Position=0;i<2;i++) {
-/*    FBAddress[Position]=Position; */
-    *((PULONG)(FBAddress+Position))=Position;
-    /* *((PULONG)(FBAddress))=Position; */
-    Position += Increment;
-  }
-
-  for (i=0,Position=0;i<2;i++) {
-/*    if (FBAddress[Position]!=Position) */
-         if ( (*(PULONG) (FBAddress + Position)) !=Position)
-    /*if ( (*(PULONG) (FBAddress )) !=Position) */
-      return 0;
-    Position += Increment;
-  }
-  return 1;
-}
-
-int
-SiS_CheckDDRRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
-{
-  ULONG Increment,Position;
-  USHORT  data;
-
-  Increment = 1<<(DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] +
-                  DRAMTYPE_TABLE[index][0] + SiS_Pr->SiS_DataBusWidth / 64 + RankNo);
-
-  Increment += Increment/2;
-
-  Position =0;
-  *((PULONG)(FBAddress+Position + 0)) = 0x01234567;
-  *((PULONG)(FBAddress+Position + 1)) = 0x456789AB;
-  *((PULONG)(FBAddress+Position + 2)) = 0x55555555;
-  *((PULONG)(FBAddress+Position + 3)) = 0x55555555;
-  *((PULONG)(FBAddress+Position + 4)) = 0xAAAAAAAA;
-  *((PULONG)(FBAddress+Position + 5)) = 0xAAAAAAAA;
-
-  if ( (*(PULONG) (FBAddress + 1)) == 0x456789AB)
-    return 1;
-
-  if ( (*(PULONG) (FBAddress + 0)) == 0x01234567)
-    return 0;
-
-  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-  data &= 0xF3;
-  data |= 0x08;
-  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,data);
-  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15);
-  data += 0x20;
-  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x15,data);
-
-  return 1;
-}
-
-int
-SiS_CheckRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
-{
-  int r;
-
-  for (r=RankNo;r>=1;r--) {
-    if (!SiS_CheckRank(SiS_Pr, r, index, DRAMTYPE_TABLE, FBAddress))
-      return 0;
-  }
-  if (!SiS_CheckBanks(SiS_Pr, index, DRAMTYPE_TABLE, FBAddress))
-    return 0;
-
-  if (!SiS_CheckColumn(SiS_Pr, index, DRAMTYPE_TABLE, FBAddress))
-    return 0;
-
-  return 1;
-}
-
-int
-SiS_CheckDDRRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],
-                  ULONG FBAddress)
-{
-  int r;
-
-  for (r=RankNo;r>=1;r--) {
-    if (!SiS_CheckDDRRank(SiS_Pr, r,index,DRAMTYPE_TABLE,FBAddress))
-      return 0;
-  }
-  if (!SiS_CheckBanks(SiS_Pr, index,DRAMTYPE_TABLE,FBAddress))
-    return 0;
-
-  if (!SiS_CheckColumn(SiS_Pr, index,DRAMTYPE_TABLE,FBAddress))
-    return 0;
-
-  return 1;
-}
-
-int
-SiS_SDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress)
-{
-  int    i;
-  UCHAR  j;
-
-  for (i=0;i<13;i++) {
-    SiS_SetDRAMSizingType(SiS_Pr, i, SiS_SDRDRAM_TYPE);
-    for (j=2;j>0;j--) {
-      if (!SiS_SetRank(SiS_Pr, i,(UCHAR) j, SiS_SDRDRAM_TYPE))
-        continue;
-      else {
-        if (SiS_CheckRanks(SiS_Pr, j,i,SiS_SDRDRAM_TYPE, FBAddress))
-          return 1;
-      }
-    }
-  }
-  return 0;
-}
-
-int
-SiS_DDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress)
-{
-
-  int    i;
-  UCHAR  j;
-
-  for (i=0; i<4; i++){
-    SiS_SetDRAMSizingType(SiS_Pr, i, SiS_DDRDRAM_TYPE);
-    SiS_DisableChannelInterleaving(SiS_Pr, i, SiS_DDRDRAM_TYPE);
-    for (j=2; j>0; j--) {
-      SiS_SetDDRChannel(SiS_Pr, i, j, SiS_DDRDRAM_TYPE);
-      if (!SiS_SetRank(SiS_Pr, i, (UCHAR) j, SiS_DDRDRAM_TYPE))
-        continue;
-      else {
-        if (SiS_CheckDDRRanks(SiS_Pr, j, i, SiS_DDRDRAM_TYPE, FBAddress))
-          return 1;
-      }
-    }
-  }
-  return 0;
-}
-
-/*
- check if read cache pointer is correct
-*/
-void
-SiS_VerifyMclk(SiS_Private *SiS_Pr, ULONG FBAddr)
-{
-   PUCHAR  pVideoMemory = (PUCHAR) FBAddr;
-   UCHAR   i, j;
-   USHORT  Temp,SR21;
-
-   pVideoMemory[0] = 0xaa;  /* alan */
-   pVideoMemory[16] = 0x55; /* note: PCI read cache is off */
-
-   if((pVideoMemory[0] != 0xaa) || (pVideoMemory[16] != 0x55)) {
-     for (i=0,j=16; i<2; i++,j+=16)  {
-       SR21 = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x21);
-       Temp = SR21 & 0xFB;           /* disable PCI post write buffer empty gating */
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,Temp);
-
-       Temp = SiS_GetReg1(SiS_Pr->SiS_P3c4, 0x3C);
-       Temp |= 0x01;                 /* MCLK reset */
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3C,Temp);
-       Temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3C);
-       Temp &= 0xFE;                 /* MCLK normal operation */
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3C,Temp);
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,SR21);
-
-       pVideoMemory[16+j] = j;
-       if(pVideoMemory[16+j] == j) {
-         pVideoMemory[j] = j;
-         break;
-       }
-     }
-   }
-}
-
-/* TW: Is this a 315E? */
-int
-Is315E(SiS_Private *SiS_Pr)
-{
-   USHORT  data;
-
-   data = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5F);
-   if(data & 0x10) return 1;
-   else return 0;
-}
-
-/* TW: For 315 only */
-void
-SiS_SetDRAMSize_310(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
-   ULONG   FBAddr   = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
-   USHORT  data;
-
-#ifdef SIS301	/* TW: SIS301 ??? */
-   /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x40);   */
-#endif
-#ifdef SIS302   /* TW: SIS302 ??? */
-   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x4D);  /* alan,should change value */
-   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x31,0xc0);  /* alan,should change value */
-   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x34,0x3F);  /* alan,should change value */
-#endif
-
-   SiSSetMode(SiS_Pr, HwDeviceExtension, 0x2e);
-
-   data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x21);
-   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x21,0xDF);                 /* disable read cache */
-
-   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20);                  /* Turn OFF Display */
-
-   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x16,0x0F);                  /* assume lowest speed DRAM */
-
-   SiS_SetDRAMModeRegister(SiS_Pr, ROMAddr, HwDeviceExtension);
-   SiS_DisableRefresh(SiS_Pr);
-   SiS_CheckBusWidth_310(SiS_Pr, ROMAddr, FBAddr, HwDeviceExtension);
-
-   SiS_VerifyMclk(SiS_Pr, FBAddr);
-
-   if(HwDeviceExtension->jChipType == SIS_330) temp = 1;
-   else temp = 2;
-
-   if(SiS_Get310DRAMType(SiS_Pr, ROMAddr, HwDeviceExtension) < temp)
-     SiS_SDRSizing(SiS_Pr, FBAddr);
-   else
-     SiS_DDRSizing(SiS_Pr, FBAddr);
-
-   if(HwDeviceExtension->jChipType != SIS_330) {
-     if(Is315E(SiS_Pr)) {
-       data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-       if((data & 0x0C) == 0x0C) { 	/* dual channel */
-     	 if((data & 0xF0) > 0x40)
-     	   data = (data & 0x0F) | 0x40;
-       } else { 				/* single channel */
-     	 if((data & 0xF0) > 0x50)
-     	   data = (data & 0x0F) | 0x50;
-       }
-     }
-   }
-
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SiS_Pr->SiS_SR15[1][SiS_Pr->SiS_RAMType]);  /* restore SR16 */
-
-   SiS_EnableRefresh(SiS_Pr, ROMAddr);
-   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x21,0x20);      	/* enable read cache */
-}
-#endif
-
-void
-SiS_SetMemoryClock(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x28,SiS_Pr->SiS_MCLKData_0[SiS_Pr->SiS_RAMType].SR28);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x29,SiS_Pr->SiS_MCLKData_0[SiS_Pr->SiS_RAMType].SR29);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2A,SiS_Pr->SiS_MCLKData_0[SiS_Pr->SiS_RAMType].SR2A);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2E,SiS_Pr->SiS_ECLKData[SiS_Pr->SiS_RAMType].SR2E);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2F,SiS_Pr->SiS_ECLKData[SiS_Pr->SiS_RAMType].SR2F);
-   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x30,SiS_Pr->SiS_ECLKData[SiS_Pr->SiS_RAMType].SR30);
-
-#ifdef SIS315H
-   if (Is315E(SiS_Pr)) {
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x28,0x3B); /* 143 */
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x29,0x22);
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2E,0x3B); /* 143 */
-     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2F,0x22);
-   }
-#endif
-}
-
-#endif /* ifdef LINUXBIOS */
-
 #ifdef SIS315H
 UCHAR
 SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
@@ -1919,8 +699,6 @@
 }
 #endif
 
-/* SiSInit END */
-
 /* ----------------------------------------- */
 
 void SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr)
@@ -1951,32 +729,47 @@
 void
 SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-/* #ifdef LINUX_XF86 */
-   if ((HwDeviceExtension->jChipType == SIS_540)||
-       (HwDeviceExtension->jChipType == SIS_630)||
-       (HwDeviceExtension->jChipType == SIS_730)||
-       (HwDeviceExtension->jChipType == SIS_300)) {
-       /* TW: Set - PCI LINEAR ADDRESSING ENABLE (0x80)
-		  - PCI IO ENABLE  (0x20)
-		  - MMIO ENABLE (0x1)
-  	*/
-       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
-       /* TW: Enable 2D (0x42) & 3D accelerator (0x18) */
-       SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0xFF,0x5A);
-   }
-   if((HwDeviceExtension->jChipType == SIS_315H)||
-      (HwDeviceExtension->jChipType == SIS_315) ||
-      (HwDeviceExtension->jChipType == SIS_315PRO)||
-      (HwDeviceExtension->jChipType == SIS_550) ||
-      (HwDeviceExtension->jChipType == SIS_650) ||
-      (HwDeviceExtension->jChipType == SIS_740) ||
-      (HwDeviceExtension->jChipType == SIS_330) ||
-      (HwDeviceExtension->jChipType == SIS_660)) {
-      /* TW: This seems to be done the same way on these chipsets */
+   switch(HwDeviceExtension->jChipType) {
+   case SIS_300:
+   case SIS_540:
+   case SIS_630:
+   case SIS_730:
+      /* Set - PCI LINEAR ADDRESSING ENABLE (0x80)
+       *     - RELOCATED VGA IO  (0x20)
+       *     - MMIO ENABLE (0x1)
+       */
       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
-      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0xFF,0x5A);
+      /*  - Enable 2D (0x40)
+       *  - Enable 3D (0x02)
+       *  - Enable 3D Vertex command fetch (0x10) ?
+       *  - Enable 3D command parser (0x08) ?
+       */
+      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x5A);
+      break;
+   case SIS_315H:
+   case SIS_315:
+   case SIS_315PRO:
+   case SIS_650:
+   case SIS_740:
+   case SIS_330:
+   case SIS_660:
+   case SIS_760:
+      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      /*  - Enable 2D (0x40)
+       *  - Enable 3D (0x02)
+       *  - Enable 3D vertex command fetch (0x10)
+       *  - Enable 3D command parser (0x08)
+       *  - Enable 3D G/L transformation engine (0x80)
+       */
+      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0xDA);
+      break;
+   case SIS_550:
+      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      /* No 3D engine ! */
+      /*  - Enable 2D (0x40)
+       */
+      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x40);
    }
-/* #endif */
 }
 
 void
@@ -2002,12 +795,12 @@
    }
 #endif
 
+   switch(HwDeviceExtension->jChipType) {
 #ifdef SIS300
-   if((HwDeviceExtension->jChipType == SIS_540) ||
-      (HwDeviceExtension->jChipType == SIS_630) ||
-      (HwDeviceExtension->jChipType == SIS_730))
-    {
-        /* TW: Check for SiS30x first */
+   case SIS_540:
+   case SIS_630:
+   case SIS_730:
+        /* Check for SiS30x first */
         temp = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
 	if((temp == 1) || (temp == 2)) return;
       	temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
@@ -2015,60 +808,58 @@
       	if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
       	if(temp == 3)   SiS_Pr->SiS_IF_DEF_TRUMPION = 1;
       	if((temp == 4) || (temp == 5)) {
-		/* TW: Save power status (and error check) - UNUSED */
+		/* Save power status (and error check) - UNUSED */
 		SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e);
 		SiS_Pr->SiS_IF_DEF_CH70xx = 1;
         }
-   }
+	break;
 #endif
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_550) ||
-      (HwDeviceExtension->jChipType == SIS_650) ||
-      (HwDeviceExtension->jChipType == SIS_740) ||
-      (HwDeviceExtension->jChipType == SIS_330) ||
-      (HwDeviceExtension->jChipType == SIS_660))
-    {
-        /* TW: CR37 is different on 315 series */
-#if 0
-        if(SiS_Pr->SiS_IF_DEF_FSTN)                       /* fstn: set CR37=0x04 */
-             SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,0x04);      /* (fake LVDS bridge) */
-#endif
-
+   case SIS_550:
+   case SIS_650:
+   case SIS_740:
+   case SIS_330:
+   case SIS_660:
+   case SIS_760:
 	temp=SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
       	temp = (temp & 0x0E) >> 1;
       	if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
-      	if(temp == 3)  {
-			SiS_Pr->SiS_IF_DEF_CH70xx = 2;
-        }
-	
-	/* HiVision (HDTV) is done differently now. */
-	/* SiS_Pr->SiS_IF_DEF_HiVision = 1; */
-    }
+      	if(temp == 3)  SiS_Pr->SiS_IF_DEF_CH70xx = 2;
+        break;
 #endif
+   default:
+        break;
+   }
 }
 
 void
 SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
+   switch(HwDeviceExtension->jChipType) {
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H) ||
-      (HwDeviceExtension->jChipType == SIS_315) ||
-      (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_550) ||
-      (HwDeviceExtension->jChipType == SIS_650) ||
-      (HwDeviceExtension->jChipType == SIS_740) ||
-      (HwDeviceExtension->jChipType == SIS_330) ||
-      (HwDeviceExtension->jChipType == SIS_660))
-     InitTo310Pointer(SiS_Pr, HwDeviceExtension);
+   case SIS_315H:
+   case SIS_315:
+   case SIS_315PRO:
+   case SIS_550:
+   case SIS_650:
+   case SIS_740:
+   case SIS_330:
+   case SIS_660:
+   case SIS_760:
+      InitTo310Pointer(SiS_Pr, HwDeviceExtension);
+      break;
 #endif
-
 #ifdef SIS300
-   if ((HwDeviceExtension->jChipType == SIS_540) ||
-       (HwDeviceExtension->jChipType == SIS_630) ||
-       (HwDeviceExtension->jChipType == SIS_730) ||
-       (HwDeviceExtension->jChipType == SIS_300))
-     InitTo300Pointer(SiS_Pr, HwDeviceExtension);
+   case SIS_300:
+   case SIS_540:
+   case SIS_630:
+   case SIS_730:
+      InitTo300Pointer(SiS_Pr, HwDeviceExtension);
+      break;
 #endif
+   default:
+      break;
+   }
 }
 
 void
@@ -2141,7 +932,7 @@
 
    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo);
 
-   return(SiSSetMode(SiS_Pr, HwDeviceExtension, pScrn, ModeNo, TRUE));   
+   return(SiSSetMode(SiS_Pr, HwDeviceExtension, pScrn, ModeNo, TRUE));
 }
 
 #ifdef SISDUALHEAD
@@ -2453,6 +1244,7 @@
    switch (HwDeviceExtension->ujVBChipID) {
      case VB_CHIP_301:
      case VB_CHIP_301B:
+     case VB_CHIP_301C:
      case VB_CHIP_301LV:
      case VB_CHIP_302:
      case VB_CHIP_302B:
@@ -2536,8 +1328,8 @@
    
    if(SiS_Pr->UseCustomMode) {
       ModeNo = 0xfe;
-   }      
-   
+   }
+
    SiSInitPtr(SiS_Pr, HwDeviceExtension);
 
    SiSRegInit(SiS_Pr, BaseAddr);
@@ -2565,7 +1357,7 @@
    if(!SiS_Pr->UseCustomMode) {
       /* TW: Shift the clear-buffer-bit away */
       ModeNo = ((ModeNo & 0x80) << 8) | (ModeNo & 0x7f);
-   }      
+   }
 
 #ifdef LINUX_XF86
    /* We never clear the buffer in X */
@@ -2586,17 +1378,17 @@
    SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
 
    if(!SiS_Pr->UseCustomMode) {
-   
+
       /* 2.Get ModeID Table  */
       temp = SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&ModeIdIndex);
       if(temp == 0) return(0);
-      
+
    } else {
-   
+
       ModeIdIndex = 0;
-      
+
    }
-    
+
    /* Determine VBType (301,301B,301LV,302B,302LV) */
    SiS_GetVBType(SiS_Pr,BaseAddr,HwDeviceExtension);
 
@@ -2630,9 +1422,11 @@
    SiS_SetHiVision(SiS_Pr,BaseAddr,HwDeviceExtension);
    SiS_GetLCDResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
 
-   /* 3. Check memory size */
+#ifndef LINUX_XF86
+   /* 3. Check memory size (Kernel framebuffer driver only) */
    temp = SiS_CheckMemorySize(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
    if(!temp) return(0);
+#endif
 
    if(HwDeviceExtension->jChipType >= SIS_315H) {
       if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
@@ -2674,6 +1468,7 @@
      switch (HwDeviceExtension->ujVBChipID) {
      case VB_CHIP_301:
      case VB_CHIP_301B:
+     case VB_CHIP_301C:
      case VB_CHIP_301LV:
      case VB_CHIP_302:
      case VB_CHIP_302B:
@@ -2999,25 +1794,26 @@
 
   flag = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
 
-  /* TW: Illegal values not welcome... */
   if(flag > 3) return;
 
   rev = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x01);
 
-  if (flag >= 2) {
+  if(flag >= 2) {
         SiS_Pr->SiS_VBType = VB_SIS302B;
-  } else if (flag == 1) {
+  } else if(flag == 1) {
         SiS_Pr->SiS_VBType = VB_SIS301;
-        if(rev >= 0xB0) {
+	if(rev >= 0xC0) {
+            	SiS_Pr->SiS_VBType = VB_SIS301C;
+        } else if(rev >= 0xB0) {
             	SiS_Pr->SiS_VBType = VB_SIS301B;
 		/* Check if 30xB DH version (no LCD support, use Panel Link instead) */
     		nolcd = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x23);
                 if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD;
         }
   }
-  if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) {
+  if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) {
         if(rev >= 0xD0) {
-	        SiS_Pr->SiS_VBType &= ~(VB_SIS301B | VB_SIS302B);
+	        SiS_Pr->SiS_VBType &= ~(VB_SIS301B | VB_SIS301C | VB_SIS302B);
           	SiS_Pr->SiS_VBType |= VB_SIS301LV;
 		SiS_Pr->SiS_VBType &= ~(VB_NoLCD);
 		if(rev >= 0xE0) {
@@ -3087,6 +1883,7 @@
    return ((BOOLEAN)ModeIdIndex);
 }
 
+#ifndef LINUX_XF86
 BOOLEAN
 SiS_CheckMemorySize(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                     USHORT ModeNo,USHORT ModeIdIndex)
@@ -3114,6 +1911,7 @@
   if(temp < memorysize) return(FALSE);
   else return(TRUE);
 }
+#endif
 
 UCHAR
 SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
@@ -3325,7 +2123,7 @@
          if(HwDeviceExtension->jChipType >= SIS_315H) {
 	    if(IS_SIS550650740660) {
 	       /* 315, 330 don't do this */
-	       if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { 
+	       if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
 	          if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
 	       } else {
 	          ARdata = 0;
@@ -3728,6 +2526,9 @@
   USHORT data,data2,data3;
   USHORT infoflag=0,modeflag;
   USHORT resindex,xres;
+#ifdef SIS315H
+  ULONG  longdata;
+#endif  
 
   if(SiS_Pr->UseCustomMode) {
      modeflag = SiS_Pr->CModeFlag;
@@ -3864,9 +2665,9 @@
 	  data2 *= data3;
 
 	  data3 = SiS_GetMCLK(SiS_Pr,ROMAddr, HwDeviceExtension);
-	  data3 *= 1024;
+	  longdata = data3 * 1024;
 
-	  data2 = data3 / data2;
+	  data2 = longdata / data2;
 
 	  if(SiS_Pr->SiS_ModeType != Mode16Bpp) {
             if(data2 >= 0x19c)      data = 0xba;
@@ -4136,6 +2937,7 @@
   SiS_SetReg3(DACData,(USHORT)bl);
 }
 
+#ifndef LINUX_XF86
 static ULONG
 GetDRAMSize(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
@@ -4144,11 +2946,11 @@
   USHORT  counter;
 #endif
 
+  switch(HwDeviceExtension->jChipType) {
 #ifdef SIS315H
-  if ((HwDeviceExtension->jChipType == SIS_315H) ||
-      (HwDeviceExtension->jChipType == SIS_315)  ||
-      (HwDeviceExtension->jChipType == SIS_315PRO)) {
-
+  case SIS_315H:
+  case SIS_315:
+  case SIS_315PRO:
     	counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
 	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
 	counter >>= 2;
@@ -4159,9 +2961,9 @@
 		AdapterMemorySize <<= 1;                           /* SINGLE_CHANNEL_2_RANK or DUAL_CHANNEL_1_RANK */
 	}
 	AdapterMemorySize *= (1024*1024);
+        break;
 
-  } else if(HwDeviceExtension->jChipType == SIS_330) {
-
+  case SIS_330:
     	counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
 	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
 	counter &= 0x0c;
@@ -4169,34 +2971,37 @@
 		AdapterMemorySize <<= 1;
 	}
 	AdapterMemorySize *= (1024*1024);
+	break;
 
-  } else if((HwDeviceExtension->jChipType == SIS_550) ||
-            (HwDeviceExtension->jChipType == SIS_740) ||
-            (HwDeviceExtension->jChipType == SIS_650) ||
-	    (HwDeviceExtension->jChipType == SIS_660)) {
-
+  case SIS_550:
+  case SIS_650:
+  case SIS_740:
+  case SIS_660:
+  case SIS_760:
   	counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
       	counter++;
       	AdapterMemorySize = counter * 4;
       	AdapterMemorySize *= (1024*1024);
-  }
+	break;
 #endif
 
 #ifdef SIS300
-  if ((HwDeviceExtension->jChipType==SIS_300) ||
-      (HwDeviceExtension->jChipType==SIS_540) ||
-      (HwDeviceExtension->jChipType==SIS_630) ||
-      (HwDeviceExtension->jChipType==SIS_730)) {
-
+  case SIS_300:
+  case SIS_540:
+  case SIS_630:
+  case SIS_730:
       	AdapterMemorySize = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
       	AdapterMemorySize++;
       	AdapterMemorySize *= (1024*1024);
-
-  }
+	break;
 #endif
+  default:
+        break;
+  }
 
   return AdapterMemorySize;
 }
+#endif
 
 #ifndef LINUX_XF86
 void
@@ -4525,46 +3330,6 @@
   return((USHORT)longtemp);
 }
 
-#if 0  /* TW: Old fragment, unused */
-USHORT
-SiS_CalcDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT key)
-{
-  USHORT data,data2,temp0,temp1;
-  UCHAR   ThLowA[]=   {61,3,52,5,68,7,100,11,
-                       43,3,42,5,54,7, 78,11,
-                       34,3,37,5,47,7, 67,11};
-
-  UCHAR   ThLowB[]=   {81,4,72,6,88,8,120,12,
-                       55,4,54,6,66,8, 90,12,
-                       42,4,45,6,55,8, 75,12};
-
-  UCHAR   ThTiming[]= {1,2,2,3,0,1,1,2};
-
-  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
-  data=data>>6;
-  data2=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
-  data2=(data2>>4)&0x0C;
-  data=data|data2;
-  data=data<1;
-  if(key==0) {
-    temp0=(USHORT)ThLowA[data];
-    temp1=(USHORT)ThLowA[data+1];
-  } else {
-    temp0=(USHORT)ThLowB[data];
-    temp1=(USHORT)ThLowB[data+1];
-  }
-
-  data2=0;
-  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
-  if(data&0x02) data2=data2|0x01;
-  if(data&0x20) data2=data2|0x02;
-  if(data&0x40) data2=data2|0x04;
-
-  data=temp1*ThTiming[data2]+temp0;
-  return(data);
-}
-#endif
-
 void
 SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
  		    PSIS_HW_DEVICE_INFO HwDeviceExtension,
@@ -4815,9 +3580,7 @@
 }
 #endif
 
-/* =============== Autodetection ================ */
-/*             I N C O M P L E T E                */
-
+#ifdef LINUX_XF86
 BOOLEAN
 SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
@@ -4890,254 +3653,7 @@
   }
   return 1;
 }
-
-
-#ifdef LINUXBIOS
-
-void
-SiS_DetectMonitor(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
-{
-  UCHAR  DAC_TEST_PARMS[] = {0x0F,0x0F,0x0F};
-  UCHAR  DAC_CLR_PARMS[]  = {0x00,0x00,0x00};
-  USHORT SR1F;
-
-  SR1F = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1F);		/* backup DAC pedestal */
-  SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1F,0x04);
-
-  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
-    if(!(SiS_BridgeIsOn(SiS_Pr, BaseAddr))) {
-      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x41);
-    }
-  }
-
-  SiSSetMode(SiS_Pr,HwDeviceExtension,0x2E);
-  if(HwDeviceExtension->jChipType >= SIS_650) {
-     /* TW: On 650 only - enable CRT1 */
-     SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x63,0xbf);
-  }
-  SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
-  SiS_ClearDAC(SiS_Pr, SiS_Pr->SiS_P3c8);
-  SiS_LongWait(SiS_Pr);
-  SiS_LongWait(SiS_Pr);
-  SiS_LongWait(SiS_Pr);
-  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xDF,0x00);
-  if(SiS_TestMonitorType(SiS_Pr, DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
-    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xDF,0x20);
-  } else if(SiS_TestMonitorType(SiS_Pr, DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
-    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xDF,0x20);
-  }
-  SiS_TestMonitorType(SiS_Pr, DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]);
-
-  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1F,SR1F);
-}
-
-USHORT
-SiS_TestMonitorType(SiS_Private *SiS_Pr, UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC)
-{
-   USHORT temp,tempbx;
-
-   tempbx = R_DAC * 0x4d + G_DAC * 0x97 + B_DAC * 0x1c;
-   if((tempbx & 0x00ff) > 0x80) tempbx += 0x100;
-   tempbx = (tempbx & 0xFF00) >> 8;
-   R_DAC = (UCHAR) tempbx;
-   G_DAC = (UCHAR) tempbx;
-   B_DAC = (UCHAR) tempbx;
-
-   SiS_SetReg3(SiS_Pr->SiS_P3c8,0x00);
-   SiS_SetReg3(SiS_Pr->SiS_P3c9,R_DAC);
-   SiS_SetReg3(SiS_Pr->SiS_P3c9,G_DAC);
-   SiS_SetReg3(SiS_Pr->SiS_P3c9,B_DAC);
-   SiS_LongWait(SiS_Pr);
-   temp=SiS_GetReg2(SiS_Pr->SiS_P3c2);
-   if(temp & 0x10) return(1);
-   else return(0);
-}
-
-void
-SiS_GetSenseStatus(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,UCHAR *ROMAddr)
-{
-  USHORT tempax=0,tempbx,tempcx,temp;
-  USHORT P2reg0=0,SenseModeNo=0,OutputSelect=*SiS_Pr->pSiS_OutputSelect;
-  USHORT ModeIdIndex,i;
-  USHORT BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
-
-  if(SiS_Pr->SiS_IF_DEF_LVDS == 1){
-    SiS_GetPanelID(SiS_Pr);
-    temp=LCDSense;
-    temp=temp|SiS_SenseCHTV(SiS_Pr);
-    tempbx=~(LCDSense|AVIDEOSense|SVIDEOSense);
-    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,tempbx,temp);
-  } else {       /* for 301 */
-    if(SiS_Pr->SiS_IF_DEF_HiVision==1) {  /* for HiVision */
-      tempax=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x38);
-      temp=tempax&0x01;
-      tempax=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
-      temp=temp|(tempax&0x02);
-      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xA0,temp);
-    } else {
-      if(SiS_BridgeIsOn(SiS_Pr, BaseAddr)==0) {    /* TW: Inserted "==0" */
-        P2reg0 = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00);
-        if(!(SiS_BridgeIsEnable(SiS_Pr, BaseAddr,HwDeviceExtension))) {
-          SenseModeNo=0x2e;
-          temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&SenseModeNo,&ModeIdIndex);
-          SiS_Pr->SiS_SetFlag = 0x00;
-          SiS_Pr->SiS_ModeType = ModeVGA;
-          SiS_Pr->SiS_VBInfo = SetCRT2ToRAMDAC |LoadDACFlag |SetInSlaveMode;
-          SiS_SetCRT2Group(SiS_Pr, BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
-          for(i=0;i<20;i++) {
-            SiS_LongWait(SiS_Pr);
-          }
-        }
-        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,0x1c);
-        tempax=0;
-        tempbx=*SiS_Pr->pSiS_RGBSenseData;
-	if(SiS_Is301B(SiS_Pr, BaseAddr)){
-                tempbx=*SiS_Pr->pSiS_RGBSenseData2;
-        }
-        tempcx=0x0E08;
-        if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
-          if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
-            tempax=tempax|Monitor2Sense;
-          }
-        }
-        tempbx=*SiS_Pr->pSiS_YCSenseData;
-        if(SiS_Is301B(SiS_Pr, BaseAddr)){
-               tempbx=*SiS_Pr->pSiS_YCSenseData2;
-        }
-        tempcx=0x0604;
-        if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
-          if(SiS_Sense(SiS_Pr,tempbx,tempcx)){
-            tempax=tempax|SVIDEOSense;
-          }
-        }
-
-	if(ROMAddr && SiS_Pr->SiS_UseROM) {
-#ifdef SIS300
-	   if((HwDeviceExtension->jChipType==SIS_630)||
-              (HwDeviceExtension->jChipType==SIS_730)) {
-		OutputSelect = ROMAddr[0xfe];
-	   }
-#endif
-#ifdef SIS315H
-	   if(HwDeviceExtension->jChipType >= SIS_315H) {
-	        OutputSelect = ROMAddr[0xf3];
-		if(HwDeviceExtension->jChipType >= SIS_330) {
-		     OutputSelect = ROMAddr[0x11b];
-		}
-	   }
 #endif
-        }
-        if(OutputSelect & BoardTVType){
-          tempbx = *SiS_Pr->pSiS_VideoSenseData;
-          if(SiS_Is301B(SiS_Pr, BaseAddr)){
-             tempbx = *SiS_Pr->pSiS_VideoSenseData2;
-          }
-          tempcx = 0x0804;
-          if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
-            if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
-              tempax |= AVIDEOSense;
-            }
-          }
-        } else {
-          if(!(tempax & SVIDEOSense)){
-            tempbx = *SiS_Pr->pSiS_VideoSenseData;
-            if(SiS_Is301B(SiS_Pr, BaseAddr)){
-              tempbx = *SiS_Pr->pSiS_VideoSenseData2;
-            }
-            tempcx = 0x0804;
-            if(SiS_Sense(SiS_Pr,tempbx,tempcx)){
-              if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
-                tempax |= AVIDEOSense;
-              }
-            }
-          }
-        }
-      }
-
-      if(SiS_SenseLCD(SiS_Pr, HwDeviceExtension)){
-        tempax |= LCDSense;
-      }
-
-      tempbx=0;
-      tempcx=0;
-      SiS_Sense(SiS_Pr, tempbx,tempcx);
-
-      if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV)) {
-         tempax &= 0x00ef;   /* 30xlv have no VGA2*/
-      }
-      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,~0xDF,tempax);
-      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,P2reg0);
-      if(!(P2reg0 & 0x20)) {
-        SiS_Pr->SiS_VBInfo = DisableCRT2Display;
-        SiS_SetCRT2Group(SiS_Pr,BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
-      }
-    }
-  }
-}
-
-BOOLEAN
-SiS_Sense(SiS_Private *SiS_Pr, USHORT tempbx,USHORT tempcx)
-{
-  USHORT temp,i,tempch;
-
-  temp = tempbx & 0xFF;
-  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x11,temp);
-  temp = (tempbx & 0xFF00) >> 8;
-  temp |= (tempcx & 0x00FF);
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,~0x1F,temp);
-
-  for(i=0; i<10; i++) SiS_LongWait(SiS_Pr);
-
-  tempch = (tempcx & 0x7F00) >> 8;
-  temp = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x03);
-  temp ^= 0x0E;
-  temp &= tempch;
-  if(temp>0) return 1;
-  else return 0;
-}
-
-USHORT
-SiS_SenseLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  USHORT temp;
-
-  temp=SiS_GetPanelID(SiS_Pr);
-  if(!temp)  temp=SiS_GetLCDDDCInfo(SiS_Pr, HwDeviceExtension);
-  return(temp);
-}
-
-BOOLEAN
-SiS_GetLCDDDCInfo(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  USHORT temp;
-  /*add lcd sense*/
-  if(HwDeviceExtension->ulCRT2LCDType==LCD_UNKNOWN)
-    	return 0;
-  else{
-     	temp=(USHORT)HwDeviceExtension->ulCRT2LCDType;
-     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
-  	return 1;
-  }
-}
-
-USHORT
-SiS_SenseCHTV(SiS_Private *SiS_Pr)
-{
-  USHORT temp,push0e,status;
-
-  status=0;
-  push0e = SiS_GetCH700x(SiS_Pr, 0x0e);
-  push0e = (push0e << 8) | 0x0e;
-  SiS_SetCH700x(SiS_Pr, 0x0b0e);
-  SiS_SetCH700x(SiS_Pr, 0x0110);
-  SiS_SetCH700x(SiS_Pr, 0x0010);
-  temp = SiS_GetCH700x(SiS_Pr, 0x10);
-  if(temp & 0x08) status |= SVIDEOSense;
-  if(temp & 0x02) status |= AVIDEOSense;
-  SiS_SetCH700x(SiS_Pr, push0e);
-  return(status);
-}
-#endif /* LINUXBIOS */
 
 /* ================ XFREE86 ================= */
 
diff -Nru a/drivers/video/sis/init.h b/drivers/video/sis/init.h
--- a/drivers/video/sis/init.h	Sun Jun 29 09:27:44 2003
+++ b/drivers/video/sis/init.h	Fri Aug 29 04:42:01 2003
@@ -28,6 +28,9 @@
  * PERFORMANCE OF THIS SOFTWARE.
  *
  * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Based on code by Silicon Intergrated Systems
+ *
  */
 
 #ifndef _INIT_
@@ -766,7 +769,8 @@
  {   12,   5, 954, 448,1270, 530,  50,   0,  50,0xf1,0x04,0x1f,0x18},
  {    9,   4, 960, 463,1644, 438,  50,   0,  50,0xf4,0x0b,0x1c,0x0a},
  {    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a},  /* 640x480, 320x240 */
- {   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},  /* 800x600, 400x300 */
+/*{  36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},*//* 800x600, 400x300 */
+ {   36,  25,1060, 648,1270, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},  /* 800x600, 400x300 - better */
  {    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},  /* 720x576 */
  {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}   /* 1024x768 */
 };
@@ -926,27 +930,45 @@
 };
 
 static const SiS_LCDDataStruct  SiS_StLCD1600x1200Data[] =
-{  /* TODO */
-	{    0,   0,   0,   0,   0,   0}
+{
+	{27,  4, 800, 500, 2160, 1250 },
+	{27,  4, 800, 500, 2160, 1250 },
+	{ 6,  1, 900, 500, 2160, 1250 },
+	{ 6,  1, 900, 500, 2160, 1250 },
+	{27,  1, 800, 500, 2160, 1250 },
+	{ 4,  1,1080, 625, 2160, 1250 },
+	{ 5,  2,1350, 800, 2160, 1250 },
+	{135,88,1600,1100, 2160, 1250 },
+	{135,88,1600,1100, 2160, 1250 },
+	{ 1,  1,2160,1250, 2160, 1250 }
 };
 
 static const SiS_LCDDataStruct  SiS_ExtLCD1600x1200Data[] =
-{  /* TODO */
-	{    0,   0,   0,   0,   0,   0}
+{
+	{27, 4, 800, 500, 2160, 1250 },
+	{27, 4, 800, 500, 2160, 1250 },
+	{ 6, 1, 900, 500, 2160, 1250 },
+	{ 6, 1, 900, 500, 2160, 1250 },
+	{27, 1, 800, 500, 2160, 1250 },
+	{ 4, 1,1080, 625, 2160, 1250 },
+	{ 5, 2,1350, 800, 2160, 1250 },
+	{27,16,1500,1064, 2160, 1250 },
+	{27,16,1500,1064, 2160, 1250 },
+	{ 1, 1,2160,1250, 2160, 1250 }
 };
 
 static const SiS_LCDDataStruct  SiS_NoScaleData1600x1200[] =
-{  /* TODO - values guessed */
-        {1,  1, 2048, 1250, 2048, 1250},
-	{1,  1, 2048, 1250, 2048, 1250},
-	{1,  1, 2048, 1250, 2048, 1250},
-	{1,  1, 2048, 1250, 2048, 1250},
-	{1,  1, 2048, 1250, 2048, 1250},
-	{1,  1, 2048, 1250, 2048, 1250},
-	{1,  1, 2048, 1250, 2048, 1250},
-	{1,  1, 2048, 1250, 2048, 1250},
-	{1,  1, 2048, 1250, 2048, 1250},
-	{1,  1, 2048, 1250, 2048, 1250}
+{
+        {1,  1, 2160, 1250, 2048, 1250},
+	{1,  1, 2160, 1250, 2048, 1250},
+	{1,  1, 2160, 1250, 2048, 1250},
+	{1,  1, 2160, 1250, 2048, 1250},
+	{1,  1, 2160, 1250, 2048, 1250},
+	{1,  1, 2160, 1250, 2048, 1250},
+	{1,  1, 2160, 1250, 2048, 1250},
+	{1,  1, 2160, 1250, 2048, 1250},
+	{1,  1, 2160, 1250, 2048, 1250},
+	{1,  1, 2160, 1250, 2048, 1250},
 };
 
 static const SiS_LCDDataStruct  SiS_NoScaleData[] =
@@ -960,7 +982,7 @@
 	{ 1, 1,1344, 806,1344, 806 },
 	{ 1, 1,1688,1066,1688,1066 },
         { 1, 1,1688, 802,1688, 802 },  /* 1280x768: 802 was 806 in both cases */
-        { 1, 1,2048,1250,2048,1250 },  /* 1600x1200 (guessed) */
+        { 1, 1,2160,1250,2160,1250 },  /* 1600x1200 */
 	{ 1, 1,1800,1000,1800,1000 }   /* 1280x960 */
 };
 
@@ -1302,6 +1324,40 @@
 	{ 800, 525,1280, 813}
 };
 
+static const SiS_LVDSDataStruct  SiS_LVDS848x480Data_1[]=
+{
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{1088, 525,1088, 525},  /* 640x480 TODO */
+	{1088, 525,1088, 525},  /* 800x600 TODO */
+	{1088, 525,1088, 525},  /* 1024x768 TODO */
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{1088, 525,1088, 525},  /* 848x480 */
+	{1088, 525,1088, 525}   /* 1360x768 TODO */
+};
+
+static const SiS_LVDSDataStruct  SiS_LVDS848x480Data_2[]=
+{
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{1088, 525,1088, 525},  /*  640x480 */
+	{1088, 525,1088, 525},  /*  800x600 */
+	{1088, 525,1088, 525},  /* 1024x768 */
+	{   0,   0,   0,   0},  
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{   0,   0,   0,   0},
+	{1088, 525,1088, 525},  /* 848x480 */
+	{1088, 525,1088, 525}	/* 1360x768 TODO */
+};
+
 /* LCDA */
 
 static const SiS_LVDSDataStruct  SiS_LCDA1400x1050Data_1[]=
@@ -2126,6 +2182,7 @@
    USHORT vendor;
    UCHAR  productnum;
    USHORT product[5];
+   const char *DDCnames[5];
    const char *plasmaname;
    UCHAR  modenum;
    UCHAR  plasmamodes[20];  /* | 0x80 = DVI-capable, | 0x40 = analog */
@@ -2233,13 +2290,17 @@
 #if 0  /* Product IDs missing */
    { 0x38a3, 4,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 42VP4/42VP4D/42VP4G/42VP4DG",
-     14,   /* All DVI, except 0, 7, 13; 3, 15, 16 unknown */
-     { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,12|0xc0,
-      13|0x40,14|0xc0,15|0xc0,16|0xc0, 0     , 0     , 0     , 0     , 0     , 0 }
+     11,   /* All DVI, except 0, 7, 13 */
+     { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0,
+      17|0xc0, 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0     , 0       }
    },
+#endif
+#if 0  /* Product IDs missing */
    { 0x38a3, 3,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 42PD1/50PD1/50PD2",
      5,   /* DVI entirely unknown */
      { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0, 0     , 0     , 0     , 0     , 0     ,
@@ -2247,6 +2308,7 @@
    },
    { 0x38a3, 1,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 42PD3",
      10,   /* DVI entirely unknown */
      { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 5|0xc0, 6|0xc0, 7|0x40, 8|0xc0, 9|0xc0,
@@ -2254,6 +2316,7 @@
    },
    { 0x38a3, 2,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 42VM3/61XM1",
      11,  /* DVI entirely unknown */
      { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 5|0xc0, 6|0xc0, 8|0xc0, 9|0xc0,11|0xc0,
@@ -2261,6 +2324,7 @@
    },
    { 0x38a3, 2,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 42MP1/42MP2",
      6,   /* DVI entirely unknown */
      { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0,11|0xc0, 0     , 0     , 0     , 0     ,
@@ -2268,6 +2332,7 @@
    },
    { 0x38a3, 1,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 50MP1",
      10,   /* DVI entirely unknown */
      { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0,
@@ -2276,6 +2341,7 @@
 #endif
    { 0x38a3, 4,
      { 0xa482, 0xa483, 0x0000, 0x0000, 0x0000 },
+     { "PX-42VM", "", "", "", "" },
      "NEC PlasmaSync 42MP3/42MP4/50MP2/61MP1",
      11,   /* All DVI except 0, 7, 13, 17 */
      { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0,
@@ -2284,6 +2350,7 @@
 #if 0  /* Product IDs missing */
    { 0x38a3, 1,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 3300W",
      3,
      { 0|0x40, 1|0xc0,18|0xc0, 0     , 0     , 0     , 0     , 0     , 0     , 0     ,
@@ -2291,6 +2358,7 @@
    },
    { 0x38a3, 1,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 4200W",
      4,   /* DVI entirely unknown */
      { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 0     , 0     , 0     , 0     , 0     , 0     ,
@@ -2298,6 +2366,7 @@
    },
    { 0x38a3, 1,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 4210W",
      6,   /* DVI entirely unknown */
      { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0,11|0xc0, 0     , 0     , 0     , 0     ,
@@ -2305,6 +2374,7 @@
    },
    { 0x38a3, 1,
      { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "NEC PlasmaSync 5000W",
      7,   /* DVI entirely unknown */
      { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,11|0xc0, 0     , 0     , 0     ,
@@ -2313,6 +2383,7 @@
 #endif
    { 0x412f, 2,
      { 0x000c, 0x000b, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "Pioneer 503CMX/PDA-5002",
      6,   /* DVI unknown */
      { 1|0xc0, 2|0xc0, 9|0xc0,11|0xc0,12|0xc0,15|0xc0, 0     , 0     , 0     , 0     ,
@@ -2320,6 +2391,7 @@
    },
    { 0x34a9, 1,
      { 0xa00e, 0x0000, 0x0000, 0x0000, 0x0000 },
+     { "", "", "", "", "" },
      "Panasonic TH-42",
      5,   /* No DVI output */
      { 1|0x40, 2|0x40, 4|0x40, 9|0x40,15|0x40, 0     , 0     , 0     , 0     , 0     ,
@@ -2338,51 +2410,21 @@
 ULONG    SiS_GetReg3(USHORT);
 USHORT   SiS_GetReg4(USHORT);
 void     SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG);
-void     SiS_SetMemoryClock(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetDRAMModeRegister(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 BOOLEAN  SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo);
 void     SiS_IsLowResolution(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
 void     SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
-
-#ifdef SIS300
-void     SiS_SetDRAMSize_300(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
-USHORT   SiS_ChkBUSWidth_300(SiS_Private *SiS_Pr, ULONG FBAddress);
-#endif
-
 #ifdef SIS315H
 UCHAR    SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_DDR_MRS(SiS_Private *SiS_Pr);
-void     SiS_SDR_MRS(SiS_Private *SiS_Pr);
-void     SiS_DisableRefresh(SiS_Private *SiS_Pr);
-void     SiS_EnableRefresh(SiS_Private *SiS_Pr, UCHAR *ROMAddr);
-void     SiS_SetDRAMSize_310(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
-void     SiS_DisableChannelInterleaving(SiS_Private *SiS_Pr, int index,USHORT SiS_DDRDRAM_TYPE[][5]);
-void     SiS_SetDRAMSizingType(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5]);
-void     SiS_CheckBusWidth_310(SiS_Private *SiS_Pr, UCHAR *ROMAddress,ULONG FBAddress,
-                               PSIS_HW_DEVICE_INFO HwDeviceExtension);
-int      SiS_SetRank(SiS_Private *SiS_Pr, int index,UCHAR RankNo,USHORT DRAMTYPE_TABLE[][5]);
-int      SiS_SetDDRChannel(SiS_Private *SiS_Pr, int index,UCHAR ChannelNo,
-                           USHORT DRAMTYPE_TABLE[][5]);
-int      SiS_CheckColumn(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int      SiS_CheckBanks(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int      SiS_CheckRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int      SiS_CheckDDRRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int      SiS_CheckRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int      SiS_CheckDDRRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int      SiS_SDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress);
-int      SiS_DDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress);
-int      Is315E(SiS_Private *SiS_Pr);
-void     SiS_VerifyMclk(SiS_Private *SiS_Pr, ULONG FBAddr);
 #endif
-
 void     SiS_HandleCRT1(SiS_Private *SiS_Pr);
 void     SiS_Handle301B_1400x1050(SiS_Private *SiS_Pr, USHORT ModeNo);
 void     SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable);
 void     SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable);
-void     SiS_Delay15us(SiS_Private *SiS_Pr);
 BOOLEAN  SiS_SearchModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo,USHORT *ModeIdIndex);
+#ifndef LINUX_XF86
 BOOLEAN  SiS_CheckMemorySize(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                              USHORT ModeNo,USHORT ModeIdIndex);
+#endif
 UCHAR    SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
 void     SiS_WhatTheHellIsThis(SiS_Private *SiS_Pr,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
 void     SiS_StrangeStuff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
@@ -2434,14 +2476,6 @@
 void     SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT ModeNo);
 void     SiS_SetCRT1Group(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                           USHORT ModeNo,USHORT ModeIdIndex,USHORT BaseAddr);
-void     SiS_DetectMonitor(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
-void     SiS_GetSenseStatus(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,UCHAR *ROMAddr);
-USHORT   SiS_TestMonitorType(SiS_Private *SiS_Pr, UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC);
-USHORT   SiS_SenseCHTV(SiS_Private *SiS_Pr);
-BOOLEAN  SiS_Sense(SiS_Private *SiS_Pr, USHORT tempbx,USHORT tempcx);
-BOOLEAN  SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
-BOOLEAN  SiS_GetLCDDDCInfo(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
-USHORT   SiS_SenseLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
 void     SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr);
 void     SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
 void     SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo);
@@ -2449,6 +2483,7 @@
 void     SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, UCHAR *ROMAddr);
 
 #ifdef LINUX_XF86
+BOOLEAN  	SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
 USHORT 		SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags);
 void    	SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr);
 void    	SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr);
diff -Nru a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c
--- a/drivers/video/sis/init301.c	Sun Jun 29 08:10:20 2003
+++ b/drivers/video/sis/init301.c	Wed Aug 27 03:41:54 2003
@@ -1,11 +1,11 @@
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.c,v 1.3 2002/22/04 01:16:16 dawes Exp $ */
 /*
- * Mode switching code (CRT2 section) for SiS 300/540/630/730/315/550/650/740/330/660
+ * Mode switching code (CRT2 section)
+ * for SiS 300/305/540/630/730/315/550/650/M650/651/740/330/660/M660/760/M760
  * (Universal module for Linux kernel framebuffer and XFree86 4.x)
  *
- * Assembler-To-C translation
  * Copyright 2002, 2003 by Thomas Winischhofer <thomas@winischhofer.net>
- * Formerly based on non-functional code-fragements by SiS, Inc.
+ * Formerly based on non-functional code-fragements for 300 series by SiS, Inc.
  *
  * If distributed as part of the linux kernel, the contents of this file
  * is entirely covered by the GPL.
@@ -107,7 +107,7 @@
        ((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) ||
        ((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) {
    	SiS_GetLVDSDesData(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-	                   HwDeviceExtension);
+	                   HwDeviceExtension, BaseAddr);
    } else {
         SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0;
    }
@@ -318,7 +318,7 @@
 
      if( (HwDeviceExtension->jChipType >= SIS_315H) &&
          (SiS_Pr->SiS_IF_DEF_LVDS == 1) &&
-	 (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+	 (SiS_Pr->SiS_VBInfo & SetInSlaveMode) ) {
 
         SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
                         RefreshRateTableIndex,HwDeviceExtension);
@@ -649,7 +649,7 @@
 		}
 		if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
 		   if(HwDeviceExtension->pdc) {
-			temp = HwDeviceExtension->pdc & 0x3c;
+		      temp = HwDeviceExtension->pdc & 0x3c;
 		   }
 		}
 	   }
@@ -695,6 +695,14 @@
 		} else {  /* LV (550/301LV checks ROM byte, other LV BIOSes do not) */
 		   tempbl = 0xF0;
 		}
+		if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD|SetCRT2ToLCDA)) {
+		   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+		      if(HwDeviceExtension->pdc) {
+		         temp = HwDeviceExtension->pdc;
+		         tempbl = 0;
+		      }
+		   }
+		}
 	   } else {
 	        if(HwDeviceExtension->jChipType == SIS_740) {
 		   temp = 0x03;
@@ -1156,7 +1164,8 @@
   if((!SiS_Pr->SiS_IF_DEF_FSTN) &&
      (!SiS_Pr->SiS_IF_DEF_DSTN) &&
      (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
-     (SiS_Pr->SiS_CustomT != CUT_BARCO1024)) {
+     (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
+     (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
      if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
@@ -1201,7 +1210,8 @@
         if((!SiS_Pr->SiS_IF_DEF_DSTN) &&
 	   (!SiS_Pr->SiS_IF_DEF_FSTN) &&
 	   (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
-	   (SiS_Pr->SiS_CustomT != CUT_BARCO1024)) {
+	   (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
+	   (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
 	      temp += 6;
               if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
@@ -1311,7 +1321,8 @@
   if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&
      (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) &&
      (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
-     (SiS_Pr->SiS_CustomT != CUT_BARCO1024)) {
+     (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
+     (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
         SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) {
 	tempcx = 0x0017;
@@ -1365,7 +1376,8 @@
 
   if((!(SiS_Pr->SiS_LCDInfo & LCDPass11)) &&
      (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
-     (SiS_Pr->SiS_CustomT != CUT_BARCO1024)) {
+     (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
+     (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
         if( (HwDeviceExtension->jChipType < SIS_315H) &&
             (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) )     tempcx = 0x0001;
@@ -1400,7 +1412,8 @@
   if(SiS_Pr->SiS_IF_DEF_FSTN ||
      SiS_Pr->SiS_IF_DEF_DSTN ||
      (SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
-     (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
+     (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
+     (SiS_Pr->SiS_CustomT == CUT_PANEL848)) {
      temp |= 0x30;
   }
   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xf0,temp); /* Part1_19h; Panel Link Vertical Retrace End (3:0); Misc.  */
@@ -2186,8 +2199,16 @@
 
          if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {	  		/* 315 - 30xLV */
 
-            tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
-            tempah &= 0xC0;
+	    if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+	       tempah = infoflag >> 8;
+	       if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+	          tempah = SiS_Pr->SiS_LCDInfo;
+	       }
+	    } else {
+               tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+	    }
+	    tempah &= 0xC0;
+
             tempah |= 0x20;
             if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
             SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
@@ -2195,15 +2216,14 @@
          } else {							/* 315 - 301, 301B */
 
             tempah = infoflag >> 8;
-            tempah &= 0xC0;
 	    if(!SiS_Pr->UseCustomMode) {
 	       if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
 	          if(SiS_Pr->SiS_LCDInfo & LCDSync) {
 	             tempah = SiS_Pr->SiS_LCDInfo;
-	             tempah &= 0xC0;
 	          }
 	       }
 	    }
+	    tempah &= 0xC0;
 	    
             tempah |= 0x20;
             if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
@@ -2687,25 +2707,26 @@
 /* Checked against 650/LVDS 1.10.07 BIOS */
 void
 SiS_GetLVDSDesData(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   USHORT RefreshRateTableIndex,
-		   PSIS_HW_DEVICE_INFO HwDeviceExtension)
+                   USHORT RefreshRateTableIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+		   USHORT BaseAddr)
 {
   USHORT modeflag;
   USHORT PanelIndex,ResIndex;
   const  SiS_LVDSDesStruct *PanelDesPtr = NULL;
 
   if((SiS_Pr->UseCustomMode) ||
-     (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom)) {
+     (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) ||
+     (SiS_Pr->SiS_CustomT == CUT_PANEL848)) {
      SiS_Pr->SiS_LCDHDES = 0;
      SiS_Pr->SiS_LCDVDES = 0;
      return;
   }
 
-  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ) {
+  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
 
 #ifdef SIS315H  
      SiS_GetLVDSDesPtrA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                        &PanelIndex,&ResIndex);
+                        &PanelIndex,&ResIndex, HwDeviceExtension, BaseAddr);
 			
      switch (PanelIndex)
      {
@@ -2717,6 +2738,8 @@
      	case  5: PanelDesPtr = SiS_Pr->LVDS1280x1024Des_2;  break;
 	case  6: PanelDesPtr = SiS_Pr->LVDS1400x1050Des_2;  break;
 	case  7: PanelDesPtr = SiS_Pr->LVDS1600x1200Des_2;  break;
+	case 80: PanelDesPtr = (SiS_LVDSDesStruct *)Clevo1024x768Des_1;  break;  /*  custom  */
+	case 81: PanelDesPtr = (SiS_LVDSDesStruct *)Clevo1024x768Des_2;  break;
 	default: PanelDesPtr = SiS_Pr->LVDS1024x768Des_1;   break;
      }
 #endif
@@ -2868,7 +2891,8 @@
 #ifdef SIS315H
 void
 SiS_GetLVDSDesPtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex)
+                   USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex,
+		   PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
 {
   USHORT tempbx=0,tempal;
 
@@ -2878,6 +2902,15 @@
 
   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx += 4;
 
+  if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+        if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr)) {
+	   tempbx = 80;
+	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
+	}
+     }
+  }
+
   if(ModeNo <= 0x13)
      tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
   else
@@ -3077,7 +3110,7 @@
 	/* For 302LV dual-channel */
 	if(HwDeviceExtension->jChipType >= SIS_315H) {
 	   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-	      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04)
+	      if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr))
 	         tempah |= 0x40;
 	   }
 	}
@@ -3439,6 +3472,8 @@
 	case 81:  LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2;  break;
 	case 82:  LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1;  break;
 	case 83:  LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_2;  break;
+	case 84:  LVDSData = SiS_Pr->SiS_LVDS848x480Data_1;    break;
+	case 85:  LVDSData = SiS_Pr->SiS_LVDS848x480Data_2;    break;
 	case 90:  LVDSData = SiS_Pr->SiS_CHTVUPALMData;        break;
       	case 91:  LVDSData = SiS_Pr->SiS_CHTVOPALMData;        break;
       	case 92:  LVDSData = SiS_Pr->SiS_CHTVUPALNData;        break;
@@ -3666,6 +3701,11 @@
          case 27: LCDPtr = SiS_Pr->SiS_NoScaleData1280x768;       break; /* Non-expanding */
          case 28: LCDPtr = SiS_Pr->SiS_StLCD1280x768Data;         break; /* Non-VESA Timing */
          case 29: LCDPtr = SiS_Pr->SiS_NoScaleData;	          break; /* Generic no-scale data */
+#ifdef SIS315H
+	 case 50: LCDPtr = (SiS_LCDDataStruct *)SiS310_ExtCompaq1280x1024Data;	break;
+	 case 51: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024;			break;
+	 case 52: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;	  		break;
+#endif
          default: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;	  break; /* Just to avoid a crash */
         }
 
@@ -3712,6 +3752,11 @@
            else if(SiS_Pr->SiS_VGAVDE == 400)  tempbx = 800;
            else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960;
            else                                tempbx = 960;
+        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+           tempax = 1600;
+           if     (SiS_Pr->SiS_VGAVDE == 350)  tempbx = 875;
+           else if(SiS_Pr->SiS_VGAVDE == 400)  tempbx = 1000;
+           else                                tempbx = 1200;
         } else {
 	   tempax = SiS_Pr->PanelXRes;
            tempbx = SiS_Pr->PanelYRes;
@@ -3785,7 +3830,7 @@
            if(xres == 720) xres = 640;
 	} else {
 	   if(SiS_Pr->SiS_VBType & VB_NoLCD) {           /* 301BDH */
-	        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVisionTV)) {
                    if(xres == 720) xres = 640;
 		}
 		if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
@@ -3797,19 +3842,13 @@
 	           }
 	        }
 	   } else {
-	      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToAVIDEO |           /* (Allow 720 for VGA2) */
-	      			       SetCRT2ToSVIDEO |
-	                               SetCRT2ToSCART  | 
-				       SetCRT2ToLCD    | 
-				       SetCRT2ToHiVisionTV)) {
+	      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVisionTV)) {
 	         if(xres == 720) xres = 640;
 	      }
 	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
 		 if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-		    if((ModeNo <= 0x13) || (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
-		       /* Panel on 301B via DVI shows 5 extra (garbage-)lines if this is done,
-		        * panel on 30xLV blinks if it's not done...
-			*/
+		    if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+		       /* BIOS bug - does this regardless of scaling */
       		       if(yres == 400) yres = 405;
 		    }
       		    if(yres == 350) yres = 360;
@@ -3905,6 +3944,14 @@
        		   }
 	        }
 
+#ifdef SIS315H
+		if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+		   tempbx = 50;
+		   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         tempbx = 51;
+		   else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 52;
+		}
+#endif
+
      	} else {						  	/* TV */
 	
        		if((SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
@@ -3912,7 +3959,7 @@
          		if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_SetFlag &= (~TVSimuMode);
          		tempbx = 2;
          		if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-            			if(!(SiS_Pr->SiS_SetFlag & TVSimuMode)) tempbx = 12; 
+            			if(!(SiS_Pr->SiS_SetFlag & TVSimuMode)) tempbx = 12;
          		}
        		} else {
          		if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx = 3;
@@ -3949,7 +3996,9 @@
 	      if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
               if(SiS_Pr->SiS_VBInfo & SetPALTV) {
 		 tempbx += 2;
-		 if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
+		 if(SiS_Pr->SiS_ModeType > ModeVGA) {
+		    if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
+		 }
 		 if(SiS_Pr->SiS_CHPALM) {
 		    tempbx = 90;
 		    if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
@@ -3999,7 +4048,12 @@
 		if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
 		   tempbx = 7;
         	}
-		
+
+		if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
+		   tempbx = 84;
+		   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
+		}
+
 	}
 
 #if 0
@@ -4063,7 +4117,8 @@
 void
 SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
 		    USHORT RefreshRateTableIndex,USHORT *CRT2Index,
-		    USHORT *ResIndex)
+		    USHORT *ResIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+		    USHORT BaseAddr)
 {
   USHORT tempbx,tempal;
 
@@ -4077,6 +4132,24 @@
   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)      tempbx += 16;
   else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx += 32;
 
+#ifdef SIS315H
+  if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+        tempbx = 100;
+        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)      tempbx = 101;
+  	else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx = 102;
+     }
+  } else if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+        if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr)) {
+           tempbx = 103;
+           if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)      tempbx = 104;
+  	   else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx = 105;
+	}
+     }
+  }
+#endif
+
   *CRT2Index = tempbx;
   *ResIndex = tempal & 0x3F;
 }
@@ -4085,10 +4158,11 @@
 SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo, USHORT ModeIdIndex,
                    PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  SHORT  LCDRefreshIndex[] = { 0x00, 0x00, 0x03, 0x01,
+  SHORT  LCDRefreshIndex[] = { 0x00, 0x00, 0x01, 0x01,
                                0x01, 0x01, 0x01, 0x01,
 			       0x01, 0x01, 0x01, 0x01,
-			       0x01, 0x01, 0x01, 0x01 };
+			       0x01, 0x01, 0x01, 0x01,
+			       0x00, 0x00, 0x00, 0x00 };
   USHORT RefreshRateTableIndex,i,backup_i;
   USHORT modeflag,index,temp,backupindex;
 
@@ -4427,6 +4501,10 @@
 		     if(resinfo == SIS_RI_512x384)  return(0);
 		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelBarco1366) {
                      if((resinfo != SIS_RI_1360x1024) && (resinfo > SIS_RI_1280x1024)) return(0);
+		}  else if(SiS_Pr->SiS_LCDResInfo == Panel_848x480) {
+                     if((resinfo != SIS_RI_1360x768) &&
+		        (resinfo != SIS_RI_848x480)  &&
+		        (resinfo > SIS_RI_1024x768)) return(0);
 		}
     	}
   }
@@ -4729,6 +4807,9 @@
       		if( (temp & 0x80) || (SiS_Pr->SiS_CHOverScan == 1) )
 		      tempbx |= SetCHTVOverScan;
     	   }
+	   if(SiS_Pr->SiS_CHSOverScan) {
+	      tempbx |= SetCHTVOverScan;
+	   }
 	}
   }
 
@@ -5056,40 +5137,50 @@
 
 	      modenum = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34);
 
-              if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+              if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {			/* LV */
 	      
 	         SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
 		 
 		 if( (modenum <= 0x13) ||
 		     (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
 		     (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ) {
-	     	      SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+	     	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE);
+		      if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+		         SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		      }
 	         }
-		 SiS_DDC2Delay(SiS_Pr,0xff00);
-		 SiS_DDC2Delay(SiS_Pr,0x6000);
-		 SiS_DDC2Delay(SiS_Pr,0x8000);
-
-	         SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
 
-                 pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
+		 if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
+		    SiS_DDC2Delay(SiS_Pr,0xff00);
+		    SiS_DDC2Delay(SiS_Pr,0x6000);
+		    SiS_DDC2Delay(SiS_Pr,0x8000);
 
-		 if(IS_SIS740) {
-		    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
-		 }
+	            SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
 
-	         SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+                    pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
 
-		 if(!(IS_SIS740)) {
-		    if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
-	               tempah = 0xef;
-	               if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
-	                  tempah = 0xf7;
-                       }
-	               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+		    if(IS_SIS740) {
+		       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
 		    }
-	         }
 
-              } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+	            SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+
+		    if(!(IS_SIS740)) {
+		       if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	                  tempah = 0xef;
+	                  if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	                     tempah = 0xf7;
+                          }
+	                  SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+		       }
+	            }
+		 }
+
+              } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {			/* B-DH */
+	         /* This is actually bullshit. The B-DH bridge has cetainly no
+		  * Part4 Index 26, since it has no ability to drive LCD panels
+		  * at all. But as the BIOS does it, we do it, too...
+		  */
 	         if(HwDeviceExtension->jChipType == SIS_650) {
 	            if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
 	               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,0xef);
@@ -5102,7 +5193,11 @@
 		 }
 	      }
 
-              if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	      if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+	         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,0xef);
+	      }
+
+              if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
 	         tempah = 0x3f;
 	         if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
 	            tempah = 0x7f;
@@ -5116,7 +5211,7 @@
               if((SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
 	         ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) {
 
-	         if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	         if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
 		    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF);
 		    SiS_DisplayOff(SiS_Pr);
 		    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
@@ -5139,7 +5234,7 @@
 
 	      } else {
 
-	         if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	         if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
 		    if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
 		       SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
 		       SiS_DisplayOff(SiS_Pr);
@@ -5163,7 +5258,7 @@
 
 	      }
 
-	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	      if((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (SiS_Pr->SiS_CustomT != CUT_COMPAQ1280)) {
 
 		 SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,~0x10);    		/* 1.10.8r, 8m */
 
@@ -5195,18 +5290,21 @@
 	         SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
 
   	      } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+
 	         if(HwDeviceExtension->jChipType == SIS_650) {
 		    if((SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
 		       (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)))) {
 		       if((!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
 		          (!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)))) {
 			  SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
-	     	          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+	     	          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
 			  SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
 	               }
 		    }
 		 }
-	      } else if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+
+	      } else if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
+
 	         if(HwDeviceExtension->jChipType == SIS_650) {
 		    if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
 	               tempah = 0xef;
@@ -5217,7 +5315,19 @@
                        }
 	               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
 		    }
+		    if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+		       if((SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+		          (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)))) {
+		          if((!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
+		             (!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)))) {
+			     SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
+	     	             SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
+			     SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
+	                  }
+		       }
+		    }
 		 }
+
 	      }
 
 	  } else {			/* 315, 330 - all bridge types */
@@ -5611,42 +5721,62 @@
 #endif
 
 	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
-	    
-	       SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef);  /* 1.10.7u */
-	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);    /* 1.10.7u */
+
+	       if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
+	          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef);  /* 1.10.7u */
+	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);    /* 1.10.7u */
+	       }
 
 	       if(!(IS_SIS740)) {
                   if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
 	             tempah = 0x10;
-	             if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
-	                tempah = 0x08;
-                     }
-	             SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+		     if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+		        if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x13) & 0x04) {
+			   if((SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) == 0x0c) {
+			      tempah = 0x08;
+			   } else {
+			      tempah = 0x18;
+			   }
+			}
+			SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+		     } else {
+	                if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	                   tempah = 0x08;
+                        }
+			SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+		     }
 	          }
 	       }
 
-	       SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
-	       SiS_DisplayOff(SiS_Pr);
-	       pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
-	       if(IS_SIS740) {
-	          SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
+	       if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
+	          SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
+	          SiS_DisplayOff(SiS_Pr);
+	          pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
+	          if(IS_SIS740) {
+	             SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
+	          }
 	       }
 
 	       if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
 	           (SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) ) {
-                   if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
-		      SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 2);
-		      SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
-	              SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 2);
-	           }
+                  if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+		     if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
+		        SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 2);
+		     }
+		     SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+	             SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 2);
+	          }
 	       }
 
-	       if(!(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x40)) {
-                  SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
-		  delaylong = TRUE;
+               if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
+	          if(!(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x40)) {
+                     SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
+		     delaylong = TRUE;
+		  }
 	       }
 
 	    } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+
 	       if(HwDeviceExtension->jChipType == SIS_650) {
 	          if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
 	             SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,0x10);
@@ -5657,33 +5787,39 @@
 		     SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 0);
 		  }
 	       }
+
   	    } else if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
 
-	         if(HwDeviceExtension->jChipType == SIS_650) {
-		    if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
-	               tempah = 0x10;
-		       if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x13) & 0x04) {
-		          tempah = 0x18;
-		          if((SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) == 0x0c) {
-			     tempah = 0x08;
-			  }
-		       }
-	               SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah);
-		    }
-		 }
-	      }
+	       if(HwDeviceExtension->jChipType == SIS_650) {
+		  if(!(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	             tempah = 0x10;
+		     if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x13) & 0x04) {
+		        tempah = 0x18;
+		        if((SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) == 0x0c) {
+			   tempah = 0x08;
+			}
+		     }
+	             SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+		  }
+	       }
+	       
+	    }
 
 	    if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
                temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
 	       if(SiS_BridgeInSlave(SiS_Pr)) {
                   tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
-                  if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+                  if(!(tempah & SetCRT2ToRAMDAC)) {
+		     if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+		        if(!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x13) & 0x04)) temp |= 0x20;
+		     } else temp |= 0x20;
+		  }
                }
                SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
 
 	       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
 	       
-	       if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	       if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
 	          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
 		  temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2e);
 		  if(!(temp & 0x80)) {
@@ -5695,12 +5831,12 @@
 	    }
 
 	    if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
-	          SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+	       SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20);
 	    }
 
 	    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
 
-	    if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	    if((SiS_Pr->SiS_VBType & VB_SIS301B302B) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280)) {
 	       temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2e);
 	       if(!(temp & 0x80)) {
 		  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
@@ -5716,7 +5852,9 @@
 	    }
             SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
 
-	    if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	    if((SiS_Pr->SiS_VBType & VB_SIS301B302B) ||
+	       ((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) &&
+	        (!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))))) {
                SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
 	    }
 
@@ -5726,60 +5864,87 @@
 	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c);
 	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20);
 
-	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x12);
-	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0xd0);
-	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x6b);
-	       if((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0x0f) == 0x02) {
-	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x0d);
-	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x70);
-	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x40);
-		  if(((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xf0) != 0x03)) {
-		     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x05);
-	             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x60);
-	             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x33);  /* 00 */
+	       if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+
+		  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x08);
+	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x10);
+	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x4d);
+		  if((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0x0f) != 0x02) {
+		     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x0d);
+	             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x70);
+	             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x6b);
 		  }
+		  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+
+	       } else {
+
+	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x12);
+	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0xd0);
+	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x6b);
+	          if((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0x0f) == 0x02) {   /* @@@@ really == ? */
+	             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x0d);
+	             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x70);
+	             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x40);
+		     if(((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xf0) != 0x03)) {
+		        SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x05);
+	                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x60);
+	                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x33);  /* 00 */
+		     }
+	          }
+	          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+	          if((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0x0f) != 0x03) {
+	             SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
+	          }
 	       }
-	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
-	       if((SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0x0f) != 0x03) {
-	          SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
+
+	       if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
+	          SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
 	       }
-	       
-	       SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
-	    
+
 	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1f,0x10);  /* 1.10.8r */
 
-	       SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
+	       if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
 
-	       if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
 	          if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
 	              ((SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension))) ) {
-		     SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
-		     if(delaylong) {
-			SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
-		     }
-                     SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
-		     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfe,0x01);
+		     SiS_DisplayOn(SiS_Pr);
+		     SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+		     SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+		     SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+	             SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
+		     if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfe,0x01);
+	  	     }
+		  }
+
+	       } else {
+
+	          SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
+
+	          if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	             if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+	                 ((SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension))) ) {
+		        SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
+		        if(delaylong) {
+			   SiS_SetPanelDelayLoop(SiS_Pr,ROMAddr, HwDeviceExtension, 3, 10);
+		        }
+                        SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+		        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfe,0x01);
+	             }
 	          }
-	       }
 
-	       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
-	       SiS_DisplayOn(SiS_Pr);
-	       SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+	          SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
+	          SiS_DisplayOn(SiS_Pr);
+	          SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+
+	          if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	             SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+	          }
 
-	       if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
-	          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
 	       }
-#if 0
-               SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
-	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c);
-	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20);
-	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x05);   /* 1.10.8r: 0x0d */
-	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x60);   /* 1.10.8r: 0x70 */
-	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x00);   /* 1.10.8r: 0x40 */
-	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
-	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
-#endif	      
+
 	    } if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+
 	       if(HwDeviceExtension->jChipType == SIS_650) {
 	          if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
 		     if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
@@ -5789,52 +5954,53 @@
 		     }
 		  }
 	       }
+
   	    }
 
 	 } else {			/* 315, 330 */
 
-	   if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
-	      temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
-	      if(SiS_BridgeInSlave(SiS_Pr)) {
-                 tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
-                 if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
-              }
-              SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+	    if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	       temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+	       if(SiS_BridgeInSlave(SiS_Pr)) {
+                  tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+                  if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+               }
+               SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
 
-	      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
+	       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
 
-	      temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
-              if(!(temp & 0x80))
-                 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
-           }
+	       temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+               if(!(temp & 0x80))
+                  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+            }
 
-	   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
 
-	   if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+	    if(SiS_Is301B(SiS_Pr,BaseAddr)) {
 
-	      temp=SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
-              if (!(temp & 0x80))
-                 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+	       temp=SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+               if(!(temp & 0x80))
+                  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+
+	       tempah = 0xc0;
+	       if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	          tempah = 0x80;
+	          if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	             tempah = 0x40;
+                  }
+	       }
+               SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
 
-	      tempah = 0xc0;
-	      if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
-	         tempah = 0x80;
-	         if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
-	            tempah = 0x40;
-                 }
-	      }
-              SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
 
-	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+	    } else {
 
-	   } else {
-	   
-	      SiS_VBLongWait(SiS_Pr);
-              SiS_DisplayOn(SiS_Pr);
-	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
-              SiS_VBLongWait(SiS_Pr);
+	       SiS_VBLongWait(SiS_Pr);
+               SiS_DisplayOn(SiS_Pr);
+	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
+               SiS_VBLongWait(SiS_Pr);
 
-	   }
+	    }
 
 	 }   /* 315, 330 */
 
@@ -5907,28 +6073,29 @@
       SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
       if(SiS_BridgeInSlave(SiS_Pr)) {
-      	SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
+      	 SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
       } else {
-      	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
+      	 SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
       }
 
       if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
-        if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension))) {
-	        SiS_SetCH700x(SiS_Pr,0x0B0E);
-        }
+         if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension))) {
+	    SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+	    SiS_SetCH700x(SiS_Pr,0x0B0E);
+         }
       }
 
       if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr,HwDeviceExtension)) {
-          if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
-              if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
-	          if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
-			SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
-        		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
-		  }
-		  SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
-                  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7);
-              }
-	  }
+         if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+            if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+	       if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+		  SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+        	  SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+	       }
+	       SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+               SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7);
+            }
+	 }
       }
 
 #endif  /* SIS300 */
@@ -6344,6 +6511,20 @@
   } else
 #endif
      return(0);
+}
+
+BOOLEAN
+SiS_IsDualLink(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if((SiS_CRT2IsLCD(SiS_Pr, BaseAddr, HwDeviceExtension)) ||
+        (SiS_IsVAMode(SiS_Pr, HwDeviceExtension, BaseAddr))) {
+        if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) return(1);
+     }
+  }
+#endif
+     return(0);
  }
 
 BOOLEAN
@@ -6471,16 +6652,6 @@
 }
 
 BOOLEAN
-SiS_IsDisableCRT2(SiS_Private *SiS_Pr, USHORT BaseAddr)
-{
-  USHORT flag;
-
-  flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
-  if(flag & 0x20) return(0);
-  else            return(1);
-}
-
-BOOLEAN
 SiS_BridgeIsOn(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT flag;
@@ -6575,6 +6746,14 @@
      }
   }
 
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+        SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x39,~0x04);
+     }
+  }
+#endif
+
   if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)))   return;
 
   if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2))) return;
@@ -6620,8 +6799,12 @@
   	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_Panel1024x768;
   }
 
-  if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
-     SiS_Pr->SiS_LCDResInfo = Panel_Barco1366;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
+        SiS_Pr->SiS_LCDResInfo = Panel_Barco1366;
+     } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
+        SiS_Pr->SiS_LCDResInfo = Panel_848x480;
+     }
   }
 
   switch(SiS_Pr->SiS_LCDResInfo) {
@@ -6643,6 +6826,7 @@
     			   SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY;
 			   break;
      case Panel_Barco1366: SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024; break;
+     case Panel_848x480:   SiS_Pr->PanelXRes =  848; SiS_Pr->PanelYRes =  480; break;
      default:		   SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  768; break;
   }
 
@@ -6655,7 +6839,13 @@
   }
 #endif
   SiS_Pr->SiS_LCDInfo = temp;
-  
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
+        SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20;   /* neg sync, RGB24 */
+     }
+  }
+
   if(!(SiS_Pr->UsePanelScaler))        SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
   else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
 
@@ -6668,11 +6858,6 @@
 	   if(ModeNo == 0x7c || ModeNo == 0x7d || ModeNo == 0x7e) {
 	      /* Bridge does not scale to 1280x960 */
               SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
-	   } else if(ModeNo == 0x2f || ModeNo == 0x5d || ModeNo == 0x5e) {
-	      if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
-	         /* Bridge does not scale to 640x400 */
-	         SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
-	      }
 	   }
         } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
            /* TEMP - no idea about the timing and zoom factors */
@@ -6686,6 +6871,11 @@
 	   /* TEMP - no idea about the timing and zoom factors */
 	   SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
 	}
+	if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
+           if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+	      SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
+	   }
+	}
      }
   }
 
@@ -6767,20 +6957,22 @@
   }
 
 #ifdef SIS315H
-  /* 650/30xLV 1.10.6s */
   if(HwDeviceExtension->jChipType >= SIS_315H) {
-     if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
-        SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x39,~0x04);
-        if(SiS_Pr->SiS_VBType & (VB_SIS302B | VB_SIS302LV)) {
-           /* Enable 302B/302LV dual link mode.
-            * (302B is a theory - not in any BIOS)
-	    */
-           if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
-              (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
-              (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) {
+     if(SiS_Pr->SiS_VBType & (VB_SIS302B | VB_SIS302LV)) {
+	/* Enable 302B/302LV dual link mode.
+         * (302B is a theory - not in any BIOS)
+	 */
+        if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
+	   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+	      /* (Sets this in SenseLCD; new paneltypes) */
 	      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x39,0x04);
 	   }
-  	}
+	}
+        if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
+	   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
+           (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) {
+	   SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x39,0x04);
+	}
      }
   }
 #endif
@@ -7124,7 +7316,7 @@
         TimingPoint = SiS_Pr->SiS_PALTiming;
         PhasePoint  = SiS_Pr->SiS_PALPhase;
 
-        if( (SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
+        if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
             ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
 	      (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
            PhasePoint = SiS_Pr->SiS_PALPhase2;
@@ -7136,7 +7328,7 @@
         TimingPoint = SiS_Pr->SiS_NTSCTiming;
         PhasePoint  = SiS_Pr->SiS_NTSCPhase;
 
-        if( (SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
+        if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
 	    ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
 	      (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
            PhasePoint = SiS_Pr->SiS_NTSCPhase2;
@@ -7161,7 +7353,7 @@
            temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,temp);
            if(temp1 & EnablePALM) {	/* 0x40 */
               PhasePoint = SiS_Pr->SiS_PALMPhase;
-	      if( (SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
+	      if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
 		  ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
 		    (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
 	         PhasePoint = SiS_Pr->SiS_PALMPhase2;
@@ -7169,7 +7361,7 @@
 	   }
            if(temp1 & EnablePALN) {	/* 0x80 */
               PhasePoint = SiS_Pr->SiS_PALNPhase;
-	      if( (SiS_Pr->SiS_VBType & VB_SIS301B302B) &&
+	      if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
 		  ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
 		    (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
 	         PhasePoint = SiS_Pr->SiS_PALNPhase2;
@@ -7266,10 +7458,8 @@
   tempcx = SiS_Pr->SiS_HT;
 
   /* 650/30xLV 1.10.6s */
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
-      	   tempcx >>= 1;
-      }
+  if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr)) {
+     tempcx >>= 1;
   }
 
   tempcx--;
@@ -7444,7 +7634,7 @@
      temp |= 0x18;
      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x46,temp);
      temp = tempbx & 0x00FF;
-     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x47,temp);	/* tv gatingno */
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x47,temp);
      if(HwDeviceExtension->jChipType >= SIS_315H) {
         if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
            tempax = 0;
@@ -7586,10 +7776,7 @@
   /* From here: Part2 LCD setup */
 
   tempbx = SiS_Pr->SiS_HDE;
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-     /* 650/30xLV 1.10.6s */
-     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
-  }
+  if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr)) tempbx >>= 1;
   tempbx--;			         	/* RHACTE=HDE-1 */
   temp = tempbx & 0x00FF;
   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2C,temp);
@@ -7649,17 +7836,23 @@
   /* 630/301 does not do all this */
   if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
      if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
-        /* 650/30xLV 1.10.6s */
-        temp |= (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37) >> 6);
-	temp |= 0x08;   					/* From 1.10.7w */
-	if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) temp |= 0x04; 	/* From 1.10.7w */
-     } else {
-        tempbx = (tempbx & 0xFF00) | (SiS_Pr->SiS_LCDInfo & 0x0FF);
-        if(tempbx & LCDSync) {
-           tempbx &= 0xFFE0;
-           tempbx = (tempbx & 0xFF00) | ((tempbx & 0x00FF) >> 6);
-           temp |= (tempbx & 0x00FF);
-        }
+	if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) &&
+	   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)) {
+#ifdef SIS315H
+	   if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+	      temp |= (SiS_Pr->SiS_LCDInfo >> 6);
+	   }
+#endif
+	} else {
+	   /* 650/30xLV 1.10.6s */
+           temp |= (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37) >> 6);
+	   temp |= 0x08;   						/* From 1.10.7w */
+	   if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) temp |= 0x04; 	/* From 1.10.7w */
+	}
+     } else {
+        if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+	   temp |= (SiS_Pr->SiS_LCDInfo >> 6);
+	}
      }
   }
   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1A,temp);
@@ -7670,12 +7863,12 @@
   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB);
   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF);
 
-  /* much data invalid/missing in tables, use old calculation in such case */
   if((HwDeviceExtension->jChipType >= SIS_315H)         &&
      (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)            &&
      ((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  ||
       (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
-      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)) ) {
+      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
+      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) ) {
      
 #ifdef SIS315H 							/* ------------- 315/330 series ------------ */
 
@@ -7685,7 +7878,7 @@
        */
 
       SiS_GetCRT2Part2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                         &CRT2Index,&resindex);
+                         &CRT2Index,&resindex,HwDeviceExtension,BaseAddr);
 
       switch(CRT2Index) {
         case Panel_1024x768      : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;  break;  /* "Normal" */
@@ -7700,6 +7893,12 @@
         case Panel_1280x1024 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_3; break;
 	case Panel_1400x1050 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_3; break;
 	case Panel_1600x1200 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_3; break;
+	case 100:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_1; break;  /* Custom */
+	case 101:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_2; break;
+	case 102:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_3; break;
+	case 103:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Clevo1024x768_1; break;    /* Custom */
+	case 104:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Clevo1024x768_2; break;
+	case 105:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Clevo1024x768_3; break;
 	default:                   CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;  break;
       }
 
@@ -8164,7 +8363,7 @@
         if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
 	   /* From 650/301LV (any, incl. 1.10.6s, 1.10.7w) */
   	   /* This is a duplicate; done at the end, too */
-	   if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+	   if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr)) {
 	      SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
 	   }
 	   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
@@ -8228,9 +8427,8 @@
         temp = 0;
 	if(SiS_Pr->SiS_VGAHDE == 1024) temp = 0x20;
   }
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) temp = 0;
-  }
+
+  if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr)) temp = 0;
 
   if(SiS_Pr->SiS_VBType & VB_SIS301) {
      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)
@@ -8281,7 +8479,7 @@
          if(modeflag & HalfDCLK) tempax >>= 1;
          if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) || (SiS_Pr->SiS_HiVision & 0x03)) {
 	    if(HwDeviceExtension->jChipType >= SIS_315H) {
-	       if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempax >>= 1;
+	       if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr)) tempax >>= 1;
 	       else if(tempax > 800) tempax -= 800;
 	    } else {
                if(tempax > 800) tempax -= 800;
@@ -8336,9 +8534,7 @@
          SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0,temp);
 
 	 tempbx = SiS_Pr->SiS_HT;
-	 if(HwDeviceExtension->jChipType >= SIS_315H) {
-	    if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
-	 }
+	 if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr)) tempbx >>= 1;
          tempbx >>= 1;
 	 tempbx -= 2;
          temp = ((tempbx & 0x0700) >> 8) << 3;
@@ -8349,6 +8545,7 @@
          if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
 	    if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
                SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x24,0x0e);
+	       /* LCD-too-dark-error-source, see FinalizeLCD() */
 	    }
 	 }
 
@@ -8357,7 +8554,7 @@
 	    /* 315, 330, 650+301B BIOS don't do this at all */
             /* This is a duplicate; done for LCDA as well (see above) */
 	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
-	       if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+	       if(SiS_IsDualLink(SiS_Pr, HwDeviceExtension, BaseAddr)) {
 		  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
 	       }
 	       SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
@@ -8606,7 +8803,9 @@
 		if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
         	if(SiS_Pr->SiS_VBInfo & SetPALTV) {
 			tempbx += 2;
-			if(SiS_Pr->SiS_CHSOverScan) tempbx = 8;
+			if(SiS_Pr->SiS_ModeType > ModeVGA) {
+			   if(SiS_Pr->SiS_CHSOverScan) tempbx = 8;
+			}
 			if(SiS_Pr->SiS_CHPALM) {
 				tempbx = 4;
 				if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
@@ -8648,10 +8847,20 @@
      		else    VCLKIndex = LVDSXlatVCLK3[VCLKIndex];
 
 		if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
-		   /* Special Timing: Barco iQ Pro R300/400 */
+		   /* Special Timing: Barco iQ Pro R300/400/... */
 		   VCLKIndex = 0x44;
 		}
 
+		if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
+		   if(HwDeviceExtension->jChipType < SIS_315H) {
+		      VCLKIndex = VCLK34_300;
+		      /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */
+		   } else {
+		      VCLKIndex = VCLK34_315;
+		      /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */
+		   }
+		}
+
 	   } else {
 
 	        VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
@@ -8730,7 +8939,8 @@
   }
 
   if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
-     (SiS_Pr->SiS_CustomT == CUT_BARCO1024))
+     (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
+     (SiS_Pr->SiS_CustomT == CUT_PANEL848))
      return;
 
   temp = SiS_GetLVDSCRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
@@ -8868,7 +9078,9 @@
         if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx++;
         if(SiS_Pr->SiS_VBInfo & SetPALTV) {
       	   tempbx += 2;
-	   if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
+	   if(SiS_Pr->SiS_ModeType > ModeVGA) {
+	      if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
+	   }
 	   if(SiS_Pr->SiS_CHPALM) {
 	      tempbx = 18;  /* PALM uses NTSC data */
 	      if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx++;
@@ -9027,7 +9239,9 @@
   if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) TVType += 1;
   if(SiS_Pr->SiS_VBInfo & SetPALTV) {
   	TVType += 2;
-	if(SiS_Pr->SiS_CHSOverScan) TVType = 8;
+	if(SiS_Pr->SiS_ModeType > ModeVGA) {
+	   if(SiS_Pr->SiS_CHSOverScan) TVType = 8;
+	}
 	if(SiS_Pr->SiS_CHPALM) {
 		TVType = 4;
 		if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) TVType += 1;
@@ -9125,37 +9339,37 @@
          if(resindex == 0x04) {   			/* 640x480 overscan: Mode 16 */
       	   SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF);   	/* loop filter off */
            SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on, no need to set FSCI */
-         } else {
-           if(resindex == 0x05) {    			/* 800x600 overscan: Mode 23 */
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);	/* 0x18-0x1f: FSCI 469,762,048 */
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0C19,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x001A,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x001B,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x001D,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x001E,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x001F,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0120,0xEF);     /* Loop filter on for mode 23 */
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);     /* ACIV off, need to set FSCI */
-           }
+         } else  if(resindex == 0x05) {    		/* 800x600 overscan: Mode 23 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);	/* 0x18-0x1f: FSCI 469,762,048 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0C19,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001A,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001B,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001D,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001E,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x001F,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0120,0xEF);       /* Loop filter on for mode 23 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);       /* ACIV off, need to set FSCI */
          }
        } else {
          if(resindex == 0x04) {     			 /* ----- 640x480 underscan; Mode 17 */
            SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	 /* loop filter off */
            SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);
-         } else {
-           if(resindex == 0x05) {   			 /* ----- 800x600 underscan: Mode 24 */
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);     /* (FSCI was 0x1f1c71c7 - this is for mode 22) */
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0919,0xF0);	 /* FSCI for mode 24 is 428,554,851 */
-             SiS_SetCH70xxANDOR(SiS_Pr,0x081A,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0b1B,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x031C,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0a1D,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x061E,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x031F,0xF0);
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF);     /* loop filter off for mode 24 */
-             SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);	 /* ACIV off, need to set FSCI */
-           }
+         } else if(resindex == 0x05) {   		 /* ----- 800x600 underscan: Mode 24 */
+#if 0
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);       /* (FSCI was 0x1f1c71c7 - this is for mode 22) */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0919,0xF0);	 /* FSCI for mode 24 is 428,554,851 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x081A,0xF0);       /* 198b3a63 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0b1B,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x041C,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x011D,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x061E,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x051F,0xF0);
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF);       /* loop filter off for mode 24 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);	 /* ACIV off, need to set FSCI */
+#endif     /* All alternatives wrong (datasheet wrong?), don't use FSCI */
+	   SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	 /* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);
          }
        }
      } else {				/* ---- PAL ---- */
@@ -9951,7 +10165,7 @@
      USHORT        temp = 0, myadaptnum = adaptnum;
 
      if(adaptnum != 0) {
-        if(!(VBFlags & (VB_301|VB_301B|VB_302B))) return 0xFFFF;
+        if(!(VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0xFFFF;
 	if((VBFlags & VB_30xBDH) && (adaptnum == 1)) return 0xFFFF;
      }	
      
@@ -10241,7 +10455,7 @@
    SiS_Pr->CP_HaveCustomData = FALSE;
    SiS_Pr->CP_MaxX = SiS_Pr->CP_MaxY = SiS_Pr->CP_MaxClock = 0;
 
-   if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_302B))) return 0;
+   if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0;
    if(pSiS->VBFlags & VB_30xBDH) return 0;
   
    if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 1, 0, FALSE) == 0xFFFF) return 0;
@@ -10476,7 +10690,8 @@
 	          (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i])  ||
 	          (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i])    ||
 	          (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i])      ||
-	          (SiS_Pr->CP_Clock[i] > 108000)                       ||
+	          ( ((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162000)) ||
+		    ((!(pSiS->VBFlags & VB_301C)) && (SiS_Pr->CP_Clock[i] > 108000)) ) ||
 		  (buffer[base+17] & 0x80)) {
 
 	          SiS_Pr->CP_DataValid[i] = FALSE;
@@ -10696,7 +10911,8 @@
 	       (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i])  ||
 	       (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i])    ||
 	       (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i])      ||
-	       (SiS_Pr->CP_Clock[i] > 108000)                       ||
+	       ( ((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162000)) ||
+		 ((!(pSiS->VBFlags & VB_301C)) && (SiS_Pr->CP_Clock[i] > 108000)) ) ||
 	       (buffer[index + 17] & 0x80)) {
 
 	       SiS_Pr->CP_DataValid[i] = FALSE;
@@ -10782,7 +10998,7 @@
    int retry;
    unsigned char buffer[256];
 
-   if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_302B))) return 0;
+   if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0;
 /* if(pSiS->VBFlags & VB_30xBDH) return 0;  */
    
    if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 2, 0, FALSE) == 0xFFFF) return 0;
@@ -10891,12 +11107,10 @@
 void
 SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh)
 {
-  USHORT tempal,tempah,tempbl;
+  USHORT tempbl;
 
-  tempal = tempax & 0x00FF;
-  tempah =(tempax >> 8) & 0x00FF;
-  tempbl = SiS_GetCH70xx(SiS_Pr,tempal);
-  tempbl = (((tempbl & tempbh) | tempah) << 8 | tempal);
+  tempbl = SiS_GetCH70xx(SiS_Pr,(tempax & 0x00FF));
+  tempbl = (((tempbl & tempbh) << 8) | tempax);
   SiS_SetCH70xx(SiS_Pr,tempbl);
 }
 
@@ -11172,7 +11386,8 @@
 SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
              UCHAR *ROMAddr, USHORT ModeNo)
 {
-  USHORT delay,index,myindex,temp,romptr=0;
+  USHORT delay=0,index,myindex,temp,romptr=0;
+  BOOLEAN dochiptest = TRUE;
 
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {			/* VGA */
      
@@ -11196,68 +11411,99 @@
         if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
            delay = 0x00;
      }
-  
+
   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {		/* LCD */
 
+     BOOLEAN gotitfrompci = FALSE;
+
      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
-  
-     index = GetLCDPtrIndexBIOS(SiS_Pr, HwDeviceExtension, BaseAddr);
-     myindex = GetLCDPtrIndex(SiS_Pr);
-     
-     if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { 	/* 650+30xLV */
-       if(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr)) {
-          if((ROMAddr) && SiS_Pr->SiS_UseROM) {
-#if 0	     /* Always use the second pointer on 650; some BIOSes */
-             /* still carry old 301 data at the first location    */  
-	     romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8);
-	     if(SiS_Pr->SiS_VBType & VB_SIS302LV) 
-#endif		
-	        romptr = ROMAddr[0x122] | (ROMAddr[0x123] << 8);
-	     if(!romptr) return;
-	     delay = ROMAddr[(romptr + index)];
-	  } else {
-             delay = SiS310_LCDDelayCompensation_650301B[myindex];   
-#if 0	     
+
+     if(HwDeviceExtension->pdc) return;
+
+     /* This is a piece of typical SiS crap: They code the OEM LCD
+      * delay into the code, at none defined place in the BIOS.
+      * We now have to start doing a PCI subsystem check here.
+      */
+
+     if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+	   gotitfrompci = TRUE;
+	   dochiptest = FALSE;
+	   delay = 0x03;
+	}
+     }
+
+     if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) ||
+        (SiS_Pr->SiS_CustomT == CUT_CLEVO10242)) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+	   gotitfrompci = TRUE;
+	   dochiptest = FALSE;
+	   delay = 0x33;
+	   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2D,delay);
+	   delay &= 0x0f;
+	}
+     }
+
+     if(!gotitfrompci) {
+
+        index = GetLCDPtrIndexBIOS(SiS_Pr, HwDeviceExtension, BaseAddr);
+        myindex = GetLCDPtrIndex(SiS_Pr);
+
+        if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { 	/* 650+30xLV */
+           if(SiS_IsNotM650or651(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+             if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+#if 0	        /* Always use the second pointer on 650; some BIOSes */
+                /* still carry old 301 data at the first location    */
+	        romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8);
+	        if(SiS_Pr->SiS_VBType & VB_SIS302LV)
+#endif
+	           romptr = ROMAddr[0x122] | (ROMAddr[0x123] << 8);
+	        if(!romptr) return;
+	        delay = ROMAddr[(romptr + index)];
+	     } else {
+                delay = SiS310_LCDDelayCompensation_650301B[myindex];
+#if 0
+	        if(SiS_Pr->SiS_VBType & VB_SIS302LV)
+	           delay = SiS310_LCDDelayCompensation_650301B[myindex];
+#endif
+	     }
+          } else {
+             delay = SiS310_LCDDelayCompensation_651301LV[myindex];
 	     if(SiS_Pr->SiS_VBType & VB_SIS302LV)
-	        delay = SiS310_LCDDelayCompensation_650301B[myindex];
-#endif		
-	  }
-       } else {
-          delay = SiS310_LCDDelayCompensation_651301LV[myindex];
-	  if(SiS_Pr->SiS_VBType & VB_SIS302LV)
-	     delay = SiS310_LCDDelayCompensation_651302LV[myindex];
-       }
-     } else {
-        if((ROMAddr) && SiS_Pr->SiS_UseROM && 				/* 315, 330, 740, 650+301B */
-	   (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)) {
-           romptr = GetLCDromptr(SiS_Pr, HwDeviceExtension, ROMAddr);
-	   if(!romptr) return;
-	   delay = ROMAddr[(romptr + index)];
+	        delay = SiS310_LCDDelayCompensation_651302LV[myindex];
+          }
         } else {
-           delay = SiS310_LCDDelayCompensation_301[myindex];
-           if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-#if 0 	      /* This data is (like the one in the BIOS) wrong. */	   
-	      if(IS_SIS550650740660) {
-	         delay = SiS310_LCDDelayCompensation_650301B[myindex];
-	      } else {
-#endif	      
-                 delay = SiS310_LCDDelayCompensation_3xx301B[myindex];
-#if 0		 
+           if((ROMAddr) && SiS_Pr->SiS_UseROM && 				/* 315, 330, 740, 650+301B */
+	      (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)) {
+              romptr = GetLCDromptr(SiS_Pr, HwDeviceExtension, ROMAddr);
+	      if(!romptr) return;
+	      delay = ROMAddr[(romptr + index)];
+           } else {
+              delay = SiS310_LCDDelayCompensation_301[myindex];
+              if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+#if 0 	         /* This data is (like the one in the BIOS) wrong. */
+	         if(IS_SIS550650740660) {
+	            delay = SiS310_LCDDelayCompensation_650301B[myindex];
+	         } else {
+#endif
+                    delay = SiS310_LCDDelayCompensation_3xx301B[myindex];
+#if 0
+	         }
+#endif
 	      }
-#endif	      
-	   }
-           if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-	      if(IS_SIS650) {
-                 delay = SiS310_LCDDelayCompensation_LVDS650[myindex];
-	      } else {
-	         delay = SiS310_LCDDelayCompensation_LVDS740[myindex];
+              if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	         if(IS_SIS650) {
+                    delay = SiS310_LCDDelayCompensation_LVDS650[myindex];
+	         } else {
+	            delay = SiS310_LCDDelayCompensation_LVDS740[myindex];
+	         }
 	      }
-	   }
+           }
         }
      }
      
   } else {							/* TV */
-  
+
      index = GetTVPtrIndex(SiS_Pr);
      
      if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
@@ -11272,16 +11518,28 @@
 	     if(!romptr) return;
 	     delay = ROMAddr[romptr + index];
 	  } else {
-	     delay = SiS310_TVDelayCompensation_301B[index];     
-#if 0	     
+	     delay = SiS310_TVDelayCompensation_301B[index];
+#if 0
 	     if(SiS_Pr->SiS_VBType & VB_SIS302LV)
-	        delay = SiS310_TVDelayCompensation_301B[index];  
+	        delay = SiS310_TVDelayCompensation_301B[index];
 #endif		
 	  }
        } else {
-          delay = SiS310_TVDelayCompensation_651301LV[index];       
-	  if(SiS_Pr->SiS_VBType & VB_SIS302LV)
-	      delay = SiS310_TVDelayCompensation_651302LV[index];   
+          switch(SiS_Pr->SiS_CustomT) {
+	  case CUT_COMPAQ1280:
+	     delay = 0x02;
+	     dochiptest = FALSE;
+	     break;
+	  case CUT_CLEVO1024:
+	  case CUT_CLEVO10242:
+	     delay = 0x03;
+	     dochiptest = FALSE;
+   	     break;
+	  default:
+             delay = SiS310_TVDelayCompensation_651301LV[index];
+	     if(SiS_Pr->SiS_VBType & VB_SIS302LV)
+	        delay = SiS310_TVDelayCompensation_651302LV[index];
+	  }
        }
      } else {
        if((ROMAddr) && SiS_Pr->SiS_UseROM) {
@@ -11291,7 +11549,7 @@
        } else {
 	    delay = SiS310_TVDelayCompensation_301[index];
             if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-	       if(IS_SIS740) 
+	       if(IS_SIS740)
 	          delay = SiS310_TVDelayCompensation_740301B[index];
 	       else 
                   delay = SiS310_TVDelayCompensation_301B[index];
@@ -11315,15 +11573,15 @@
         }
      }
   } else {
-     if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+     if(dochiptest && IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
         temp = (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xf0) >> 4;
-        if(temp == 8) {		/* 1400x1050 BIOS */
+        if(temp == 8) {		/* 1400x1050 BIOS (ECS) */
 	   delay &= 0x0f;
 	   delay |= 0xb0;
         } else if(temp == 6) {
            delay &= 0x0f;
 	   delay |= 0xc0;
-        } else if(temp > 7) {	/* 1280x1024 BIOS */
+        } else if(temp > 7) {	/* 1280x1024 BIOS (which one?) */
 	   delay = 0x35;
         }
         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2D,delay);
@@ -11451,6 +11709,7 @@
                  }
               }
          }
+	 /* PALN : Is this data correct? */
          if(temp == EnablePALN) {
               if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
                  for(i=0x35, j=0; i<=0x38; i++, j++) {
@@ -11478,13 +11737,13 @@
   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return;
 
   temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);        /* if PALM/N not set */
-  temp1 &=  (EnablePALM | EnablePALN);
+  temp1 &= (EnablePALM | EnablePALN);
   if(temp1) return;
 
-  if (ModeNo<=0x13) {
-    resinfo =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  if(ModeNo<=0x13) {
+     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
   } else {
-    resinfo =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
   }
 
   temp = GetTVPtrIndex(SiS_Pr);
@@ -11583,9 +11842,17 @@
 
   if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) return;
 
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(SiS_Pr->LVDSHL != -1) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,SiS_Pr->LVDSHL);
+     }
+  }
+
   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
   if(SiS_Pr->UseCustomMode) return;
 
+  if(SiS_Pr->SiS_CustomT == CUT_COMPAQ12802) return;
+
   if(ModeNo <= 0x13) {
 	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
 	modeflag =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
@@ -11594,8 +11861,43 @@
 	modeflag =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
 
-  if((SiS_GetReg1(SiS_Pr->SiS_P3d4, 0x5f) & 0xf0)) {
-     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03);
+  if(IS_SIS650) {
+     if(!(SiS_GetReg1(SiS_Pr->SiS_P3d4, 0x5f) & 0xf0)) {
+        if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x02);
+	} else {
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03);
+	}
+     }
+  }
+
+  if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {  /* Maybe all panels? */
+        if(SiS_Pr->LVDSHL == -1) {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
+	}
+	return;
+     }
+  }
+
+  if(SiS_Pr->SiS_CustomT == CUT_CLEVO10242) {
+     if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {  /* Maybe all panels? */
+	   if(SiS_Pr->LVDSHL == -1) {
+              SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
+	   }
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	      tempch = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) >> 4;
+	      if(tempch == 3) {
+	         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,0x02);
+	         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1b,0x25);
+	         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1c,0x00);
+	         SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1d,0x1b);
+	      }
+	   }
+	   return;
+	}
+     }
   }
 
   if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
@@ -11603,8 +11905,11 @@
         SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
 	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
 	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
-     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {   /* For all panels? */
-        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
+     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {   /* Maybe all panels? */
+        if(SiS_Pr->LVDSHL == -1) {
+           /* Maybe ACER only? */
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
+	}
      }
      tempch = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
      tempch &= 0xf0;
@@ -12167,5 +12472,4 @@
   }
 }
 #endif
-
 
diff -Nru a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h
--- a/drivers/video/sis/init301.h	Sun Jun 29 09:27:44 2003
+++ b/drivers/video/sis/init301.h	Fri Aug 29 04:42:03 2003
@@ -28,6 +28,9 @@
  * PERFORMANCE OF THIS SOFTWARE.
  *
  * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Based on code by Silicon Intergrated Systems 
+ *
  */
 
 #ifndef  _INIT301_
@@ -121,9 +124,9 @@
 
 BOOLEAN  SiS_Is301B(SiS_Private *SiS_Pr, USHORT BaseAddr);
 BOOLEAN  SiS_IsNotM650or651(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
-BOOLEAN  SiS_IsDisableCRT2(SiS_Private *SiS_Pr, USHORT BaseAddr);
 BOOLEAN  SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
 BOOLEAN  SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_IsDualLink(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
 BOOLEAN  SiS_CRT2IsLCD(SiS_Private *SiS_Pr, USHORT BaseAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
 void     SiS_SetDefCRT2ExtRegs(SiS_Private *SiS_Pr, USHORT BaseAddr);
 USHORT   SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
@@ -140,7 +143,8 @@
                          USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex);
 #endif
 void     SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-		             USHORT RefreshRateTableIndex,USHORT *CRT2Index, USHORT *ResIndex);
+		             USHORT RefreshRateTableIndex,USHORT *CRT2Index, USHORT *ResIndex,
+			     PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
 void     SiS_GetCRT2Data301(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                             USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 USHORT   SiS_GetResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
@@ -155,7 +159,8 @@
                              PSIS_HW_DEVICE_INFO );
 void     SiS_SetHiVision(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 void     SiS_GetLVDSDesData(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-			    USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+			    USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+			    USHORT BaseAddr);
 void     SiS_SetCRT2Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                            USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 USHORT   SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
@@ -206,9 +211,10 @@
 void     SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                            USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex,
 			   PSIS_HW_DEVICE_INFO HwDeviceExtension);
-#ifdef SIS315H			   
+#ifdef SIS315H
 void     SiS_GetLVDSDesPtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                            USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex);
+                            USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex,
+			    PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
 #endif			    
 void     SiS_SetTPData(SiS_Private *SiS_Pr);
 void     SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo);
diff -Nru a/drivers/video/sis/initdef.h b/drivers/video/sis/initdef.h
--- a/drivers/video/sis/initdef.h	Sun Jun 29 08:10:19 2003
+++ b/drivers/video/sis/initdef.h	Tue Aug 26 10:32:33 2003
@@ -4,6 +4,11 @@
  *
  * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria
  *
+ * If distributed as part of the linux kernel, the contents of this file
+ * is entirely covered by the GPL.
+ *
+ * Otherwise, the following terms apply:
+ *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  * the above copyright notice appear in all copies and that both that
@@ -23,6 +28,9 @@
  * PERFORMANCE OF THIS SOFTWARE.
  *
  * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Based on code by Silicon Intergrated Systems
+ *
  */
 
 #ifndef _INITDEF_
@@ -39,25 +47,30 @@
 #define VB_SIS302B        	0x0004
 #define VB_SIS301LV     	0x0008
 #define VB_SIS302LV     	0x0010
+#define VB_SIS301C              0x0020
 #define VB_SIS30xLV		VB_SIS301LV
 #define VB_SIS30xNEW		VB_SIS302LV
 #define VB_NoLCD        	0x8000
-#define VB_SIS301BLV302BLV      (VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)
-#define VB_SIS301B302B          (VB_SIS301B|VB_SIS302B)
+#define VB_SIS301BLV302BLV      (VB_SIS301B|VB_SIS301C|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)
+#define VB_SIS301B302B          (VB_SIS301B|VB_SIS301C|VB_SIS302B)
 #define VB_SIS301LV302LV        (VB_SIS301LV|VB_SIS302LV)
 
-#define IS_SIS650		(HwDeviceExtension->jChipType == SIS_650)
-#define IS_SIS740		(HwDeviceExtension->jChipType == SIS_740)
 #define IS_SIS330		(HwDeviceExtension->jChipType == SIS_330)
 #define IS_SIS550		(HwDeviceExtension->jChipType == SIS_550)
+#define IS_SIS650		(HwDeviceExtension->jChipType == SIS_650)
+#define IS_SIS740		(HwDeviceExtension->jChipType == SIS_740)
 #define IS_SIS651	        (SiS_Pr->SiS_SysFlags & (SF_Is651 | SF_Is652))
 #define IS_SISM650	        (SiS_Pr->SiS_SysFlags & (SF_IsM650 | SF_IsM652 | SF_IsM653))
+#define IS_SIS661		(SiS_Pr->SiS_SysFlags & (SF_Is661 | SF_IsM651))
+#define IS_SIS741		(SiS_Pr->SiS_SysFlags & SF_IsM741)
 #define IS_SIS65x               (IS_SIS651 || IS_SISM650)
+#define IS_SIS661741	        (SiS_Pr->SiS_SysFlags & (SF_Is661 | SF_IsM661 | SF_Is741))
 #define IS_SIS660		(HwDeviceExtension->jChipType == SIS_660)
+#define IS_SIS760		(HwDeviceExtension->jChipType == SIS_760)
 #define IS_SIS650660            (IS_SIS650 || IS_SIS660)
 #define IS_SIS650740            ((HwDeviceExtension->jChipType >= SIS_650) && (HwDeviceExtension->jChipType < SIS_330))
-#define IS_SIS650740660         (IS_SIS650 || IS_SIS660 || IS_SIS740)
-#define IS_SIS550650740660      (IS_SIS550 || IS_SIS650 || IS_SIS660 || IS_SIS740)
+#define IS_SIS650740660         (IS_SIS650 || IS_SIS660 || IS_SIS740 || IS_SIS760)
+#define IS_SIS550650740660      (IS_SIS550 || IS_SIS650 || IS_SIS660 || IS_SIS740 || IS_SIS760)
 
 #define CRT1Len                 17
 #define LVDSCRT1Len             15
@@ -151,6 +164,9 @@
 #define SF_Is652		0x0004
 #define SF_IsM652		0x0008
 #define SF_IsM653		0x0010
+#define SF_Is661		0x0020
+#define SF_IsM661		0x0040
+#define SF_Is741		0x0080
 #define SF_Is660		0x8000
 
 #define PanelRGB18Bit           0x0100
@@ -296,6 +312,7 @@
 #define Panel_320x480           0x0e    /* fstn - TW: This is fake, can be any */
 #define Panel_Custom		0x0f
 #define Panel_Barco1366         0x10
+#define Panel_848x480		0x11
 
 /* Index in ModeResInfo table */
 #define SIS_RI_320x200 0
@@ -367,12 +384,14 @@
 #define VCLK81_300		0x3f   /* Index in VCLKData table (300) */
 #define VCLK108_3_300           0x42   /* Index in VCLKData table (300) */
 #define VCLK100_300             0x43   /* Index in VCLKData table (300) */
+#define VCLK34_300              0x3d   /* Index in VCLKData table (300) */
 #define VCLK65_315              0x0b   /* Index in (VB)VCLKData table (315) */
 #define VCLK108_2_315           0x19   /* Index in (VB)VCLKData table (315) */
 #define VCLK81_315		0x5b   /* Index in (VB)VCLKData table (315) */
 #define VCLK162_315             0x21   /* Index in (VB)VCLKData table (315) */
 #define VCLK108_3_315           0x45   /* Index in VBVCLKData table (315) */
 #define VCLK100_315             0x46   /* Index in VBVCLKData table (315) */
+#define VCLK34_315              0x55   /* Index in VBVCLKData table (315) */
 
 #define TVCLKBASE_300		0x21   /* Indices on TV clocks in VCLKData table (300) */
 #define TVCLKBASE_315	        0x3a   /* Indices on TV clocks in (VB)VCLKData table (315) */
diff -Nru a/drivers/video/sis/oem300.h b/drivers/video/sis/oem300.h
--- a/drivers/video/sis/oem300.h	Sun Jun 29 08:10:20 2003
+++ b/drivers/video/sis/oem300.h	Wed Jun 18 02:01:55 2003
@@ -9,7 +9,6 @@
  *
  * Otherwise, the following terms apply:
  *
- *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  * the above copyright notice appear in all copies and that both that
@@ -29,6 +28,8 @@
  * PERFORMANCE OF THIS SOFTWARE.
  *
  * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Based on code by Silicon Intergrated Systems
  *
  */
 
diff -Nru a/drivers/video/sis/oem310.h b/drivers/video/sis/oem310.h
--- a/drivers/video/sis/oem310.h	Sun Jun 29 08:10:20 2003
+++ b/drivers/video/sis/oem310.h	Thu Aug  7 06:55:35 2003
@@ -29,6 +29,8 @@
  *
  * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
  *
+ * Based on code by Silicon Intergrated Systems 
+ *
  */
 
 const UCHAR SiS310_LCDDelayCompensation_301[] =	    	/* 301 */
@@ -391,5 +393,124 @@
  }
 };
 
+/* OEM data for Compaq Presario 3045US */
+static const SiS_LCDDataStruct  SiS310_ExtCompaq1280x1024Data[] =
+{
+	{  211,  60,1024, 501,1688,1066},
+	{  211,  60,1024, 508,1688,1066},
+	{  211,  60,1024, 501,1688,1066},
+	{  211,  60,1024, 508,1688,1066},
+	{   32,  15,1696, 501,1696,1066},
+	{  212,  75,1024, 621,1696,1066},
+	{    4,   3,1696, 810,1696,1066},
+	{    1,   1,1696,1066,1696,1066}
+};
+
+static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_1[] =
+{
+ {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
+ {{0x35,0x1B,0xA0,0xC0,0x80,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
+ {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
+ {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
+ {{0x45,0x1C,0x20,0x3F,0xFF,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
+ {{0x49,0x1C,0x40,0x7F,0xFF,0xAD,0x23,0x0A,0x07,0xF3,0x8A,0x12}},
+ {{0x4C,0x1C,0x18,0x2F,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
+ {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}
+};
+
+static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_2[] =
+{
+ {{0x2B,0x12,0xD9,0xE5,0xD5,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
+ {{0x22,0x12,0xC0,0xCC,0xBC,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
+ {{0x2B,0x12,0xD9,0xE5,0xD5,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
+ {{0x22,0x12,0xC0,0xCC,0xBC,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
+ {{0x33,0x13,0x01,0x0D,0xFD,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
+ {{0x3F,0x1B,0x3D,0x49,0x39,0x54,0x23,0xC0,0x27,0x66,0x30,0x42}},
+ {{0x33,0x1B,0x91,0x9D,0x8D,0x8C,0x23,0xF8,0x27,0x9E,0x68,0x42}},
+ {{0x43,0x24,0x11,0x1D,0x0D,0xCC,0x23,0x38,0x37,0xDE,0xA8,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xEA,0x23,0x0A,0x07,0x32,0xC6,0x42}}
+};
+
+static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_3[] =
+{
+ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
+ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
+ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
+ {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
+ {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}},
+ {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}},
+ {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}},
+ {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}}
+};
+
+static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Clevo1024x768_1[] =
+{
+ {{0x25,0x12,0xC9,0xDC,0xB6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
+ {{0x2C,0x12,0x9A,0xAE,0x88,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
+ {{0x25,0x12,0xC9,0xDC,0xB6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x38,0x13,0x16,0x0C,0xE6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
+ {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
+ {{0x36,0x13,0x13,0x25,0xFF,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x25,0x12,0xC9,0xDC,0xB6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}
+};
+
+static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Clevo1024x768_2[] =
+{
+  {{0x25,0x12,0x51,0x6E,0x48,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}},
+  {{0x2C,0x12,0x38,0x55,0x2F,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}},
+  {{0x25,0x12,0x51,0x6E,0x48,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}},
+  {{0x2C,0x12,0x38,0x55,0x2F,0xE0,0x12,0xB1,0x47,0x30,0x71,0x33}},
+  {{0x2D,0x12,0x79,0x96,0x70,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}},
+  {{0x29,0x12,0xB5,0xD2,0xAC,0xF4,0x12,0xD9,0x47,0x44,0x99,0x33}},
+  {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
+#if 0
+  {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
+  {{0x2C,0x12,0x38,0x55,0x2F,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
+  {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
+  {{0x2C,0x12,0x38,0x55,0x2F,0xC1,0x35,0xB1,0x47,0xE9,0x71,0x33}},
+  {{0x2D,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
+  {{0x29,0x12,0xB5,0xD2,0xAC,0xE9,0x35,0xD9,0x47,0x11,0x99,0x33}},
+  {{0x36,0x13,0x13,0x25,0xFF,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}
+#endif
+};
+
+static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Clevo1024x768_3[] =
+{
+ {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}}, /* Corrected */
+ {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
+ {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
+ {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
+ {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x25,0x13,0xC9,0x25,0xFF,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}
+};
+
+static const SiS_LVDSDesStruct Clevo1024x768Des_1[] =
+{
+  { 0, 0 },
+  { 0, 0 },
+  { 0, 0 },
+  { 0, 0 },
+  { 0, 0 },
+  { 0, 0 },
+  { 0, 0 }
+};
+
+static const SiS_LVDSDesStruct Clevo1024x768Des_2[] =
+{
+  { 1184, 622 },
+  { 1184, 597 },
+  { 1184, 622 },
+  { 1184, 597 },
+  { 1152, 622 },
+  { 1232, 722 },
+  {    0,   0 },
+  {    0, 794 },
+  {    0,   0 }
+};
 
 
diff -Nru a/drivers/video/sis/sis_accel.c b/drivers/video/sis/sis_accel.c
--- a/drivers/video/sis/sis_accel.c	Sun Jun 29 08:10:20 2003
+++ b/drivers/video/sis/sis_accel.c	Sat Jun 28 06:49:18 2003
@@ -230,7 +230,7 @@
 		/* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
 	}
 	SiS310SetupCMDFlag(ivideo.SiS310_AccelDepth)
-	/* TW: The 315 series is smart enough to know the direction */
+	/* The 315 series is smart enough to know the direction */
 }
 
 static void
diff -Nru a/drivers/video/sis/sis_accel.h b/drivers/video/sis/sis_accel.h
--- a/drivers/video/sis/sis_accel.h	Sun Jun 29 09:27:44 2003
+++ b/drivers/video/sis/sis_accel.h	Fri Aug 29 04:29:19 2003
@@ -342,16 +342,27 @@
    bits 7:0:   2D counter 1
 
    Where is the command queue length (current amount of commands the queue
-   can accept) on the 315 series? (The current implementation is taken
-   from 300 series and certainly wrong...)
+   can accept) on the 315 series?
 */
 
 /* TW: FIXME: CmdQueLen is... where....? */
+/* We assume a length of 4 bytes per command; since 512K of
+ * of RAM are allocated, the number of commands is easily
+ * calculated (assuming that there is no 3D support yet)
+ * We calculate it very cautiously (128K only) and let the
+ * rest to the (never?)-to-come (?) 3D engine. (The 3D engine
+ * can use a similar technique, using the remaining 384K,
+ * hence a queue overflow is avoided)
+ * UPDATE: This technique causes a terrible system latency
+ * on integrated chipsets. Disable the queue handling for
+ * now.
+ */
 #define SiS310Idle \
   { \
   while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
   while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
-  CmdQueLen=MMIO_IN16(ivideo.mmio_vbase, Q_STATUS); \
+  CmdQueLen = 0; \
+  /*CmdQueLen = ((128 * 1024) / 4) - 64; */ \
   }
 
 #define SiS310SetupSRCBase(base) \
diff -Nru a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
--- a/drivers/video/sis/sis_main.c	Sun Jun 29 08:10:19 2003
+++ b/drivers/video/sis/sis_main.c	Fri Aug 29 04:39:42 2003
@@ -1,12 +1,14 @@
 /*
- * SiS 300/630/730/540/315/550/650/740/330/660 frame buffer device
- * for Linux kernels 2.4.x and 2.5.x
+ * SiS 300/630/730/540/315/550/650/651/M650/661FX/M661FX/740/741/330
+ * frame buffer driver for Linux kernels 2.4.x and 2.5.x
  *
  * (C) 1999 Silicon Integrated Systems, Inc.
  * (C) 2001-2003 Thomas Winischhofer, Vienna, Austria.
  *
- * Authors:   	SiS (www.sis.com.tw)
- *		Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:   	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Author of code base:
+ *		SiS (www.sis.com.tw)
  *
  * See http://www.winischhofer.net/ for more information and updates
  *
@@ -31,6 +33,9 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#include <linux/vmalloc.h>
+#endif
 #include <linux/vt_kern.h>
 #include <linux/capability.h>
 #include <linux/fs.h>
@@ -67,12 +72,6 @@
 #include "sis_main.h"
 #include "sis.h"
 
-#if 0
-#ifdef LINUXBIOS
-#include "bios.h"
-#endif
-#endif
-
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69)
 #error "This version of sisfb requires at least 2.5.69"
@@ -134,7 +133,11 @@
 
 	if (!init) {
 		init = TRUE;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
 		pci_for_each_dev(pdev) {
+#else
+		while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
+#endif
 			DPRINTK("sisfb: Current: 0x%x, target: 0x%x\n",
 			         pdev->device, ivideo.chip_id);
 			if ((pdev->vendor == PCI_VENDOR_ID_SI)
@@ -169,6 +172,7 @@
 	if (!init) {
 		init = TRUE;
 		switch (ivideo.chip) {
+#ifdef CONFIG_FB_SIS_300
 		case SIS_540:
 			nbridge_id = PCI_DEVICE_ID_SI_540;
 			break;
@@ -178,6 +182,8 @@
 		case SIS_730:
 			nbridge_id = PCI_DEVICE_ID_SI_730;
 			break;
+#endif
+#ifdef CONFIG_FB_SIS_315
 		case SIS_550:
 			nbridge_id = PCI_DEVICE_ID_SI_550;
 			break;
@@ -190,12 +196,20 @@
 		case SIS_660:
 			nbridge_id = PCI_DEVICE_ID_SI_660;
 			break;
+		case SIS_760:
+			nbridge_id = PCI_DEVICE_ID_SI_760;
+			break;
+#endif
 		default:
 			nbridge_id = 0;
 			break;
 		}
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
 		pci_for_each_dev(pdev) {
+#else
+		while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
+#endif
 			DPRINTK("Current: 0x%x, target: 0x%x\n",
 					pdev->device, ivideo.chip_id);
 			if ((pdev->vendor == PCI_VENDOR_ID_SI)
@@ -247,7 +261,7 @@
 	return TRUE;
 };
 
-static BOOLEAN sisfb_interpret_edid(struct sisfb_monitor *monitor, unsigned char *buffer)
+static BOOLEAN sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
 {
 	int i, j, xres, yres, refresh, index;
 	u32 emodes;
@@ -256,7 +270,7 @@
 	   buffer[2] != 0xff || buffer[3] != 0xff ||
 	   buffer[4] != 0xff || buffer[5] != 0xff ||
 	   buffer[6] != 0xff || buffer[7] != 0x00) {
-	   printk(KERN_INFO "sisfb: Bad EDID header\n");
+	   printk(KERN_DEBUG "sisfb: Bad EDID header\n");
 	   return FALSE;
 	}
 
@@ -349,8 +363,8 @@
 
 static void sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno)
 {
-	USHORT        temp, i, realcrtno = crtno;
-   	unsigned char buffer[256];
+	USHORT  temp, i, realcrtno = crtno;
+   	u8      buffer[256];
 
 	monitor->datavalid = FALSE;
 
@@ -448,7 +462,7 @@
 	}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-        if (!strcmp(name, sisbios_mode[MODE_INDEX_NONE].name)) {
+        if (!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
 	   if(!quiet)
 	      printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
 	   sisfb_mode_idx = DEFAULT_MODE;
@@ -486,7 +500,7 @@
 
 	i = 0; j = 0;
 	while(sisbios_mode[i].mode_no != 0) {
-		if(!strcmp(nameptr, sisbios_mode[i++].name)) {
+		if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
 		   if(sisfb_fstn) {
 		      if(sisbios_mode[i-1].mode_no == 0x50 ||
 		         sisbios_mode[i-1].mode_no == 0x56 ||
@@ -501,11 +515,12 @@
 		}
 	}
 	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
+
 }
 
 static int sisfb_validate_mode(int myindex, unsigned long vbflags)
 {
-   u16 xres, yres;
+   u16 xres, yres, myres;
 
 #ifdef CONFIG_FB_SIS_300
    if(sisvga_engine == SIS_300_VGA) {
@@ -522,6 +537,8 @@
    }
 #endif
 
+   myres = sisbios_mode[myindex].yres;
+
    switch (vbflags & VB_DISPTYPE_DISP2) {
      case CRT2_LCD:
 	switch (sishw_ext.ulCRT2LCDType) {
@@ -553,23 +570,28 @@
 	default:
 	        xres =    0; yres =    0;  break;
 	}
+
 	if(SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
 	   	xres = 1360; yres = 1024;
 	}
-	if(sisbios_mode[myindex].xres > xres) {
+
+	if(SiS_Pr.SiS_CustomT == CUT_PANEL848) {
+	   	xres = 848;  yres =  480;
+	} else {
+	   if(sisbios_mode[myindex].xres > xres) {
 	        return(-1);
-	}
-        if(sisbios_mode[myindex].yres > yres) {
+	   }
+           if(myres > yres) {
 	        return(-1);
+	   }
 	}
+
 	if(vbflags & (VB_LVDS | VB_30xBDH)) {
 	   switch (sisbios_mode[myindex].xres) {
 	   	case 320:
-			if((sisbios_mode[myindex].yres != 200) &&
-	           	   (sisbios_mode[myindex].yres != 240))
+			if((myres != 200) && (myres != 240))
 		          	return(-1);
-			if((sisbios_mode[myindex].yres == 240) ||
-			   (sisbios_mode[myindex].yres == 480)) {
+			if((myres == 240) || (myres == 480)) {
 			   	if(!sisfb_fstn) {
 				   if(sisbios_mode[myindex].mode_no == 0x5a ||
 				      sisbios_mode[myindex].mode_no == 0x5b)
@@ -581,51 +603,62 @@
 					return(-1);
 				}
 			}
+			if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
 			break;
 		case 400:
-	       		if(sisbios_mode[myindex].yres != 300) return(-1);
+	       		if(myres != 300) return(-1);
+			if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
 	       		break;
 	   	case 512:
-	       		if(sisbios_mode[myindex].yres != 384) return(-1);
+	       		if(myres != 384) return(-1);
 			if(sishw_ext.ulCRT2LCDType == LCD_1024x600) return(-1);
+			if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
 	       		break;
 	   	case 640:
-		       	if((sisbios_mode[myindex].yres != 400) &&
-	           	   (sisbios_mode[myindex].yres != 480))
+		       	if((myres != 400) && (myres != 480))
 		          	return -1;
+			if(SiS_Pr.SiS_CustomT == CUT_PANEL848) {
+			   if(myres == 400)
+			 	return(-1);
+			}
 	       		break;
 	   	case 800:
-		       	if(sisbios_mode[myindex].yres != 600) return(-1);
+		       	if(myres != 600) return(-1);
+	       		break;
+		case 848:
+		        if(SiS_Pr.SiS_CustomT != CUT_PANEL848) return(-1);
+		       	if(myres != 480) return(-1);
 	       		break;
 	   	case 1024:
-		       	if((sisbios_mode[myindex].yres != 600) &&
-	           	   (sisbios_mode[myindex].yres != 768))
+		       	if((myres != 600) && (myres != 768))
 		          	return(-1);
-			if((sisbios_mode[myindex].yres == 600) &&
+			if((myres == 600) &&
 			   (sishw_ext.ulCRT2LCDType != LCD_1024x600))
 			   	return(-1);
 			break;
 		case 1152:
-			if((sisbios_mode[myindex].yres) != 768) return(-1);
+			if(myres != 768) return(-1);
 			if(sishw_ext.ulCRT2LCDType != LCD_1152x768) return(-1);
 			break;
 	   	case 1280:
-		   	if((sisbios_mode[myindex].yres != 768) &&
-	           	   (sisbios_mode[myindex].yres != 1024))
+		   	if((myres != 768) && (myres != 1024))
 		          	return(-1);
-			if((sisbios_mode[myindex].yres == 768) &&
+			if((myres == 768) &&
 			   (sishw_ext.ulCRT2LCDType != LCD_1280x768))
 			   	return(-1);
+			if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
 			break;
 		case 1360:
 			if(SiS_Pr.SiS_CustomT != CUT_BARCO1366) return(-1);
-			if(sisbios_mode[myindex].yres != 1024) return(-1);
+			if(myres != 1024) return(-1);
 			break;
 	   	case 1400:
-		   	if(sisbios_mode[myindex].yres != 1050) return(-1);
+		   	if(myres != 1050) return(-1);
+			if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
 			break;
 	   	case 1600:
-		   	if(sisbios_mode[myindex].yres != 1200) return(-1);
+		   	if(myres != 1200) return(-1);
+			if(SiS_Pr.SiS_CustomT == CUT_PANEL848) return(-1);
 			break;
 	   	default:
 		        return(-1);
@@ -633,74 +666,85 @@
 	} else {
 	   switch (sisbios_mode[myindex].xres) {
 	   	case 320:
-			if((sisbios_mode[myindex].yres != 200) &&
-	           	   (sisbios_mode[myindex].yres != 240))
+			if((myres != 200) && (myres != 240))
 		          	return -1;
 			break;
 		case 400:
-	       		if(sisbios_mode[myindex].yres != 300) return(-1);
+	       		if(myres != 300) return(-1);
 	       		break;
 	   	case 512:
-	       		if(sisbios_mode[myindex].yres != 384) return(-1);
+	       		if(myres != 384) return(-1);
 	       		break;
 	   	case 640:
-		       	if((sisbios_mode[myindex].yres != 400) &&
-	           	   (sisbios_mode[myindex].yres != 480))
+		       	if((myres != 400) && (myres != 480))
 		          	return(-1);
 	       		break;
 	   	case 800:
-		       	if(sisbios_mode[myindex].yres != 600) return(-1);
+		       	if(myres != 600) return(-1);
 	       		break;
 	   	case 1024:
-		       	if(sisbios_mode[myindex].yres != 768) return(-1);
+		       	if(myres != 768) return(-1);
 			break;
 	   	case 1280:
-		   	if((sisbios_mode[myindex].yres != 960) &&
-			   (sisbios_mode[myindex].yres != 768) &&
-	           	   (sisbios_mode[myindex].yres != 1024))
+		   	if((myres != 960) && (myres != 768) && (myres != 1024))
 		          	return(-1);
-			if((sisbios_mode[myindex].yres == 768) ||
-			   (sisbios_mode[myindex].yres == 960)) {
+			if((myres == 768) || (myres == 960)) {
 			    	if(sishw_ext.ulCRT2LCDType == LCD_1400x1050)
 			   		return(-1);
 			}
-			if(sisbios_mode[myindex].yres == 768) {
+			if(myres == 768) {
 			    	if(sishw_ext.ulCRT2LCDType == LCD_1280x960)
 			   		return(-1);
 			}
 			break;
 	   	case 1400:
-		   	if(sisbios_mode[myindex].yres != 1050) return(-1);
+		   	if(myres != 1050) return(-1);
 			break;
 	   	case 1600:
-		   	if(sisbios_mode[myindex].yres != 1200) return(-1);
+		   	if(myres != 1200) return(-1);
 			break;
 	   	default:
 		        return(-1);
 	   }
 	}
 	break;
-     case CRT2_TV:
+
+     case CRT2_TV:  
 	switch (sisbios_mode[myindex].xres) {
-	case 512:
+	case 320:
 		if(vbflags & VB_CHRONTEL) return(-1);
+		if((myres != 200) && (myres != 240))
+		       	return(-1);
+		break;
+	case 400:
+		if(vbflags & VB_CHRONTEL) return(-1);
+		if(myres != 300) return(-1);
+		break;
+	case 512:
+		if((vbflags & VB_CHRONTEL) && (ivideo.chip < SIS_315H))
+			return(-1);
 		if((vbflags & VB_SISBRIDGE) && (vbflags & TV_NTSC))
 		   	return(-1);
-		/* fall through */
+		if(myres != 384) return(-1);
+		break;
 	case 640:
-	case 800:
+		if((myres != 400) && (myres != 480))
+		       	return(-1);
 		break;
 	case 720:
-		if(vbflags & VB_CHRONTEL) return -1;
-		if(vbflags & TV_NTSC) {
-			if (sisbios_mode[myindex].yres != 480) {
-				return(-1);
-			}
-		} else if(vbflags & TV_PAL) {
-			if (sisbios_mode[myindex].yres != 576) {
-				return(-1);
-			}
-		}
+		if(vbflags & VB_CHRONTEL) return(-1);
+		if((vbflags & TV_NTSC) && (myres != 480))
+			return(-1);
+		if((vbflags & TV_PAL) && (myres != 576))
+			return(-1);
+		break;
+	case 768:
+		if(vbflags & VB_CHRONTEL) return(-1);
+		if(!(vbflags & TV_PAL)) return(-1);
+		if(myres != 576) return(-1);
+		break;
+	case 800:
+		if(myres != 600) return(-1);
 		break;
 	case 1024:
 		if(vbflags & VB_301) return(-1);
@@ -714,9 +758,10 @@
 		return(-1);
 	}
 	break;
-     case CRT2_VGA:	
+
+     case CRT2_VGA:
         if(sisbios_mode[myindex].xres > 1600) return(-1);
-	if(!(vbflags & (VB_301B|VB_302B))) {
+	if(!(vbflags & (VB_301B|VB_301C|VB_302B))) {
 	   if(sisbios_mode[myindex].xres > 1400) return(-1);
 	}
 	break;	
@@ -732,7 +777,7 @@
 		return;
 
 	while(sis_crt2type[i].type_no != -1) {
-		if (!strcmp(name, sis_crt2type[i].name)) {
+		if (!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
 			sisfb_crt2type = sis_crt2type[i].type_no;
 			sisfb_tvplug = sis_crt2type[i].tvplug_no;
 			sisfb_dstn = (sis_crt2type[i].flags & FL_550_DSTN) ? 1 : 0;
@@ -756,7 +801,7 @@
 		return;
 
 	while (sis_queuemode[i].type_no != -1) {
-		if (!strcmp(name, sis_queuemode[i].name)) {
+		if (!strnicmp(name, sis_queuemode[i].name, strlen(sis_queuemode[i].name))) {
 			sisfb_queuemode = sis_queuemode[i].type_no;
 			break;
 		}
@@ -820,7 +865,7 @@
 		return;
 
 	while (sis_tvtype[i].type_no != -1) {
-		if (!strcmp(name, sis_tvtype[i].name)) {
+		if (!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
 			ivideo.vbflags |= sis_tvtype[i].type_no;
 			break;
 		}
@@ -828,6 +873,43 @@
 	}
 }
 
+static void sisfb_search_specialtiming(const char *name)
+{
+	int i = 0;
+	BOOLEAN found = FALSE;
+
+	if(name == NULL)
+		return;
+
+	if(!strnicmp(name, "none", 4)) {
+	        SiS_Pr.SiS_CustomT = CUT_FORCENONE;
+		printk(KERN_DEBUG "sisfb: Special timing disabled\n");
+	} else {
+	   while(mycustomttable[i].chipID != 0) {
+	      if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
+		 SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
+		 found = TRUE;
+		 printk(KERN_INFO "sisfb: Special timing for %s %s forced\n",
+		 mycustomttable[i].vendorName, mycustomttable[i].cardName);
+		 break;
+	      }
+	      i++;
+	   }
+	   if(!found) {
+	      printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
+	      printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
+	      i = 0;
+	      while(mycustomttable[i].chipID != 0) {
+		 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
+		     mycustomttable[i].optionName,
+		     mycustomttable[i].vendorName,
+		     mycustomttable[i].cardName);
+		 i++;
+	      }
+           }
+ 	}
+}
+
 static BOOLEAN sisfb_bridgeisslave(void)
 {
    unsigned char P1_00;
@@ -989,12 +1071,12 @@
       }
 
       if(sisvga_engine == SIS_300_VGA) {
-         if((ivideo.vbflags & (VB_301B|VB_302B)) &&
+         if((ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) &&
             (!(ivideo.vbflags & VB_30xBDH))) {
 	    setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
 	 }
       } else if(sisvga_engine == SIS_315_VGA) {
-         if((ivideo.vbflags & (VB_301B|VB_302B)) &&
+         if((ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) &&
             (!(ivideo.vbflags & VB_30xBDH))) {
 	    setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
 	 }
@@ -1002,7 +1084,7 @@
 
    } else if(ivideo.currentvbflags & CRT2_VGA) {
 
-      if(ivideo.vbflags & (VB_301B|VB_302B)) {
+      if(ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) {
          setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
       }
 
@@ -1749,6 +1831,7 @@
 	if (boot_cpu_data.x86 > 3)
 		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 #endif
+        /* RedHat requires vma as the first paramater to the following call */
 	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
 				vma->vm_page_prot))
 		return -EAGAIN;
@@ -1846,11 +1929,9 @@
 		rc = 256;	
 		break;
 	case 16:
-		rc = 16;	
-		break;		
 	case 32:
 		rc = 16;
-		break;	
+		break;
 	}
 	return rc;
 }
@@ -2249,7 +2330,7 @@
 		if(copy_to_user((void *)arg, &sisapdata, sizeof(sisapdata)))
 			return -EFAULT;
 		break;
-	   case SISFB_GET_INFO:  /* New for communication with X driver */
+	   case SISFB_GET_INFO:  /* For communication with X driver */
 	        {
 			sisfb_info x;
 
@@ -2262,7 +2343,7 @@
 			x.heapstart = ivideo.heapstart / 1024;
 			x.fbvidmode = sisfb_mode_no;
 			x.sisfb_caps = sisfb_caps;
-			x.sisfb_tqlen = 512; /* yet unused */
+			x.sisfb_tqlen = 512; /* yet fixed */
 			x.sisfb_pcibus = ivideo.pcibus;
 			x.sisfb_pcislot = ivideo.pcislot;
 			x.sisfb_pcifunc = ivideo.pcifunc;
@@ -2270,6 +2351,8 @@
 			x.sisfb_lcda = sisfb_detectedlcda;
 			x.sisfb_vbflags = ivideo.vbflags;
 			x.sisfb_currentvbflags = ivideo.currentvbflags;
+			x.sisfb_scalelcd = SiS_Pr.UsePanelScaler;
+			x.sisfb_specialtiming = SiS_Pr.SiS_CustomT;
 			if(copy_to_user((void *)arg, &x, sizeof(x)))
 				return -EFAULT;
 	                break;
@@ -2332,7 +2415,7 @@
 	fix->mmio_len    = sisfb_mmio_size;
 	if(sisvga_engine == SIS_300_VGA) 
 	   fix->accel    = FB_ACCEL_SIS_GLAMOUR;
-	else if((ivideo.chip == SIS_330) || (ivideo.chip == SIS_660))
+	else if((ivideo.chip == SIS_330) || (ivideo.chip == SIS_660) || (ivideo.chip == SIS_760))
 	   fix->accel    = FB_ACCEL_SIS_XABRE;
 	else
 	   fix->accel    = FB_ACCEL_SIS_GLAMOUR_2;
@@ -2418,9 +2501,12 @@
 
 	} else {		/* 540, 630, 730 */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
 		pci_for_each_dev(pdev) {
-
-			if ((pdev->vendor == PCI_VENDOR_ID_SI) 
+#else
+		while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
+#endif
+			if ((pdev->vendor == PCI_VENDOR_ID_SI)
 				       && (pdev->device == nbridge_id)) {
 				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
 				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
@@ -2461,7 +2547,7 @@
 #endif  /* CONFIG_FB_SIS_300 */
 
 
-#ifdef CONFIG_FB_SIS_315    /* for SiS 315/550/650/740/330 */
+#ifdef CONFIG_FB_SIS_315    /* for SiS 315/550/650/740/330/660/760 */
 
 static int sisfb_get_dram_size_315(void)
 {
@@ -2473,24 +2559,30 @@
 	if (ivideo.chip == SIS_550 ||
 	    ivideo.chip == SIS_650 ||
 	    ivideo.chip == SIS_740 ||
-	    ivideo.chip == SIS_660) {
+	    ivideo.chip == SIS_660 ||
+	    ivideo.chip == SIS_760) {
 
 #ifdef LINUXBIOS
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
 		pci_for_each_dev(pdev) {
+#else
+		while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
+#endif
 
 			if ( (pdev->vendor == PCI_VENDOR_ID_SI)
 				&& ( (pdev->device == PCI_DEVICE_ID_SI_550) ||
 				     (pdev->device == PCI_DEVICE_ID_SI_650) ||
 				     (pdev->device == PCI_DEVICE_ID_SI_740) ||
-				     (pdev->device == PCI_DEVICE_ID_SI_660))) {
+				     (pdev->device == PCI_DEVICE_ID_SI_660) ||
+				     (pdev->device == PCI_DEVICE_ID_SI_760))) {
 				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
 				                     &pci_data);
 				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
 				ivideo.video_size = (unsigned int)(1 << (pci_data + 21));
 				pdev_valid = 1;
 
-				/* TW: Initialize SR14 "by hand" */
+				/* Initialize SR14 "by hand" */
 				inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
 				reg &= 0xC0;
 				switch (pci_data) {
@@ -2552,7 +2644,11 @@
 			       "now reading from PCI config\n");
 			pdev_valid = 0;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
 			pci_for_each_dev(pdev) {
+#else
+			while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
+#endif
 
 			   if ( (pdev->vendor == PCI_VENDOR_ID_SI)
 			         && (pdev->device == PCI_DEVICE_ID_SI_550) ) {
@@ -2625,7 +2721,7 @@
 		reg >>= 2;
 		
 		if(ivideo.chip == SIS_330) {
-		
+
 		   if(reg) ivideo.video_size <<= 1;
 		
 		} else {
@@ -2786,10 +2882,14 @@
 			ivideo.vbflags |= VB_301;
 			sishw_ext.ujVBChipID = VB_CHIP_301;
 			printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
-		} else if(reg < 0xd0) {
+		} else if(reg < 0xc0) {
 		 	ivideo.vbflags |= VB_301B;
 			sishw_ext.ujVBChipID = VB_CHIP_301B;
 			printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
+		} else if(reg < 0xd0) {
+		 	ivideo.vbflags |= VB_301C;
+			sishw_ext.ujVBChipID = VB_CHIP_301C;
+			printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
 		} else if(reg < 0xe0) {
 			ivideo.vbflags |= VB_301LV;
 			sishw_ext.ujVBChipID = VB_CHIP_301LV;
@@ -2842,10 +2942,9 @@
 				break;
 			   case SIS_EXTERNAL_CHIP_TRUMPION:
 				ivideo.hasVB = HASVB_TRUMPION;
-				ivideo.vbflags |= VB_TRUMPION;
 				sishw_ext.usExternalChip = 0x02;
 				printk(KERN_INFO "%s Trumpion LCD scaler\n", stdstr);
-				break;	   
+				break;
 			   case SIS_EXTERNAL_CHIP_CHRONTEL:
 				ivideo.hasVB = HASVB_CHRONTEL;
 				ivideo.vbflags |= VB_CHRONTEL;
@@ -2927,7 +3026,7 @@
 
   if(sisvga_engine == SIS_300_VGA) {
 
-	if(ivideo.vbflags & (VB_301B|VB_302B|VB_301LV|VB_302LV)) {
+	if(ivideo.vbflags & (VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV)) {
 	   	testvga2_tempbh = 0x01; testvga2_tempbl = 0x90;
 	   	testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
 	   	testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
@@ -2959,7 +3058,7 @@
 
   } else {
 
-	if(ivideo.vbflags & (VB_301B|VB_302B)) {
+	if(ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) {
 		testvga2_tempbh = 0x01; testvga2_tempbl = 0x90;
 		testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
 		testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
@@ -2972,7 +3071,7 @@
         	testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
 		testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
 	}
-	if(ivideo.vbflags & (VB_301|VB_301B|VB_302B)) {
+	if(ivideo.vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) {
 	   inSISIDXREG(SISPART4,0x01,myflag);
 	   if(myflag & 0x04) {
 	      testvga2_tempbh = 0x00; testvga2_tempbl = 0xfd;
@@ -3196,8 +3295,13 @@
 	unsigned long *write_port = 0;
 	SIS_CMDTYPE    cmd_type;
 #ifndef AGPOFF
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	struct agp_kern_info  *agp_info;
+	struct agp_memory     *agp;
+#else
 	agp_kern_info  *agp_info;
 	agp_memory     *agp;
+#endif
 	u32            agp_phys;
 #endif
 #endif
@@ -3211,8 +3315,9 @@
  *     in XF86Config-4.
  *     The heap start can also be specified by parameter "mem" when starting the sisfb
  *     driver. sisfb mem=1024 lets heap starts at 1MB, etc.
- *     On the 315 series, the default is a 1MB heap since DRI is not supported
- *     there.
+ *
+ *     On the 315 and Xabre series, the default is a 1MB heap since DRI is not
+ *     supported there.
  */
      if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
         if(sisvga_engine == SIS_300_VGA) {
@@ -3280,8 +3385,13 @@
 
 #ifndef AGPOFF
 	if (sisfb_queuemode == AGP_CMD_QUEUE) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+		agp_info = vmalloc(sizeof(*agp_info));
+		memset((void*)agp_info, 0x00, sizeof(*agp_info));
+#else
 		agp_info = vmalloc(sizeof(agp_kern_info));
 		memset((void*)agp_info, 0x00, sizeof(agp_kern_info));
+#endif
 		agp_copy_info(agp_info);
 
 		agp_backend_acquire();
@@ -3382,10 +3492,6 @@
 		break;
 
 	   default:  /* MMIO */
-	   	/* TW: This previously only wrote SIS_MMIO_CMD_ENABLE
-		 * to IND_SIS_CMDQUEUE_SET. I doubt that this is
-		 * enough. Reserve memory in any way.
-		 */
 	   	sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
 		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
 
@@ -3394,7 +3500,7 @@
 
 		*write_port = *read_port;
 
-		/* TW: Set Auto_Correction bit */
+		/* Set Auto_Correction bit */
 		temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
 		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
 
@@ -3782,6 +3888,13 @@
 	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR31, cr31);
 	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, cr33);
 
+#ifdef CONFIG_FB_SIS_315
+        if(sisvga_engine == SIS_315_VGA) {
+	   /* Clear LCDA and PAL-N/M bits */
+	   andSISIDXREG(SISCR,0x38,~0xc3);
+	}
+#endif
+
 	if(ivideo.accel) sisfb_syncaccel();
 
 	SiS_Pr.SiS_UseOEM = sisfb_useoem;
@@ -3871,6 +3984,7 @@
 		   case 720:
 			filter_tb = (ivideo.vbflags & TV_NTSC) ? 6 : 14;
 			break;
+		   case 400:
 		   case 800:
 			filter_tb = (ivideo.vbflags & TV_NTSC) ? 7 : 15;
 			break;
@@ -3906,6 +4020,7 @@
 					outSISIDXREG(SISPART2, 0x37, 0x22);
 					outSISIDXREG(SISPART2, 0x38, 0x08);
 					break;
+				case 400:
 				case 800:
 					outSISIDXREG(SISPART2, 0x35, 0xEB);
 					outSISIDXREG(SISPART2, 0x36, 0x15);
@@ -3940,6 +4055,7 @@
 					outSISIDXREG(SISPART2, 0x37, 0x1D);
 					outSISIDXREG(SISPART2, 0x38, 0x20);
 					break;
+				case 400:
 				case 800:
 					outSISIDXREG(SISPART2, 0x35, 0xFC);
 					outSISIDXREG(SISPART2, 0x36, 0xFB);
@@ -3950,7 +4066,7 @@
 			}
 		}
 
-		if ((filter >= 0) && (filter <=7)) {
+		if ((filter >= 0) && (filter <= 7)) {
 			DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter,
 				sis_TV_filter[filter_tb].filter[filter][0],
 				sis_TV_filter[filter_tb].filter[filter][1],
@@ -3974,11 +4090,14 @@
 	
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	sis_fb_info.fontname[0] = '\0';
-#endif	
+#endif
 
 	ivideo.refresh_rate = 0;
+	SiS_Pr.SiS_CustomT = CUT_NONE;
+	SiS_Pr.UsePanelScaler = -1;
+	SiS_Pr.LVDSHL = -1;
 
-        printk(KERN_INFO "sisfb: Options %s\n", options);
+        printk(KERN_DEBUG "sisfb: Options %s\n", options);
 
 	if (!options || !*options)
 		return 0;
@@ -3987,57 +4106,67 @@
 
 		if (!*this_opt)	continue;
 
-		if (!strncmp(this_opt, "mode:", 5)) {
+		if (!strnicmp(this_opt, "mode:", 5)) {
 			sisfb_search_mode(this_opt + 5, FALSE);
-		} else if (!strncmp(this_opt, "vesa:", 5)) {
+		} else if (!strnicmp(this_opt, "vesa:", 5)) {
 			sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)			
-		} else if (!strcmp(this_opt, "inverse")) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+		} else if (!strnicmp(this_opt, "inverse", 7)) {
 			sisfb_inverse = 1;
 			/* fb_invert_cmaps(); */
-		} else if (!strncmp(this_opt, "font:", 5)) {
+		} else if (!strnicmp(this_opt, "font:", 5)) {
 			strcpy(sis_fb_info.fontname, this_opt + 5);
 #endif
-		} else if (!strncmp(this_opt, "vrate:", 6)) {
+		} else if (!strnicmp(this_opt, "vrate:", 6)) {
 			ivideo.refresh_rate = simple_strtoul(this_opt + 6, NULL, 0);
 			sisfb_parm_rate = ivideo.refresh_rate;
-		} else if (!strncmp(this_opt, "rate:", 5)) {
+		} else if (!strnicmp(this_opt, "rate:", 5)) {
 			ivideo.refresh_rate = simple_strtoul(this_opt + 5, NULL, 0);
 			sisfb_parm_rate = ivideo.refresh_rate;
-		} else if (!strncmp(this_opt, "off", 3)) {
+		} else if (!strnicmp(this_opt, "off", 3)) {
 			sisfb_off = 1;
-		} else if (!strncmp(this_opt, "crt1off", 7)) {
+		} else if (!strnicmp(this_opt, "crt1off", 7)) {
 			sisfb_crt1off = 1;
-		} else if (!strncmp(this_opt, "filter:", 7)) {
+		} else if (!strnicmp(this_opt, "filter:", 7)) {
 			filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
-		} else if (!strncmp(this_opt, "forcecrt2type:", 14)) {
+		} else if (!strnicmp(this_opt, "forcecrt2type:", 14)) {
 			sisfb_search_crt2type(this_opt + 14);
-		} else if (!strncmp(this_opt, "forcecrt1:", 10)) {
+		} else if (!strnicmp(this_opt, "forcecrt1:", 10)) {
 			sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
-                } else if (!strncmp(this_opt, "tvmode:",7)) {
+                } else if (!strnicmp(this_opt, "tvmode:",7)) {
 		        sisfb_search_tvstd(this_opt + 7);
-                } else if (!strncmp(this_opt, "tvstandard:",11)) {
+                } else if (!strnicmp(this_opt, "tvstandard:",11)) {
 			sisfb_search_tvstd(this_opt + 7);
-                } else if (!strncmp(this_opt, "mem:",4)) {
+                } else if (!strnicmp(this_opt, "mem:",4)) {
 		        sisfb_mem = simple_strtoul(this_opt + 4, NULL, 0);
-		} else if (!strncmp(this_opt, "queuemode:", 10)) {
+		} else if (!strnicmp(this_opt, "queuemode:", 10)) {
 			sisfb_search_queuemode(this_opt + 10);
-		} else if (!strncmp(this_opt, "pdc:", 4)) {
+		} else if (!strnicmp(this_opt, "pdc:", 4)) {
 		        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
-		        if(sisfb_pdc & ~0x3c) {
-			   printk(KERN_INFO "sisfb: Illegal pdc parameter\n");
-			   sisfb_pdc = 0;
-		        }
-		} else if (!strncmp(this_opt, "noaccel", 7)) {
+		} else if (!strnicmp(this_opt, "noaccel", 7)) {
 			sisfb_accel = 0;
-		} else if (!strncmp(this_opt, "noypan", 6)) {
+		} else if (!strnicmp(this_opt, "noypan", 6)) {
 		        sisfb_ypan = 0;
-		} else if (!strncmp(this_opt, "userom:", 7)) {
+		} else if (!strnicmp(this_opt, "userom:", 7)) {
 			sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
-		} else if (!strncmp(this_opt, "useoem:", 7)) {
+		} else if (!strnicmp(this_opt, "useoem:", 7)) {
 			sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
-		} else if (!strncmp(this_opt, "nocrt2rate", 10)) {
-			sisfb_nocrt2rate = 1;			
+		} else if (!strnicmp(this_opt, "nocrt2rate", 10)) {
+			sisfb_nocrt2rate = 1;
+	 	} else if (!strnicmp(this_opt, "scalelcd:", 9)) {
+		        unsigned long temp = 2;
+		        temp = simple_strtoul(this_opt + 9, NULL, 0);
+		        if((temp == 0) || (temp == 1)) {
+			   SiS_Pr.UsePanelScaler = temp ^ 1;
+		        }
+		} else if (!strnicmp(this_opt, "specialtiming:", 14)) {
+			sisfb_search_specialtiming(this_opt + 14);
+		} else if (!strnicmp(this_opt, "lvdshl:", 7)) {
+		        unsigned long temp = 4;
+		        temp = simple_strtoul(this_opt + 7, NULL, 0);
+		        if((temp >= 0) && (temp <= 3)) {
+			   SiS_Pr.LVDSHL = temp;
+		        }
 		} else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
 			sisfb_search_mode(this_opt, TRUE);
 		} else {
@@ -4066,14 +4195,14 @@
         char *sis_sig_300[4] = {
           "300", "540", "630", "730"
         };
-        char *sis_sig_310[8] = {
-          "315", "315", "315", "5315", "6325", "6325", "Xabre", "6330"
+        char *sis_sig_310[9] = {
+          "315", "315", "315", "5315", "6325", "6325", "Xabre", "6330", "6330"
         };
 	ushort sis_nums_300[4] = {
 	  SIS_300, SIS_540, SIS_630, SIS_730
 	};
-	unsigned short sis_nums_310[8] = {
-	  SIS_315PRO, SIS_315H, SIS_315, SIS_550, SIS_650, SIS_740, SIS_330, SIS_660
+	unsigned short sis_nums_310[9] = {
+	  SIS_315PRO, SIS_315H, SIS_315, SIS_550, SIS_650, SIS_740, SIS_330, SIS_660, SIS_760
 	};
 
         for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
@@ -4110,7 +4239,7 @@
                     }
                 }
 		if(stage != 4) {
-                   for(i = 0;(i < 8) && (stage != 4); i++) {
+                   for(i = 0;(i < 9) && (stage != 4); i++) {
                       if(strncmp(sis_sig_310[i], rom, strlen(sis_sig_310[i])) == 0) {
 		          if(sis_nums_310[i] == ivideo.chip) {
                              stage = 4;
@@ -4169,7 +4298,11 @@
 	memset(&sis_disp, 0, sizeof(sis_disp));
 #endif	
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
 	pci_for_each_dev(pdev) {
+#else
+	while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
+#endif
 		for (b = sisdev_list; b->vendor; b++) {
 			if ((b->vendor == pdev->vendor)
 			    && (b->device == pdev->device)) {
@@ -4211,18 +4344,17 @@
 		break;
 	   case PCI_DEVICE_ID_SI_630_VGA:
 		{
+			ivideo.chip = SIS_630;
 			sisfb_set_reg4(0xCF8, 0x80000000);
 			reg32 = sisfb_get_reg3(0xCFC);
 			if(reg32 == 0x07301039) {
 				ivideo.chip = SIS_730;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)				
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
 				strcpy(sis_fb_info.modename, "SIS 730");
 #else
 				strcpy(myid, "SIS 730");
-#endif				
-			} else
-				ivideo.chip = SIS_630;
-
+#endif
+			}
 			sisvga_engine = SIS_300_VGA;
 			sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;
 			sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
@@ -4267,11 +4399,11 @@
 			reg32 = sisfb_get_reg3(0xCFC);
 			if(reg32 == 0x07401039) {
 				ivideo.chip = SIS_740;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)				
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
 				strcpy(sis_fb_info.modename, "SIS 740");
 #else
-				strcpy(myid, "SIS 740");				
-#endif				
+				strcpy(myid, "SIS 740");
+#endif
 			}
 			sisvga_engine = SIS_315_VGA;
 			sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
@@ -4285,11 +4417,23 @@
 		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
 		break;
 	   case PCI_DEVICE_ID_SI_660_VGA:
-		ivideo.chip = SIS_660;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
+	   	{
+			ivideo.chip = SIS_660;
+			sisfb_set_reg4(0xCF8, 0x80000000);
+			reg32 = sisfb_get_reg3(0xCFC);
+			if(reg32 == 0x07601039) {
+				ivideo.chip = SIS_760;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+				strcpy(sis_fb_info.modename, "SIS 760");
+#else
+				strcpy(myid, "SIS 760");
+#endif
+			}
+			sisvga_engine = SIS_315_VGA;
+			sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
+			sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
+			break;
+		}
 #endif
            default:
 	        return -ENODEV;
@@ -4315,9 +4459,7 @@
 	SiS_Pr.SiS_Backup70xx = 0xff;
         SiS_Pr.SiS_CHOverScan = -1;
         SiS_Pr.SiS_ChSW = FALSE;
-	SiS_Pr.SiS_CustomT = CUT_NONE;
 	SiS_Pr.SiS_UseLCDA = FALSE;
-	SiS_Pr.UsePanelScaler = -1;
 	SiSRegInit(&SiS_Pr, (USHORT)sishw_ext.ulIOAddress);
 
 #ifdef CONFIG_FB_SIS_300
@@ -4364,7 +4506,8 @@
 #endif
 #ifdef CONFIG_FB_SIS_315
 	if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650 ||
-	    ivideo.chip == SIS_740 || ivideo.chip == SIS_660) {
+	    ivideo.chip == SIS_740 || ivideo.chip == SIS_660 ||
+	    ivideo.chip == SIS_760) {
 	        outSISIDXREG(SISSR, 0x28, 0x5a);
 
                 outSISIDXREG(SISSR, 0x29, 0x64);
@@ -4386,6 +4529,7 @@
 		   case SIS_650:
 		   case SIS_740:
 		   case SIS_660:
+		   case SIS_760:
 			sishw_ext.bIntegratedMMEnabled = TRUE;
 			break;
 		   default:
@@ -4426,26 +4570,46 @@
 	strcpy(sishw_ext.szVBIOSVer, "0.84");
 
         /* Find systems for special custom timing */
-	if(sishw_ext.UseROM) {
-	   int i=0,j;
-	   unsigned char *biosver = sishw_ext.pjVirtualRomBase + 0x06;
-           unsigned char *biosdate = sishw_ext.pjVirtualRomBase + 0x2c;
+	if(SiS_Pr.SiS_CustomT == CUT_NONE) {
+	   int i=0, j;
+	   unsigned char *biosver = NULL;
+           unsigned char *biosdate = NULL;
 	   BOOLEAN footprint;
+	   unsigned long chksum = 0;
+
+	   if(sishw_ext.UseROM) {
+	      biosver = sishw_ext.pjVirtualRomBase + 0x06;
+	      biosdate = sishw_ext.pjVirtualRomBase + 0x2c;
+              for(i=0; i<32768; i++) chksum += sishw_ext.pjVirtualRomBase[i];
+	   }
+
+	   i=0;
            do {
 	      if( (mycustomttable[i].chipID == ivideo.chip) &&
-	          (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))) &&
-	          (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))) ) {
+	          ((!strlen(mycustomttable[i].biosversion)) ||
+		   (sishw_ext.UseROM &&
+		   (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
+	          ((!strlen(mycustomttable[i].biosdate)) ||
+		   (sishw_ext.UseROM &&
+		   (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
+		  ((!mycustomttable[i].bioschksum) ||
+		   (sishw_ext.UseROM &&
+	           (mycustomttable[i].bioschksum == chksum)))	&&
+		  (mycustomttable[i].pcisubsysvendor == ivideo.subsysvendor) &&
+		  (mycustomttable[i].pcisubsyscard == ivideo.subsysdevice) ) {
 		 footprint = TRUE;
-	         for(j=0; j<5; j++) {
-	           if(mycustomttable[i].biosFootprintAddr[j]) {
-	              if(sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
+		 if(sishw_ext.UseROM) {
+	            for(j=0; j<5; j++) {
+	               if(mycustomttable[i].biosFootprintAddr[j]) {
+	                  if(sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
 		      		mycustomttable[i].biosFootprintData[j])
-		         footprint = FALSE;
-		   }
+		          footprint = FALSE;
+		       }
+		    }
 	         }
 	         if(footprint) {
 	 	    SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
-		    printk(KERN_DEBUG "sisfb: Identified [%s %s] for non-standard timing\n",
+		    printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
 		        mycustomttable[i].vendorName,
 			mycustomttable[i].cardName);
 	            break;
@@ -4456,7 +4620,7 @@
 	}
 
 #ifdef CONFIG_FB_SIS_300
-	/* TW: Mode numbers for 1280x768 are different for 300 and 315 series */
+	/* Mode numbers for 1280x768 are different for 300 and 315 series */
 	if(sisvga_engine == SIS_300_VGA) {
 		sisbios_mode[MODEINDEX_1280x768].mode_no = 0x55;
 		sisbios_mode[MODEINDEX_1280x768+1].mode_no = 0x5a;
@@ -4579,6 +4743,7 @@
 
 	sishw_ext.ulVideoMemorySize = ivideo.video_size;
 
+	if(sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
 	if(sisfb_pdc) {
 	    sishw_ext.pdc = sisfb_pdc;
 	} else {
@@ -4700,8 +4865,31 @@
 	        sisfb_detectedlcda = 0xff;
 #ifndef LINUXBIOS
 #ifdef CONFIG_FB_SIS_315
-                /* TW: Try to find about LCDA */
+
 		if(sisvga_engine == SIS_315_VGA) {
+		   /* Save PDC */
+		   if(ivideo.vbflags & (VB_301LV | VB_302LV)) {
+		      int tmp;
+		      inSISIDXREG(SISCR,0x30,tmp);
+		      if(tmp & 0x20) {
+		         /* Currently on LCD? If yes, read current pdc */
+		         inSISIDXREG(SISPART1,0x2D,sisfb_detectedpdc);
+			 if(sishw_ext.pdc == 0) {
+			    /* Let option override detection */
+			    sishw_ext.pdc = sisfb_detectedpdc;
+			 }
+			 printk(KERN_INFO
+			        "sisfb: Detected LCD PanelDelayCompensation %d\n",
+  			         sisfb_detectedpdc);
+		      }
+		      if((sishw_ext.pdc) && (sishw_ext.pdc != sisfb_detectedpdc)) {
+		         printk(KERN_INFO
+			         "sisfb: Using LCD PanelDelayCompensation %d\n",
+				 sishw_ext.pdc);
+		      }
+		   }
+
+		   /* Try to find about LCDA */
 		   if(ivideo.vbflags & (VB_302B | VB_301LV | VB_302LV)) {
 		      int tmp;
 		      inSISIDXREG(SISCR,0x34,tmp);
@@ -4727,7 +4915,7 @@
 		      }
 		      if(SiS_Pr.SiS_UseLCDA) {
 		         sisfb_detectedlcda = 0x03;
-		         printk(KERN_INFO
+		         printk(KERN_DEBUG
 			        "sisfb: Bridge uses LCDA for low resolution and text modes\n");
 		      }
 	          }
@@ -4738,7 +4926,7 @@
 		if (!sisfb_crt1off) {
 		   	sisfb_handle_ddc(&sisfb_thismonitor, 0);
 		} else {
-		   	if ((ivideo.vbflags & (VB_301|VB_301B|VB_302B)) &&
+		   	if ((ivideo.vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
 		      	    (ivideo.vbflags & (CRT2_VGA | CRT2_LCD))) {
 		      		sisfb_handle_ddc(&sisfb_thismonitor, 1);
 		   	}
@@ -4839,7 +5027,7 @@
 		default_var.xres = default_var.xres_virtual = ivideo.video_width;
 		default_var.yres = default_var.yres_virtual = ivideo.video_height;
 		default_var.bits_per_pixel = ivideo.video_bpp;
-		
+
 		sisfb_bpp_to_var(&default_var);
 		
 		default_var.pixclock = (u32) (1E12 /
@@ -4856,7 +5044,7 @@
 				default_var.pixclock <<= 1;
 	   		}
 	        }
-		
+
 		ivideo.accel = 0;
 		if(sisfb_accel) {
 		   ivideo.accel = -1;
@@ -4870,7 +5058,7 @@
 	    		if(default_var.yres_virtual <= default_var.yres) {
 	        		default_var.yres_virtual = default_var.yres;
 	    		}
-		} 
+		}
 
 		sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
 		sis_fb_info.var = default_var;
@@ -4878,6 +5066,9 @@
 		sis_fb_info.par = &ivideo;
 		sis_fb_info.screen_base = ivideo.video_vbase;
 		sis_fb_info.fbops = &sisfb_ops;
+#if 0  		/* Waits for class patch to go in */
+		sis_fb_info.dev = &pdev->dev;
+#endif
 		sisfb_get_fix(&sis_fb_info.fix, -1, &sis_fb_info);
 		sis_fb_info.pseudo_palette = pseudo_palette;
 		
@@ -4893,6 +5084,7 @@
 		if(ivideo.mtrr) {
 			printk(KERN_INFO "sisfb: Added MTRRs\n");
 		}
+
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
@@ -4913,6 +5105,7 @@
 		sisfb_registered = 1;			
 
 		printk(KERN_INFO "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO);
+		printk(KERN_INFO "sisfb: Installed SISFB_GET_VBRSTATUS ioctl (%x)\n", SISFB_GET_VBRSTATUS);
 		
 		printk(KERN_INFO "sisfb: 2D acceleration is %s, scrolling mode %s\n",
 		     sisfb_accel ? "enabled" : "disabled",
@@ -4956,8 +5149,11 @@
 static int          useoem = -1;
 static char         *tvstandard = NULL;
 static int	    nocrt2rate = 0;
+static int          scalelcd = -1;
+static char	    *specialtiming = NULL;
+static int	    lvdshl = -1;
 
-MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/740/330/660 framebuffer driver");
+MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/651/661/740/741/330 framebuffer driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>; SiS; Various others");
 
@@ -5024,11 +5220,12 @@
 MODULE_PARM(mem,    "i");
 MODULE_PARM_DESC(mem,
 	"\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
-	  "for video RAM management for eg. DRM/DRI. The default depends on the amount\n"
-	  "of video RAM available. If 8MB of video RAM or less is available, the heap\n"
-	  "starts at 4096KB, if between 8 and 16MB are available at 8192KB, otherwise\n"
-	  "at 12288KB. The value is to be specified without 'KB' and should match\n"
-	  "the MaxXFBMem setting for XFree 4.x (x>=2).");
+	  "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
+	  "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
+	  "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
+	  "otherwise at 12288KB. On 315 and Xabre series, the heap is 1MB by default. The\n"
+	  "value is to be specified without 'KB' and should match the MaxXFBMem setting for\n"
+	  "XFree 4.x (x>=2).");
 
 MODULE_PARM(forcecrt2type, "s");
 MODULE_PARM_DESC(forcecrt2type,
@@ -5046,11 +5243,12 @@
 
 MODULE_PARM(pdc, "i");
 MODULE_PARM_DESC(pdc,
-        "\n(300 series only) This is for manually selecting the LCD panel delay\n"
-	  "compensation. The driver should detect this correctly in most cases; however,\n"
-	  "sometimes this is not possible. If you see 'small waves' on the LCD, try\n"
-	  "setting this to 4, 32 or 24. If the problem persists, try other values\n"
-	  "between 4 and 60 in steps of 4. (default: [autodetected])");
+        "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
+	  "should detect this correctly in most cases; however, sometimes this is not\n"
+	  "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
+	  "on a 300 series chipset; 3 or 51 on a 315 series chipset. If the problem persists,\n"
+	  "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
+	  "and value from 0 to 255). (default: [autodetected])");
 
 MODULE_PARM(noaccel, "i");
 MODULE_PARM_DESC(noaccel,
@@ -5060,8 +5258,7 @@
 MODULE_PARM(noypan, "i");
 MODULE_PARM_DESC(noypan,
         "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
- 	  "will be performed by redrawing the screen. This required 2D acceleration, so\n"
-	  "if the option noaccel is set, y-panning will be disabled. (default: 0)");
+ 	  "will be performed by redrawing the screen. (default: 0)");
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	
 MODULE_PARM(inverse, "i");
@@ -5078,24 +5275,44 @@
 MODULE_PARM(useoem, "i");
 MODULE_PARM_DESC(useoem,
         "\nSetting this to 0 keeps sisfb from using its internel OEM data for some LCD\n"
-	  "panels and TV connector types. (default: auto)");
+	  "panels and TV connector types. (default: [auto])");
 
 MODULE_PARM(tvstandard, "s");
 MODULE_PARM_DESC(tvstandard,
 	"\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
-	  "pal and ntsc. (default: auto)");
+	  "pal and ntsc. (default: [auto])");
 
 MODULE_PARM(nocrt2rate, "i");
 MODULE_PARM_DESC(nocrt2rate,
 	"\nSetting this to 1 will force the driver to use the default refresh rate for\n"
-	  "CRT2 if CRT2 type is VGA. (default: 0, use same rate as crt1)");
-	
+	  "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)");
+
+MODULE_PARM(scalelcd, "i");
+MODULE_PARM_DESC(scalelcd,
+	"\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
+	  "native resolution. Setting it to 0 will disable scaling; if the panel can scale\n"
+	  "by itself, it will probably do this, otherwise you will see a black bar around\n"
+	  "the screen image. Default: [autodetect if panel can scale]");
+
+MODULE_PARM(specialtiming, "s");
+
+MODULE_PARM(lvdshl, "i");
+
+
 int init_module(void)
 {
 	int err;
 
+	SiS_Pr.UsePanelScaler = -1;
+	SiS_Pr.SiS_CustomT = CUT_NONE;
+	SiS_Pr.LVDSHL = -1;
+
 	ivideo.refresh_rate = sisfb_parm_rate = rate;
 
+	if((scalelcd == 0) || (scalelcd == 1)) {
+	   SiS_Pr.UsePanelScaler = scalelcd ^ 1;
+	}
+
 	if(mode)
 		sisfb_search_mode(mode, FALSE);
 	else if(vesa != -1)
@@ -5150,13 +5367,14 @@
 	        sisfb_accel = 0;
 	}
 
-        if(pdc) {
-	   if(!(pdc & ~0x3c)) {
-	        sisfb_pdc = pdc & 0x3c;
-	   }
-	}
-	
+        if(pdc) sisfb_pdc = pdc & 0x3c;
+
 	sisfb_nocrt2rate = nocrt2rate;
+
+	if(specialtiming)
+		sisfb_search_specialtiming(specialtiming);
+
+	if((lvdshl >= 0) && (lvdshl <= 3)) SiS_Pr.LVDSHL = lvdshl;
 
 	if((err = sisfb_init()) < 0) return err;
 
diff -Nru a/drivers/video/sis/sis_main.h b/drivers/video/sis/sis_main.h
--- a/drivers/video/sis/sis_main.h	Sun Jun 29 08:10:19 2003
+++ b/drivers/video/sis/sis_main.h	Fri Aug 29 04:41:58 2003
@@ -12,7 +12,7 @@
 
 #define VER_MAJOR                 1
 #define VER_MINOR                 6
-#define VER_LEVEL                 11
+#define VER_LEVEL                 16
 
 #include "sis.h"
 
@@ -35,13 +35,16 @@
 #ifndef PCI_DEVICE_ID_SI_660_VGA
 #define PCI_DEVICE_ID_SI_660_VGA  0x6330
 #endif
+#ifndef PCI_DEVICE_ID_SI_760
+#define PCI_DEVICE_ID_SI_760      0x0760
+#endif
 
 /* To be included in fb.h */
 #ifndef FB_ACCEL_SIS_GLAMOUR_2
-#define FB_ACCEL_SIS_GLAMOUR_2  40	/* SiS 315, 650, 740		*/
+#define FB_ACCEL_SIS_GLAMOUR_2  40	/* SiS 315, 650, 661, 740		*/
 #endif
 #ifndef FB_ACCEL_SIS_XABRE
-#define FB_ACCEL_SIS_XABRE      41	/* SiS 330 ("Xabre")		*/
+#define FB_ACCEL_SIS_XABRE      41	/* SiS 330 ("Xabre"), 660, 760 (DOA)	*/
 #endif
 
 #define MAX_ROM_SCAN              0x10000
@@ -57,7 +60,7 @@
 #define TURBO_QUEUE_AREA_SIZE     0x80000 /* 512K */
 #endif
 
-/* For 315 series */
+/* For 315/Xabre series */
 #ifdef CONFIG_FB_SIS_315
 #define COMMAND_QUEUE_AREA_SIZE   0x80000 /* 512K */
 #define COMMAND_QUEUE_THRESHOLD   0x1F
@@ -325,7 +328,7 @@
 	.xpanstep	= 0,
 	.ypanstep	= 1,
 };
-static char myid[20];
+static char myid[40];
 static u32 pseudo_palette[17];
 #endif
 
@@ -370,7 +373,7 @@
 VGA_ENGINE sisvga_engine = UNKNOWN_VGA;
 int 	   sisfb_accel = -1;
 
-/* TW: These are to adapted according to VGA_ENGINE type */
+/* These are to adapted according to VGA_ENGINE type */
 static int sisfb_hwcursor_size = 0;
 static int sisfb_CRT2_write_enable = 0;
 
@@ -423,9 +426,11 @@
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315,     "SIS 315"},
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO,  "SIS 315PRO"},
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550 VGA"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 650/M650/651/740 VGA"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 650/M650/651/661FX/M661FX/740/741 VGA"},
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330,     "SIS 330"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, "SIS 660 VGA"},
+#if 0
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, "SIS 660/M660/760/M760 VGA"},
+#endif
 	{0, 0, NULL}
 };
 
@@ -483,13 +488,17 @@
 	{"720x576x16",   0x34, 0x0000, 0x0000,  720,  576, 16, 1,  90, 36, MD_SIS300|MD_SIS315},
 	{"720x576x24",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
 	{"720x576x32",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"768x576x8",    0x5f, 0x0000, 0x0000,  768,  576,  8, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"768x576x16",   0x60, 0x0000, 0x0000,  768,  576, 16, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"768x576x24",   0x61, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"768x576x32",   0x61, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
 	{"800x480x8",    0x70, 0x0000, 0x0000,  800,  480,  8, 1, 100, 30, MD_SIS300|MD_SIS315},
 	{"800x480x16",   0x7a, 0x0000, 0x0000,  800,  480, 16, 1, 100, 30, MD_SIS300|MD_SIS315},
 	{"800x480x24",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
 	{"800x480x32",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
-#define DEFAULT_MODE              39 /* index for 800x600x8 */
-#define DEFAULT_LCDMODE           39 /* index for 800x600x8 */
-#define DEFAULT_TVMODE            39 /* index for 800x600x8 */
+#define DEFAULT_MODE              43 /* index for 800x600x8 */
+#define DEFAULT_LCDMODE           43 /* index for 800x600x8 */
+#define DEFAULT_TVMODE            43 /* index for 800x600x8 */
 	{"800x600x8",    0x30, 0x0103, 0x0103,  800,  600,  8, 2, 100, 37, MD_SIS300|MD_SIS315},
 	{"800x600x16",   0x47, 0x0114, 0x0114,  800,  600, 16, 2, 100, 37, MD_SIS300|MD_SIS315},
 	{"800x600x24",   0x63, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
@@ -526,7 +535,7 @@
 	{"1280x720x16",  0x75, 0x0000, 0x0000, 1280,  720, 16, 1, 160, 45, MD_SIS300|MD_SIS315},
 	{"1280x720x24",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
 	{"1280x720x32",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
-#define MODEINDEX_1280x768 75
+#define MODEINDEX_1280x768 79
 	{"1280x768x8",   0x23, 0x0000, 0x0000, 1280,  768,  8, 1, 160, 48, MD_SIS300|MD_SIS315},
 	{"1280x768x16",  0x24, 0x0000, 0x0000, 1280,  768, 16, 1, 160, 48, MD_SIS300|MD_SIS315},
 	{"1280x768x24",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48, MD_SIS300|MD_SIS315},
@@ -575,11 +584,11 @@
 u8  sisfb_mode_no  = 0;
 u8  sisfb_rate_idx = 0;
 
-/* TW: CR36 evaluation */
+/* CR36 evaluation */
 const USHORT sis300paneltype[] =
     { LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
       LCD_1280x960,  LCD_640x480,   LCD_1024x600,  LCD_1152x768,
-      LCD_1024x768,   LCD_1024x768,  LCD_1024x768,  LCD_1024x768,
+      LCD_1024x768,  LCD_1024x768,  LCD_1024x768,  LCD_1024x768,
       LCD_1024x768,  LCD_1024x768,  LCD_320x480,   LCD_1024x768 };
 
 const USHORT sis310paneltype[] =
@@ -604,17 +613,8 @@
 	{"SVIDEO", 	CRT2_TV, 	TV_SVIDEO, 0},
 	{"COMPOSITE", 	CRT2_TV, 	TV_AVIDEO, 0},
 	{"SCART", 	CRT2_TV, 	TV_SCART,  0},
-	{"none", 	0, 		-1,        0},
-	{"lcd",  	CRT2_LCD, 	-1,        0},
-	{"tv",   	CRT2_TV, 	-1,        0},
-	{"vga",  	CRT2_VGA, 	-1,        0},
-	{"svideo", 	CRT2_TV, 	TV_SVIDEO, 0},
-	{"composite", 	CRT2_TV, 	TV_AVIDEO, 0},
-	{"scart", 	CRT2_TV, 	TV_SCART,  0},
 	{"DSTN",        CRT2_LCD,       -1,        FL_550_DSTN},
-	{"dstn",        CRT2_LCD,       -1,        FL_550_DSTN},
 	{"FSTN",        CRT2_LCD,       -1,        FL_550_FSTN},
-	{"fstn",        CRT2_LCD,       -1,        FL_550_FSTN},
 	{"\0",  	-1, 		-1,        0}
 };
 
@@ -626,9 +626,6 @@
 	{"AGP",  	AGP_CMD_QUEUE},
 	{"VRAM", 	VM_CMD_QUEUE},
 	{"MMIO", 	MMIO_CMD},
-	{"agp",  	AGP_CMD_QUEUE},
-	{"vram", 	VM_CMD_QUEUE},
-	{"mmio", 	MMIO_CMD},
 	{"\0",   	-1}
 };
 
@@ -639,8 +636,6 @@
 } sis_tvtype[] = {
 	{"PAL",  	TV_PAL},
 	{"NTSC", 	TV_NTSC},
-	{"pal", 	TV_PAL},
-	{"ntsc",  	TV_NTSC},
 	{"\0",   	-1}
 };
 
@@ -662,6 +657,7 @@
 	{7,  640,  480, 160,  TRUE}, {8,  640,  480, 200,  TRUE},
 	{1,  720,  480,  60,  TRUE},
 	{1,  720,  576,  58,  TRUE},
+	{1,  768,  576,  58,  TRUE},
 	{1,  800,  480,  60,  TRUE}, {2,  800,  480,  75,  TRUE}, {3,  800,  480,  85,  TRUE},
 	{1,  800,  600,  56,  TRUE}, {2,  800,  600,  60,  TRUE}, {3,  800,  600,  72,  TRUE},
 	{4,  800,  600,  75,  TRUE}, {5,  800,  600,  85,  TRUE}, {6,  800,  600, 105,  TRUE},
@@ -760,26 +756,63 @@
     unsigned short chipID;
     char *biosversion;
     char *biosdate;
+    unsigned long bioschksum;
     unsigned short biosFootprintAddr[5];
     unsigned char biosFootprintData[5];
+    unsigned short pcisubsysvendor;
+    unsigned short pcisubsyscard;
     char *vendorName;
     char *cardName;
     unsigned long SpecialID;
     char *optionName;
 } mycustomttable[] = {
         { SIS_630, "2.00.07", "09/27/2002-13:38:25",
+	  0x3240A8,
 	  { 0x220, 0x227, 0x228, 0x229, 0x22a },
 	  {  0x01,  0xe3,  0x9a,  0x6a,  0x00 },
+	  0x1039, 0x6300,
 	  "Barco", "iQ R200L/300/400", CUT_BARCO1366, "BARCO1366"
 	},
 	{ SIS_630, "2.00.07", "09/27/2002-13:38:25",
+	  0x323FBD,
 	  { 0x220, 0x227, 0x228, 0x229, 0x22a },
 	  {  0x00,  0x5a,  0x64,  0x41,  0x00 },
+	  0x1039, 0x6300,
 	  "Barco", "iQ G200L/300/400/500", CUT_BARCO1024, "BARCO1024"
 	},
+	{ SIS_650, "", "",
+	  0,
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0x0e11, 0x083c,
+	  "Compaq", "Presario 3017cl/3045US", CUT_COMPAQ12802, "COMPAQ1280"
+	},
+	{ SIS_650, "", "",
+	  0,
+	  { 0x00c, 0, 0, 0, 0 },
+	  { 'e'  , 0, 0, 0, 0 },
+	  0x1558, 0x0287,
+	  "Clevo", "L285/L287 (Version 1)", CUT_CLEVO1024, "CLEVO1024"
+	},
+	{ SIS_650, "", "",
+	  0,
+	  { 0x00c, 0, 0, 0, 0 },
+	  { 'y'  , 0, 0, 0, 0 },
+	  0x1558, 0x0287,
+	  "Clevo", "L285/L287 (Version 2)", CUT_CLEVO10242, "CLEVO10242"
+	},
+	{ 4321, "", "",			/* This is hopefully NEVER autodetected */
+	  0,
+	  { 0, 0, 0, 0, 0 },
+	  { 0, 0, 0, 0, 0 },
+	  0, 0,
+	  "Generic", "LVDS/Parallel 848x480", CUT_PANEL848, "PANEL848x480"
+	},
 	{ 0, "", "",
+	  0,
 	  { 0, 0, 0, 0 },
 	  { 0, 0, 0, 0 },
+	  0, 0,
 	  "", "", CUT_NONE, ""
 	}
 };
@@ -841,7 +874,7 @@
 	   {0xF8,0xF4,0x18,0x38},
 	   {0xFC,0xFB,0x14,0x2A},
 	   {0x00,0x00,0x10,0x20},
-	   {0x00,0x04,0x10,0x18}, 
+	   {0x00,0x04,0x10,0x18},
 	   {0xFF,0xFF,0xFF,0xFF} }},
 	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_2 */
 	   {0xF5,0xEE,0x1B,0x44},
@@ -861,7 +894,7 @@
 	   {0xF9,0x0A,0x17,0x0C},
 	   {0x00,0x07,0x10,0x12}, 
 	   {0xFF,0xFF,0xFF,0xFF} }},
-	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_4 */
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_4 - 320 */
 	   {0x00,0xE0,0x10,0x60},
 	   {0x00,0xEE,0x10,0x44},
 	   {0x00,0xF4,0x10,0x38},
@@ -870,7 +903,7 @@
 	   {0x00,0x00,0x10,0x20},
 	   {0x00,0x04,0x10,0x18}, 
 	   {0xFF,0xFF,0xFF,0xFF} }},
-	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_5 */
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_5 - 640 */
 	   {0xF5,0xEE,0x1B,0x44},
 	   {0xF8,0xF4,0x18,0x38},
 	   {0xEB,0x04,0x25,0x18},
@@ -879,7 +912,7 @@
 	   {0xFA,0x06,0x16,0x14},
 	   {0x00,0x04,0x10,0x18}, 
 	   {0xFF,0xFF,0xFF,0xFF} }},
-	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_6 */
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_6 - 720 */
 	   {0xEB,0x04,0x25,0x18},
 	   {0xE7,0x0E,0x29,0x04},
 	   {0xEE,0x0C,0x22,0x08},
@@ -888,7 +921,7 @@
 	   {0xFC,0x0A,0x14,0x0C},
 	   {0x00,0x08,0x10,0x10}, 
 	   {0xFF,0xFF,0xFF,0xFF} }},
-	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_7 */
+	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_7 - 800 */
 	   {0xEC,0x02,0x24,0x1C},
 	   {0xF2,0x04,0x1E,0x18},
 	   {0xEB,0x15,0x25,0xF6},
@@ -933,7 +966,7 @@
 	   {0xFB,0x04,0x15,0x18},
 	   {0x00,0x06,0x10,0x14}, 
 	   {0xFF,0xFF,0xFF,0xFF} }},
-	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_4 */
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_4 - 320 */
 	   {0x00,0xE0,0x10,0x60},
 	   {0x00,0xEE,0x10,0x44},
 	   {0x00,0xF4,0x10,0x38},
@@ -942,7 +975,7 @@
 	   {0x00,0x00,0x10,0x20},
 	   {0x00,0x04,0x10,0x18}, 
 	   {0xFF,0xFF,0xFF,0xFF} }},
-	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_5 */
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_5 - 640 */
 	   {0xF5,0xEE,0x1B,0x44},
 	   {0xF8,0xF4,0x18,0x38},
 	   {0xF1,0xF7,0x1F,0x32},
@@ -951,7 +984,7 @@
 	   {0xFB,0x01,0x15,0x1E},
 	   {0x00,0x04,0x10,0x18}, 
 	   {0xFF,0xFF,0xFF,0xFF} }},
-	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_6 */
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_6 - 720 */
 	   {0xF5,0xEE,0x1B,0x2A},
 	   {0xEE,0xFE,0x22,0x24},
 	   {0xF3,0x00,0x1D,0x20},
@@ -960,7 +993,7 @@
 	   {0xFB,0x04,0x15,0x18},
 	   {0x00,0x06,0x10,0x14}, 
 	   {0xFF,0xFF,0xFF,0xFF} }},
-	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_7 */
+	{ {{0x00,0x00,0x00,0x40},  /* PALFilter_7 - 800 */
 	   {0xF5,0xEE,0x1B,0x44},
 	   {0xF8,0xF4,0x18,0x38},
 	   {0xFC,0xFB,0x14,0x2A},
diff -Nru a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h
--- a/drivers/video/sis/vgatypes.h	Sun Jun 29 09:27:44 2003
+++ b/drivers/video/sis/vgatypes.h	Tue Aug 26 10:29:08 2003
@@ -27,7 +27,8 @@
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * Authors: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *		Silicon Integrated Systems
  *
  */
 #ifndef _VGATYPES_
@@ -132,6 +133,7 @@
     SIS_740,
     SIS_330,
     SIS_660,
+    SIS_760,
     MAX_SIS_CHIP
 } SIS_CHIP_TYPE;
 #endif
@@ -146,6 +148,7 @@
     VB_CHIP_302,
     VB_CHIP_302B,
     VB_CHIP_302LV,
+    VB_CHIP_301C,
     VB_CHIP_UNKNOWN, /* other video bridge or no video bridge */
     MAX_VB_CHIP
 } SIS_VB_CHIP_TYPE;
@@ -170,6 +173,7 @@
     LCD_1024x600,
     LCD_640x480_2,     /* FSTN, DSTN */
     LCD_640x480_3,     /* FSTN, DSTN */
+    LCD_848x480,
     LCD_CUSTOM,
     LCD_UNKNOWN
 } SIS_LCD_TYPE;
@@ -309,7 +313,13 @@
 	
 	unsigned char sisfb_lcda;
 
-	char reserved[235]; 		/* for future use */
+	unsigned long sisfb_vbflags;
+	unsigned long sisfb_currentvbflags;
+
+	int sisfb_scalelcd;
+	unsigned long sisfb_specialtiming;
+
+	char reserved[219]; 		/* for future use */
 };
 #endif
 
diff -Nru a/drivers/video/sis/vstruct.h b/drivers/video/sis/vstruct.h
--- a/drivers/video/sis/vstruct.h	Sun Jun 29 08:10:19 2003
+++ b/drivers/video/sis/vstruct.h	Mon Aug 25 10:48:07 2003
@@ -27,8 +27,8 @@
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
- *              ?
+ * Authors: 	Thomas Winischhofer <thomas@winischhofer.net>
+ *              Silicon Integrated Systems
  *
  */
  
@@ -214,10 +214,15 @@
 typedef UCHAR DRAM4Type[4];
 
 /* Defines for SiS_Customt */
-#define CUT_NONE       0
-#define CUT_FORCENONE  1
-#define CUT_BARCO1366  2
-#define CUT_BARCO1024  3
+#define CUT_NONE        0
+#define CUT_FORCENONE   1
+#define CUT_BARCO1366   2
+#define CUT_BARCO1024   3
+#define CUT_COMPAQ1280  4
+#define CUT_COMPAQ12802 5
+#define CUT_PANEL848    6
+#define CUT_CLEVO1024   7
+#define CUT_CLEVO10242  8
 
 typedef struct _SiS_Private
 {
@@ -443,6 +448,8 @@
 	const SiS_LVDSDataStruct  *SiS_LVDSBARCO1366Data_2;
 	const SiS_LVDSDataStruct  *SiS_LVDSBARCO1024Data_1;
 	const SiS_LVDSDataStruct  *SiS_LVDSBARCO1024Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS848x480Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS848x480Data_2;
 	const SiS_LVDSDataStruct  *SiS_CHTVUNTSCData;
 	const SiS_LVDSDataStruct  *SiS_CHTVONTSCData;
 	const SiS_LVDSDataStruct  *SiS_CHTVUPALData;
@@ -631,6 +638,8 @@
 
 	BOOLEAN SiS_CHPALM;
 	BOOLEAN SiS_CHPALN;
+
+	int	LVDSHL;
 	
 	BOOLEAN Backup;
 	UCHAR Backup_Mode;
diff -Nru a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
--- a/drivers/video/tdfxfb.c	Wed Apr 23 06:19:16 2003
+++ b/drivers/video/tdfxfb.c	Thu Jul 31 06:22:43 2003
@@ -764,7 +764,11 @@
    tdfx_outl(SRCXY,     0);
    tdfx_outl(DSTXY,     xx | (yy << 16));
    tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (ROP_COPY << 24));
+#ifdef __BIG_ENDIAN
+   tdfx_outl(SRCFORMAT, 0x400000 | BIT(20) );   
+#else
    tdfx_outl(SRCFORMAT, 0x400000);
+#endif
    tdfx_outl(DSTFORMAT, fmt);
    tdfx_outl(DSTSIZE,   fontwidth(p) | (fontheight(p) << 16));
    i=fontheight(p);
@@ -822,7 +826,11 @@
    tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
    tdfx_outl(COLORFORE, fgx);
    tdfx_outl(COLORBACK, bgx);
+#ifdef __BIG_ENDIAN
+   tdfx_outl(SRCFORMAT, 0x400000 | BIT(20) );   
+#else
    tdfx_outl(SRCFORMAT, 0x400000);
+#endif   
    tdfx_outl(DSTFORMAT, fmt);
    tdfx_outl(DSTSIZE, w | (h << 16));
    tdfx_outl(SRCXY,     0);
@@ -1475,6 +1483,7 @@
 #if defined(__BIG_ENDIAN)
   switch (par->bpp) {
     case 8:
+    case 24:
       reg.miscinit0 &= ~(1 << 30);
       reg.miscinit0 &= ~(1 << 31);
       break;
@@ -1482,7 +1491,6 @@
       reg.miscinit0 |= (1 << 30);
       reg.miscinit0 |= (1 << 31);
       break;
-    case 24:
     case 32:
       reg.miscinit0 |= (1 << 30);
       reg.miscinit0 &= ~(1 << 31);
@@ -1635,10 +1643,6 @@
     v.blue.length  = 5;
     break;
   case 24:
-    v.red.offset=16;
-    v.green.offset=8;
-    v.blue.offset=0;
-    v.red.length = v.green.length = v.blue.length = 8;
   case 32:
     v.red.offset   = 16;
     v.green.offset = 8;
@@ -1942,6 +1946,12 @@
 			break;
 	}
 	
+        if (pci_enable_device(pdev)) 
+        {
+                printk(KERN_WARNING "fb: Unable to enable %s PCI device.\n", name);
+                return -ENXIO;
+        }
+
 	fb_info.regbase_phys = pci_resource_start(pdev, 0);
 	fb_info.regbase_size = 1 << 24;
 	fb_info.regbase_virt = ioremap_nocache(fb_info.regbase_phys, 1 << 24);
@@ -1970,6 +1980,13 @@
 
 	fb_info.iobase = pci_resource_start (pdev, 2);
       
+        if (!fb_info.iobase) {
+	        printk(KERN_WARNING "fb: Can't access %s I/O ports.\n", name);
+		iounmap(fb_info.regbase_virt);
+		iounmap(fb_info.bufbase_virt);
+                return -ENXIO;
+	}
+   
 	printk("fb: %s memory = %ldK\n", name, fb_info.bufbase_size >> 10);
 
 #ifdef CONFIG_MTRR
@@ -2363,10 +2380,25 @@
    unsigned int h,to;
 
    tdfxfb_createcursorshape(p);
-   xline = ~((1 << (32 - fb_info.cursor.w)) - 1);
+   xline = (~0) << (32 - fb_info.cursor.w);
 
 #ifdef __LITTLE_ENDIAN
    xline = swab32(xline);
+#else
+   switch (p->var.bits_per_pixel) {
+      case 8:
+      case 24:
+         xline = swab32(xline);
+         break;
+      case 16:
+         xline = ((xline & 0xff000000 ) >> 16 )
+               | ((xline & 0x00ff0000 ) >> 16 )
+               | ((xline & 0x0000ff00 ) << 16 )
+               | ((xline & 0x000000ff ) << 16 );
+         break;
+      case 32:
+         break;
+   }
 #endif
 
    cursorbase=(u8*)fb_info.bufbase_virt;
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Sun Aug 17 10:15:13 2003
+++ b/fs/buffer.c	Mon Aug  4 18:42:38 2003
@@ -612,7 +612,7 @@
 	if (buffer_attached(bh))
 		list_del(&bh->b_inode_buffers);
 	set_buffer_attached(bh);
-	list_add(&bh->b_inode_buffers, list);
+	list_add_tail(&bh->b_inode_buffers, list);
 	spin_unlock(&lru_list_lock);
 }
 
@@ -1749,7 +1749,7 @@
 		if (!buffer_mapped(bh)) {
 			if (iblock < lblock) {
 				if (get_block(inode, iblock, bh, 0))
-					continue;
+					SetPageError(page);
 			}
 			if (!buffer_mapped(bh)) {
 				memset(kmap(page) + i*blocksize, 0, blocksize);
@@ -1769,10 +1769,11 @@
 
 	if (!nr) {
 		/*
-		 * all buffers are uptodate - we can set the page
-		 * uptodate as well.
+		 * All buffers are uptodate - we can set the page uptodate
+		 * as well. But not if get_block() returned an error.
 		 */
-		SetPageUptodate(page);
+		if (!PageError(page))
+			SetPageUptodate(page);
 		UnlockPage(page);
 		return 0;
 	}
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Fri Aug  8 20:04:35 2003
+++ b/fs/exec.c	Thu Aug 28 09:06:29 2003
@@ -50,6 +50,7 @@
 
 int core_uses_pid;
 char core_pattern[65] = "core";
+int core_setuid_ok = 0;
 /* The maximal length of core_pattern is also specified in sysctl.c */ 
 
 static struct linux_binfmt *formats;
@@ -1104,13 +1105,18 @@
 	struct file * file;
 	struct inode * inode;
 	int retval = 0;
+	int fsuid = current->fsuid;
 
 	lock_kernel();
 	binfmt = current->binfmt;
 	if (!binfmt || !binfmt->core_dump)
 		goto fail;
 	if (!is_dumpable(current))
-		goto fail;
+	{
+		if(!core_setuid_ok || !current->task_dumpable)
+			goto fail;
+		current->fsuid = 0;
+	}
 	current->mm->dumpable = 0;
 	if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
 		goto fail;
@@ -1139,6 +1145,8 @@
 close_fail:
 	filp_close(file, NULL);
 fail:
+	if (fsuid != current->fsuid)
+		current->fsuid = fsuid;
 	unlock_kernel();
 	return retval;
 }
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Thu Aug  7 17:00:00 2003
+++ b/fs/inode.c	Sat Aug 30 10:42:30 2003
@@ -583,22 +583,25 @@
  * Dispose-list gets a local list with local inodes in it, so it doesn't
  * need to worry about list corruption and SMP locks.
  */
-static void dispose_list(struct list_head * head)
+static void dispose_list(struct list_head *head)
 {
-	struct list_head * inode_entry;
-	struct inode * inode;
+	int nr_disposed = 0;
 
-	while ((inode_entry = head->next) != head)
-	{
-		list_del(inode_entry);
+	while (!list_empty(head)) {
+		struct inode *inode;
+
+		inode = list_entry(head->next, struct inode, i_list);
+		list_del(&inode->i_list);
 
-		inode = list_entry(inode_entry, struct inode, i_list);
 		if (inode->i_data.nrpages)
 			truncate_inode_pages(&inode->i_data, 0);
 		clear_inode(inode);
 		destroy_inode(inode);
-		inodes_stat.nr_inodes--;
+		nr_disposed++;
 	}
+	spin_lock(&inode_lock);
+	inodes_stat.nr_inodes -= nr_disposed;
+	spin_unlock(&inode_lock);
 }
 
 /*
diff -Nru a/fs/jbd/transaction.c b/fs/jbd/transaction.c
--- a/fs/jbd/transaction.c	Fri Mar 28 06:31:57 2003
+++ b/fs/jbd/transaction.c	Mon Dec  2 18:10:15 2002
@@ -1581,9 +1581,6 @@
 	assert_spin_locked(&journal_datalist_lock);
 	transaction = jh->b_transaction;
 
-#ifdef __SMP__
-	J_ASSERT (current->lock_depth >= 0);
-#endif
 	J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
 
 	if (jh->b_jlist != BJ_None)
@@ -2016,9 +2013,6 @@
 
 	assert_spin_locked(&journal_datalist_lock);
 	
-#ifdef __SMP__
-	J_ASSERT (current->lock_depth >= 0);
-#endif
 	J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
 	J_ASSERT_JH(jh, jh->b_transaction == transaction ||
 				jh->b_transaction == 0);
@@ -2108,9 +2102,6 @@
 	int was_dirty = 0;
 
 	assert_spin_locked(&journal_datalist_lock);
-#ifdef __SMP__
-	J_ASSERT_JH(jh, current->lock_depth >= 0);
-#endif
 	/* If the buffer is now unused, just drop it. */
 	if (jh->b_next_transaction == NULL) {
 		__journal_unfile_buffer(jh);
diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c	Fri Jan 17 12:39:06 2003
+++ b/fs/jfs/inode.c	Mon Aug 25 08:50:59 2003
@@ -149,7 +149,7 @@
 	rc = txCommit(tid, 1, &inode, wait ? COMMIT_SYNC : 0);
 	txEnd(tid);
 	up(&JFS_IP(inode)->commit_sem);
-	return -rc;
+	return rc;
 }
 
 void jfs_write_inode(struct inode *inode, int wait)
@@ -303,7 +303,7 @@
 		else
 			IREAD_UNLOCK(ip);
 	}
-	return -rc;
+	return rc;
 }
 
 static int jfs_writepage(struct page *page)
diff -Nru a/fs/jfs/jfs_btree.h b/fs/jfs/jfs_btree.h
--- a/fs/jfs/jfs_btree.h	Fri Jan 17 12:39:06 2003
+++ b/fs/jfs/jfs_btree.h	Mon Aug 25 08:50:59 2003
@@ -81,7 +81,7 @@
 		} else {\
 			P = NULL;\
 			jfs_err("bread failed!");\
-			RC = EIO;\
+			RC = -EIO;\
 		}\
 	}\
 }
diff -Nru a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
--- a/fs/jfs/jfs_dmap.c	Wed Feb 12 11:35:28 2003
+++ b/fs/jfs/jfs_dmap.c	Mon Aug 25 09:00:11 2003
@@ -189,8 +189,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOMEM	- insufficient memory
- *      EIO	- i/o error
+ *      -ENOMEM	- insufficient memory
+ *      -EIO	- i/o error
  */
 int dbMount(struct inode *ipbmap)
 {
@@ -205,7 +205,7 @@
 	/* allocate memory for the in-memory bmap descriptor */
 	bmp = kmalloc(sizeof(struct bmap), GFP_KERNEL);
 	if (bmp == NULL)
-		return (ENOMEM);
+		return -ENOMEM;
 
 	/* read the on-disk bmap descriptor. */
 	mp = read_metapage(ipbmap,
@@ -213,7 +213,7 @@
 			   PSIZE, 0);
 	if (mp == NULL) {
 		kfree(bmp);
-		return (EIO);
+		return -EIO;
 	}
 
 	/* copy the on-disk bmap descriptor to its in-memory version. */
@@ -268,7 +268,7 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      EIO	- i/o error
+ *      -EIO	- i/o error
  */
 int dbUnmount(struct inode *ipbmap, int mounterror)
 {
@@ -316,7 +316,7 @@
 			   PSIZE, 0);
 	if (mp == NULL) {
 		jfs_err("dbSync: read_metapage failed!");
-		return (EIO);
+		return -EIO;
 	}
 	/* copy the in-memory version of the bmap to the on-disk version */
 	dbmp_le = (struct dbmap *) mp->data;
@@ -368,7 +368,7 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      EIO	- i/o error
+ *      -EIO	- i/o error
  */
 int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
 {
@@ -414,7 +414,7 @@
 		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
 		if (mp == NULL) {
 			IREAD_UNLOCK(ipbmap);
-			return (EIO);
+			return -EIO;
 		}
 		dp = (struct dmap *) mp->data;
 
@@ -463,7 +463,7 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      EIO	- i/o error
+ *      -EIO	- i/o error
  */
 int
 dbUpdatePMap(struct inode *ipbmap,
@@ -503,7 +503,7 @@
 			mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE,
 					   0);
 			if (mp == NULL)
-				return (EIO);
+				return -EIO;
 		}
 		dp = (struct dmap *) mp->data;
 
@@ -737,8 +737,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  */
 int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
 {
@@ -758,7 +758,7 @@
 #ifdef _STILL_TO_PORT
 	/* DASD limit check                                     F226941 */
 	if (OVER_LIMIT(ip, nblocks))
-		return ENOSPC;
+		return -ENOSPC;
 #endif				/* _STILL_TO_PORT */
 
 	/* get the log2 number of blocks to be allocated.
@@ -828,7 +828,7 @@
 
 		/* get the buffer for the dmap containing the hint.
 		 */
-		rc = EIO;
+		rc = -EIO;
 		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
 		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
 		if (mp == NULL)
@@ -840,7 +840,7 @@
 		 * blocks beginning at the hint.
 		 */
 		if ((rc = dbAllocNext(bmp, dp, blkno, (int) nblocks))
-		    != ENOSPC) {
+		    != -ENOSPC) {
 			if (rc == 0) {
 				*results = blkno;
 				DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
@@ -869,7 +869,7 @@
 		 */
 		if ((rc =
 		     dbAllocNear(bmp, dp, blkno, (int) nblocks, l2nb, results))
-		    != ENOSPC) {
+		    != -ENOSPC) {
 			if (rc == 0) {
 				DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
 					*results, nblocks);
@@ -884,7 +884,7 @@
 		 * the same dmap as the hint.
 		 */
 		if ((rc = dbAllocDmapLev(bmp, dp, (int) nblocks, l2nb, results))
-		    != ENOSPC) {
+		    != -ENOSPC) {
 			if (rc == 0) {
 				DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
 					*results, nblocks);
@@ -904,7 +904,7 @@
 	 */
 	IWRITE_LOCK(ipbmap);
 	if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results))
-	    != ENOSPC) {
+	    != -ENOSPC) {
 		if (rc == 0)
 			DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
 				*results, nblocks);
@@ -923,7 +923,7 @@
 	/* Try to allocate within this allocation group.  if that fails, try to
 	 * allocate anywhere in the map.
 	 */
-	if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) == ENOSPC)
+	if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) == -ENOSPC)
 		rc = dbAllocAny(bmp, nblocks, l2nb, results);
 	if (rc == 0) {
 		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, nblocks);
@@ -953,8 +953,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  */
 int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
 {
@@ -976,13 +976,13 @@
 	 */
 	if (nblocks <= 0 || nblocks > BPERDMAP || blkno >= bmp->db_mapsize) {
 		IREAD_UNLOCK(ipbmap);
-		return EINVAL;
+		return -EINVAL;
 	}
 
 	if (nblocks > ((s64) 1 << bmp->db_maxfreebud)) {
 		/* the free space is no longer available */
 		IREAD_UNLOCK(ipbmap);
-		return ENOSPC;
+		return -ENOSPC;
 	}
 
 	/* read in the dmap covering the extent */
@@ -990,7 +990,7 @@
 	mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
 	if (mp == NULL) {
 		IREAD_UNLOCK(ipbmap);
-		return (EIO);
+		return -EIO;
 	}
 	dp = (struct dmap *) mp->data;
 
@@ -1038,8 +1038,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  */
 int
 dbReAlloc(struct inode *ip,
@@ -1053,7 +1053,7 @@
 		*results = blkno;
 		return (0);
 	} else {
-		if (rc != ENOSPC)
+		if (rc != -ENOSPC)
 			return (rc);
 	}
 
@@ -1087,8 +1087,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  */
 int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
 {
@@ -1106,7 +1106,7 @@
 	 */
 	if (((rel_block = blkno & (sbi->nbperpage - 1))) &&
 	    (rel_block + nblocks + addnblocks > sbi->nbperpage))
-		return (ENOSPC);
+		return -ENOSPC;
 
 	/* get the last block of the current allocation */
 	lastblkno = blkno + nblocks - 1;
@@ -1133,7 +1133,7 @@
 	if (addnblocks > BPERDMAP || extblkno >= bmp->db_mapsize ||
 	    (extblkno & (bmp->db_agsize - 1)) == 0) {
 		IREAD_UNLOCK(ipbmap);
-		return (ENOSPC);
+		return -ENOSPC;
 	}
 
 	/* get the buffer for the dmap containing the first block
@@ -1143,7 +1143,7 @@
 	mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
 	if (mp == NULL) {
 		IREAD_UNLOCK(ipbmap);
-		return (EIO);
+		return -EIO;
 	}
 
 	DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks);
@@ -1164,7 +1164,7 @@
 	} else {
 		/* we were not successful */
 		release_metapage(mp);
-		assert(rc == ENOSPC || rc == EIO);
+		assert(rc == -ENOSPC || rc == -EIO);
 	}
 
 	return (rc);
@@ -1185,8 +1185,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
  */
@@ -1212,13 +1212,13 @@
 	 * this dmap.
 	 */
 	if (dbitno + nblocks > BPERDMAP)
-		return (ENOSPC);
+		return -ENOSPC;
 
 	/* check if the starting leaf indicates that anything
 	 * is free.
 	 */
 	if (leaf[word] == NOFREE)
-		return (ENOSPC);
+		return -ENOSPC;
 
 	/* check the dmaps words corresponding to block range to see
 	 * if the block range is free.  not all bits of the first and
@@ -1247,7 +1247,7 @@
 			 */
 			mask = (ONES << (DBWORD - nb) >> wbitno);
 			if ((mask & ~le32_to_cpu(dp->wmap[word])) != mask)
-				return (ENOSPC);
+				return -ENOSPC;
 
 			word += 1;
 		} else {
@@ -1265,7 +1265,7 @@
 				/* does the leaf describe any free space ?
 				 */
 				if (leaf[word] < BUDMIN)
-					return (ENOSPC);
+					return -ENOSPC;
 
 				/* determine the l2 number of bits provided
 				 * by this leaf.
@@ -1311,8 +1311,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
  */
@@ -1360,7 +1360,7 @@
 		return (rc);
 	}
 
-	return (ENOSPC);
+	return -ENOSPC;
 }
 
 
@@ -1413,8 +1413,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  *
  * note: IWRITE_LOCK(ipmap) held on entry/exit;
  */
@@ -1457,8 +1457,8 @@
 	if (bmp->db_agsize == BPERDMAP
 	    || bmp->db_agfree[agno] == bmp->db_agsize) {
 		rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
-		/* assert(!(rc == ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */
-		if ((rc == ENOSPC) &&
+		/* assert(!(rc == -ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */
+		if ((rc == -ENOSPC) &&
 		    (bmp->db_agfree[agno] == bmp->db_agsize)) {
 			jfs_err("dbAllocAG: removed assert, but still need to "
 				"debug here\nblkno = 0x%Lx, nblocks = 0x%Lx",
@@ -1474,7 +1474,7 @@
 	lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, bmp->db_aglevel);
 	mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
 	if (mp == NULL)
-		return (EIO);
+		return -EIO;
 	dcp = (struct dmapctl *) mp->data;
 	budmin = dcp->budmin;
 
@@ -1547,7 +1547,7 @@
 			if ((rc =
 			     dbFindCtl(bmp, l2nb, bmp->db_aglevel - 1,
 				       &blkno))) {
-				assert(rc != ENOSPC);
+				assert(rc != -ENOSPC);
 				return (rc);
 			}
 		}
@@ -1555,16 +1555,16 @@
 		/* allocate the blocks.
 		 */
 		rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
-		assert(rc != ENOSPC);
+		assert(rc != -ENOSPC);
 		return (rc);
 	}
 
 	/* no space in the allocation group.  release the buffer and
-	 * return ENOSPC.
+	 * return -ENOSPC.
 	 */
 	release_metapage(mp);
 
-	return (ENOSPC);
+	return -ENOSPC;
 }
 
 
@@ -1589,8 +1589,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  *
  * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -1611,7 +1611,7 @@
 	/* allocate the blocks.
 	 */
 	rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
-	assert(rc != ENOSPC);
+	assert(rc != -ENOSPC);
 	return (rc);
 }
 
@@ -1639,8 +1639,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  *
  * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -1664,7 +1664,7 @@
 		lblkno = BLKTOCTL(b, bmp->db_l2nbperpage, lev);
 		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
 		if (mp == NULL)
-			return (EIO);
+			return -EIO;
 		dcp = (struct dmapctl *) mp->data;
 		budmin = dcp->budmin;
 
@@ -1683,7 +1683,7 @@
 		 */
 		if (rc) {
 			assert(lev == level);
-			return (ENOSPC);
+			return -ENOSPC;
 		}
 
 		/* adjust the block number to reflect the location within
@@ -1746,8 +1746,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  *
  * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -1767,7 +1767,7 @@
 		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
 		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
 		if (mp == NULL)
-			return (EIO);
+			return -EIO;
 		dp = (struct dmap *) mp->data;
 
 		/* try to allocate the blocks.
@@ -1794,7 +1794,7 @@
 		lblkno = BLKTODMAP(b, bmp->db_l2nbperpage);
 		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
 		if (mp == NULL) {
-			rc = EIO;
+			rc = -EIO;
 			goto backout;
 		}
 		dp = (struct dmap *) mp->data;
@@ -1891,8 +1891,8 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient disk resources
- *      EIO	- i/o error
+ *      -ENOSPC	- insufficient disk resources
+ *      -EIO	- i/o error
  *
  * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or 
  *	IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit;
@@ -1912,7 +1912,7 @@
 	 * returns the index of the leaf at which free space was found.
 	 */
 	if (dbFindLeaf((dmtree_t *) & dp->tree, l2nb, &leafidx))
-		return (ENOSPC);
+		return -ENOSPC;
 
 	/* determine the block number within the file system corresponding
 	 * to the leaf at which free space was found.
@@ -1957,7 +1957,7 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      EIO	- i/o error
+ *      -EIO	- i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -2012,7 +2012,7 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      EIO	- i/o error
+ *      -EIO	- i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -2392,7 +2392,7 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      EIO	- i/o error
+ *      -EIO	- i/o error
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
@@ -2412,7 +2412,7 @@
 	lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, level);
 	mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
 	if (mp == NULL)
-		return (EIO);
+		return -EIO;
 	dcp = (struct dmapctl *) mp->data;
 
 	/* determine the leaf number corresponding to the block and
@@ -2835,7 +2835,7 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      ENOSPC	- insufficient free blocks. 
+ *      -ENOSPC	- insufficient free blocks. 
  */
 static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
 {
@@ -2845,7 +2845,7 @@
 	 * sufficient free space.
 	 */
 	if (l2nb > tp->dmt_stree[ROOT])
-		return (ENOSPC);
+		return -ENOSPC;
 
 	/* sufficient free space available. now search down the tree
 	 * starting at the next level for the leftmost leaf that
@@ -3066,7 +3066,7 @@
  * RETURN VALUES:
  *      none
  */
-void fsDirty()
+void fsDirty(void)
 {
 	printk("fsDirty(): bye-bye\n");
 	assert(0);
@@ -3089,7 +3089,7 @@
  *
  * RETURN VALUES:
  *      0	- success
- *      EIO	- i/o error
+ *      -EIO	- i/o error
  */
 int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks)
 {
@@ -3120,7 +3120,7 @@
 		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
 		if (mp == NULL) {
 			IREAD_UNLOCK(ipbmap);
-			return (EIO);
+			return -EIO;
 		}
 		dp = (struct dmap *) mp->data;
 
@@ -3530,7 +3530,7 @@
 	return 0;
 
       errout:
-	return EIO;
+	return -EIO;
 }
 
 
diff -Nru a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
--- a/fs/jfs/jfs_dtree.c	Mon Jun 23 14:45:42 2003
+++ b/fs/jfs/jfs_dtree.c	Mon Aug 25 08:50:59 2003
@@ -134,7 +134,7 @@
 			BT_PUTPAGE(MP);\
 			updateSuper((IP)->i_sb, FM_DIRTY);\
 			MP = NULL;\
-			RC = EIO;\
+			RC = -EIO;\
 		}\
 	}\
 }
@@ -404,7 +404,7 @@
 		     xtInsert(tid, ip, 0, 0, sbi->nbperpage,
 			      &xaddr, 0))) {
 			jfs_warn("add_index: xtInsert failed!");
-			return -1;
+			return -EPERM;
 		}
 		ip->i_size = PSIZE;
 		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
@@ -412,7 +412,7 @@
 		if ((mp = get_index_page(ip, 0)) == 0) {
 			jfs_err("add_index: get_metapage failed!");
 			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
-			return -1;
+			return -EPERM;
 		}
 		tlck = txLock(tid, ip, mp, tlckDATA);
 		llck = (struct linelock *) & tlck->lock;
@@ -447,7 +447,7 @@
 			      &xaddr, 0))) {
 			jfs_warn("add_index: xtInsert failed!");
 			jfs_ip->next_index--;
-			return -1;
+			return -EPERM;
 		}
 		ip->i_size += PSIZE;
 		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
@@ -461,7 +461,7 @@
 
 	if (mp == 0) {
 		jfs_err("add_index: get/read_metapage failed!");
-		return -1;
+		return -EPERM;
 	}
 
 	lock_index(tid, ip, mp, index);
@@ -588,7 +588,7 @@
 	    (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
 				GFP_NOFS);
 	if (ciKey.name == 0) {
-		rc = ENOMEM;
+		rc = -ENOMEM;
 		goto dtSearch_Exit2;
 	}
 
@@ -674,7 +674,7 @@
 					 */
 					if (flag == JFS_CREATE) {
 						*data = inumber;
-						rc = EEXIST;
+						rc = -EEXIST;
 						goto out;
 					}
 
@@ -684,7 +684,7 @@
 					if ((flag == JFS_REMOVE ||
 					     flag == JFS_RENAME) &&
 					    *data != inumber) {
-						rc = ESTALE;
+						rc = -ESTALE;
 						goto out;
 					}
 
@@ -732,7 +732,7 @@
 			 */
 			if (flag == JFS_LOOKUP || flag == JFS_REMOVE ||
 			    flag == JFS_RENAME) {
-				rc = ENOENT;
+				rc = -ENOENT;
 				goto out;
 			}
 
@@ -770,7 +770,7 @@
 			 */
 			jfs_err("stack overrun in dtSearch!");
 			updateSuper(sb, FM_DIRTY);
-			rc = EIO;
+			rc = -EIO;
 			goto out;
 		}
 		btstack->nsplit++;
@@ -840,7 +840,7 @@
 	if (DO_INDEX(ip)) {
 		if (JFS_IP(ip)->next_index == DIREND) {
 			DT_PUTPAGE(mp);
-			return EMLINK;
+			return -EMLINK;
 		}
 		n = NDTLEAF(name->namlen);
 		data.leaf.tid = tid;
@@ -953,7 +953,7 @@
 				GFP_NOFS);
 	if (key.name == 0) {
 		DT_PUTPAGE(smp);
-		rc = ENOMEM;
+		rc = -ENOMEM;
 		goto dtSplitUp_Exit;
 	}
 
@@ -1328,7 +1328,7 @@
 	rbn = addressPXD(pxd);
 	rmp = get_metapage(ip, rbn, PSIZE, 1);
 	if (rmp == NULL)
-		return EIO;
+		return -EIO;
 
 	jfs_info("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
 
@@ -1579,7 +1579,7 @@
 
 	ip->i_blocks += LBLK2PBLK(sb, lengthPXD(pxd));
 
-	return 0;
+	return rc;
 }
 
 
@@ -2628,7 +2628,7 @@
 		 * descend down to leftmost child page
 		 */
 		if (p->header.flag & BT_LEAF)
-			return ESTALE;
+			return -ESTALE;
 
 		/* get the leftmost entry */
 		stbl = DT_GETSTBL(p);
@@ -2666,7 +2666,7 @@
 		bn = le64_to_cpu(p->header.next);
 	else {
 		DT_PUTPAGE(mp);
-		return ESTALE;
+		return -ESTALE;
 	}
 
 	/* unpin current page */
@@ -3068,7 +3068,7 @@
 			}
 
 			if ((rc = dtReadFirst(ip, &btstack)))
-				return -rc;
+				return rc;
 
 			DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
 		}
@@ -3268,7 +3268,7 @@
 		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 		if (rc) {
 			free_page(dirent_buf);
-			return -rc;
+			return rc;
 		}
 	}
 
@@ -4434,8 +4434,8 @@
  *	flag	- JFS_RENAME
  *
  * RETURNS:
- *	ESTALE	- If entry found does not match orig_ino passed in
- *	ENOENT	- If no entry can be found to match key
+ *	-ESTALE	- If entry found does not match orig_ino passed in
+ *	-ENOENT	- If no entry can be found to match key
  *	0	- If successfully modified entry
  */
 int dtModify(tid_t tid, struct inode *ip,
diff -Nru a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
--- a/fs/jfs/jfs_extent.c	Fri Apr  4 12:07:39 2003
+++ b/fs/jfs/jfs_extent.c	Mon Aug 25 08:50:59 2003
@@ -83,8 +83,8 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO	- i/o error.
- *      ENOSPC	- insufficient disk resources.
+ *      -EIO	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
  */
 int
 extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
@@ -208,8 +208,8 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO	- i/o error.
- *      ENOSPC	- insufficient disk resources.
+ *      -EIO	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
  */
 int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
 {
@@ -351,7 +351,7 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO	- i/o error.
+ *      -EIO	- i/o error.
  */
 int extHint(struct inode *ip, s64 offset, xad_t * xp)
 {
@@ -422,8 +422,8 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO	- i/o error.
- *      ENOSPC	- insufficient disk resources.
+ *      -EIO	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
  */
 int extRecord(struct inode *ip, xad_t * xp)
 {
@@ -437,7 +437,7 @@
 	rc = xtUpdate(0, ip, xp);
 
 	up(&JFS_IP(ip)->commit_sem);
-	return (rc);
+	return rc;
 }
 
 
@@ -454,8 +454,8 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO	- i/o error.
- *      ENOSPC	- insufficient disk resources.
+ *      -EIO	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
  */
 int extFill(struct inode *ip, xad_t * xp)
 {
@@ -506,8 +506,8 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO	- i/o error.
- *      ENOSPC	- insufficient disk resources.
+ *      -EIO	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
  */
 static int
 extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
@@ -536,7 +536,7 @@
 		/* if something other than an out of space error,
 		 * stop and return this error.
 		 */
-		if (rc != ENOSPC)
+		if (rc != -ENOSPC)
 			return (rc);
 
 		/* decrease the allocation request size */
@@ -597,8 +597,8 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO	- i/o error.
- *      ENOSPC	- insufficient disk resources.
+ *      -EIO	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
  */
 static int
 extBrealloc(struct inode *ip,
@@ -611,7 +611,7 @@
 		*newblkno = blkno;
 		return (0);
 	} else {
-		if (rc != ENOSPC)
+		if (rc != -ENOSPC)
 			return (rc);
 	}
 
diff -Nru a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h
--- a/fs/jfs/jfs_filsys.h	Fri May 31 06:19:24 2002
+++ b/fs/jfs/jfs_filsys.h	Mon Aug 25 11:19:31 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2001
+ *   Copyright (c) International Business Machines Corp., 2000-2003
  *
  *   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
@@ -29,6 +29,9 @@
 /*
  *	 file system option (superblock flag)
  */
+/* mount time flag to disable journaling to disk */
+#define JFS_NOINTEGRITY 0x00000010
+
 /* platform option (conditional compilation) */
 #define JFS_AIX		0x80000000	/* AIX support */
 /*	POSIX name/directory  support */
diff -Nru a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
--- a/fs/jfs/jfs_imap.c	Mon Mar 10 13:11:19 2003
+++ b/fs/jfs/jfs_imap.c	Mon Aug 25 08:50:59 2003
@@ -120,8 +120,8 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      ENOMEM  - insufficient free virtual memory.
- *      EIO  	- i/o error.
+ *      -ENOMEM  - insufficient free virtual memory.
+ *      -EIO  	- i/o error.
  */
 int diMount(struct inode *ipimap)
 {
@@ -137,7 +137,7 @@
 	imap = (struct inomap *) kmalloc(sizeof(struct inomap), GFP_KERNEL);
 	if (imap == NULL) {
 		jfs_err("diMount: kmalloc returned NULL!");
-		return (ENOMEM);
+		return -ENOMEM;
 	}
 
 	/* read the on-disk inode map control structure. */
@@ -147,7 +147,7 @@
 			   PSIZE, 0);
 	if (mp == NULL) {
 		kfree(imap);
-		return (EIO);
+		return -EIO;
 	}
 
 	/* copy the on-disk version to the in-memory version. */
@@ -206,8 +206,8 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      ENOMEM  - insufficient free virtual memory.
- *      EIO  	- i/o error.
+ *      -ENOMEM  - insufficient free virtual memory.
+ *      -EIO  	- i/o error.
  */
 int diUnmount(struct inode *ipimap, int mounterror)
 {
@@ -253,7 +253,7 @@
 			  PSIZE, 0);
 	if (mp == NULL) {
 		jfs_err("diSync: get_metapage failed!");
-		return EIO;
+		return -EIO;
 	}
 
 	/* copy the in-memory version to the on-disk version */
@@ -318,8 +318,8 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO  	- i/o error.
- *      ENOMEM	- insufficient memory
+ *      -EIO  	- i/o error.
+ *      -ENOMEM	- insufficient memory
  *      
  */
 int diRead(struct inode *ip)
@@ -364,7 +364,7 @@
 	if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) ||
 	    (addressPXD(&iagp->inoext[extno]) == 0)) {
 		release_metapage(mp);
-		return ESTALE;
+		return -ESTALE;
 	}
 
 	/* get disk block number of the page within the inode extent
@@ -399,7 +399,7 @@
 	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
 	if (mp == 0) {
 		jfs_err("diRead: read_metapage failed");
-		return EIO;
+		return -EIO;
 	}
 
 	/* locate the the disk inode requested */
@@ -409,9 +409,9 @@
 	if (ip->i_ino != le32_to_cpu(dp->di_number)) {
 		jfs_err("diRead: i_ino != di_number");
 		updateSuper(ip->i_sb, FM_DIRTY);
-		rc = EIO;
+		rc = -EIO;
 	} else if (le32_to_cpu(dp->di_nlink) == 0)
-		rc = ESTALE;
+		rc = -ESTALE;
 	else
 		/* copy the disk inode to the in-memory inode */
 		rc = copy_from_dinode(dp, ip);
@@ -617,7 +617,7 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO  	- i/o error.
+ *      -EIO  	- i/o error.
  */
 int diWrite(tid_t tid, struct inode *ip)
 {
@@ -676,7 +676,7 @@
       retry:
 	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
 	if (mp == 0)
-		return (EIO);
+		return -EIO;
 
 	/* get the pointer to the disk inode */
 	dp = (struct dinode *) mp->data;
@@ -890,7 +890,7 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      EIO  	- i/o error.
+ *      -EIO  	- i/o error.
  */
 int diFree(struct inode *ip)
 {
@@ -928,7 +928,7 @@
 			(uint) inum, iagno, imap->im_nextiag);
 		dump_mem("imap", imap, 32);
 		updateSuper(ip->i_sb, FM_DIRTY);
-		return EIO;
+		return -EIO;
 	}
 
 	/* get the allocation group for this ino.
@@ -977,7 +977,7 @@
 		IREAD_UNLOCK(ipimap);
 		AG_UNLOCK(imap, agno);
 		updateSuper(ip->i_sb, FM_DIRTY);
-		return EIO;
+		return -EIO;
 	}
 	/*
 	 *      inode extent still has some inodes or below low water mark:
@@ -1367,8 +1367,8 @@
  *
  * RETURN VALUES:
  *      0       - success.
- *      ENOSPC 	- insufficient disk resources.
- *      EIO  	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
+ *      -EIO  	- i/o error.
  */
 int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
 {
@@ -1476,7 +1476,7 @@
 				rc = diAllocBit(imap, iagp, ino);
 				IREAD_UNLOCK(ipimap);
 				if (rc) {
-					assert(rc == EIO);
+					assert(rc == -EIO);
 				} else {
 					/* set the results of the allocation
 					 * and write the iag.
@@ -1553,7 +1553,7 @@
 				rc = diAllocBit(imap, iagp, ino);
 				IREAD_UNLOCK(ipimap);
 				if (rc) {
-					assert(rc == EIO);
+					assert(rc == -EIO);
 				} else {
 					/* set the results of the allocation
 					 * and write the iag.
@@ -1589,10 +1589,10 @@
 					 * new extent, try to allocate the
 					 * disk inode from somewhere else.
 					 */
-					if (rc == ENOSPC)
+					if (rc == -ENOSPC)
 						break;
 
-					assert(rc == EIO);
+					assert(rc == -EIO);
 				} else {
 					/* set the results of the allocation
 					 * and write the iag.
@@ -1631,7 +1631,7 @@
 
 	AG_UNLOCK(imap, agno);
 
-	if (rc != ENOSPC)
+	if (rc != -ENOSPC)
 		return (rc);
 
 	/*
@@ -1667,8 +1667,8 @@
  *
  * RETURN VALUES:
  *      0       - success.
- *      ENOSPC 	- insufficient disk resources.
- *      EIO  	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
+ *      -EIO  	- i/o error.
  */
 static int
 diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
@@ -1684,7 +1684,7 @@
 	if (numfree > numinos) {
 		jfs_err("diAllocAG: numfree > numinos");
 		updateSuper(ip->i_sb, FM_DIRTY);
-		return EIO;
+		return -EIO;
 	}
 
 	/* determine if we should allocate a new extent of free inodes
@@ -1707,7 +1707,7 @@
 		 * below to allocate a free and existing (already backed)
 		 * inode from the ag.
 		 */
-		if ((rc = diAllocExt(imap, agno, ip)) != ENOSPC)
+		if ((rc = diAllocExt(imap, agno, ip)) != -ENOSPC)
 			return (rc);
 	}
 
@@ -1738,8 +1738,8 @@
  *
  * RETURN VALUES:
  *      0       - success.
- *      ENOSPC 	- insufficient disk resources.
- *      EIO  	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
+ *      -EIO  	- i/o error.
  */
 static int
 diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
@@ -1758,7 +1758,7 @@
 
 		AG_UNLOCK(imap, ag);
 
-		if (rc != ENOSPC)
+		if (rc != -ENOSPC)
 			return (rc);
 	}
 
@@ -1771,13 +1771,13 @@
 
 		AG_UNLOCK(imap, ag);
 
-		if (rc != ENOSPC)
+		if (rc != -ENOSPC)
 			return (rc);
 	}
 
 	/* no free disk inodes.
 	 */
-	return (ENOSPC);
+	return -ENOSPC;
 }
 
 
@@ -1803,8 +1803,8 @@
  *
  * RETURN VALUES:
  *      0       - success.
- *      ENOSPC 	- insufficient disk resources.
- *      EIO  	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
+ *      -EIO  	- i/o error.
  */
 static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
 {
@@ -1815,7 +1815,7 @@
 	/* check if there are iags on the ag's free inode list.
 	 */
 	if ((iagno = imap->im_agctl[agno].inofree) < 0)
-		return (ENOSPC);
+		return -ENOSPC;
 
 	/* obtain read lock on imap inode */
 	IREAD_LOCK(imap->im_ipimap);
@@ -1837,7 +1837,7 @@
 		jfs_err("  agno = %d, iagno = %d", agno, iagno);
 		dump_mem("iag", iagp, 64);
 		updateSuper(ip->i_sb, FM_DIRTY);
-		return EIO;
+		return -EIO;
 	}
 
 	/* scan the free inode summary map to find an extent
@@ -1913,8 +1913,8 @@
  *
  * RETURN VALUES:
  *      0       - success.
- *      ENOSPC 	- insufficient disk resources.
- *      EIO  	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
+ *      -EIO  	- i/o error.
  */
 static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
 {
@@ -2018,8 +2018,8 @@
  *
  * RETURN VALUES:
  *      0       - success.
- *      ENOSPC 	- insufficient disk resources.
- *      EIO  	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
+ *      -EIO  	- i/o error.
  */
 static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
 {
@@ -2158,8 +2158,8 @@
  *
  * RETURN VALUES:
  *      0       - success.
- *      ENOSPC 	- insufficient disk resources.
- *      EIO  	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
+ *      -EIO  	- i/o error.
  */
 static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
 {
@@ -2272,7 +2272,7 @@
 		 */
 		dmp = get_metapage(ipimap, blkno + i, PSIZE, 1);
 		if (dmp == NULL) {
-			rc = EIO;
+			rc = -EIO;
 			goto error_out;
 		}
 		dp = (struct dinode *) dmp->data;
@@ -2418,8 +2418,8 @@
  *
  * RETURN VALUES:
  *      0       - success.
- *      ENOSPC 	- insufficient disk resources.
- *      EIO  	- i/o error.
+ *      -ENOSPC	- insufficient disk resources.
+ *      -EIO  	- i/o error.
  *
  * serialization: 
  *	AG lock held on entry/exit;
@@ -2490,7 +2490,7 @@
 			/* release the inode map lock */
 			IWRITE_UNLOCK(ipimap);
 
-			rc = ENOSPC;
+			rc = -ENOSPC;
 			goto out;
 		}
 
@@ -2521,7 +2521,7 @@
 			/* release the inode map lock */
 			IWRITE_UNLOCK(ipimap);
 
-			rc = EIO;
+			rc = -EIO;
 			goto out;
 		}
 		iagp = (struct iag *) mp->data;
@@ -2553,7 +2553,7 @@
 			/* release the inode map lock */
 			IWRITE_UNLOCK(ipimap);
 
-			rc = EIO;
+			rc = -EIO;
 			goto out;
 		}
 
@@ -2619,7 +2619,7 @@
 	/* read the iag */
 	if ((rc = diIAGRead(imap, iagno, &mp))) {
 		IREAD_UNLOCK(ipimap);
-		rc = EIO;
+		rc = -EIO;
 		goto out;
 	}
 	iagp = (struct iag *) mp->data;
@@ -2658,7 +2658,7 @@
  *
  * RETURN VALUES:
  *      0       - success.
- *      EIO  	- i/o error.
+ *      -EIO  	- i/o error.
  */
 static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp)
 {
@@ -2671,7 +2671,7 @@
 	/* read the iag. */
 	*mpp = read_metapage(ipimap, blkno, PSIZE, 0);
 	if (*mpp == NULL) {
-		return (EIO);
+		return -EIO;
 	}
 
 	return (0);
@@ -2718,7 +2718,8 @@
  *	is_free	- If TRUE indicates inode should be marked freed, otherwise
  *		  indicates inode should be marked allocated.
  *
- * RETURNS: 0 for success
+ * RETURN VALUES: 
+ *		0 for success
  */
 int
 diUpdatePMap(struct inode *ipimap,
@@ -3016,7 +3017,7 @@
  *
  * RETURN VALUES:
  *      0       - success
- *      ENOMEM	- insufficient memory
+ *      -ENOMEM	- insufficient memory
  */
 static int copy_from_dinode(struct dinode * dip, struct inode *ip)
 {
diff -Nru a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
--- a/fs/jfs/jfs_incore.h	Fri Apr  4 12:07:39 2003
+++ b/fs/jfs/jfs_incore.h	Mon Aug 25 11:19:31 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (c) International Business Machines Corp., 2000-2003
  *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -126,32 +126,34 @@
  * JFS-private superblock information.
  */
 struct jfs_sb_info {
-	unsigned long	mntflag;	/* 4: aggregate attributes	*/
-	struct inode	*ipbmap;	/* 4: block map inode		*/
-	struct inode	*ipaimap;	/* 4: aggregate inode map inode	*/
-	struct inode	*ipaimap2;	/* 4: secondary aimap inode	*/
-	struct inode	*ipimap;	/* 4: aggregate inode map inode	*/
-	struct jfs_log	*log;		/* 4: log			*/
-	short		bsize;		/* 2: logical block size	*/
-	short		l2bsize;	/* 2: log2 logical block size	*/
-	short		nbperpage;	/* 2: blocks per page		*/
-	short		l2nbperpage;	/* 2: log2 blocks per page	*/
-	short		l2niperblk;	/* 2: log2 inodes per page	*/
-	kdev_t		logdev;		/* 2: external log device	*/
+	unsigned long	mntflag;	/* aggregate attributes	*/
+	struct inode	*ipbmap;	/* block map inode		*/
+	struct inode	*ipaimap;	/* aggregate inode map inode	*/
+	struct inode	*ipaimap2;	/* secondary aimap inode	*/
+	struct inode	*ipimap;	/* aggregate inode map inode	*/
+	struct jfs_log	*log;		/* log			*/
+	short		bsize;		/* logical block size	*/
+	short		l2bsize;	/* log2 logical block size	*/
+	short		nbperpage;	/* blocks per page		*/
+	short		l2nbperpage;	/* log2 blocks per page	*/
+	short		l2niperblk;	/* log2 inodes per page	*/
+	kdev_t		logdev;		/* external log device	*/
 	uint		aggregate;	/* volume identifier in log record */
-	pxd_t		logpxd;		/* 8: pxd describing log	*/
-	pxd_t		fsckpxd;	/* 8: pxd describing fsck wkspc */
-	pxd_t		ait2;		/* 8: pxd describing AIT copy	*/
-	char		uuid[16];	/* 16: 128-bit uuid for volume	*/
-	char		loguuid[16];	/* 16: 128-bit uuid for log	*/
+	pxd_t		logpxd;		/* pxd describing log	*/
+	pxd_t		fsckpxd;	/* pxd describing fsck wkspc */
+	pxd_t		ait2;		/* pxd describing AIT copy	*/
+	char		uuid[16];	/* 128-bit uuid for volume	*/
+	char		loguuid[16];	/* 128-bit uuid for log	*/
 	/* Formerly in ipimap */
-	uint		gengen;		/* 4: inode generation generator*/
-	uint		inostamp;	/* 4: shows inode belongs to fileset*/
+	uint		gengen;		/* inode generation generator*/
+	uint		inostamp;	/* shows inode belongs to fileset*/
 
         /* Formerly in ipbmap */
-	struct bmap	*bmap;		/* 4: incore bmap descriptor	*/
-	struct nls_table *nls_tab;	/* 4: current codepage		*/
-	uint		state;		/* 4: mount/recovery state	*/
+	struct bmap	*bmap;		/* incore bmap descriptor	*/
+	struct nls_table *nls_tab;	/* current codepage		*/
+	uint		state;		/* mount/recovery state	*/
+	unsigned long	flag;		/* mount time flags */
+	uint		p_state;	/* state prior to going no integrity */
 };
 
 static inline struct jfs_inode_info *JFS_IP(struct inode *inode)
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Mon Mar 10 10:35:52 2003
+++ b/fs/jfs/jfs_logmgr.c	Mon Aug 25 11:19:31 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (c) International Business Machines Corp., 2000-2003
  *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -666,7 +666,7 @@
 	/* group committed already ? */
 	if (tblk->flag & tblkGC_COMMITTED) {
 		if (tblk->flag & tblkGC_ERROR)
-			rc = EIO;
+			rc = -EIO;
 
 		LOGGC_UNLOCK(log);
 		return rc;
@@ -700,7 +700,7 @@
 
 	if (tblk->flag & tblkGC_COMMITTED) {
 		if (tblk->flag & tblkGC_ERROR)
-			rc = EIO;
+			rc = -EIO;
 
 		LOGGC_UNLOCK(log);
 		return rc;
@@ -716,7 +716,7 @@
 
 	/* removed from commit queue */
 	if (tblk->flag & tblkGC_ERROR)
-		rc = EIO;
+		rc = -EIO;
 
 	LOGGC_UNLOCK(log);
 	return rc;
@@ -1064,7 +1064,7 @@
 	struct jfs_log *log;
 
 	if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL)))
-		return ENOMEM;
+		return -ENOMEM;
 	memset(log, 0, sizeof(struct jfs_log));
 	init_waitqueue_head(&log->syncwait);
 
@@ -1106,12 +1106,11 @@
 	 */
 
 	if (!(bdev = bdget(kdev_t_to_nr(JFS_SBI(sb)->logdev)))) {
-		rc = ENODEV;
+		rc = -ENODEV;
 		goto free;
 	}
 
 	if ((rc = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS))) {
-		rc = -rc;
 		goto free;
 	}
 
@@ -1164,7 +1163,7 @@
  * PARAMETER:	log	- log structure
  *
  * RETURN:	0	- if ok
- *		EINVAL	- bad log magic number or superblock dirty
+ *		-EINVAL	- bad log magic number or superblock dirty
  *		error returned from logwait()
  *			
  * serialization: single first open thread
@@ -1206,21 +1205,21 @@
 
 	if (logsuper->magic != cpu_to_le32(LOGMAGIC)) {
 		jfs_warn("*** Log Format Error ! ***");
-		rc = EINVAL;
+		rc = -EINVAL;
 		goto errout20;
 	}
 
 	/* logredo() should have been run successfully. */
 	if (logsuper->state != cpu_to_le32(LOGREDONE)) {
 		jfs_warn("*** Log Is Dirty ! ***");
-		rc = EINVAL;
+		rc = -EINVAL;
 		goto errout20;
 	}
 
 	/* initialize log inode from log superblock */
 	if (test_bit(log_INLINELOG,&log->flag)) {
 		if (log->size != le32_to_cpu(logsuper->size)) {
-			rc = EINVAL;
+			rc = -EINVAL;
 			goto errout20;
 		}
 		jfs_info("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x",
@@ -1239,6 +1238,15 @@
 	log->page = le32_to_cpu(logsuper->end) / LOGPSIZE;
 	log->eor = le32_to_cpu(logsuper->end) - (LOGPSIZE * log->page);
 
+	/* check for disabled journaling to disk */
+	if (JFS_SBI(log->sb)->flag & JFS_NOINTEGRITY) {
+		log->no_integrity = 1;
+		log->ni_page = log->page;
+		log->ni_eor = log->eor;
+	}
+	else
+		log->no_integrity = 0;
+
 	/*
 	 * initialize for log append write mode
 	 */
@@ -1519,6 +1527,14 @@
 	lrd.type = cpu_to_le16(LOG_SYNCPT);
 	lrd.length = 0;
 	lrd.log.syncpt.sync = 0;
+	
+	/* check for disabled journaling to disk */
+	if (JFS_SBI(log->sb)->flag & JFS_NOINTEGRITY) {
+		log->no_integrity = 0;
+		log->page = log->ni_page;
+		log->eor = log->ni_eor;
+	}
+
 	lsn = lmWriteRecord(log, NULL, &lrd, NULL);
 	bp = log->bp;
 	lp = (struct logpage *) bp->l_ldata;
@@ -1593,7 +1609,7 @@
 		if (i == MAX_ACTIVE) {
 			jfs_warn("Too many file systems sharing journal!");
 			lbmFree(bpsuper);
-			return EMFILE;	/* Is there a better rc? */
+			return -EMFILE;	/* Is there a better rc? */
 		}
 	} else {
 		for (i = 0; i < MAX_ACTIVE; i++)
@@ -1604,7 +1620,7 @@
 		if (i == MAX_ACTIVE) {
 			jfs_warn("Somebody stomped on the journal!");
 			lbmFree(bpsuper);
-			return EIO;
+			return -EIO;
 		}
 		
 	}
@@ -1701,7 +1717,7 @@
 
       error:
 	lbmLogShutdown(log);
-	return (ENOMEM);
+	return -ENOMEM;
 }
 
 
@@ -1974,7 +1990,12 @@
 	set_bit(BH_Req, &bp->l_bh.b_state);
 	bp->l_bh.b_rdev = bp->l_bh.b_dev;
 	bp->l_bh.b_rsector = bp->l_blkno << (bp->l_log->l2bsize - 9);
-	generic_make_request(WRITE, &bp->l_bh);
+
+	if (bp->l_log->no_integrity)
+		/* don't really do I/O */
+		lbmIODone(&bp->l_bh, 1);
+	 else
+		generic_make_request(WRITE, &bp->l_bh);
 
 	INCREMENT(lmStat.submitted);
 	run_task_queue(&tq_disk);
@@ -1995,7 +2016,7 @@
 
 	LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag & lbmDONE), flags);
 
-	rc = (bp->l_flag & lbmERROR) ? EIO : 0;
+	rc = (bp->l_flag & lbmERROR) ? -EIO : 0;
 
 	if (flag & lbmFREE)
 		lbmfree(bp);
diff -Nru a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
--- a/fs/jfs/jfs_logmgr.h	Tue Feb 18 06:18:44 2003
+++ b/fs/jfs/jfs_logmgr.h	Mon Aug 25 11:19:31 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (c) International Business Machines Corp., 2000-2003
  *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -417,6 +417,10 @@
 	struct lbuf *wqueue;	/* 4: log pageout queue */
 	int count;		/* 4: count */
 	char uuid[16];		/* 16: 128-bit uuid of log device */
+
+	int no_integrity;	/* flag to disable journaling to disk */
+	int ni_page;		/* backup of page for nointegrity option */
+	int ni_eor;		/* backup of eor for nointegrity option */
 };
 
 /*
diff -Nru a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
--- a/fs/jfs/jfs_mount.c	Fri Jan 17 12:39:06 2003
+++ b/fs/jfs/jfs_mount.c	Mon Aug 25 11:19:31 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (c) International Business Machines Corp., 2000-2003
  *
  *   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
@@ -72,11 +72,11 @@
  *
  * PARAMETER:	sb	- super block
  *
- * RETURN:	EBUSY	- device already mounted or open for write
- *		EBUSY	- cvrdvp already mounted;
- *		EBUSY	- mount table full
- *		ENOTDIR	- cvrdvp not directory on a device mount
- *		ENXIO	- device open failure
+ * RETURN:	-EBUSY	- device already mounted or open for write
+ *		-EBUSY	- cvrdvp already mounted;
+ *		-EBUSY	- mount table full
+ *		-ENOTDIR- cvrdvp not directory on a device mount
+ *		-ENXIO	- device open failure
  */
 int jfs_mount(struct super_block *sb)
 {
@@ -98,7 +98,7 @@
 	ipaimap = diReadSpecial(sb, AGGREGATE_I, 0);
 	if (ipaimap == NULL) {
 		jfs_err("jfs_mount: Faild to read AGGREGATE_I");
-		rc = EIO;
+		rc = -EIO;
 		goto errout20;
 	}
 	sbi->ipaimap = ipaimap;
@@ -118,7 +118,7 @@
 	 */
 	ipbmap = diReadSpecial(sb, BMAP_I, 0);
 	if (ipbmap == NULL) {
-		rc = EIO;
+		rc = -EIO;
 		goto errout22;
 	}
 
@@ -149,7 +149,7 @@
 		ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1);
 		if (ipaimap2 == 0) {
 			jfs_err("jfs_mount: Faild to read AGGREGATE_I");
-			rc = EIO;
+			rc = -EIO;
 			goto errout35;
 		}
 		sbi->ipaimap2 = ipaimap2;
@@ -178,7 +178,7 @@
 	if (ipimap == NULL) {
 		jfs_err("jfs_mount: Failed to read FILESYSTEM_I");
 		/* open fileset secondary inode allocation map */
-		rc = EIO;
+		rc = -EIO;
 		goto errout40;
 	}
 	jfs_info("jfs_mount: ipimap:0x%p", ipimap);
@@ -327,8 +327,7 @@
 	/* validate fs signature */
 	if (strncmp(j_sb->s_magic, JFS_MAGIC, 4) ||
 	    j_sb->s_version > cpu_to_le32(JFS_VERSION)) {
-		//rc = EFORMAT;
-		rc = EINVAL;
+		rc = -EINVAL;
 		goto out;
 	}
 
@@ -336,7 +335,7 @@
 #ifdef _JFS_4K
 	if (bsize != PSIZE) {
 		jfs_err("Currently only 4K block size supported!");
-		rc = EINVAL;
+		rc = -EINVAL;
 		goto out;
 	}
 #endif				/* _JFS_4K */
@@ -372,7 +371,7 @@
 	if (j_sb->s_state != cpu_to_le32(FM_CLEAN) &&
 	    !(sb->s_flags & MS_RDONLY)) {
 		jfs_err("jfs_mount: Mount Failure: File System Dirty.");
-		rc = EINVAL;
+		rc = -EINVAL;
 		goto out;
 	}
 
@@ -421,12 +420,20 @@
 	struct buffer_head *bh;
 	int rc;
 
-	/*
-	 * Only fsck can fix dirty state
-	 */
-	if (sbi->state == FM_DIRTY)
+	if (sbi->flag & JFS_NOINTEGRITY) {
+		if (state == FM_DIRTY) {
+			sbi->p_state = state;
+			return 0;
+		} else if (state == FM_MOUNT) {
+			sbi->p_state = sbi->state;
+			state = FM_DIRTY;
+		} else if (state == FM_CLEAN) {
+			state = sbi->p_state;
+		} else
+			jfs_err("updateSuper: bad state");
+	} else if (sbi->state == FM_DIRTY)
 		return 0;
-
+	
 	if ((rc = readSuper(sb, &bh)))
 		return rc;
 
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Thu Apr 17 13:16:58 2003
+++ b/fs/jfs/jfs_txnmgr.c	Mon Aug 25 11:19:31 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (c) International Business Machines Corp., 2000-2003
  *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -177,7 +177,7 @@
 	       struct tlock * tlck);
 void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
 	    struct tlock * tlck);
-void txAbortCommit(struct commit * cd, int exval);
+static void txAbortCommit(struct commit * cd);
 static void txAllocPMap(struct inode *ip, struct maplock * maplock,
 			struct tblock * tblk);
 void txForce(struct tblock * tblk);
@@ -256,7 +256,7 @@
 	size = sizeof(struct tblock) * nTxBlock;
 	TxBlock = (struct tblock *) vmalloc(size);
 	if (TxBlock == NULL)
-		return ENOMEM;
+		return -ENOMEM;
 
 	for (k = 1; k < nTxBlock - 1; k++) {
 		TxBlock[k].next = k + 1;
@@ -282,7 +282,7 @@
 	TxLock = (struct tlock *) vmalloc(size);
 	if (TxLock == NULL) {
 		vfree(TxBlock);
-		return ENOMEM;
+		return -ENOMEM;
 	}
 
 	/* initialize tlock table */
@@ -1099,7 +1099,7 @@
 	     struct inode **iplist,	/* list of inode to commit */
 	     int flag)
 {
-	int rc = 0, rc1 = 0;
+	int rc = 0;
 	struct commit cd;
 	struct jfs_log *log;
 	struct tblock *tblk;
@@ -1114,7 +1114,7 @@
 	jfs_info("txCommit, tid = %d, flag = %d", tid, flag);
 	/* is read-only file system ? */
 	if (isReadOnly(iplist[0])) {
-		rc = EROFS;
+		rc = -EROFS;
 		goto TheEnd;
 	}
 
@@ -1297,9 +1297,7 @@
 
       out:
 	if (rc != 0)
-		txAbortCommit(&cd, rc);
-	else
-		rc = rc1;
+		txAbortCommit(&cd);
 
       TheEnd:
 	jfs_info("txCommit: tid = %d, returning %d", tid, rc);
@@ -2654,14 +2652,13 @@
  * log age of page-frames in memory for which caller has
  * are reset to 0 (to avoid logwarap).
  */
-void txAbortCommit(struct commit * cd, int exval)
+static void txAbortCommit(struct commit * cd)
 {
 	struct tblock *tblk;
 	tid_t tid;
 	lid_t lid, next;
 	struct metapage *mp;
 
-	assert(exval == EIO || exval == ENOMEM);
 	jfs_warn("txAbortCommit: cd:0x%p", cd);
 
 	/*
@@ -2718,7 +2715,7 @@
 		/* We must have gotten ahead of the user thread
 		 */
 		jfs_info("txLazyCommit: tblk 0x%p not unlocked", tblk);
-		schedule();
+		yield();
 	}
 
 	jfs_info("txLazyCommit: processing tblk 0x%p", tblk);
diff -Nru a/fs/jfs/jfs_unicode.c b/fs/jfs/jfs_unicode.c
--- a/fs/jfs/jfs_unicode.c	Fri Jan 17 12:39:06 2003
+++ b/fs/jfs/jfs_unicode.c	Mon Aug 25 08:51:00 2003
@@ -68,8 +68,7 @@
 			jfs_err("jfs_strtoUCS: char2uni returned %d.", charlen);
 			jfs_err("charset = %s, char = 0x%x",
 				codepage->charset, (unsigned char) *from);
-			to[i] = 0x003f;	/* a question mark */
-			charlen = 1;
+			return charlen;
 		}
 	}
 
@@ -89,16 +88,21 @@
 	int length = dentry->d_name.len;
 
 	if (length > JFS_NAME_MAX)
-		return ENAMETOOLONG;
+		return -ENAMETOOLONG;
 
 	uniName->name =
 	    kmalloc((length + 1) * sizeof(wchar_t), GFP_NOFS);
 
 	if (uniName->name == NULL)
-		return ENOSPC;
+		return -ENOSPC;
 
 	uniName->namlen = jfs_strtoUCS(uniName->name, dentry->d_name.name,
 				       length, nls_tab);
+
+	if (uniName->namlen < 0) {
+		kfree(uniName->name);
+		return uniName->namlen;
+	}
 
 	return 0;
 }
diff -Nru a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
--- a/fs/jfs/jfs_xtree.c	Mon Mar 10 13:11:20 2003
+++ b/fs/jfs/jfs_xtree.c	Mon Aug 25 09:00:11 2003
@@ -73,7 +73,7 @@
 			BT_PUTPAGE(MP);\
 			updateSuper((IP)->i_sb, FM_DIRTY);\
 			MP = NULL;\
-                        RC = EIO;\
+                        RC = -EIO;\
                 }\
         }\
 }
@@ -814,7 +814,7 @@
 	/* This test must follow XT_GETSEARCH since mp must be valid if
 	 * we branch to out: */
 	if (cmp == 0) {
-		rc = EEXIST;
+		rc = -EEXIST;
 		goto out;
 	}
 
@@ -1033,7 +1033,7 @@
 	    xtSplitRoot(tid, ip, split, &rmp) :
 	    xtSplitPage(tid, ip, split, &rmp, &rbn);
 	if (rc)
-		return EIO;
+		return -EIO;
 
 	XT_PUTPAGE(smp);
 
@@ -1238,7 +1238,7 @@
 	rbn = addressPXD(pxd);
 	rmp = get_metapage(ip, rbn, PSIZE, 1);
 	if (rmp == NULL)
-		return EIO;
+		return -EIO;
 
 	jfs_info("xtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
 
@@ -1485,7 +1485,7 @@
 	rbn = addressPXD(pxd);
 	rmp = get_metapage(ip, rbn, PSIZE, 1);
 	if (rmp == NULL)
-		return EIO;
+		return -EIO;
 
 	jfs_info("xtSplitRoot: ip:0x%p rmp:0x%p", ip, rmp);
 
@@ -2409,7 +2409,7 @@
 	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
 
 	if (cmp == 0) {
-		rc = EEXIST;
+		rc = -EEXIST;
 		goto out;
 	}
 //insert:
@@ -2557,7 +2557,7 @@
 	if (cmp) {
 		/* unpin the leaf page */
 		XT_PUTPAGE(mp);
-		return ENOENT;
+		return -ENOENT;
 	}
 
 	/*
@@ -2788,7 +2788,7 @@
 	/* validate extent offset */
 	offset = xoff << JFS_SBI(ip->i_sb)->l2bsize;
 	if (offset >= ip->i_size)
-		return ESTALE;	/* stale extent */
+		return -ESTALE;	/* stale extent */
 
 	jfs_info("xtRelocate: xtype:%d xoff:0x%lx xlen:0x%x xaddr:0x%lx:0x%lx",
 		 xtype, (ulong) xoff, xlen, (ulong) oxaddr, (ulong) nxaddr);
@@ -2804,7 +2804,7 @@
 			return rc;
 		if (cmp) {
 			XT_PUTPAGE(pmp);
-			return ESTALE;
+			return -ESTALE;
 		}
 
 		/* retrieve search result */
@@ -2814,7 +2814,7 @@
 		xad = &pp->xad[index];
 		if (addressXAD(xad) != oxaddr || lengthXAD(xad) != xlen) {
 			XT_PUTPAGE(pmp);
-			return ESTALE;
+			return -ESTALE;
 		}
 	} else {		/* (xtype == XTPAGE) */
 
@@ -2824,7 +2824,7 @@
 			return rc;
 		if (cmp) {
 			XT_PUTPAGE(pmp);
-			return ESTALE;
+			return -ESTALE;
 		}
 
 		/* retrieve search result */
@@ -3127,7 +3127,7 @@
 		if (rc)
 			return rc;
 		if (p->header.flag & BT_LEAF)
-			return ESTALE;
+			return -ESTALE;
 
 		lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
 
@@ -3439,7 +3439,7 @@
       getPage:
 	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 	if (rc)
-		return -rc;
+		return rc;
 
 	/* process entries backward from last index */
 	index = le16_to_cpu(p->header.nextindex) - 1;
@@ -3667,7 +3667,7 @@
 	bn = parent->bn;
 	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 	if (rc)
-		return -rc;
+		return rc;
 
 	index = parent->index;
 
@@ -3924,7 +3924,7 @@
 		xoff = (committed_size >> JFS_SBI(ip->i_sb)->l2bsize) - 1;
 		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
 		if (rc)
-			return -rc;
+			return rc;
 		assert(cmp == 0);
 		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
 	} else {
@@ -3941,7 +3941,7 @@
       getPage:
 		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 		if (rc)
-			return -rc;
+			return rc;
 
 		/* process entries backward from last index */
 		index = le16_to_cpu(p->header.nextindex) - 1;
@@ -3986,7 +3986,7 @@
 	bn = parent->bn;
 	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 	if (rc)
-		return -rc;
+		return rc;
 
 	index = parent->index;
 
@@ -4225,8 +4225,7 @@
  *      at the current entry at the current subtree root page
  *
  */
-int xtGather(t)
-btree_t *t;
+int xtGather(btree_t *t)
 {
 	int rc = 0;
 	xtpage_t *p;
@@ -4312,7 +4311,7 @@
 			bn = parent->bn;
 			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 			if (rc)
-				return EIO;
+				return -EIO;
 
 			/* first subroot page which
 			 * covers all new allocated blocks
diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c
--- a/fs/jfs/namei.c	Thu Apr 17 06:06:12 2003
+++ b/fs/jfs/namei.c	Mon Aug 25 08:51:00 2003
@@ -83,7 +83,7 @@
 	 */
 	ip = ialloc(dip, mode);
 	if (ip == NULL) {
-		rc = ENOSPC;
+		rc = -ENOSPC;
 		goto out2;
 	}
 
@@ -116,7 +116,7 @@
 	ino = ip->i_ino;
 	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
 		jfs_err("jfs_create: dtInsert returned %d", rc);
-		if (rc == EIO)
+		if (rc == -EIO)
 			txAbort(tid, 1);	/* Marks Filesystem dirty */
 		else
 			txAbort(tid, 0);	/* Filesystem full */
@@ -151,8 +151,8 @@
 
       out1:
 
-	jfs_info("jfs_create: rc:%d", -rc);
-	return -rc;
+	jfs_info("jfs_create: rc:%d", rc);
+	return rc;
 }
 
 
@@ -186,7 +186,7 @@
 
 	/* link count overflow on parent directory ? */
 	if (dip->i_nlink == JFS_LINK_MAX) {
-		rc = EMLINK;
+		rc = -EMLINK;
 		goto out1;
 	}
 
@@ -204,7 +204,7 @@
 	 */
 	ip = ialloc(dip, S_IFDIR | mode);
 	if (ip == NULL) {
-		rc = ENOSPC;
+		rc = -ENOSPC;
 		goto out2;
 	}
 
@@ -238,7 +238,7 @@
 	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
 		jfs_err("jfs_mkdir: dtInsert returned %d", rc);
 
-		if (rc == EIO)
+		if (rc == -EIO)
 			txAbort(tid, 1);	/* Marks Filesystem dirty */
 		else
 			txAbort(tid, 0);	/* Filesystem full */
@@ -276,8 +276,8 @@
 
       out1:
 
-	jfs_info("jfs_mkdir: rc:%d", -rc);
-	return -rc;
+	jfs_info("jfs_mkdir: rc:%d", rc);
+	return rc;
 }
 
 /*
@@ -288,8 +288,8 @@
  * PARAMETER:	dip 	- parent inode
  *		dentry	- child directory dentry
  *
- * RETURN:	EINVAL	- if name is . or ..
- *		EINVAL  - if . or .. exist but are invalid.
+ * RETURN:	-EINVAL	- if name is . or ..
+ *		-EINVAL  - if . or .. exist but are invalid.
  *		errors from subroutines
  *
  * note:
@@ -313,7 +313,7 @@
 
 	/* directory must be empty to be removed */
 	if (!dtEmpty(ip)) {
-		rc = ENOTEMPTY;
+		rc = -ENOTEMPTY;
 		goto out;
 	}
 
@@ -339,7 +339,7 @@
 	ino = ip->i_ino;
 	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
 		jfs_err("jfs_rmdir: dtDelete returned %d", rc);
-		if (rc == EIO)
+		if (rc == -EIO)
 			txAbort(tid, 1);
 		txEnd(tid);
 		up(&JFS_IP(dip)->commit_sem);
@@ -399,7 +399,7 @@
 
       out:
 	jfs_info("jfs_rmdir: rc:%d", rc);
-	return -rc;
+	return rc;
 }
 
 /*
@@ -455,7 +455,7 @@
 	ino = ip->i_ino;
 	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
 		jfs_err("jfs_unlink: dtDelete returned %d", rc);
-		if (rc == EIO)
+		if (rc == -EIO)
 			txAbort(tid, 1);	/* Marks FS Dirty */
 		txEnd(tid);
 		up(&JFS_IP(dip)->commit_sem);
@@ -485,7 +485,7 @@
 			up(&JFS_IP(dip)->commit_sem);
 			up(&JFS_IP(ip)->commit_sem);
 			IWRITE_UNLOCK(ip);
-			rc = -new_size;		/* We return -rc */
+			rc = new_size;
 			goto out1;
 		}
 		tblk = tid_to_tblock(tid);
@@ -521,7 +521,7 @@
 		new_size = xtTruncate_pmap(tid, ip, new_size);
 		if (new_size < 0) {
 			txAbort(tid, 1);	/* Marks FS Dirty */
-			rc = -new_size;		/* We return -rc */
+			rc = new_size;
 		} else
 			rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
 		txEnd(tid);
@@ -547,8 +547,8 @@
       out1:
 	free_UCSname(&dname);
       out:
-	jfs_info("jfs_unlink: rc:%d", -rc);
-	return -rc;
+	jfs_info("jfs_unlink: rc:%d", rc);
+	return rc;
 }
 
 /*
@@ -573,7 +573,7 @@
  * PARAMETERS:	cd	- pointer to commit data structure.
  *			  current inode is the one to truncate.
  *
- * RETURN :	Errors from subroutines
+ * RETURN:	Errors from subroutines
  */
 s64 commitZeroLink(tid_t tid, struct inode *ip)
 {
@@ -767,7 +767,7 @@
 	down(&JFS_IP(ip)->commit_sem);
 
 	if (ip->i_nlink == JFS_LINK_MAX) {
-		rc = EMLINK;
+		rc = -EMLINK;
 		goto out;
 	}
 
@@ -805,7 +805,7 @@
 	up(&JFS_IP(ip)->commit_sem);
 
 	jfs_info("jfs_link: rc:%d", rc);
-	return -rc;
+	return rc;
 }
 
 /*
@@ -863,7 +863,7 @@
 	 */
 	ip = ialloc(dip, S_IFLNK | 0777);
 	if (ip == NULL) {
-		rc = ENOSPC;
+		rc = -ENOSPC;
 		goto out2;
 	}
 
@@ -955,7 +955,7 @@
 				if (mp == NULL) {
 					dtDelete(tid, dip, &dname, &ino,
 						 JFS_REMOVE);
-					rc = EIO;
+					rc = -EIO;
 					goto out3;
 				}
 				memcpy(mp->data, name, copy_size);
@@ -975,7 +975,7 @@
 			ip->i_blocks = LBLK2PBLK(sb, xlen);
 		} else {
 			dtDelete(tid, dip, &dname, &ino, JFS_REMOVE);
-			rc = ENOSPC;
+			rc = -ENOSPC;
 			goto out3;
 		}
 	}
@@ -1017,8 +1017,8 @@
 	free_UCSname(&dname);
 
       out1:
-	jfs_info("jfs_symlink: rc:%d", -rc);
-	return -rc;
+	jfs_info("jfs_symlink: rc:%d", rc);
+	return rc;
 }
 
 
@@ -1067,7 +1067,7 @@
 	 */
 	rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
 	if (rc || (ino != old_ip->i_ino)) {
-		rc = ENOENT;
+		rc = -ENOENT;
 		goto out3;
 	}
 
@@ -1077,26 +1077,26 @@
 	rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
 	if (rc == 0) {
 		if ((new_ip == 0) || (ino != new_ip->i_ino)) {
-			rc = ESTALE;
+			rc = -ESTALE;
 			goto out3;
 		}
-	} else if (rc != ENOENT)
+	} else if (rc != -ENOENT)
 		goto out3;
 	else if (new_ip) {
 		/* no entry exists, but one was expected */
-		rc = ESTALE;
+		rc = -ESTALE;
 		goto out3;
 	}
 
 	if (S_ISDIR(old_ip->i_mode)) {
 		if (new_ip) {
 			if (!dtEmpty(new_ip)) {
-				rc = ENOTEMPTY;
+				rc = -ENOTEMPTY;
 				goto out3;
 			}
 		} else if ((new_dir != old_dir) &&
 			   (new_dir->i_nlink == JFS_LINK_MAX)) {
-			rc = EMLINK;
+			rc = -EMLINK;
 			goto out3;
 		}
 	} else if (new_ip)
@@ -1134,7 +1134,7 @@
 			/* free block resources */
 			if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
 				txAbort(tid, 1);	/* Marks FS Dirty */
-				rc = -new_size;		/* We return -rc */
+				rc = new_size;		
 				goto out4;
 			}
 			tblk = tid_to_tblock(tid);
@@ -1251,7 +1251,7 @@
 		new_size = xtTruncate_pmap(tid, new_ip, new_size);
 		if (new_size < 0) {
 			txAbort(tid, 1);
-			rc = -new_size;		/* We return -rc */
+			rc = new_size;		
 		} else
 			rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
 		txEnd(tid);
@@ -1278,7 +1278,7 @@
 	}
 
 	jfs_info("jfs_rename: returning %d", rc);
-	return -rc;
+	return rc;
 }
 
 
@@ -1305,7 +1305,7 @@
 
 	ip = ialloc(dir, mode);
 	if (ip == NULL) {
-		rc = ENOSPC;
+		rc = -ENOSPC;
 		goto out1;
 	}
 
@@ -1354,7 +1354,7 @@
 
       out:
 	jfs_info("jfs_mknod: returning %d", rc);
-	return -rc;
+	return rc;
 }
 
 static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry)
@@ -1377,15 +1377,15 @@
 	else {
 		if ((rc =
 		     get_UCSname(&key, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
-			return ERR_PTR(-rc);
+			return ERR_PTR(rc);
 		rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
 		free_UCSname(&key);
-		if (rc == ENOENT) {
+		if (rc == -ENOENT) {
 			d_add(dentry, NULL);
 			return ERR_PTR(0);
 		} else if (rc) {
 			jfs_err("jfs_lookup: dtSearch returned %d", rc);
-			return ERR_PTR(-rc);
+			return ERR_PTR(rc);
 		}
 	}
 
diff -Nru a/fs/jfs/resize.c b/fs/jfs/resize.c
--- a/fs/jfs/resize.c	Thu May 29 08:40:22 2003
+++ b/fs/jfs/resize.c	Mon Aug 25 08:51:00 2003
@@ -184,7 +184,7 @@
 
 	/* file system cannot be shrinked */
 	if (newFSSize < bmp->db_mapsize) {
-		rc = EINVAL;
+		rc = -EINVAL;
 		goto out;
 	}
 
@@ -317,8 +317,8 @@
 	t64 = dbMapFileSizeToMapSize(ipbmap);
 	if (mapSize > t64) {
 		printk(KERN_ERR "jfs_extendfs: mapSize (0x%Lx) > t64 (0x%Lx)\n",
-		       (long long)mapSize, (long long)t64);
-		rc = EIO;
+		       (long long) mapSize, (long long) t64);
+		rc = -EIO;
 		goto error_out;
 	}
 	nblocks = min(t64 - mapSize, XSize);
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	Thu Jul 31 08:36:43 2003
+++ b/fs/jfs/super.c	Mon Aug 25 11:19:31 2003
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (c) International Business Machines Corp., 2000-2003
  *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -142,7 +142,8 @@
 	return 0;
 }
 
-static int parse_options(char *options, struct super_block *sb, s64 *newLVSize)
+static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
+			 int *flag)
 {
 	void *nls_map = NULL;
 	char *this_char;
@@ -158,7 +159,11 @@
 			continue;
 		if ((value = strchr(this_char, '=')) != NULL)
 			*value++ = 0;
-		if (!strcmp(this_char, "iocharset")) {
+		if (!strcmp(this_char, "integrity")) {
+			*flag &= ~JFS_NOINTEGRITY;
+		} else 	if (!strcmp(this_char, "nointegrity")) {
+			*flag |= JFS_NOINTEGRITY;
+		} else if (!strcmp(this_char, "iocharset")) {
 			if (!value || !*value)
 				goto needs_arg;
 			if (nls_map)	/* specified iocharset twice! */
@@ -208,8 +213,9 @@
 {
 	s64 newLVSize = 0;
 	int rc = 0;
+	int flag = JFS_SBI(sb)->flag;
 
-	if (!parse_options(data, sb, &newLVSize)) {
+	if (!parse_options(data, sb, &newLVSize, &flag)) {
 		return -EINVAL;
 	}
 	if (newLVSize) {
@@ -223,10 +229,24 @@
 			return rc;
 	}
 
-	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY))
+	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
+		JFS_SBI(sb)->flag = flag;
 		return jfs_mount_rw(sb, 1);
-	else if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY))
-		return jfs_umount_rw(sb);
+	}
+	if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) {
+		rc = jfs_umount_rw(sb);
+		JFS_SBI(sb)->flag = flag;
+		return rc;
+	}
+	if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY))
+		if (!(sb->s_flags & MS_RDONLY)) {
+			rc = jfs_umount_rw(sb);
+			if (rc)
+				return rc;
+			JFS_SBI(sb)->flag = flag;
+			return jfs_mount_rw(sb, 1);
+		}
+	JFS_SBI(sb)->flag = flag;
 
 	return 0;
 }
@@ -238,6 +258,7 @@
 	struct inode *inode;
 	int rc;
 	s64 newLVSize = 0;
+	int flag;
 
 	jfs_info("In jfs_read_super s_dev=0x%x s_flags=0x%lx", sb->s_dev,
 		 sb->s_flags);
@@ -248,10 +269,12 @@
 	memset(sbi, 0, sizeof (struct jfs_sb_info));
 	sb->u.generic_sbp = sbi;
 
-	if (!parse_options((char *) data, sb, &newLVSize)) {
+	flag = 0;
+	if (!parse_options((char *) data, sb, &newLVSize, &flag)) {
 		kfree(sbi);
 		return NULL;
 	}
+	sbi->flag = flag;
 
 	if (newLVSize) {
 		printk(KERN_ERR "resize option for remount only\n");
@@ -483,7 +506,7 @@
 	metapage_exit();
 free_slab:
 	kmem_cache_destroy(jfs_inode_cachep);
-	return -rc;
+	return rc;
 }
 
 static void __exit exit_jfs_fs(void)
diff -Nru a/fs/jfs/xattr.c b/fs/jfs/xattr.c
--- a/fs/jfs/xattr.c	Wed Oct 23 13:58:57 2002
+++ b/fs/jfs/xattr.c	Mon Aug 25 08:51:00 2003
@@ -182,7 +182,7 @@
 		 * used for an inline EA.
 		 */
 		if (!(ji->mode2 & INLINEEA) && !(ji->ea.flag & DXD_INLINE))
-			return -1;
+			return -EPERM;
 
 		DXDsize(ea, size);
 		DXDlength(ea, 0);
@@ -252,7 +252,7 @@
 
 	rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno);
 	if (rc)
-		return -rc;
+		return rc;
 
 	/*
 	 * Now have nblocks worth of storage to stuff into the FEALIST.
@@ -513,7 +513,7 @@
 		rc = dbAlloc(inode, INOHINT(inode), (s64) blocks_needed,
 			     &blkno);
 		if (rc)
-			return -rc;
+			return rc;
 
 		DXDlength(&ea_buf->new_ea, blocks_needed);
 		DXDaddress(&ea_buf->new_ea, blkno);
diff -Nru a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c	Tue Jul  8 12:31:53 2003
+++ b/fs/namespace.c	Tue Jun 17 17:48:47 2003
@@ -763,7 +763,7 @@
 		return -EPERM;
 	}
 
-	new_ns = kmalloc(sizeof(struct namespace *), GFP_KERNEL);
+	new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL);
 	if (!new_ns)
 		goto out;
 
diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c
--- a/fs/ntfs/dir.c	Mon Feb  4 23:54:05 2002
+++ b/fs/ntfs/dir.c	Mon Aug 25 03:54:54 2003
@@ -802,17 +802,17 @@
 	u8 ibs_bits;
 
 	if (!ino) {
-		ntfs_error(__FUNCTION__ "(): No inode! Returning -EINVAL.\n");
+		ntfs_error("%s(): No inode! Returning -EINVAL.\n",__FUNCTION__);
 		return -EINVAL;
 	}
 	vol = ino->vol;
 	if (!vol) {
-		ntfs_error(__FUNCTION__ "(): Inode 0x%lx has no volume. "
-				"Returning -EINVAL.\n", ino->i_number);
+		ntfs_error("%s(): Inode 0x%lx has no volume. Returning "
+			    "-EINVAL.\n", __FUNCTION__, ino->i_number);
 		return -EINVAL;
 	}
-	ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 1: Entering for "
-			"inode 0x%lx, p_high = 0x%x, p_low = 0x%x.\n",
+	ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 1: Entering for inode 0x%lx, "
+			"p_high = 0x%x, p_low = 0x%x.\n", __FUNCTION__,
 			ino->i_number, *p_high, *p_low);
 	if (!*p_high) {
 		/* We are still in the index root. */
@@ -827,8 +827,8 @@
 		ino->u.index.recordsize = ibs = NTFS_GETU32(buf + 0x8);
 		ino->u.index.clusters_per_record = NTFS_GETU32(buf + 0xC);
 		entry = buf + 0x20;
-		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 2: In index "
-				"root.\n");
+		ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 2: In index root.\n",
+				__FUNCTION__);
 		ibs_bits = ffs(ibs) - 1;
 		/* Compensate for faked "." and "..". */
 		start = 2;
@@ -850,15 +850,15 @@
 		if (err || io.size != ibs)
 			goto read_err_ret;
 		if (!ntfs_check_index_record(ino, buf)) {
-			ntfs_error(__FUNCTION__ "(): Index block 0x%x is not "
-					"an index record. Returning "
-					"-ENOTDIR.\n", *p_high - 1);
+			ntfs_error("%s(): Index block 0x%x is not an index "
+					"record. Returning -ENOTDIR.\n",
+					 __FUNCTION__, *p_high - 1);
 			ntfs_free(buf);
 			return -ENOTDIR;
 		}
 		entry = buf + 0x18 + NTFS_GETU16(buf + 0x18);
-		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 3: In index "
-				"allocation.\n");
+		ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 3: In index "
+				"allocation.\n", __FUNCTION__);
 		start = 0;
 	}
 	/* Process the entries. */
@@ -867,29 +867,30 @@
 			entry += NTFS_GETU16(entry + 8)) {
 		if (start < finish) {
 			/* Skip entries that were already processed. */
-			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 4: "
-					"Skipping already processed entry "
-					"p_high 0x%x, p_low 0x%x.\n", *p_high,
+			ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 4: Skipping "
+					"already processed entry p_high 0x%x, "
+					"p_low 0x%x.\n", __FUNCTION__, *p_high,
 					start);
 			start++;
 			continue;
 		}
-		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 5: "
-				"Processing entry p_high 0x%x, p_low 0x%x.\n",
+		ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 5: Processing entry "
+				"p_high 0x%x, p_low 0x%x.\n", __FUNCTION__,
 				*p_high, *p_low);
 		if ((err = cb(entry, param))) {
 			/* filldir signalled us to stop. */
-			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): "
-					"Unsorted 6: cb returned %i, "
-					"returning 0, p_high 0x%x, p_low 0x%x."
-					"\n", *p_high, *p_low);
+			ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 6: cb returned "
+					"%i, returning 0, p_high 0x%x, "
+					"p_low 0x%x.\n", __FUNCTION__, err,
+					*p_high, *p_low);
 			ntfs_free(buf);
 			return 0;
 		}
 		++*p_low;
 	}
-	ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 7: After processing "
-			"entries, p_high 0x%x, p_low 0x%x.\n", *p_high, *p_low);
+	ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 7: After processing entries, "
+			"p_high 0x%x, p_low 0x%x.\n", __FUNCTION__, *p_high,
+			*p_low);
 	/* We have to locate the next record. */
 	ntfs_free(buf);
 	buf = 0;
@@ -898,15 +899,15 @@
 	if (!attr) {
 		/* Directory does not have index bitmap and index allocation. */
 		*p_high = 0x7fff;
-		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 8: No index "
-				"allocation. Returning 0, p_high 0x7fff, "
-				"p_low 0x0.\n");
+		ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 8: No index allocation. "
+				"Returning 0, p_high 0x7fff, p_low 0x0.\n",
+				__FUNCTION__);
 		return 0;
 	}
 	max_size = attr->size;
 	if (max_size > 0x7fff >> 3) {
-		ntfs_error(__FUNCTION__ "(): Directory too large. Visible "
-				"length is truncated.\n");
+		ntfs_error("%s(): Directory too large. Visible "
+				"length is truncated.\n", __FUNCTION__);
 		max_size = 0x7fff >> 3;
 	}
 	buf = ntfs_malloc(max_size);
@@ -920,26 +921,26 @@
 	attr = ntfs_find_attr(ino, vol->at_index_allocation, I30);
 	if (!attr) {
 		ntfs_free(buf);
-		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 9: Find "
-				"attr failed. Returning -EIO.\n");
+		ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 9: Find attr failed. "
+				"Returning -EIO.\n", __FUNCTION__);
 		return -EIO;
 	}
 	if (attr->resident) {
 		ntfs_free(buf);
-		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 9.5: IA is "
-				"resident. Not allowed. Returning EINVAL.\n");
+		ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 9.5: IA is resident. Not"
+				" allowed. Returning EINVAL.\n", __FUNCTION__);
 		return -EINVAL;
 	}
 	/* Loop while going through non-allocated index records. */
 	max_size <<= 3;
 	while (1) {
 		if (++*p_high >= 0x7fff) {
-			ntfs_error(__FUNCTION__ "(): Unsorted 10: Directory "
+			ntfs_error("%s(): Unsorted 10: Directory "
 					"inode 0x%lx overflowed the maximum "
 					"number of index allocation buffers "
 					"the driver can cope with. Pretending "
 					"to be at end of directory.\n",
-					ino->i_number);
+					__FUNCTION__, ino->i_number);
 			goto fake_eod;
 		}
 		if (*p_high > max_size || (s64)*p_high << ibs_bits >
@@ -949,10 +950,9 @@
 			*p_high = 0x7fff;
 			*p_low = 0;
 			ntfs_free(buf);
-			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted "
-					"10.5: No more index records. "
-					"Returning 0, p_high 0x7fff, p_low "
-					"0.\n");
+			ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 10.5: No more "
+					"index records. Returning 0, p_high "
+					"0x7fff, p_low 0.\n", __FUNCTION__);
 			return 0;
 		}
 		byte = (ntfs_cluster_t)(*p_high - 1);
@@ -961,16 +961,15 @@
 		if ((buf[byte] & bit))
 			break;
 	};
-	ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 11: Done. "
-			"Returning 0, p_high 0x%x, p_low 0x%x.\n", *p_high,
-			*p_low);
+	ntfs_debug(DEBUG_DIR3, "%s(): Unsorted 11: Done. Returning 0, p_high "
+			"0x%x, p_low 0x%x.\n", __FUNCTION__, *p_high, *p_low);
 	ntfs_free(buf);
 	return 0;
 read_err_ret:
 	if (!err)
 		err = -EIO;
-	ntfs_error(__FUNCTION__ "(): Read failed. Returning error code %i.\n",
-			err);
+	ntfs_error("%s(): Read failed. Returning error code %i.\n",
+			__FUNCTION__, err);
 	ntfs_free(buf);
 	return err;
 }
diff -Nru a/fs/ntfs/fs.c b/fs/ntfs/fs.c
--- a/fs/ntfs/fs.c	Thu Feb 28 05:57:29 2002
+++ b/fs/ntfs/fs.c	Mon Aug 25 03:54:54 2003
@@ -114,9 +114,9 @@
 
 	if (!ntfs_ino)
 		return -EINVAL;
-	ntfs_debug(DEBUG_LINUX, __FUNCTION__ "(): Entering for inode 0x%lx, "
-			"*pos 0x%Lx, count 0x%x.\n", ntfs_ino->i_number, *pos,
-			count);
+	ntfs_debug(DEBUG_LINUX, "%s(): Entering for inode 0x%lx, *pos 0x%Lx, "
+			"count 0x%x.\n", __FUNCTION__, ntfs_ino->i_number,
+			*pos, count);
 	/* Allows to lock fs ro at any time. */
 	if (vfs_ino->i_sb->s_flags & MS_RDONLY)
 		return -EROFS;
@@ -140,7 +140,7 @@
 	io.size = count;
 	io.do_read = 0;
 	err = ntfs_readwrite_attr(ntfs_ino, data, *pos, &io);
-	ntfs_debug(DEBUG_LINUX, __FUNCTION__ "(): Returning %i\n", -err);
+	ntfs_debug(DEBUG_LINUX, "%s(): Returning %i\n", __FUNCTION__, -err);
 	if (!err) {
 		*pos += io.size;
 		if (*pos > vfs_ino->i_size)
@@ -196,20 +196,20 @@
 	err = ntfs_encodeuni(NTFS_INO2VOL(nf->dir), (ntfs_u16*)(entry + 0x52),
 			name_len, &nf->name, &nf->namelen);
 	if (err) {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping "
-				"unrepresentable file.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Skipping unrepresentable "
+				"file.\n", __FUNCTION__);
 		err = 0;
 		goto err_ret;
 	}
 	if (!show_sys_files && inum < 0x10UL) {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping system "
-				"file (%s).\n", nf->name);
+		ntfs_debug(DEBUG_OTHER, "%s(): Skipping system file (%s).\n",
+				__FUNCTION__, nf->name);
 		err = 0;
 		goto err_ret;
 	}
 	/* Do not return ".", as this is faked. */
 	if (nf->namelen == 1 && nf->name[0] == '.') {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping \".\"\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Skipping \".\"\n", __FUNCTION__);
 		err = 0;
 		goto err_ret;
 	}
@@ -218,8 +218,8 @@
 		file_type = DT_DIR;
 	else
 		file_type = DT_REG;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling filldir for %s with "
-			"len %i, f_pos 0x%Lx, inode %lu, %s.\n",
+	ntfs_debug(DEBUG_OTHER, "%s(): Calling filldir for %s with "
+			"len %i, f_pos 0x%Lx, inode %lu, %s.\n", __FUNCTION__,
 			nf->name, nf->namelen, (loff_t)(nf->ph << 16) | nf->pl,
 			inum, file_type == DT_DIR ? "DT_DIR" : "DT_REG");
 	/*
@@ -254,16 +254,16 @@
 	cb.pl = filp->f_pos & 0xffff;
 	cb.ph = (filp->f_pos >> 16) & 0x7fff;
 	filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Entering for inode %lu, "
-			"f_pos 0x%Lx, i_mode 0x%x, i_count %lu.\n", dir->i_ino,
-			filp->f_pos, (unsigned int)dir->i_mode,
+	ntfs_debug(DEBUG_OTHER, "%s(): Entering for inode %lu, f_pos 0x%Lx, "
+			"i_mode 0x%x, i_count %lu.\n", __FUNCTION__,
+			dir->i_ino, filp->f_pos, (unsigned int)dir->i_mode,
 			atomic_read(&dir->i_count));
 	if (!cb.ph) {
 		/* Start of directory. Emulate "." and "..". */
 		if (!cb.pl) {
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling "
-				    "filldir for . with len 1, f_pos 0x%Lx, "
-				    "inode %lu, DT_DIR.\n", filp->f_pos,
+			ntfs_debug(DEBUG_OTHER, "%s(): Calling filldir for . "
+				    "with len 1, f_pos 0x%Lx, inode %lu, "
+				    "DT_DIR.\n", __FUNCTION__, filp->f_pos,
 				    dir->i_ino);
 			cb.ret_code = filldir(dirent, ".", 1, filp->f_pos,
 				    dir->i_ino, DT_DIR);
@@ -273,9 +273,9 @@
 			filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
 		}
 		if (cb.pl == (u32)1) {
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling "
-				    "filldir for .. with len 2, f_pos 0x%Lx, "
-				    "inode %lu, DT_DIR.\n", filp->f_pos,
+			ntfs_debug(DEBUG_OTHER, "%s(): Calling filldir for .. "
+				    "with len 2, f_pos 0x%Lx, inode %lu, "
+				    "DT_DIR.\n", __FUNCTION__, filp->f_pos,
 				    filp->f_dentry->d_parent->d_inode->i_ino);
 			cb.ret_code = filldir(dirent, "..", 2, filp->f_pos,
 				    filp->f_dentry->d_parent->d_inode->i_ino,
@@ -293,30 +293,31 @@
 	cb.dirent = dirent;
 	cb.type = NTFS_INO2VOL(dir)->ngt;
 	do {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Looking for next "
-				"file using ntfs_getdir_unsorted(), f_pos "
-				"0x%Lx.\n", (loff_t)(cb.ph << 16) | cb.pl);
+		ntfs_debug(DEBUG_OTHER, "%s(): Looking for next file using "
+				"ntfs_getdir_unsorted(), f_pos 0x%Lx.\n",
+				__FUNCTION__, (loff_t)(cb.ph << 16) | cb.pl);
 		err = ntfs_getdir_unsorted(NTFS_LINO2NINO(dir), &cb.ph, &cb.pl,
 				ntfs_printcb, &cb);
 	} while (!err && !cb.ret_code && cb.ph < 0x7fff);
 	filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After ntfs_getdir_unsorted()"
-			" calls, f_pos 0x%Lx.\n", filp->f_pos);
+	ntfs_debug(DEBUG_OTHER, "%s(): After ntfs_getdir_unsorted()"
+			" calls, f_pos 0x%Lx.\n", __FUNCTION__, filp->f_pos);
 	if (!err) {
 done:
 #ifdef DEBUG
 		if (!cb.ret_code)
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): EOD, f_pos "
-					"0x%Lx, returning 0.\n", filp->f_pos);
+			ntfs_debug(DEBUG_OTHER, "%s(): EOD, f_pos 0x%Lx, "
+					"returning 0.\n", __FUNCTION__,
+					filp->f_pos);
 		else 
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): filldir "
-					"returned %i, returning 0, f_pos "
-					"0x%Lx.\n", cb.ret_code, filp->f_pos);
+			ntfs_debug(DEBUG_OTHER, "%s(): filldir returned %i, "
+					"returning 0, f_pos 0x%Lx.\n",
+					__FUNCTION__, cb.ret_code, filp->f_pos);
 #endif
 		return 0;
 	}
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning %i, f_pos 0x%Lx.\n",
-			err, filp->f_pos);
+	ntfs_debug(DEBUG_OTHER, "%s(): Returning %i, f_pos 0x%Lx.\n",
+			__FUNCTION__, err, filp->f_pos);
 	return err;
 }
 
@@ -524,8 +525,8 @@
 	ntfs_iterate_s walk;
 	int err;
 	
-	ntfs_debug(DEBUG_NAME1, __FUNCTION__ "(): Looking up %s in directory "
-			"ino 0x%x.\n", d->d_name.name, (unsigned)dir->i_ino);
+	ntfs_debug(DEBUG_NAME1, "%s(): Looking up %s in directory ino 0x%x.\n",
+			__FUNCTION__, d->d_name.name, (unsigned)dir->i_ino);
 	walk.name = NULL;
 	walk.namelen = 0;
 	/* Convert to wide string. */
@@ -847,7 +848,6 @@
 			goto unl_out;
 		}
 		break;
-	default:
 		/* Nothing. Just clear the inode and exit. */
 	}
 	ntfs_clear_inode(&inode->u.ntfs_i);
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c	Tue Feb  5 06:08:23 2002
+++ b/fs/ntfs/inode.c	Mon Aug 25 03:54:54 2003
@@ -671,8 +671,8 @@
 	ntfs_cluster_t cluster, s_cluster, vcn, len;
 	__s64 l, chunk, copied;
 
-	ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): %s 0x%x bytes at offset "
-			"0x%Lx %s inode 0x%x, attr type 0x%x.\n",
+	ntfs_debug(DEBUG_FILE3, "%s(): %s 0x%x bytes at offset "
+			"0x%Lx %s inode 0x%x, attr type 0x%x.\n", __FUNCTION__,
 			dest->do_read ? "Read" : "Write", dest->size, offset,
 			dest->do_read ? "from" : "to", ino->i_number,
 			attr->type);
@@ -746,10 +746,10 @@
 			vcn + attr->d.r.runlist[rnum].len <= s_vcn; rnum++)
 		vcn += attr->d.r.runlist[rnum].len;
 	if (rnum == attr->d.r.len) {
-		ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): EOPNOTSUPP: "
+		ntfs_debug(DEBUG_FILE3, "%s(): EOPNOTSUPP: "
 			"inode = 0x%x, rnum = %i, offset = 0x%Lx, vcn = 0x%x, "
-			"s_vcn = 0x%x.\n", ino->i_number, rnum, offset, vcn,
-			s_vcn);
+			"s_vcn = 0x%x.\n", __FUNCTION__, ino->i_number, rnum,
+			offset, vcn, s_vcn);
 		dump_runlist(attr->d.r.runlist, attr->d.r.len);
 		/*FIXME: Should extend runlist. */
 		return -EOPNOTSUPP;
@@ -793,8 +793,8 @@
 	buf->do_read = 1;
 	attr = ntfs_find_attr(ino, type, name);
 	if (!attr) {
-		ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): attr 0x%x not found "
-				"in inode 0x%x\n", type, ino->i_number);
+		ntfs_debug(DEBUG_FILE3, "%s(): attr 0x%x not found in inode "
+				"0x%x\n", __FUNCTION__, type, ino->i_number);
 		return -EINVAL;
 	}
 	return ntfs_readwrite_attr(ino, attr, offset, buf);
@@ -808,8 +808,8 @@
 	buf->do_read = 0;
 	attr = ntfs_find_attr(ino, type, name);
 	if (!attr) {
-		ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): attr 0x%x not found "
-				"in inode 0x%x\n", type, ino->i_number);
+		ntfs_debug(DEBUG_FILE3, "%s(): attr 0x%x not found in inode "
+				"0x%x\n", __FUNCTION__, type, ino->i_number);
 		return -EINVAL;
 	}
 	return ntfs_readwrite_attr(ino, attr, offset, buf);
@@ -1332,7 +1332,7 @@
 	int i;
 	ntfs_cluster_t ct;
 
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): rlen = %i.\n", rlen);
+	ntfs_debug(DEBUG_OTHER, "%s(): rlen = %i.\n", __FUNCTION__, rlen);
 	ntfs_debug(DEBUG_OTHER, "VCN        LCN        Run length\n");
 	for (i = 0, ct = 0; i < rlen; ct += rl[i++].len) {
 		if (rl[i].lcn == (ntfs_cluster_t)-1)
@@ -1372,30 +1372,31 @@
 	ntfs_runlist *rl;
 	int rlen, rl_size, rl2_pos;
 
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Entering with *r1len = %i, "
-			"r2len = %i.\n", *r1len, r2len);
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Dumping 1st runlist.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): Entering with *r1len = %i, "
+			"r2len = %i.\n", __FUNCTION__, *r1len, r2len);
+	ntfs_debug(DEBUG_OTHER, "%s(): Dumping 1st runlist.\n", __FUNCTION__);
 	if (*rl1)
 		dump_runlist(*rl1, *r1len);
 	else
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Not present.\n");
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Dumping 2nd runlist.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Not present.\n", __FUNCTION__);
+	ntfs_debug(DEBUG_OTHER, "%s(): Dumping 2nd runlist.\n", __FUNCTION__);
 	dump_runlist(rl2, r2len);
 	rlen = *r1len + r2len + 1;
 	rl_size = (rlen * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
 			PAGE_MASK;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): rlen = %i, rl_size = %i.\n",
-			rlen, rl_size);
+	ntfs_debug(DEBUG_OTHER, "%s(): rlen = %i, rl_size = %i.\n",
+			__FUNCTION__, rlen, rl_size);
 	/* Do we have enough space? */
 	if (rl_size <= ((*r1len * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
 			PAGE_MASK)) {
 		/* Have enough space already. */
 		rl = *rl1;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Have enough space "
-				"already.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Have enough space already.\n",
+				__FUNCTION__);
 	} else {
 		/* Need more space. Reallocate. */
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Need more space.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Need more space.\n",
+				__FUNCTION__);
 		rl = ntfs_vmalloc(rlen << sizeof(ntfs_runlist));
 		if (!rl)
 			return -ENOMEM;
@@ -1406,17 +1407,17 @@
 	}
 	/* Reuse rl_size as the current position index into rl. */
 	rl_size = *r1len - 1;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): rl_size = %i.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): rl_size = %i.\n", __FUNCTION__,rl_size);
 	/* Coalesce neighbouring elements, if present. */
 	rl2_pos = 0;
 	if (rl[rl_size].lcn + rl[rl_size].len == rl2[rl2_pos].lcn) {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Coalescing adjacent "
-				"runs.\n");
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: "
-				"rl[rl_size].len = %i.\n", rl[rl_size].len);
+		ntfs_debug(DEBUG_OTHER, "%s(): Coalescing adjacent runs.\n",
+				__FUNCTION__);
+		ntfs_debug(DEBUG_OTHER, "%s(): Before: rl[rl_size].len = %i.\n",
+				__FUNCTION__, rl[rl_size].len);
 		rl[rl_size].len += rl2[rl2_pos].len;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: "
-				"rl[rl_size].len = %i.\n", rl[rl_size].len);
+		ntfs_debug(DEBUG_OTHER, "%s(): After: rl[rl_size].len = %i.\n",
+				__FUNCTION__, rl[rl_size].len);
 		rl2_pos++;
 		r2len--;
 		rlen--;
@@ -1428,10 +1429,11 @@
 	rl[rlen].lcn = (ntfs_cluster_t)-1;
 	rl[rlen].len = (ntfs_cluster_t)0;
 	*r1len = rlen;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Dumping result runlist.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): Dumping result runlist.\n",
+			__FUNCTION__);
 	dump_runlist(*rl1, *r1len);
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning with *r1len = "
-			"%i.\n", rlen);
+	ntfs_debug(DEBUG_OTHER, "%s(): Returning with *r1len = %i.\n",
+			__FUNCTION__, rlen);
 	return 0;
 }
 
@@ -1546,7 +1548,7 @@
 	/* Determine the number of allocated mft records in the mft. */
 	pass_end = nr_mft_records = data->allocated >>
 			vol->mft_record_size_bits;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): nr_mft_records = %lu.\n",
+	ntfs_debug(DEBUG_OTHER, "%s(): nr_mft_records = %lu.\n", __FUNCTION__,
 			nr_mft_records);
 	/* Make sure we don't overflow the bitmap. */
 	l = bmp->initialized << 3;
@@ -1565,9 +1567,10 @@
 	lcn = rl[rlen].lcn + rl[rlen].len;
 	io.fn_put = ntfs_put;
 	io.fn_get = ntfs_get;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Starting bitmap search.\n");
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): pass = %i, pass_start = %lu, "
-			"pass_end = %lu.\n", pass, pass_start, pass_end);
+	ntfs_debug(DEBUG_OTHER, "%s(): Starting bitmap search.\n",
+			__FUNCTION__);
+	ntfs_debug(DEBUG_OTHER, "%s(): pass = %i, pass_start = %lu, pass_end = "
+			"%lu.\n", __FUNCTION__, pass, pass_start, pass_end);
 	byte = NULL; // FIXME: For debugging only.
 	/* Loop until a free mft record is found. */
 	io.size = (nr_mft_records >> 3) & ~PAGE_MASK;
@@ -1575,29 +1578,29 @@
 		io.param = buf;
 		io.do_read = 1;
 		last_read_pos = buf_pos >> 3;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: "
-				"bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
-				"bmp->initialized = 0x%Lx.\n", bmp->allocated,
+		ntfs_debug(DEBUG_OTHER, "%s(): Before: bmp->allocated = 0x%Lx, "
+				"bmp->size = 0x%Lx, bmp->initialized = "
+				"0x%Lx.\n", __FUNCTION__, bmp->allocated,
 				bmp->size, bmp->initialized);
 		err = ntfs_readwrite_attr(vol->mft_ino, bmp, last_read_pos,
 				&io);
 		if (err)
 			goto err_ret;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Read %lu bytes.\n",
+		ntfs_debug(DEBUG_OTHER, "%s(): Read %lu bytes.\n", __FUNCTION__,
 				(unsigned long)io.size);
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: "
-				"bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
-				"bmp->initialized = 0x%Lx.\n", bmp->allocated,
+		ntfs_debug(DEBUG_OTHER, "%s(): After: bmp->allocated = 0x%Lx, "
+				"bmp->size = 0x%Lx, bmp->initialized = "
+				"0x%Lx.\n", __FUNCTION__, bmp->allocated,
 				bmp->size, bmp->initialized);
 		if (!io.size)
 			goto pass_done;
 		buf_size = io.size << 3;
 		bit = buf_pos & 7UL;
 		buf_pos &= ~7UL;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before loop: "
-				"buf_size = %lu, buf_pos = %lu, bit = %lu, "
-				"*byte = 0x%x, b = %u.\n",
-				buf_size, buf_pos, bit, byte ? *byte : -1, b);
+		ntfs_debug(DEBUG_OTHER, "%s(): Before loop: buf_size = %lu, "
+				"buf_pos = %lu, bit = %lu, *byte = 0x%x, b = "
+				"%u.\n", __FUNCTION__, buf_size, buf_pos, bit,
+				byte ? *byte : -1, b);
 		for (; bit < buf_size && bit + buf_pos < pass_end;
 				bit &= ~7UL, bit += 8UL) {
 			byte = buf + (bit >> 3);
@@ -1606,34 +1609,35 @@
 			b = ffz((unsigned long)*byte);
 			if (b < (__u8)8 && b >= (bit & 7UL)) {
 				bit = b + (bit & ~7UL) + buf_pos;
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Found free rec in for loop. "
-						"bit = %lu\n", bit);
+				ntfs_debug(DEBUG_OTHER, "%s(): Found free rec "
+						"in for loop. bit = %lu\n",
+						__FUNCTION__, bit);
 				goto found_free_rec;
 			}
 		}
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After loop: "
-				"buf_size = %lu, buf_pos = %lu, bit = %lu, "
-				"*byte = 0x%x, b = %u.\n",
-				buf_size, buf_pos, bit, byte ? *byte : -1, b);
+		ntfs_debug(DEBUG_OTHER, "%s(): After loop: buf_size = %lu, "
+				"buf_pos = %lu, bit = %lu, *byte = 0x%x, b = "
+				"%u.\n", __FUNCTION__, buf_size, buf_pos, bit,
+				byte ? *byte : -1, b);
 		buf_pos += buf_size;
 		if (buf_pos < pass_end)
 			continue;
 pass_done:	/* Finished with the current pass. */
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At pass_done.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): At pass_done.\n", __FUNCTION__);
 		if (pass == 1) {
 			/*
 			 * Now do pass 2, scanning the first part of the zone
 			 * we omitted in pass 1.
 			 */
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Done pass "
-					"1.\n");
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Pass = 2.\n");
+			ntfs_debug(DEBUG_OTHER, "%s(): Done pass 1.\n",
+					__FUNCTION__);
+			ntfs_debug(DEBUG_OTHER, "%s(): Pass = 2.\n",
+					__FUNCTION__);
 			pass = 2;
 			pass_end = pass_start;
 			buf_pos = pass_start = 24UL;
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): pass = %i, "
-					"pass_start = %lu, pass_end = %lu.\n",
+			ntfs_debug(DEBUG_OTHER, "%s(): pass = %i, pass_start = "
+					"%lu, pass_end = %lu.\n", __FUNCTION__,
 					pass, pass_start, pass_end);
 			continue;
 		} /* pass == 2 */
@@ -1649,21 +1653,21 @@
 			bit = nr_mft_records;
 			if (bit < 24UL)
 				bit = 24UL;
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Found free "
-					"record bit (#1) = 0x%lx.\n", bit);
+			ntfs_debug(DEBUG_OTHER, "%s(): Found free record bit "
+					"(#1) = 0x%lx.\n", __FUNCTION__, bit);
 			goto found_free_rec;
 		}
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Done pass 2.\n");
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: "
-				"bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
-				"bmp->initialized = 0x%Lx.\n", bmp->allocated,
+		ntfs_debug(DEBUG_OTHER, "%s(): Done pass 2.\n", __FUNCTION__);
+		ntfs_debug(DEBUG_OTHER, "%s(): Before: bmp->allocated = 0x%Lx, "
+				"bmp->size = 0x%Lx, bmp->initialized = "
+				"0x%Lx.\n", __FUNCTION__, bmp->allocated,
 				bmp->size, bmp->initialized);
 		/* Need to extend the mft bitmap. */
 		if (bmp->initialized + 8LL > bmp->allocated) {
 			ntfs_io io2;
 
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Initialized "
-					"> allocated.\n");
+			ntfs_debug(DEBUG_OTHER, "%s(): Initialized "
+					"> allocated.\n", __FUNCTION__);
 			/* Need to extend bitmap by one more cluster. */
 			rl = bmp->d.r.runlist;
 			rlen = bmp->d.r.len - 1;
@@ -1677,8 +1681,8 @@
 					&io2);
 			if (err)
 				goto err_ret;
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Read %lu "
-					"bytes.\n", (unsigned long)io2.size);
+			ntfs_debug(DEBUG_OTHER, "%s(): Read %lu bytes.\n",
+					__FUNCTION__, (unsigned long)io2.size);
 			if (io2.size == 1 && b != 0xff) {
 				__u8 tb = 1 << (lcn & (ntfs_cluster_t)7);
 				if (!(b & tb)) {
@@ -1695,9 +1699,10 @@
 					}
 append_mftbmp_simple:			rl[rlen].len++;
 					have_allocated_mftbmp |= 1;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Appending one "
-							"cluster to mftbmp.\n");
+					ntfs_debug(DEBUG_OTHER, "%s(): "
+							"Appending one cluster "
+							"to mftbmp.\n",
+							__FUNCTION__);
 				}
 			}
 			if (!have_allocated_mftbmp) {
@@ -1713,11 +1718,12 @@
 					if (count > 0) {
 rl2_dealloc_err_out:				if (ntfs_deallocate_clusters(
 							vol, rl2, r2len))
-							ntfs_error(__FUNCTION__
-							"(): Cluster "
+							ntfs_error("%s(): "
+							"Cluster "
 							"deallocation in error "
 							"code path failed! You "
-							"should run chkdsk.\n");
+							"should run chkdsk.\n",
+							__FUNCTION__);
 					}
 					ntfs_vfree(rl2);
 					if (!err)
@@ -1752,10 +1758,9 @@
 				rl[rlen].len = count;
 				bmp->d.r.len = ++rlen;
 				have_allocated_mftbmp |= 2;
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Adding run to mftbmp. "
-						"LCN = %i, len = %i\n", lcn,
-						count);
+				ntfs_debug(DEBUG_OTHER, "%s(): Adding run to "
+						"mftbmp. LCN = %i, len = %i\n",
+						__FUNCTION__, lcn, count);
 			}
 			/*
 			 * We now have extended the mft bitmap allocated size
@@ -1763,24 +1768,24 @@
 			 */
 			bmp->allocated += (__s64)vol->cluster_size;
 		}
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: "
-				"bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
-				"bmp->initialized = 0x%Lx.\n", bmp->allocated,
+		ntfs_debug(DEBUG_OTHER, "%s(): After: bmp->allocated = 0x%Lx, "
+				"bmp->size = 0x%Lx, bmp->initialized = "
+				"0x%Lx.\n", __FUNCTION__, bmp->allocated,
 				bmp->size, bmp->initialized);
 		/* We now have sufficient allocated space. */
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Now have sufficient "
-				"allocated space in mftbmp.\n");
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before: "
-				"bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
-				"bmp->initialized = 0x%Lx.\n", bmp->allocated,
+		ntfs_debug(DEBUG_OTHER, "%s(): Now have sufficient allocated "
+				"space in mftbmp.\n", __FUNCTION__);
+		ntfs_debug(DEBUG_OTHER, "%s(): Before: bmp->allocated = 0x%Lx, "
+				"bmp->size = 0x%Lx, bmp->initialized = "
+				"0x%Lx.\n", __FUNCTION__, bmp->allocated,
 				bmp->size, bmp->initialized);
 		buf_pos = bmp->initialized;
 		bmp->initialized += 8LL;
 		if (bmp->initialized > bmp->size)
 			bmp->size = bmp->initialized;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After: "
-				"bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
-				"bmp->initialized = 0x%Lx.\n", bmp->allocated,
+		ntfs_debug(DEBUG_OTHER, "%s(): After: bmp->allocated = 0x%Lx, "
+				"bmp->size = 0x%Lx, bmp->initialized = "
+				"0x%Lx.\n", __FUNCTION__, bmp->allocated,
 				bmp->size, bmp->initialized);
 		have_allocated_mftbmp |= 4;
 		/* Update the mft bitmap attribute value. */
@@ -1794,27 +1799,27 @@
 				err = -EIO;
 			goto shrink_mftbmp_err_ret;
 		}
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote extended "
-				"mftbmp bytes %lu.\n", (unsigned long)io.size);
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After write: "
-				"bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
-				"bmp->initialized = 0x%Lx.\n", bmp->allocated,
+		ntfs_debug(DEBUG_OTHER, "%s(): Wrote extended mftbmp bytes "
+				"%lu.\n", __FUNCTION__, (unsigned long)io.size);
+		ntfs_debug(DEBUG_OTHER, "%s(): After write: bmp->allocated = "
+				"0x%Lx, bmp->size = 0x%Lx, bmp->initialized = "
+				"0x%Lx.\n", __FUNCTION__, bmp->allocated,
 				bmp->size, bmp->initialized);
 		bit = buf_pos << 3;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Found free record "
-				"bit (#2) = 0x%lx.\n", bit);
+		ntfs_debug(DEBUG_OTHER, "%s(): Found free record bit (#2) = "
+				"0x%lx.\n", __FUNCTION__, bit);
 		goto found_free_rec;
 	}
 found_free_rec:
 	/* bit is the found free mft record. Allocate it in the mft bitmap. */
 	vol->mft_data_pos = bit;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At found_free_rec.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At found_free_rec.\n", __FUNCTION__);
 	io.param = buf;
 	io.size = 1;
 	io.do_read = 1;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before update: "
-			"bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
-			"bmp->initialized = 0x%Lx.\n", bmp->allocated,
+	ntfs_debug(DEBUG_OTHER, "%s(): Before update: bmp->allocated = 0x%Lx, "
+			"bmp->size = 0x%Lx, bmp->initialized = 0x%Lx.\n",
+			__FUNCTION__, bmp->allocated,
 			bmp->size, bmp->initialized);
 	err = ntfs_readwrite_attr(vol->mft_ino, bmp, bit >> 3, &io);
 	if (err || io.size != 1) {
@@ -1822,7 +1827,7 @@
 			err = -EIO;
 		goto shrink_mftbmp_err_ret;
 	}
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Read %lu bytes.\n",
+	ntfs_debug(DEBUG_OTHER, "%s(): Read %lu bytes.\n", __FUNCTION__,
 			(unsigned long)io.size);
 #ifdef DEBUG
 	/* Check our bit is really zero! */
@@ -1838,22 +1843,22 @@
 			err = -EIO;
 		goto shrink_mftbmp_err_ret;
 	}
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote %lu bytes.\n",
+	ntfs_debug(DEBUG_OTHER, "%s(): Wrote %lu bytes.\n", __FUNCTION__,
 			(unsigned long)io.size);
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After update: "
-			"bmp->allocated = 0x%Lx, bmp->size = 0x%Lx, "
-			"bmp->initialized = 0x%Lx.\n", bmp->allocated,
+	ntfs_debug(DEBUG_OTHER, "%s(): After update: bmp->allocated = 0x%Lx, "
+			"bmp->size = 0x%Lx, bmp->initialized = 0x%Lx.\n",
+			__FUNCTION__, bmp->allocated,
 			bmp->size, bmp->initialized);
 	/* The mft bitmap is now uptodate. Deal with mft data attribute now. */
 	ll = (__s64)(bit + 1) << vol->mft_record_size_bits;
 	if (ll <= data->initialized) {
 		/* The allocated record is already initialized. We are done! */
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated mft record "
-				"already initialized!\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Allocated mft record "
+				"already initialized!\n", __FUNCTION__);
 		goto done_ret;
 	}
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated mft record needs "
-			"to be initialized.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): Allocated mft record needs "
+			"to be initialized.\n", __FUNCTION__);
 	/* The mft record is outside the initialized data. */
 	mft_rec_size = (unsigned long)vol->mft_record_size;
 	/* Preserve old values for undo purposes. */
@@ -1868,32 +1873,31 @@
 	while (ll > data->allocated) {
 		ntfs_cluster_t lcn2, nr_lcn2, nr, min_nr;
 
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Extending mft "
-				"data allocation, data->allocated = 0x%Lx, "
-				"data->size = 0x%Lx, data->initialized = "
-				"0x%Lx.\n", data->allocated, data->size,
-				data->initialized);
+		ntfs_debug(DEBUG_OTHER, "%s(): Extending mft data allocation, "
+				"data->allocated = 0x%Lx, data->size = 0x%Lx, "
+				"data->initialized = 0x%Lx.\n", __FUNCTION__,
+				data->allocated, data->size, data->initialized);
 		/* Minimum allocation is one mft record worth of clusters. */
 		if (mft_rec_size <= vol->cluster_size)
 			min_nr = (ntfs_cluster_t)1;
 		else
 			min_nr = mft_rec_size >> vol->cluster_size_bits;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): min_nr = %i.\n",
+		ntfs_debug(DEBUG_OTHER, "%s(): min_nr = %i.\n", __FUNCTION__,
 				min_nr);
 		/* Allocate 16 mft records worth of clusters. */
 		nr = mft_rec_size << 4 >> vol->cluster_size_bits;
 		if (!nr)
 			nr = (ntfs_cluster_t)1;
 		/* Determine the preferred allocation location. */
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): nr = %i.\n", nr);
+		ntfs_debug(DEBUG_OTHER, "%s(): nr = %i.\n", __FUNCTION__, nr);
 		rl2 = data->d.r.runlist;
 		r2len = data->d.r.len;
 		lcn2 = rl2[r2len - 1].lcn + rl2[r2len - 1].len;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): rl2[r2len - 1].lcn "
-				"= %i, .len = %i.\n", rl2[r2len - 1].lcn,
+		ntfs_debug(DEBUG_OTHER, "%s(): rl2[r2len - 1].lcn = %i, .len = "
+				"%i.\n", __FUNCTION__, rl2[r2len - 1].lcn,
 				rl2[r2len - 1].len);
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): lcn2 = %i, r2len = "
-				"%i.\n", lcn2, r2len);
+		ntfs_debug(DEBUG_OTHER, "%s(): lcn2 = %i, r2len = %i.\n",
+				__FUNCTION__, lcn2, r2len);
 retry_mft_data_allocation:
 		nr_lcn2 = nr;
 		err = ntfs_allocate_clusters(vol, &lcn2, &nr_lcn2, &rl2,
@@ -1913,36 +1917,34 @@
 			if (err == -ENOSPC && nr > min_nr &&
 					nr_lcn2 >= min_nr) {
 				nr = min_nr;
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Retrying mft data "
-						"allocation, nr = min_nr = %i"
-						".\n", nr);
+				ntfs_debug(DEBUG_OTHER, "%s(): Retrying mft "
+						"data allocation, nr = min_nr "
+						"= %i.\n", __FUNCTION__, nr);
 				goto retry_mft_data_allocation;
 			}
 			goto undo_mftbmp_alloc_err_ret;
 		}
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated %i "
-				"clusters starting at LCN %i.\n", nr_lcn2,
-				lcn2);
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Allocated "
-				"runlist:\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Allocated %i clusters starting "
+				"at LCN %i.\n", __FUNCTION__, nr_lcn2, lcn2);
+		ntfs_debug(DEBUG_OTHER, "%s(): Allocated runlist:\n",
+				__FUNCTION__);
 		dump_runlist(rl2, r2len);
 		/* Append rl2 to the mft data attribute's run list. */
 		err = splice_runlists(&data->d.r.runlist, (int*)&data->d.r.len,
 				rl2, r2len);
 		if (err) {
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-					"splice_runlists failed with error "
-					"code %i.\n", -err);
+			ntfs_debug(DEBUG_OTHER, "%s(): splice_runlists failed "
+					"with error code %i.\n", __FUNCTION__,
+					-err);
 			goto undo_partial_data_alloc_err_ret;
 		}
 		/* Reflect the allocated clusters in the mft allocated data. */
 		data->allocated += nr_lcn2 << vol->cluster_size_bits;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After extending mft "
-				"data allocation, data->allocated = 0x%Lx, "
+		ntfs_debug(DEBUG_OTHER, "%s(): After extending mft data "
+				"allocation, data->allocated = 0x%Lx, "
 				"data->size = 0x%Lx, data->initialized = "
-				"0x%Lx.\n", data->allocated, data->size,
-				data->initialized);
+				"0x%Lx.\n", __FUNCTION__, data->allocated,
+				data->size, data->initialized);
 	}
 	/* Prepare a formatted (empty) mft record. */
 	memset(buf, 0, mft_rec_size);
@@ -1959,8 +1961,8 @@
 	old_data_initialized = data->initialized;
 	old_data_size = data->size;
 	while (ll > data->initialized) {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Initializing mft "
-				"record 0x%Lx.\n",
+		ntfs_debug(DEBUG_OTHER, "%s(): Initializing mft record "
+				"0x%Lx.\n", __FUNCTION__, 
 				data->initialized >> vol->mft_record_size_bits);
 		io.param = buf;
 		io.size = mft_rec_size;
@@ -1972,15 +1974,15 @@
 				err = -EIO;
 			goto undo_data_init_err_ret;
 		}
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote %i bytes to "
-				"mft data.\n", io.size);
+		ntfs_debug(DEBUG_OTHER, "%s(): Wrote %i bytes to mft data.\n",
+				__FUNCTION__, io.size);
 	}
 	/* Update the VFS inode size as well. */
 	VFS_I(vol->mft_ino)->i_size = data->size;
 #ifdef DEBUG
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After mft record "
+	ntfs_debug(DEBUG_OTHER, "%s(): After mft record "
 			"initialization: data->allocated = 0x%Lx, data->size "
-			"= 0x%Lx, data->initialized = 0x%Lx.\n",
+			"= 0x%Lx, data->initialized = 0x%Lx.\n", __FUNCTION__,
 			data->allocated, data->size, data->initialized);
 	/* Sanity checks. */
 	if (data->size > data->allocated || data->size < data->initialized ||
@@ -1989,45 +1991,47 @@
 #endif
 done_ret:
 	/* Return the number of the allocated mft record. */
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At done_ret. *result = bit = "
-			"0x%lx.\n", bit);
+	ntfs_debug(DEBUG_OTHER, "%s(): At done_ret. *result = bit = 0x%lx.\n",
+			__FUNCTION__, bit);
 	*result = bit;
 	vol->mft_data_pos = bit + 1;
 err_ret:
 	unlock_kernel();
 	free_page((unsigned long)buf);
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Syncing inode $MFT.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): Syncing inode $MFT.\n", __FUNCTION__);
 	if (ntfs_update_inode(vol->mft_ino))
-		ntfs_error(__FUNCTION__ "(): Failed to sync inode $MFT. "
-				"Continuing anyway.\n");
+		ntfs_error("%s(): Failed to sync inode $MFT. "
+				"Continuing anyway.\n",__FUNCTION__);
 	if (!err) {
-		ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): Done. Allocated mft "
-				"record number *result = 0x%lx.\n", *result);
+		ntfs_debug(DEBUG_FILE3, "%s(): Done. Allocated mft record "
+				"number *result = 0x%lx.\n", __FUNCTION__,
+				*result);
 		return 0;
 	}
 	if (err != -ENOSPC)
-		ntfs_error(__FUNCTION__ "(): Failed to allocate an mft "
-				"record. Returning error code %i.\n", -err);
+		ntfs_error("%s(): Failed to allocate an mft record. Returning "
+				"error code %i.\n", __FUNCTION__, -err);
 	else
-		ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): Failed to allocate "
-				"an mft record due to lack of free space.\n");
+		ntfs_debug(DEBUG_FILE3, "%s(): Failed to allocate an mft "
+				"record due to lack of free space.\n",
+				__FUNCTION__);
 	return err;
 undo_data_init_err_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At "
-			"undo_data_init_err_ret.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At undo_data_init_err_ret.\n",
+			__FUNCTION__);
 	data->initialized = old_data_initialized;
 	data->size = old_data_size;
 undo_data_alloc_err_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At undo_data_alloc_err_ret."
-			"\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At undo_data_alloc_err_ret.\n",
+			__FUNCTION__);
 	data->allocated = old_data_allocated;
 undo_partial_data_alloc_err_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At "
-			"undo_partial_data_alloc_err_ret.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At undo_partial_data_alloc_err_ret.\n",
+			__FUNCTION__);
 	/* Deallocate the clusters. */
 	if (ntfs_deallocate_clusters(vol, rl2, r2len))
-		ntfs_error(__FUNCTION__ "(): Error deallocating clusters in "
-				"error code path. You should run chkdsk.\n");
+		ntfs_error("%s(): Error deallocating clusters in error code "
+			"path. You should run chkdsk.\n", __FUNCTION__);
 	ntfs_vfree(rl2);
 	/* Revert the run list back to what it was before. */
 	r2len = data->d.r.len;
@@ -2047,13 +2051,13 @@
 			ntfs_vfree(data->d.r.runlist);
 			data->d.r.runlist = rl2;
 		} else
-			ntfs_error(__FUNCTION__ "(): Error reallocating "
+			ntfs_error("%s(): Error reallocating "
 					"memory in error code path. This "
-					"should be harmless.\n");
+					"should be harmless.\n", __FUNCTION__);
 	}	
 undo_mftbmp_alloc_err_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At "
-			"undo_mftbmp_alloc_err_ret.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At undo_mftbmp_alloc_err_ret.\n",
+			__FUNCTION__);
 	/* Deallocate the allocated bit in the mft bitmap. */
 	io.param = buf;
 	io.size = 1;
@@ -2068,13 +2072,14 @@
 	if (err || io.size != 1) {
 		if (!err)
 			err = -EIO;
-		ntfs_error(__FUNCTION__ "(): Error deallocating mft record in "
-				"error code path. You should run chkdsk.\n");
+		ntfs_error("%s(): Error deallocating mft record in error code "
+			"path. You should run chkdsk.\n", __FUNCTION__);
 	}
 shrink_mftbmp_err_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At shrink_mftbmp_err_ret.\n");
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): have_allocated_mftbmp = "
-			"%i.\n", have_allocated_mftbmp);
+	ntfs_debug(DEBUG_OTHER, "%s(): At shrink_mftbmp_err_ret.\n",
+			__FUNCTION__);
+	ntfs_debug(DEBUG_OTHER, "%s(): have_allocated_mftbmp = %i.\n",
+			__FUNCTION__, have_allocated_mftbmp);
 	if (!have_allocated_mftbmp)
 		goto err_ret;
 	/* Shrink the mftbmp back to previous size. */
@@ -2083,15 +2088,15 @@
 	bmp->initialized -= 8LL;
 	have_allocated_mftbmp &= ~4;
 	/* If no allocation occured then we are done. */
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): have_allocated_mftbmp = "
-			"%i.\n", have_allocated_mftbmp);
+	ntfs_debug(DEBUG_OTHER, "%s(): have_allocated_mftbmp = %i.\n",
+			__FUNCTION__, have_allocated_mftbmp);
 	if (!have_allocated_mftbmp)
 		goto err_ret;
 	/* Deallocate the allocated cluster. */
 	bmp->allocated -= (__s64)vol->cluster_size;
 	if (ntfs_deallocate_cluster_run(vol, lcn, (ntfs_cluster_t)1))
-		ntfs_error(__FUNCTION__ "(): Error deallocating cluster in "
-				"error code path. You should run chkdsk.\n");
+		ntfs_error("%s(): Error deallocating cluster in error code "
+			"path. You should run chkdsk.\n", __FUNCTION__);
 	switch (have_allocated_mftbmp & 3) {
 	case 1:
 		/* Delete the last lcn from the last run of mftbmp. */
@@ -2111,10 +2116,10 @@
 				ntfs_vfree(rl);
 				bmp->d.r.runlist = rl = rlt;
 			} else
-				ntfs_error(__FUNCTION__ "(): Error "
+				ntfs_error("%s(): Error "
 						"reallocating memory in error "
 						"code path. This should be "
-						"harmless.\n");
+						"harmless.\n", __FUNCTION__);
 		}
 		bmp->d.r.runlist[bmp->d.r.len].lcn = (ntfs_cluster_t)-1;
 		bmp->d.r.runlist[bmp->d.r.len].len = (ntfs_cluster_t)0;
@@ -2256,7 +2261,7 @@
 	err = ntfs_alloc_mft_record(vol, &(result->i_number));
 	if (err) {
 		if (err == -ENOSPC)
-			ntfs_error(__FUNCTION__ "(): No free inodes.\n");
+			ntfs_error("%s(): No free inodes.\n", __FUNCTION__);
 		return err;
 	}
 	/* Get the sequence number. */
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c	Mon Feb  4 23:44:57 2002
+++ b/fs/ntfs/super.c	Mon Aug 25 03:54:54 2003
@@ -639,13 +639,13 @@
 	int rlpos = 0, rlsize, buf_size, err = 0;
 	ntfs_io io;
 
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Entering with *location = "
-			"0x%x, *count = 0x%x, zone = %s_ZONE.\n", *location,
-			*count, zone == DATA_ZONE ? "DATA" : "MFT");
+	ntfs_debug(DEBUG_OTHER, "%s(): Entering with *location = 0x%x, "
+			"*count = 0x%x, zone = %s_ZONE.\n", __FUNCTION__,
+			*location, *count, zone == DATA_ZONE ? "DATA" : "MFT");
 	buf = (char*)__get_free_page(GFP_NOFS);
 	if (!buf) {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning "
-				"-ENOMEM.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Returning -ENOMEM.\n",
+				__FUNCTION__);
 		return -ENOMEM;
 	}
 	io.fn_put = ntfs_put;
@@ -721,101 +721,101 @@
 	clusters = *count;
 	rlpos = rlsize = 0;
 	if (*count <= 0) {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): *count <= 0, "
-				"returning -EINVAL.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): *count <= 0, "
+				"returning -EINVAL.\n", __FUNCTION__);
 		err = -EINVAL;
 		goto err_ret;
 	}
 	while (1) {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Start of outer while "
+		ntfs_debug(DEBUG_OTHER, "%s(): Start of outer while "
 				"loop: done_zones = 0x%x, search_zone = %i, "
 				"pass = %i, zone_start = 0x%x, zone_end = "
 				"0x%x, initial_location = 0x%x, buf_pos = "
 				"0x%x, rlpos = %i, rlsize = %i.\n",
-				done_zones, search_zone, pass, zone_start,
-				zone_end, initial_location, buf_pos, rlpos,
-				rlsize);
+				__FUNCTION__, done_zones, search_zone, pass,
+				zone_start, zone_end, initial_location, buf_pos,
+				rlpos, rlsize);
 		/* Loop until we run out of free clusters. */
 		io.param = buf;
 		io.size = PAGE_SIZE;
 		io.do_read = 1;
 		last_read_pos = buf_pos >> 3;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): last_read_pos = "
-				"0x%x.\n", last_read_pos);
+		ntfs_debug(DEBUG_OTHER, "%s(): last_read_pos = 0x%x.\n",
+				__FUNCTION__, last_read_pos);
 		err = ntfs_readwrite_attr(vol->bitmap, data, last_read_pos,
 				&io);
 		if (err) {
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-					"ntfs_read_attr failed with error "
-					"code %i, going to err_ret.\n", -err);
+			ntfs_debug(DEBUG_OTHER, "%s(): ntfs_read_attr failed "
+					"with error code %i, going to "
+					"err_ret.\n", __FUNCTION__, -err);
 			goto err_ret;
 		}
 		if (!io.size) {
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): !io.size, "
-					"going to zone_pass_done.\n");
+			ntfs_debug(DEBUG_OTHER, "%s(): !io.size, going to "
+					"zone_pass_done.\n", __FUNCTION__);
 			goto zone_pass_done;
 		}
 		buf_size = io.size << 3;
 		lcn = buf_pos & 7;
 		buf_pos &= ~7;
 		need_writeback = 0;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Before inner while "
+		ntfs_debug(DEBUG_OTHER, "%s(): Before inner while "
 				"loop: buf_size = 0x%x, lcn = 0x%x, buf_pos = "
-				"0x%x, need_writeback = %i.\n", buf_size, lcn,
-				buf_pos, need_writeback);
+				"0x%x, need_writeback = %i.\n", __FUNCTION__,
+				buf_size, lcn, buf_pos, need_writeback);
 		while (lcn < buf_size && lcn + buf_pos < zone_end) {
 			byte = buf + (lcn >> 3);
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): In inner "
-					"while loop: buf_size = 0x%x, lcn = "
-					"0x%x, buf_pos = 0x%x, need_writeback "
-					"= %i, byte ofs = 0x%x, *byte = "
-					"0x%x.\n", buf_size, lcn, buf_pos,
-					need_writeback, lcn >> 3, *byte);
+			ntfs_debug(DEBUG_OTHER, "%s(): In inner while loop: "
+					"buf_size = 0x%x, lcn = 0x%x, buf_pos "
+					"= 0x%x, need_writeback = %i, byte ofs "
+					"= 0x%x, *byte = 0x%x.\n", __FUNCTION__,
+					buf_size, lcn, buf_pos,	need_writeback,
+					lcn >> 3, *byte);
 			/* Skip full bytes. */
 			if (*byte == 0xff) {
 				lcn += 8;
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"continuing while loop 1.\n");
+				ntfs_debug(DEBUG_OTHER, "%s(): continuing while"
+					    " loop 1.\n", __FUNCTION__);
 				continue;
 			}
 			bit = 1 << (lcn & 7);
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): bit = %i.\n",
-					bit);
+			ntfs_debug(DEBUG_OTHER, "%s(): bit = %i.\n",
+					__FUNCTION__, bit);
 			/* If the bit is already set, go onto the next one. */
 			if (*byte & bit) {
 				lcn++;
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"continuing while loop 2.\n");
+				ntfs_debug(DEBUG_OTHER, "%s(): continuing while"
+					    " loop 2.\n", __FUNCTION__);
 				continue;
 			}
 			/* Allocate the bitmap bit. */
 			*byte |= bit;
 			/* We need to write this bitmap buffer back to disk! */
 			need_writeback = 1;
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): *byte = "
-					"0x%x, need_writeback = %i.\n", *byte,
-					need_writeback);
+			ntfs_debug(DEBUG_OTHER, "%s(): *byte = 0x%x, "
+					"need_writeback = %i.\n", __FUNCTION__,
+					*byte, need_writeback);
 			/* Reallocate memory if necessary. */
 			if ((rlpos + 2) * sizeof(ntfs_runlist) >= rlsize) {
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Reallocating space.\n");
+				ntfs_debug(DEBUG_OTHER, "%s(): Reallocating "
+						"space.\n", __FUNCTION__);
 				/* Setup first free bit return value. */
 				if (!rl2) {
 					*location = lcn + buf_pos;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): *location = "
-							"0x%x.\n", *location);
+					ntfs_debug(DEBUG_OTHER,	"%s(): "
+							"*location = 0x%x.\n",
+							__FUNCTION__,
+							*location);
 				}
 				rlsize += PAGE_SIZE;
 				rlt = ntfs_vmalloc(rlsize);
 				if (!rlt) {
 					err = -ENOMEM;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Failed to "
-							"allocate memory, "
+					ntfs_debug(DEBUG_OTHER, "%s(): Failed "
+							"to allocate memory, "
 							"returning -ENOMEM, "
-							"going to "
-							"wb_err_ret.\n");
+							"going to wb_err_ret.\n",
+							__FUNCTION__);
 					goto wb_err_ret;
 				}
 				if (rl2) {
@@ -824,45 +824,46 @@
 					ntfs_vfree(rl2);
 				}
 				rl2 = rlt;
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Reallocated memory, rlsize = "
-						"0x%x.\n", rlsize);
+				ntfs_debug(DEBUG_OTHER, "%s(): Reallocated "
+						"memory, rlsize = 0x%x.\n",
+						__FUNCTION__, rlsize);
 			}
 			/*
 			 * Coalesce with previous run if adjacent LCNs.
 			 * Otherwise, append a new run.
 			 */
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Adding run "
-					"(lcn 0x%x, len 0x%x), prev_lcn = "
-					"0x%x, lcn = 0x%x, buf_pos = 0x%x, "
-					"prev_run_len = 0x%x, rlpos = %i.\n",
+			ntfs_debug(DEBUG_OTHER, "%s(): Adding run (lcn 0x%x, "
+					"len 0x%x), prev_lcn = 0x%x, lcn = "
+					"0x%x, buf_pos = 0x%x, prev_run_len = "
+					"0x%x, rlpos = %i.\n", __FUNCTION__,
 					lcn + buf_pos, 1, prev_lcn, lcn,
 					buf_pos, prev_run_len, rlpos);
 			if (prev_lcn == lcn + buf_pos - prev_run_len && rlpos) {
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Coalescing to run (lcn 0x%x, "
-						"len 0x%x).\n",
+				ntfs_debug(DEBUG_OTHER, "%s(): Coalescing to "
+						"run (lcn 0x%x, len 0x%x).\n",
+						__FUNCTION__,
 						rl2[rlpos - 1].lcn,
 						rl2[rlpos - 1].len);
 				rl2[rlpos - 1].len = ++prev_run_len;
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Run now (lcn 0x%x, len 0x%x), "
-						"prev_run_len = 0x%x.\n",
+				ntfs_debug(DEBUG_OTHER, "%s(): Run now (lcn "
+						"0x%x, len 0x%x), prev_run_len "
+						"= 0x%x.\n", __FUNCTION__,
 						rl2[rlpos - 1].lcn,
 						rl2[rlpos - 1].len,
 						prev_run_len);
 			} else {
 				if (rlpos)
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Adding new run, "
-							"(previous run lcn "
-							"0x%x, len 0x%x).\n",
+					ntfs_debug(DEBUG_OTHER, "%s(): Adding "
+							"new run, (previous "
+							"run lcn 0x%x, "
+							"len 0x%x).\n",
+							__FUNCTION__,
 							rl2[rlpos - 1].lcn,
 							rl2[rlpos - 1].len);
 				else
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Adding new run, "
-							"is first run.\n");
+					ntfs_debug(DEBUG_OTHER, "%s(): Adding "
+							"new run, is first "
+							"run.\n", __FUNCTION__);
 				rl2[rlpos].lcn = prev_lcn = lcn + buf_pos;
 				rl2[rlpos].len = prev_run_len =
 						(ntfs_cluster_t)1;
@@ -878,17 +879,16 @@
 				 * during the respective zone switches.
 				 */
 				tc = lcn + buf_pos + 1;
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Done. Updating current zone "
-						"position, tc = 0x%x, "
-						"search_zone = %i.\n", tc,
-						search_zone);
+				ntfs_debug(DEBUG_OTHER, "%s(): Done. Updating "
+						"current zone position, tc = "
+						"0x%x, search_zone = %i.\n",
+						__FUNCTION__, tc, search_zone);
 				switch (search_zone) {
 				case 1:
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Before checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): Before checks, "
 							"vol->mft_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->mft_zone_pos);
 					if (tc >= vol->mft_zone_end) {
 						vol->mft_zone_pos =
@@ -901,17 +901,17 @@
 							tc > vol->mft_zone_pos)
 							&& tc >= vol->mft_lcn)
 						vol->mft_zone_pos = tc;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): After checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): After checks, "
 							"vol->mft_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->mft_zone_pos);
 					break;
 				case 2:
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Before checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): Before checks, "
 							"vol->data1_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->data1_zone_pos);
 					if (tc >= vol->nr_clusters)
 						vol->data1_zone_pos =
@@ -921,17 +921,17 @@
 						    tc > vol->data1_zone_pos)
 						    && tc >= vol->mft_zone_end)
 						vol->data1_zone_pos = tc;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): After checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): After checks, "
 							"vol->data1_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->data1_zone_pos);
 					break;
 				case 4:
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Before checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): Before checks, "
 							"vol->data2_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->data2_zone_pos);
 					if (tc >= vol->mft_zone_start)
 						vol->data2_zone_pos =
@@ -940,52 +940,52 @@
 						      vol->data2_zone_pos ||
 						      tc > vol->data2_zone_pos)
 						vol->data2_zone_pos = tc;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): After checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): After checks, "
 							"vol->data2_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->data2_zone_pos);
 					break;
 				default:
 					BUG();
 				}
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Going to done_ret.\n");
+				ntfs_debug(DEBUG_OTHER, "%s(): Going to "
+						"done_ret.\n", __FUNCTION__);
 				goto done_ret;
 			}
 			lcn++;
 		}
 		buf_pos += buf_size;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After inner while "
+		ntfs_debug(DEBUG_OTHER, "%s(): After inner while "
 				"loop: buf_size = 0x%x, lcn = 0x%x, buf_pos = "
-				"0x%x, need_writeback = %i.\n", buf_size, lcn,
-				buf_pos, need_writeback);
+				"0x%x, need_writeback = %i.\n", __FUNCTION__,
+				buf_size, lcn, buf_pos, need_writeback);
 		if (need_writeback) {
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Writing "
-					"back.\n");
+			ntfs_debug(DEBUG_OTHER, "%s(): Writing back.\n",
+					__FUNCTION__);
 			need_writeback = 0;
 			io.param = buf;
 			io.do_read = 0;
 			err = ntfs_readwrite_attr(vol->bitmap, data,
 					last_read_pos, &io);
 			if (err) {
-				ntfs_error(__FUNCTION__ "(): Bitmap writeback "
-						"failed in read next buffer "
-						"code path with error code "
-						"%i.\n", -err);
+				ntfs_error("%s(): Bitmap writeback failed "
+						"in read next buffer code "
+						"path with error code %i.\n",
+						__FUNCTION__, -err);
 				goto err_ret;
 			}
 		}
 		if (buf_pos < zone_end) {
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Continuing "
+			ntfs_debug(DEBUG_OTHER, "%s(): Continuing "
 					"outer while loop, buf_pos = 0x%x, "
-					"zone_end = 0x%x.\n", buf_pos,
-					zone_end);
+					"zone_end = 0x%x.\n", __FUNCTION__,
+					buf_pos, zone_end);
 			continue;
 		}
 zone_pass_done:	/* Finished with the current zone pass. */
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At zone_pass_done, "
-				"pass = %i.\n", pass);
+		ntfs_debug(DEBUG_OTHER, "%s(): At zone_pass_done, pass = %i.\n",
+				__FUNCTION__, pass);
 		if (pass == 1) {
 			/*
 			 * Now do pass 2, scanning the first part of the zone
@@ -1010,36 +1010,37 @@
 			if (zone_end < zone_start)
 				zone_end = zone_start;
 			buf_pos = zone_start;
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Continuing "
+			ntfs_debug(DEBUG_OTHER, "%s(): Continuing "
 					"outer while loop, pass = 2, "
 					"zone_start = 0x%x, zone_end = 0x%x, "
-					"buf_pos = 0x%x.\n");
+					"buf_pos = 0x%x.\n", __FUNCTION__,
+					zone_start, zone_end, buf_pos);
 			continue;
 		} /* pass == 2 */
 done_zones_check:
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At done_zones_check, "
+		ntfs_debug(DEBUG_OTHER, "%s(): At done_zones_check, "
 				"search_zone = %i, done_zones before = 0x%x, "
-				"done_zones after = 0x%x.\n",
+				"done_zones after = 0x%x.\n", __FUNCTION__,
 				search_zone, done_zones, done_zones |
 				search_zone);
 		done_zones |= search_zone;
 		if (done_zones < 7) {
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Switching "
-					"zone.\n");
+			ntfs_debug(DEBUG_OTHER, "%s(): Switching zone.\n",
+					__FUNCTION__);
 			/* Now switch to the next zone we haven't done yet. */
 			pass = 1;
 			switch (search_zone) {
 			case 1:
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Switching from mft zone to "
-						"data1 zone.\n");
+				ntfs_debug(DEBUG_OTHER, "%s(): Switching from "
+						"mft zone to data1 zone.\n",
+						__FUNCTION__);
 				/* Update mft zone position. */
 				if (rlpos) {
 					ntfs_cluster_t tc;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Before checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): Before checks, "
 							"vol->mft_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->mft_zone_pos);
 					tc = rl2[rlpos - 1].lcn +
 							rl2[rlpos - 1].len;
@@ -1054,10 +1055,10 @@
 							tc > vol->mft_zone_pos)
 							&& tc >= vol->mft_lcn)
 						vol->mft_zone_pos = tc;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): After checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): After checks, "
 							"vol->mft_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->mft_zone_pos);
 				}
 				/* Switch from mft zone to data1 zone. */
@@ -1074,16 +1075,16 @@
 				}
 				break;
 			case 2:
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Switching from data1 zone to "
-						"data2 zone.\n");
+				ntfs_debug(DEBUG_OTHER, "%s(): Switching from "
+						"data1 zone to data2 zone.\n",
+						__FUNCTION__);
 				/* Update data1 zone position. */
 				if (rlpos) {
 					ntfs_cluster_t tc;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Before checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): Before checks, "
 							"vol->data1_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->data1_zone_pos);
 					tc = rl2[rlpos - 1].lcn +
 							rl2[rlpos - 1].len;
@@ -1095,10 +1096,10 @@
 						    tc > vol->data1_zone_pos)
 						    && tc >= vol->mft_zone_end)
 						vol->data1_zone_pos = tc;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): After checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): After checks, "
 							"vol->data1_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->data1_zone_pos);
 				}
 				/* Switch from data1 zone to data2 zone. */
@@ -1116,16 +1117,16 @@
 				}
 				break;
 			case 4:
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Switching from data2 zone to "
-						"data1 zone.\n");
+				ntfs_debug(DEBUG_OTHER, "%s(): Switching from "
+						"data2 zone to data1 zone.\n",
+						__FUNCTION__);
 				/* Update data2 zone position. */
 				if (rlpos) {
 					ntfs_cluster_t tc;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): Before checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): Before checks, "
 							"vol->data2_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->data2_zone_pos);
 					tc = rl2[rlpos - 1].lcn +
 							rl2[rlpos - 1].len;
@@ -1136,10 +1137,10 @@
 						      vol->data2_zone_pos ||
 						      tc > vol->data2_zone_pos)
 						vol->data2_zone_pos = tc;
-					ntfs_debug(DEBUG_OTHER, __FUNCTION__
-							"(): After checks, "
+					ntfs_debug(DEBUG_OTHER,
+							"%s(): After checks, "
 							"vol->data2_zone_pos = "
-							"0x%x.\n",
+							"0x%x.\n", __FUNCTION__,
 							vol->data2_zone_pos);
 				}
 				/* Switch from data2 zone to data1 zone. */
@@ -1147,45 +1148,45 @@
 			default:
 				BUG();
 			}
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After zone "
-					"switch, search_zone = %i, pass = %i, "
+			ntfs_debug(DEBUG_OTHER, "%s(): After zone switch, "
+					"search_zone = %i, pass = %i, "
 					"initial_location = 0x%x, zone_start "
 					"= 0x%x, zone_end = 0x%x.\n",
-					search_zone, pass, initial_location,
-					zone_start, zone_end);
+					__FUNCTION__, search_zone, pass,
+					initial_location, zone_start, zone_end);
 			buf_pos = zone_start;
 			if (zone_start == zone_end) {
-				ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): "
-						"Empty zone, going to "
-						"done_zones_check.\n");
+				ntfs_debug(DEBUG_OTHER, "%s(): Empty zone, "
+						"going to done_zones_check.\n",
+						__FUNCTION__);
 				/* Empty zone. Don't bother searching it. */
 				goto done_zones_check;
 			}
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Continuing "
-					"outer while loop.\n");
+			ntfs_debug(DEBUG_OTHER, "%s(): Continuing outer while "
+					"loop.\n", __FUNCTION__);
 			continue;
 		} /* done_zones == 7 */
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): All zones are "
-				"finished.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): All zones are finished.\n",
+				__FUNCTION__);
 		/*
 		 * All zones are finished! If DATA_ZONE, shrink mft zone. If
 		 * MFT_ZONE, we have really run out of space.
 		 */
 		mft_zone_size = vol->mft_zone_end - vol->mft_zone_start;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): vol->mft_zone_start "
-				"= 0x%x, vol->mft_zone_end = 0x%x, "
-				"mft_zone_size = 0x%x.\n", vol->mft_zone_start,
+		ntfs_debug(DEBUG_OTHER, "%s(): vol->mft_zone_start = 0x%x, "
+				"vol->mft_zone_end = 0x%x, mft_zone_size = "
+				"0x%x.\n", __FUNCTION__, vol->mft_zone_start,
 				vol->mft_zone_end, mft_zone_size);
 		if (zone == MFT_ZONE || mft_zone_size <= (ntfs_cluster_t)0) {
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): No free "
-					"clusters left, returning -ENOSPC, "
-					"going to fail_ret.\n");
+			ntfs_debug(DEBUG_OTHER, "%s(): No free clusters left, "
+					"returning -ENOSPC, going to "
+					"fail_ret.\n", __FUNCTION__);
 			/* Really no more space left on device. */
 			err = -ENOSPC;
 			goto fail_ret;
 		} /* zone == DATA_ZONE && mft_zone_size > 0 */
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Shrinking mft "
-				"zone.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Shrinking mft zone.\n",
+				__FUNCTION__);
 		zone_end = vol->mft_zone_end;
 		mft_zone_size >>= 1;
 		if (mft_zone_size > (ntfs_cluster_t)0)
@@ -1203,71 +1204,72 @@
 		search_zone = 2;
 		pass = 2;
 		done_zones &= ~2;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After shrinking mft "
+		ntfs_debug(DEBUG_OTHER, "%s(): After shrinking mft "
 				"zone, mft_zone_size = 0x%x, "
 				"vol->mft_zone_start = 0x%x, vol->mft_zone_end "
 				"= 0x%x, vol->mft_zone_pos = 0x%x, search_zone "
 				"= 2, pass = 2, dones_zones = 0x%x, zone_start "
 				"= 0x%x, zone_end = 0x%x, vol->data1_zone_pos "
 				"= 0x%x, continuing outer while loop.\n",
-				mft_zone_size, vol->mft_zone_start,
-				vol->mft_zone_end, vol->mft_zone_pos,
-				search_zone, pass, done_zones, zone_start,
+				__FUNCTION__, mft_zone_size,
+				vol->mft_zone_start, vol->mft_zone_end,
+				vol->mft_zone_pos, done_zones, zone_start,
 				zone_end, vol->data1_zone_pos);
 	}
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After outer while loop.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): After outer while loop.\n",
+			__FUNCTION__);
 done_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At done_ret.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At done_ret.\n", __FUNCTION__);
 	rl2[rlpos].lcn = (ntfs_cluster_t)-1;
 	rl2[rlpos].len = (ntfs_cluster_t)0;
 	*rl = rl2;
 	*rl_len = rlpos;
 	if (need_writeback) {
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Writing back.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Writing back.\n", __FUNCTION__);
 		need_writeback = 0;
 		io.param = buf;
 		io.do_read = 0;
 		err = ntfs_readwrite_attr(vol->bitmap, data, last_read_pos,
 				&io);
 		if (err) {
-			ntfs_error(__FUNCTION__ "(): Bitmap writeback failed "
-					"in done code path with error code "
-					"%i.\n", -err);
+			ntfs_error("%s(): Bitmap writeback failed in done "
+					"code path with error code %i.\n",
+					__FUNCTION__, -err);
 			goto err_ret;
 		}
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Wrote 0x%Lx bytes.\n",
-				io.size);
+		ntfs_debug(DEBUG_OTHER, "%s(): Wrote 0x%Lx bytes.\n",
+				__FUNCTION__, io.size);
 	}
 done_fail_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At done_fail_ret (follows "
-			"done_ret).\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At done_fail_ret (follows done_ret).\n",
+			 __FUNCTION__);
 	unlock_kernel();
 	free_page((unsigned long)buf);
 	if (err)
-		ntfs_debug(DEBUG_FILE3, __FUNCTION__ "(): Failed to allocate "
+		ntfs_debug(DEBUG_FILE3, "%s(): Failed to allocate "
 				"clusters. Returning with error code %i.\n",
-				-err);
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Syncing $Bitmap inode.\n");
+				__FUNCTION__, -err);
+	ntfs_debug(DEBUG_OTHER, "%s(): Syncing $Bitmap inode.\n", __FUNCTION__);
 	if (ntfs_update_inode(vol->bitmap))
-		ntfs_error(__FUNCTION__ "(): Failed to sync inode $Bitmap. "
-				"Continuing anyway.\n");
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning with code %i.\n",
+		ntfs_error("%s(): Failed to sync inode $Bitmap. "
+				"Continuing anyway.\n", __FUNCTION__);
+	ntfs_debug(DEBUG_OTHER, "%s(): Returning with code %i.\n", __FUNCTION__,
 			err);
 	return err;
 fail_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At fail_ret.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At fail_ret.\n", __FUNCTION__);
 	if (rl2) {
 		if (err == -ENOSPC) {
 			/* Return first free lcn and count of free clusters. */
 			*location = rl2[0].lcn;
 			*count -= clusters;
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): err = "
-					"-ENOSPC, *location = 0x%x, *count = "
-					"0x%x.\n", *location, *count);
+			ntfs_debug(DEBUG_OTHER, "%s(): err = -ENOSPC, "
+					"*location = 0x%x, *count = 0x%x.\n",
+					__FUNCTION__, *location, *count);
 		}
 		/* Deallocate all allocated clusters. */
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Deallocating "
-				"allocated clusters.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Deallocating allocated "
+				"clusters.\n", __FUNCTION__);
 		ntfs_deallocate_clusters(vol, rl2, rlpos);
 		/* Free the runlist. */
 		ntfs_vfree(rl2);
@@ -1276,34 +1278,35 @@
 			/* Nothing free at all. */
 			*location = vol->data1_zone_pos; /* Irrelevant... */
 			*count = 0;
-			ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): No space "
-					"left at all, err = -ENOSPC, *location "
-					"= 0x%x, *count = 0.\n", *location);
+			ntfs_debug(DEBUG_OTHER, "%s(): No space left at all, "
+					"err = -ENOSPC, *location = 0x%x, "
+					"*count = 0.\n",
+					__FUNCTION__, *location);
 		}
 	}
 	*rl = NULL;
 	*rl_len = 0;
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): *rl = NULL, *rl_len = 0, "
-			"going to done_fail_ret.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): *rl = NULL, *rl_len = 0, "
+			"going to done_fail_ret.\n", __FUNCTION__);
 	goto done_fail_ret;
 wb_err_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At wb_err_ret.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At wb_err_ret.\n", __FUNCTION__);
 	if (need_writeback) {
 		int __err;
-		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Writing back.\n");
+		ntfs_debug(DEBUG_OTHER, "%s(): Writing back.\n", __FUNCTION__);
 		io.param = buf;
 		io.do_read = 0;
 		__err = ntfs_readwrite_attr(vol->bitmap, data, last_read_pos,
 				&io);
 		if (__err)
-			ntfs_error(__FUNCTION__ "(): Bitmap writeback failed "
-					"in error code path with error code "
-					"%i.\n", -__err);
+			ntfs_error("%s(): Bitmap writeback failed in error "
+					"code path with error code %i.\n",
+					__FUNCTION__, -__err);
 		need_writeback = 0;
 	}
 err_ret:
-	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): At err_ret, *location = -1, "
-			"*count = 0, going to fail_ret.\n");
+	ntfs_debug(DEBUG_OTHER, "%s(): At err_ret, *location = -1, "
+			"*count = 0, going to fail_ret.\n", __FUNCTION__);
 	*location = -1;
 	*count = 0;
 	goto fail_ret;
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Mon Jul 14 13:10:30 2003
+++ b/fs/proc/proc_misc.c	Sat Aug 30 05:02:26 2003
@@ -58,7 +58,9 @@
 extern int get_device_list(char *);
 extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
+#ifndef CONFIG_X86
 extern int get_irq_list(char *);
+#endif
 extern int get_dma_list(char *);
 extern int get_locks_status (char *, char **, off_t, int);
 extern int get_swaparea_info (char *);
@@ -389,6 +391,7 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
+#ifndef CONFIG_X86
 #if !defined(CONFIG_ARCH_S390)
 static int interrupts_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -398,6 +401,35 @@
 }
 #endif
 
+#else /* !CONFIG_X86 */
+
+extern int show_interrupts(struct seq_file *p, void *v);
+static int interrupts_open(struct inode *inode, struct file *file)
+{
+	unsigned size = PAGE_SIZE * (1 + smp_num_cpus / 8);
+	char *buf = kmalloc(size, GFP_KERNEL);
+	struct seq_file *m;
+	int res;
+
+	if (!buf)
+		return -ENOMEM;
+	res = single_open(file, show_interrupts, NULL);
+	if (!res) {
+		m = file->private_data;
+		m->buf = buf;
+		m->size = size;
+	} else
+		kfree(buf);
+	return res;
+}
+static struct file_operations proc_interrupts_operations = {
+	.open		= interrupts_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+#endif /* !CONFIG_X86 */
+
 static int filesystems_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
@@ -588,7 +620,7 @@
 #endif
 		{"stat",	kstat_read_proc},
 		{"devices",	devices_read_proc},
-#if !defined(CONFIG_ARCH_S390)
+#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86)
 		{"interrupts",	interrupts_read_proc},
 #endif
 		{"filesystems",	filesystems_read_proc},
@@ -614,6 +646,9 @@
 	if (entry)
 		entry->proc_fops = &proc_kmsg_operations;
 	create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
+#if defined(CONFIG_X86)
+	create_seq_entry("interrupts", 0, &proc_interrupts_operations);
+#endif
 	create_seq_entry("partitions", 0, &proc_partitions_operations);
 	create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
 #ifdef CONFIG_MODULES
diff -Nru a/fs/seq_file.c b/fs/seq_file.c
--- a/fs/seq_file.c	Tue Feb  4 07:02:42 2003
+++ b/fs/seq_file.c	Mon Aug 25 09:34:39 2003
@@ -1,7 +1,7 @@
 /*
  * linux/fs/seq_file.c
  *
- * helper functions for making syntetic files from sequences of records.
+ * helper functions for making synthetic files from sequences of records.
  * initial implementation -- AV, Oct 2001.
  */
 
@@ -10,6 +10,7 @@
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
+#include <asm/page.h>
 
 /**
  *	seq_open -	initialize sequential file
@@ -214,7 +215,7 @@
 				while ((retval=traverse(m, offset)) == -EAGAIN)
 					;
 				if (retval) {
-					/* with extreme perjudice... */
+					/* with extreme prejudice... */
 					file->f_pos = 0;
 					m->index = 0;
 					m->count = 0;
@@ -249,7 +250,7 @@
  *	@s:	string
  *	@esc:	set of characters that need escaping
  *
- *	Puts string into buffer, replacing each occurence of character from
+ *	Puts string into buffer, replacing each occurrence of character from
  *	@esc with usual octal escape.  Returns 0 in case of success, -1 - in
  *	case of overflow.
  */
@@ -295,3 +296,86 @@
 	m->count = m->size;
 	return -1;
 }
+
+int seq_path(struct seq_file *m,
+		struct vfsmount *mnt, struct dentry *dentry,
+		char *esc)
+{
+	if (m->count < m->size) {
+		char *s = m->buf + m->count;
+		char *p = d_path(dentry, mnt, s, m->size - m->count);
+		if (!IS_ERR(p)) {
+			while (s <= p) {
+				char c = *p++;
+				if (!c) {
+					p = m->buf + m->count;
+					m->count = s - m->buf;
+					return s - p;
+				} else if (!strchr(esc, c)) {
+					*s++ = c;
+				} else if (s + 4 > p) {
+					break;
+				} else {
+					*s++ = '\\';
+					*s++ = '0' + ((c & 0300) >> 6);
+					*s++ = '0' + ((c & 070) >> 3);
+					*s++ = '0' + (c & 07);
+				}
+			}
+		}
+	}
+	m->count = m->size;
+	return -1;
+}
+
+static void *single_start(struct seq_file *p, loff_t *pos)
+{
+	return NULL + (*pos == 0);
+}
+
+static void *single_next(struct seq_file *p, void *v, loff_t *pos)
+{
+	++*pos;
+	return NULL;
+}
+
+static void single_stop(struct seq_file *p, void *v)
+{
+}
+
+int single_open(struct file *file, int (*show)(struct seq_file *, void*), void *data)
+{
+	struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
+	int res = -ENOMEM;
+
+	if (op) {
+		op->start = single_start;
+		op->next = single_next;
+		op->stop = single_stop;
+		op->show = show;
+		res = seq_open(file, op);
+		if (!res)
+			((struct seq_file *)file->private_data)->private = data;
+		else
+			kfree(op);
+	}
+	return res;
+}
+
+int single_release(struct inode *inode, struct file *file)
+{
+	struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
+	int res = seq_release(inode, file);
+	kfree(op);
+	return res;
+}
+
+int seq_release_private(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+
+	kfree(seq->private);
+	seq->private = NULL;
+	return seq_release(inode, file);
+}
+
diff -Nru a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
--- a/include/asm-i386/cpufeature.h	Sun Jul  6 10:21:50 2003
+++ b/include/asm-i386/cpufeature.h	Thu Aug  7 19:37:21 2003
@@ -10,9 +10,9 @@
 /* Sample usage: CPU_FEATURE_P(cpu.x86_capability, FPU) */
 #define CPU_FEATURE_P(CAP, FEATURE) test_bit(CAP, X86_FEATURE_##FEATURE ##_BIT)
 
-#define NCAPINTS	4	/* Currently we have 4 32-bit words worth of info */
+#define NCAPINTS	6	/* Currently we have 6 32-bit words worth of info */
 
-/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
+/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
 #define X86_FEATURE_FPU		(0*32+ 0) /* Onboard FPU */
 #define X86_FEATURE_VME		(0*32+ 1) /* Virtual Mode Extensions */
 #define X86_FEATURE_DE		(0*32+ 2) /* Debugging Extensions */
@@ -47,6 +47,7 @@
 /* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
 /* Don't duplicate feature flags which are redundant with Intel! */
 #define X86_FEATURE_SYSCALL	(1*32+11) /* SYSCALL/SYSRET */
+#define X86_FEATURE_MP		(1*32+19) /* MP Capable. */
 #define X86_FEATURE_MMXEXT	(1*32+22) /* AMD MMX extensions */
 #define X86_FEATURE_LM		(1*32+29) /* Long Mode (x86-64) */
 #define X86_FEATURE_3DNOWEXT	(1*32+30) /* AMD 3DNow! extensions */
@@ -63,10 +64,19 @@
 #define X86_FEATURE_K6_MTRR	(3*32+ 1) /* AMD K6 nonstandard MTRRs */
 #define X86_FEATURE_CYRIX_ARR	(3*32+ 2) /* Cyrix ARRs (= MTRRs) */
 #define X86_FEATURE_CENTAUR_MCR	(3*32+ 3) /* Centaur MCRs (= MTRRs) */
+/* cpu types for specific tunings: */
+#define X86_FEATURE_K8		(3*32+ 4) /* Opteron, Athlon64 */
+#define X86_FEATURE_K7		(3*32+ 5) /* Athlon */
+#define X86_FEATURE_P3		(3*32+ 6) /* P3 */
+#define X86_FEATURE_P4		(3*32+ 7) /* P4 */
 
-/* Intel defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
+/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_EST		(4*32+ 7) /* Enhanced SpeedStep */
 
+/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
+#define X86_FEATURE_XSTORE	(5*32+ 2) /* on-CPU RNG present (xstore insn) */
+
+
 #define cpu_has(c, bit)		test_bit(bit, (c)->x86_capability)
 #define boot_cpu_has(bit)	test_bit(bit, boot_cpu_data.x86_capability)
 
@@ -77,7 +87,9 @@
 #define cpu_has_tsc		boot_cpu_has(X86_FEATURE_TSC)
 #define cpu_has_pae		boot_cpu_has(X86_FEATURE_PAE)
 #define cpu_has_pge		boot_cpu_has(X86_FEATURE_PGE)
+#define cpu_has_sse2		boot_cpu_has(X86_FEATURE_XMM2)
 #define cpu_has_apic		boot_cpu_has(X86_FEATURE_APIC)
+#define cpu_has_sep		boot_cpu_has(X86_FEATURE_SEP)
 #define cpu_has_mtrr		boot_cpu_has(X86_FEATURE_MTRR)
 #define cpu_has_mmx		boot_cpu_has(X86_FEATURE_MMX)
 #define cpu_has_fxsr		boot_cpu_has(X86_FEATURE_FXSR)
@@ -87,6 +99,7 @@
 #define cpu_has_k6_mtrr		boot_cpu_has(X86_FEATURE_K6_MTRR)
 #define cpu_has_cyrix_arr	boot_cpu_has(X86_FEATURE_CYRIX_ARR)
 #define cpu_has_centaur_mcr	boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
+#define cpu_has_xstore		boot_cpu_has(X86_FEATURE_XSTORE)
 
 #endif /* __ASM_I386_CPUFEATURE_H */
 
diff -Nru a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
--- a/include/asm-i386/hardirq.h	Mon Feb  4 23:55:11 2002
+++ b/include/asm-i386/hardirq.h	Wed Aug 27 07:05:59 2003
@@ -67,6 +67,8 @@
 {
 	++local_irq_count(cpu);
 
+	smp_mb();
+
 	while (test_bit(0,&global_irq_lock)) {
 		cpu_relax();
 	}
diff -Nru a/include/asm-i386/msr.h b/include/asm-i386/msr.h
--- a/include/asm-i386/msr.h	Sun Jun 29 08:09:26 2003
+++ b/include/asm-i386/msr.h	Thu Aug  7 19:37:21 2003
@@ -113,6 +113,7 @@
 /* VIA Cyrix defined MSRs*/
 #define MSR_VIA_FCR			0x1107
 #define MSR_VIA_LONGHAUL		0x110a
+#define MSR_VIA_RNG			0x110b
 #define MSR_VIA_BCR2			0x1147
 
 /* Transmeta defined MSRs */
diff -Nru a/include/asm-m68k/mc146818rtc.h b/include/asm-m68k/mc146818rtc.h
--- a/include/asm-m68k/mc146818rtc.h	Mon Feb  4 23:53:47 2002
+++ b/include/asm-m68k/mc146818rtc.h	Mon Jun 30 08:15:42 2003
@@ -4,37 +4,12 @@
 #ifndef _ASM_MC146818RTC_H
 #define _ASM_MC146818RTC_H
 
-#include <linux/config.h>
-#include <asm/atarihw.h>
-
 #ifdef CONFIG_ATARI
 /* RTC in Atari machines */
 
 #include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/io.h>
-#define RTC_HAS_IRQ	(ATARIHW_PRESENT(TT_MFP))
-#define RTC_IRQ 	IRQ_TT_MFP_RTC
-#define RTC_IRQ_FLAGS	IRQ_TYPE_FAST
-#define RTC_PORT(x)	(TT_RTC_BAS + 2*(x))
-#define RTC_ALWAYS_BCD	0	/* TOS uses binary mode, Linux should be able
-				 * to deal with both modes */
 
-#define RTC_CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
-#define RTC_MACH_INIT()							\
-    do {								\
-	epoch = atari_rtc_year_offset + 1900;				\
-	if (RTC_HAS_IRQ)						\
-	    /* select RTC int on H->L edge */				\
-	    tt_mfp.active_edge &= ~0x40;				\
-    } while(0)
-#define RTC_MACH_EXIT()
-
-/* On Atari, the year was stored with base 1970 in old TOS versions (before
- * 3.06). Later, Atari recognized that this broke leap year recognition, and
- * changed the base to 1968. Medusa and Hades always use the new version. */
-#define RTC_CENTURY_SWITCH	-1	/* no century switch */
-#define RTC_MINYEAR		epoch
+#define RTC_PORT(x)	(TT_RTC_BAS + 2*(x))
 
 #define CMOS_READ(addr) ({ \
 atari_outb_p((addr),RTC_PORT(0)); \
diff -Nru a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h
--- a/include/asm-m68k/processor.h	Wed Mar 19 09:54:55 2003
+++ b/include/asm-m68k/processor.h	Wed Jul 23 11:26:22 2003
@@ -155,6 +155,6 @@
 #define init_task	(init_task_union.task)
 #define init_stack	(init_task_union.stack)
 
-#define cpu_relax()	do { } while (0)
+#define cpu_relax()	barrier()
 
 #endif
diff -Nru a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h
--- a/include/asm-ppc/cache.h	Wed Mar 19 15:05:05 2003
+++ b/include/asm-ppc/cache.h	Thu Aug 28 03:51:50 2003
@@ -41,6 +41,8 @@
 extern void flush_dcache_range(unsigned long start, unsigned long stop);
 extern void invalidate_dcache_range(unsigned long start, unsigned long stop);
 extern void clean_dcache_range(unsigned long start, unsigned long stop);
+extern void flush_dcache_all(void);
+
 #endif /* __ASSEMBLY__ */
 
 /* prep registers for L2 */
diff -Nru a/include/asm-ppc/ibm44x.h b/include/asm-ppc/ibm44x.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc/ibm44x.h	Thu Aug 28 04:55:49 2003
@@ -0,0 +1,435 @@
+/*
+ * include/asm-ppc/ibm44x.h
+ *
+ * PPC44x definitions
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002-2003 MontaVista Software 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBM44x_H__
+#define __ASM_IBM44x_H__
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Ebony" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ *
+ * Ebony firmware stores MAC addresses in the F/W VPD area. The
+ * firmware must store the other dynamic values in NVRAM like on
+ * the previous 40x systems so they  should be accessible if we
+ * really want them.
+ */
+typedef struct board_info {
+	unsigned char	bi_enetaddr[2][6];	/* EMAC addresses */
+	unsigned int	bi_opb_busfreq;		/* OPB clock in Hz */
+	int		bi_iic_fast[2];		/* Use fast i2c mode */
+} bd_t;
+#endif /* __ASSEMBLY__ */
+
+#ifndef NR_BOARD_IRQS
+#define NR_BOARD_IRQS 0
+#endif
+
+#define _IO_BASE	isa_io_base
+#define _ISA_MEM_BASE	isa_mem_base
+#define PCI_DRAM_OFFSET	pci_dram_offset
+
+/* TLB entry offset/size used for pinning kernel lowmem */
+#define PPC44x_PIN_SHIFT	28
+#define PPC44x_PIN_SIZE		(1 << PPC44x_PIN_SHIFT)
+
+/* Lowest TLB slot consumed by the default pinned TLBs */
+#define PPC44x_LOW_SLOT		62
+
+/*
+ * Standard 4GB "page" definitions
+ */
+#define	PPC44x_IO_PAGE		0x0000000100000000ULL
+#define	PPC44x_PCICFG_PAGE	0x0000000200000000ULL
+#define	PPC44x_PCIIO_PAGE	PPC44x_PCICFG_PAGE
+#define	PPC44x_PCIMEM_PAGE	0x0000000300000000ULL
+
+/*
+ * 36-bit trap ranges
+ */
+#define PPC44x_IO_LO		0x40000000
+#define PPC44x_IO_HI		0x40001000
+#define PPC44x_PCICFG_LO	0x0ec00000
+#define PPC44x_PCICFG_HI	0x0ec7ffff
+#define PPC44x_PCIMEM_LO	0x80002000
+#define PPC44x_PCIMEM_HI	0xffffffff
+
+/*
+ * The "residual" board information structure the boot loader passes
+ * into the kernel.
+ */
+#ifndef __ASSEMBLY__
+
+/*
+ * SPRN definitions
+ */
+#define SPRN_CPC0_GPIO		0xe5/BEARLRL
+
+/*
+ * DCRN definitions
+ */ 
+
+#ifdef CONFIG_440GX
+/* SDRs */
+#define DCRN_SDR_CONFIG_ADDR 	0xe 
+#define DCRN_SDR_CONFIG_DATA	0xf
+#define DCRN_SDR_PFC0		0x4100
+#define DCRN_SDR_PFC1		0x4101
+#define DCRN_SDR_MFR		0x4300
+#define DCRN_SDR_MFR_TAH0 	0x80000000  	/* TAHOE0 Enable */
+#define DCRN_SDR_MFR_TAH1 	0x40000000  	/* TAHOE1 Enable */
+#define DCRN_SDR_MFR_PCM  	0x10000000  	/* PPC440GP irq compat mode */
+#define DCRN_SDR_MFR_ECS  	0x08000000  	/* EMAC int clk */
+#define DCRN_SDR_MFR_T0TXFL	0x00080000
+#define DCRN_SDR_MFR_T0TXFH	0x00040000
+#define DCRN_SDR_MFR_T1TXFL	0x00020000
+#define DCRN_SDR_MFR_T1TXFH	0x00010000
+#define DCRN_SDR_MFR_E0TXFL	0x00008000
+#define DCRN_SDR_MFR_E0TXFH	0x00004000
+#define DCRN_SDR_MFR_E0RXFL	0x00002000
+#define DCRN_SDR_MFR_E0RXFH	0x00001000
+#define DCRN_SDR_MFR_E1TXFL	0x00000800
+#define DCRN_SDR_MFR_E1TXFH	0x00000400
+#define DCRN_SDR_MFR_E1RXFL	0x00000200 
+#define DCRN_SDR_MFR_E1RXFH	0x00000100
+#define DCRN_SDR_MFR_E2TXFL	0x00000080
+#define DCRN_SDR_MFR_E2TXFH	0x00000040
+#define DCRN_SDR_MFR_E2RXFL	0x00000020
+#define DCRN_SDR_MFR_E2RXFH	0x00000010
+#define DCRN_SDR_MFR_E3TXFL	0x00000008
+#define DCRN_SDR_MFR_E3TXFH	0x00000004
+#define DCRN_SDR_MFR_E3RXFL	0x00000002
+#define DCRN_SDR_MFR_E3RXFH	0x00000001
+
+/* SDR read/write helper macros */
+#define SDR_READ(offset) ({\
+	mtdcr(DCRN_SDR_CONFIG_ADDR, offset); \
+	mfdcr(DCRN_SDR_CONFIG_DATA);})
+#define SDR_WRITE(offset, data) ({\
+	mtdcr(DCRN_SDR_CONFIG_ADDR, offset); \
+	mtdcr(DCRN_SDR_CONFIG_DATA,data);})
+#endif /* CONFIG_440GX */
+
+/* Base DCRNs */
+#define DCRN_DMA0_BASE		0x100
+#define DCRN_DMA1_BASE		0x108
+#define DCRN_DMA2_BASE		0x110
+#define DCRN_DMA3_BASE		0x118
+#define DCRN_DMASR_BASE		0x120
+#define DCRNCAP_DMA_SG		1	/* have DMA scatter/gather capability */
+#define DCRN_MAL_BASE		0x180
+
+/* UIC */
+#define DCRN_UIC0_BASE	0xc0
+#define DCRN_UIC1_BASE	0xd0
+#define UIC0		DCRN_UIC0_BASE
+#define UIC1		DCRN_UIC1_BASE
+
+#define DCRN_UIC_SR(base)       (base + 0x0)
+#define DCRN_UIC_ER(base)       (base + 0x2)
+#define DCRN_UIC_CR(base)       (base + 0x3)
+#define DCRN_UIC_PR(base)       (base + 0x4)
+#define DCRN_UIC_TR(base)       (base + 0x5)
+#define DCRN_UIC_MSR(base)      (base + 0x6)
+#define DCRN_UIC_VR(base)       (base + 0x7)
+#define DCRN_UIC_VCR(base)      (base + 0x8)
+
+#define UIC0_UIC1NC      30	/* UIC1 non-critical interrupt */
+#define UIC0_UIC1CR      31	/* UIC1 critical interrupt */
+
+/* 440GP MAL DCRs */
+#define DCRN_MALCR(base)		(base + 0x0)	/* Configuration */
+#define DCRN_MALESR(base)		(base + 0x1)	/* Error Status */
+#define DCRN_MALIER(base)		(base + 0x2)	/* Interrupt Enable */
+#define DCRN_MALTXCASR(base)		(base + 0x4)	/* Tx Channel Active Set */
+#define DCRN_MALTXCARR(base)		(base + 0x5)	/* Tx Channel Active Reset */
+#define DCRN_MALTXEOBISR(base)		(base + 0x6)	/* Tx End of Buffer Interrupt Status */
+#define DCRN_MALTXDEIR(base)		(base + 0x7)	/* Tx Descriptor Error Interrupt */
+#define DCRN_MALRXCASR(base)		(base + 0x10)	/* Rx Channel Active Set */
+#define DCRN_MALRXCARR(base)		(base + 0x11)	/* Rx Channel Active Reset */
+#define DCRN_MALRXEOBISR(base)		(base + 0x12)	/* Rx End of Buffer Interrupt Status */
+#define DCRN_MALRXDEIR(base)		(base + 0x13)	/* Rx Descriptor Error Interrupt */
+#define DCRN_MALTXCTP0R(base)		(base + 0x20)	/* Channel Tx 0 Channel Table Pointer */	
+#define DCRN_MALTXCTP1R(base)		(base + 0x21)	/* Channel Tx 1 Channel Table Pointer */
+#define DCRN_MALTXCTP2R(base)		(base + 0x22)	/* Channel Tx 2 Channel Table Pointer */
+#define DCRN_MALTXCTP3R(base)		(base + 0x23)	/* Channel Tx 3 Channel Table Pointer */
+#define DCRN_MALRXCTP0R(base)		(base + 0x40)	/* Channel Rx 0 Channel Table Pointer */	
+#define DCRN_MALRXCTP1R(base)		(base + 0x41)	/* Channel Rx 1 Channel Table Pointer */	
+#define DCRN_MALRCBS0(base)		(base + 0x60)	/* Channel Rx 0 Channel Buffer Size */	
+#define DCRN_MALRCBS1(base)		(base + 0x61)	/* Channel Rx 1 Channel Buffer Size */	
+
+/* Compatibility DCRN's */
+#define DCRN_MALRXCTP2R(base)	((base) + 0x42)	/* Channel Rx 2 Channel Table Pointer */
+#define DCRN_MALRXCTP3R(base)	((base) + 0x43)	/* Channel Rx 3 Channel Table Pointer */
+#define DCRN_MALTXCTP4R(base)	((base) + 0x24)	/* Channel Tx 4 Channel Table Pointer */
+#define DCRN_MALTXCTP5R(base)	((base) + 0x25)	/* Channel Tx 5 Channel Table Pointer */
+#define DCRN_MALTXCTP6R(base)	((base) + 0x26)	/* Channel Tx 6 Channel Table Pointer */
+#define DCRN_MALTXCTP7R(base)	((base) + 0x27)	/* Channel Tx 7 Channel Table Pointer */
+#define DCRN_MALRCBS2(base)	((base) + 0x62)	/* Channel Rx 2 Channel Buffer Size */
+#define DCRN_MALRCBS3(base)	((base) + 0x63)	/* Channel Rx 3 Channel Buffer Size */
+
+
+#define MALCR_MMSR		0x80000000	/* MAL Software reset */
+#define MALCR_PLBP_1		0x00400000	/* MAL reqest priority: */
+#define MALCR_PLBP_2		0x00800000	/* lowsest is 00 */
+#define MALCR_PLBP_3		0x00C00000	/* highest */
+#define MALCR_GA		0x00200000	/* Guarded Active Bit */
+#define MALCR_OA		0x00100000	/* Ordered Active Bit */
+#define MALCR_PLBLE		0x00080000	/* PLB Lock Error Bit */
+#define MALCR_PLBLT_1		0x00040000	/* PLB Latency Timer */
+#define MALCR_PLBLT_2 		0x00020000
+#define MALCR_PLBLT_3		0x00010000
+#define MALCR_PLBLT_4		0x00008000
+#ifdef CONFIG_440GP
+#define MALCR_PLBLT_DEFAULT	0x00330000	/* PLB Latency Timer default */
+#else
+#define MALCR_PLBLT_DEFAULT	0x00ff0000	/* PLB Latency Timer default */
+#endif
+#define MALCR_PLBB		0x00004000	/* PLB Burst Deactivation Bit */
+#define MALCR_OPBBL		0x00000080	/* OPB Lock Bit */
+#define MALCR_EOPIE		0x00000004	/* End Of Packet Interrupt Enable */
+#define MALCR_LEA		0x00000002	/* Locked Error Active */
+#define MALCR_MSD		0x00000001	/* MAL Scroll Descriptor Bit */
+/* DCRN_MALESR */
+#define MALESR_EVB		0x80000000	/* Error Valid Bit */
+#define MALESR_CIDRX		0x40000000	/* Channel ID Receive */
+#define MALESR_DE		0x00100000	/* Descriptor Error */
+#define MALESR_OEN		0x00080000	/* OPB Non-Fullword Error */
+#define MALESR_OTE		0x00040000	/* OPB Timeout Error */
+#define MALESR_OSE		0x00020000	/* OPB Slave Error */
+#define MALESR_PEIN		0x00010000	/* PLB Bus Error Indication */
+#define MALESR_DEI		0x00000010	/* Descriptor Error Interrupt */
+#define MALESR_ONEI		0x00000008	/* OPB Non-Fullword Error Interrupt */
+#define MALESR_OTEI		0x00000004	/* OPB Timeout Error Interrupt */
+#define MALESR_OSEI		0x00000002	/* OPB Slace Error Interrupt */
+#define MALESR_PBEI		0x00000001	/* PLB Bus Error Interrupt */
+/* DCRN_MALIER */
+#define MALIER_DE		0x00000010	/* Descriptor Error Interrupt Enable */
+#define MALIER_NE		0x00000008	/* OPB Non-word Transfer Int Enable */
+#define MALIER_TE		0x00000004	/* OPB Time Out Error Interrupt Enable */
+#define MALIER_OPBE		0x00000002	/* OPB Slave Error Interrupt Enable */
+#define MALIER_PLBE		0x00000001	/* PLB Error Interrupt Enable */
+/* DCRN_MALTXEOBISR */
+#define MALOBISR_CH0		0x80000000	/* EOB channel 1 bit */
+#define MALOBISR_CH2		0x40000000	/* EOB channel 2 bit */
+
+/* 440GP PLB Arbiter DCRs */
+#define DCRN_PLB0_REVID		0x082		/* PLB Arbiter Revision ID */
+#define DCRN_PLB0_ACR		0x083		/* PLB Arbiter Control */
+#define DCRN_PLB0_BESR		0x084		/* PLB Error Status */
+#define DCRN_PLB0_BEARL		0x086		/* PLB Error Address Low */
+#define DCRN_PLB0_BEAR		DCRN_PLB0_BEARL	/* 40x compatibility */
+#define DCRN_PLB0_BEARH		0x087		/* PLB Error Address High */
+
+/* 440GP Clock, PM, chip control */
+#define DCRN_CPC0_SR		0x0b0
+#define DCRN_CPC0_ER		0x0b1
+#define DCRN_CPC0_FR		0x0b2
+#define DCRN_CPC0_SYS0		0x0e0
+#define DCRN_CPC0_SYS1		0x0e1
+#define DCRN_CPC0_CUST0		0x0e2
+#define DCRN_CPC0_CUST1		0x0e3
+#define DCRN_CPC0_STRP0		0x0e4
+#define DCRN_CPC0_STRP1		0x0e5
+#define DCRN_CPC0_STRP2		0x0e6
+#define DCRN_CPC0_STRP3		0x0e7
+#define DCRN_CPC0_GPIO		0x0e8
+#define DCRN_CPC0_PLB		0x0e9
+#define DCRN_CPC0_CR1		0x0ea
+#define DCRN_CPC0_CR0		0x0eb
+#define DCRN_CPC0_MIRQ0		0x0ec
+#define DCRN_CPC0_MIRQ1		0x0ed
+#define DCRN_CPC0_JTAGID	0x0ef
+
+/* 440GP DMA controller DCRs */
+#define DCRN_DMACR0	(DCRN_DMA0_BASE + 0x0)	/* DMA Channel Control 0 */
+#define DCRN_DMACT0	(DCRN_DMA0_BASE + 0x1)  /* DMA Count 0 */
+#define DCRN_DMASAH0	(DCRN_DMA0_BASE + 0x2)	/* DMA Src Addr High 0 */
+#define DCRN_DMASA0	(DCRN_DMA0_BASE + 0x3)	/* DMA Src Addr Low 0 */
+#define DCRN_DMADAH0	(DCRN_DMA0_BASE + 0x4)	/* DMA Dest Addr High 0 */
+#define DCRN_DMADA0	(DCRN_DMA0_BASE + 0x5)	/* DMA Dest Addr Low 0 */
+#define DCRN_ASGH0	(DCRN_DMA0_BASE + 0x6)	/* DMA SG Desc Addr High 0 */
+#define DCRN_ASG0	(DCRN_DMA0_BASE + 0x7)	/* DMA SG Desc Addr Low 0 */
+
+#define DCRN_DMACR1	(DCRN_DMA1_BASE + 0x0)	/* DMA Channel Control 1 */
+#define DCRN_DMACT1	(DCRN_DMA1_BASE + 0x1)  /* DMA Count 1 */
+#define DCRN_DMASAH1	(DCRN_DMA1_BASE + 0x2)	/* DMA Src Addr High 1 */
+#define DCRN_DMASA1	(DCRN_DMA1_BASE + 0x3)	/* DMA Src Addr Low 1 */
+#define DCRN_DMADAH1	(DCRN_DMA1_BASE + 0x4)	/* DMA Dest Addr High 1 */
+#define DCRN_DMADA1	(DCRN_DMA1_BASE + 0x5)	/* DMA Dest Addr Low 1 */
+#define DCRN_ASGH1	(DCRN_DMA1_BASE + 0x6)	/* DMA SG Desc Addr High 1 */
+#define DCRN_ASG1	(DCRN_DMA1_BASE + 0x7)	/* DMA SG Desc Addr Low 1 */
+
+#define DCRN_DMACR2	(DCRN_DMA2_BASE + 0x0)	/* DMA Channel Control 2 */
+#define DCRN_DMACT2	(DCRN_DMA2_BASE + 0x1)  /* DMA Count 2 */
+#define DCRN_DMASAH2	(DCRN_DMA2_BASE + 0x2)	/* DMA Src Addr High 2 */
+#define DCRN_DMASA2	(DCRN_DMA2_BASE + 0x3)	/* DMA Src Addr Low 2 */
+#define DCRN_DMADAH2	(DCRN_DMA2_BASE + 0x4)	/* DMA Dest Addr High 2 */
+#define DCRN_DMADA2	(DCRN_DMA2_BASE + 0x5)	/* DMA Dest Addr Low 2 */
+#define DCRN_ASGH2	(DCRN_DMA2_BASE + 0x6)	/* DMA SG Desc Addr High 2 */
+#define DCRN_ASG2	(DCRN_DMA2_BASE + 0x7)	/* DMA SG Desc Addr Low 2 */
+
+#define DCRN_DMACR3	(DCRN_DMA3_BASE + 0x0)	/* DMA Channel Control 3 */
+#define DCRN_DMACT3	(DCRN_DMA3_BASE + 0x1)  /* DMA Count 3 */
+#define DCRN_DMASAH3	(DCRN_DMA3_BASE + 0x2)	/* DMA Src Addr High 3 */
+#define DCRN_DMASA3	(DCRN_DMA3_BASE + 0x3)	/* DMA Src Addr Low 3 */
+#define DCRN_DMADAH3	(DCRN_DMA3_BASE + 0x4)	/* DMA Dest Addr High 3 */
+#define DCRN_DMADA3	(DCRN_DMA3_BASE + 0x5)	/* DMA Dest Addr Low 3 */
+#define DCRN_ASGH3	(DCRN_DMA3_BASE + 0x6)	/* DMA SG Desc Addr High 3 */
+#define DCRN_ASG3	(DCRN_DMA3_BASE + 0x7)	/* DMA SG Desc Addr Low 3 */
+
+#define DCRN_DMASR	(DCRN_DMASR_BASE + 0x0)	/* DMA Status Register */
+#define DCRN_ASGC	(DCRN_DMASR_BASE + 0x3)	/* DMA Scatter/Gather Command */
+#define DCRN_SLP	(DCRN_DMASR_BASE + 0x5)	/* DMA Sleep Register */
+#define DCRN_POL	(DCRN_DMASR_BASE + 0x6)	/* DMA Polarity Register */
+
+/* 440GP DRAM controller DCRs */
+#define DCRN_SDRAM0_CFGADDR		0x010
+#define DCRN_SDRAM0_CFGDATA		0x011
+
+#define SDRAM0_B0CR	0x40
+#define SDRAM0_B1CR	0x44
+#define SDRAM0_B2CR	0x48
+#define SDRAM0_B3CR	0x4c
+
+#define SDRAM_CONFIG_BANK_ENABLE	0x00000001
+#define SDRAM_CONFIG_SIZE_MASK		0x000e0000
+#define SDRAM_CONFIG_BANK_SIZE(reg)	((reg & SDRAM_CONFIG_SIZE_MASK) >> 17)
+#define SDRAM_CONFIG_SIZE_8M		0x00000001
+#define SDRAM_CONFIG_SIZE_16M		0x00000002
+#define SDRAM_CONFIG_SIZE_32M		0x00000003
+#define SDRAM_CONFIG_SIZE_64M		0x00000004
+#define SDRAM_CONFIG_SIZE_128M		0x00000005
+#define SDRAM_CONFIG_SIZE_256M		0x00000006
+#define SDRAM_CONFIG_SIZE_512M		0x00000007
+#define PPC44x_MEM_SIZE_8M		0x00800000
+#define PPC44x_MEM_SIZE_16M		0x01000000
+#define PPC44x_MEM_SIZE_32M		0x02000000
+#define PPC44x_MEM_SIZE_64M		0x04000000
+#define PPC44x_MEM_SIZE_128M		0x08000000
+#define PPC44x_MEM_SIZE_256M		0x10000000
+#define PPC44x_MEM_SIZE_512M		0x20000000
+
+/*
+ * PCI-X definitions
+ */
+#define PCIX0_REG_BASE		0x20ec80000ULL
+#define PCIX0_REG_SIZE		0x200
+
+#define PCIX0_VENDID		0x000
+#define PCIX0_DEVID		0x002
+#define PCIX0_COMMAND		0x004
+#define PCIX0_STATUS		0x006
+#define PCIX0_REVID		0x008
+#define PCIX0_CLS		0x009
+#define PCIX0_CACHELS		0x00c
+#define PCIX0_LATTIM		0x00d
+#define PCIX0_HDTYPE		0x00e
+#define PCIX0_BIST		0x00f
+#define PCIX0_BAR0L		0x010
+#define PCIX0_BAR0H		0x014
+#define PCIX0_BAR1		0x018
+#define PCIX0_BAR2L		0x01c
+#define PCIX0_BAR2H		0x020
+#define PCIX0_BAR3		0x024
+#define PCIX0_CISPTR		0x028
+#define PCIX0_SBSYSVID		0x02c
+#define PCIX0_SBSYSID		0x02e
+#define PCIX0_EROMBA		0x030
+#define PCIX0_CAP		0x034
+#define PCIX0_RES0		0x035
+#define PCIX0_RES1		0x036
+#define PCIX0_RES2		0x038
+#define PCIX0_INTLN		0x03c
+#define PCIX0_INTPN		0x03d
+#define PCIX0_MINGNT		0x03e
+#define PCIX0_MAXLTNCY		0x03f
+#define PCIX0_BRDGOPT1		0x040
+#define PCIX0_BRDGOPT2		0x044
+#define PCIX0_ERREN		0x050
+#define PCIX0_ERRSTS		0x054
+#define PCIX0_PLBBESR		0x058
+#define PCIX0_PLBBEARL		0x05c
+#define PCIX0_PLBBEARH		0x060
+#define PCIX0_POM0LAL		0x068
+#define PCIX0_POM0LAH		0x06c
+#define PCIX0_POM0SA		0x070
+#define PCIX0_POM0PCIAL		0x074
+#define PCIX0_POM0PCIAH		0x078
+#define PCIX0_POM1LAL		0x07c
+#define PCIX0_POM1LAH		0x080
+#define PCIX0_POM1SA		0x084
+#define PCIX0_POM1PCIAL		0x088
+#define PCIX0_POM1PCIAH		0x08c
+#define PCIX0_POM2SA		0x090
+#define PCIX0_PIM0SAL		0x098
+#define PCIX0_PIM0SA		PCIX0_PIM0SAL
+#define PCIX0_PIM0LAL		0x09c
+#define PCIX0_PIM0LAH		0x0a0
+#define PCIX0_PIM1SA		0x0a4
+#define PCIX0_PIM1LAL		0x0a8
+#define PCIX0_PIM1LAH		0x0ac
+#define PCIX0_PIM2SAL		0x0b0
+#define PCIX0_PIM2SA		PCIX0_PIM2SAL
+#define PCIX0_PIM2LAL		0x0b4
+#define PCIX0_PIM2LAH		0x0b8
+#define PCIX0_OMCAPID		0x0c0
+#define PCIX0_OMNIPTR		0x0c1
+#define PCIX0_OMMC		0x0c2
+#define PCIX0_OMMA		0x0c4
+#define PCIX0_OMMUA		0x0c8
+#define PCIX0_OMMDATA		0x0cc
+#define PCIX0_OMMEOI		0x0ce
+#define PCIX0_PMCAPID		0x0d0
+#define PCIX0_PMNIPTR		0x0d1
+#define PCIX0_PMC		0x0d2
+#define PCIX0_PMCSR		0x0d4
+#define PCIX0_PMCSRBSE		0x0d6
+#define PCIX0_PMDATA		0x0d7
+#define PCIX0_PMSCRR		0x0d8
+#define PCIX0_CAPID		0x0dc
+#define PCIX0_NIPTR		0x0dd
+#define PCIX0_CMD		0x0de
+#define PCIX0_STS		0x0e0
+#define PCIX0_IDR		0x0e4
+#define PCIX0_CID		0x0e8
+#define PCIX0_RID		0x0ec
+#define PCIX0_PIM0SAH		0x0f8
+#define PCIX0_PIM2SAH		0x0fc
+#define PCIX0_MSGIL		0x100
+#define PCIX0_MSGIH		0x104
+#define PCIX0_MSGOL		0x108
+#define PCIX0_MSGOH		0x10c
+#define PCIX0_IM		0x1f8
+
+#define IIC_OWN			0x55
+#define IIC_CLOCK		50
+
+#undef NR_UICS
+#define NR_UICS 2
+#define UIC_CASCADE_MASK	0x0003		/* bits 30 & 31 */
+
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i]
+
+#include <asm/ibm4xx.h>
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_IBM44x_H__ */
+#endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
--- a/include/asm-ppc/ibm4xx.h	Thu Jul  3 09:56:35 2003
+++ b/include/asm-ppc/ibm4xx.h	Fri Aug 29 03:37:49 2003
@@ -80,6 +80,16 @@
 #define PCI_DRAM_OFFSET	0
 #endif
 
+#elif CONFIG_44x
+
+#if defined(CONFIG_EBONY)
+#include <platforms/ebony.h>
+#endif
+
+#if defined(CONFIG_OCOTEA)
+#include <platforms/ocotea.h>
+#endif
+
 #endif /* CONFIG_40x */
 
 #ifndef __ASSEMBLY__
diff -Nru a/include/asm-ppc/io.h b/include/asm-ppc/io.h
--- a/include/asm-ppc/io.h	Thu Jun 19 05:23:14 2003
+++ b/include/asm-ppc/io.h	Fri Aug 29 03:37:49 2003
@@ -3,7 +3,9 @@
 #define _PPC_IO_H
 
 #include <linux/config.h>
+#include <linux/mm.h>
 #include <linux/types.h>
+#include <asm/mmu.h>
 #include <asm/page.h>
 #include <asm/byteorder.h>
 
@@ -40,6 +42,7 @@
 extern unsigned long isa_io_base;
 extern unsigned long isa_mem_base;
 extern unsigned long pci_dram_offset;
+
 #define readb(addr) in_8((volatile u8 *)(addr))
 #define writeb(b,addr) out_8((volatile u8 *)(addr), (b))
 #if defined(CONFIG_APUS)
@@ -195,14 +198,15 @@
  * Map in an area of physical address space, for accessing
  * I/O devices etc.
  */
-extern void *__ioremap(unsigned long address, unsigned long size,
+extern void *__ioremap(phys_addr_t address, unsigned long size,
 		       unsigned long flags);
-extern void *ioremap(unsigned long address, unsigned long size);
+extern void *ioremap(phys_addr_t address, unsigned long size);
+extern void *ioremap64(unsigned long long address, unsigned long size);
 #define ioremap_nocache(addr, size)	ioremap((addr), (size))
 extern void iounmap(void *addr);
 extern unsigned long iopa(unsigned long addr);
 extern unsigned long mm_ptov(unsigned long addr) __attribute__ ((const));
-extern void io_block_mapping(unsigned long virt, unsigned long phys,
+extern void io_block_mapping(unsigned long virt, phys_addr_t phys,
 			     unsigned int size, int flags);
 
 /*
@@ -223,10 +227,7 @@
  */
 extern inline unsigned long virt_to_bus(volatile void * address)
 {
-#if defined(CONFIG_APUS) || defined(CONFIG_8xx) || defined(CONFIG_4xx)
-	/* I think everyone will be using this version if we start allowing
-	 * uncached pages in alternate virtual spaces.  --  Dan
-	 */
+#ifdef CONFIG_APUS
 	return (iopa((unsigned long) address) + PCI_DRAM_OFFSET);
 #else
 	if (address == (void *)0)
@@ -237,7 +238,7 @@
 
 extern inline void * bus_to_virt(unsigned long address)
 {
-#if defined(CONFIG_APUS) || defined(CONFIG_8xx) || defined(CONFIG_40x)
+#ifdef CONFIG_APUS
 	return (void*) mm_ptov (address - PCI_DRAM_OFFSET);
 #else
 	if (address == 0)
@@ -252,7 +253,7 @@
  */
 extern inline unsigned long virt_to_phys(volatile void * address)
 {
-#if defined(CONFIG_APUS) || defined(CONFIG_8xx) || defined(CONFIG_40x)
+#ifdef CONFIG_APUS
 	return iopa ((unsigned long) address);
 #else
 	return (unsigned long) address - KERNELBASE;
@@ -261,7 +262,7 @@
 
 extern inline void * phys_to_virt(unsigned long address)
 {
-#if defined(CONFIG_APUS) || defined(CONFIG_8xx) || defined(CONFIG_40x)
+#ifdef CONFIG_APUS
 	return (void*) mm_ptov (address);
 #else
 	return (void *) (address + KERNELBASE);
@@ -401,11 +402,43 @@
 	return 0;
 }
 
-/* Nothing to do */
+#ifdef CONFIG_NOT_COHERENT_CACHE
+
+/*
+ * DMA-consistent mapping functions for PowerPCs that don't support
+ * cache snooping.  These allocate/free a region of uncached mapped
+ * memory space for use with DMA devices.  Alternatively, you could
+ * allocate the space "normally" and use the cache management functions
+ * to ensure it is consistent.
+ */
+extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
+extern void consistent_free(void *vaddr);
+extern void consistent_sync(void *vaddr, size_t size, int rw);
+extern void consistent_sync_page(struct page *page, unsigned long offset,
+				 size_t size, int rw);
+
+#define dma_cache_inv(_start,_size) \
+	invalidate_dcache_range(_start, (_start + _size))
+#define dma_cache_wback(_start,_size) \
+	clean_dcache_range(_start, (_start + _size))
+#define dma_cache_wback_inv(_start,_size) \
+	flush_dcache_range(_start, (_start + _size))
+
+#else /* ! CONFIG_NOT_COHERENT_CACHE */
+
+/*
+ * Cache coherent cores.
+ */
 
 #define dma_cache_inv(_start,_size)		do { } while (0)
 #define dma_cache_wback(_start,_size)		do { } while (0)
 #define dma_cache_wback_inv(_start,_size)	do { } while (0)
 
-#endif
+#define consistent_alloc(gfp, size, handle)	NULL
+#define consistent_free(addr, size)		do { } while (0)
+#define consistent_sync(addr, size, rw)		do { } while (0)
+#define consistent_sync_page(pg, off, sz, rw)	do { } while (0)
+
+#endif /* CONFIG_NOT_COHERENT_CACHE */
+#endif /* _PPC_IO_H */
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/ipc.h b/include/asm-ppc/ipc.h
--- a/include/asm-ppc/ipc.h	Thu Jul  3 09:56:35 2003
+++ b/include/asm-ppc/ipc.h	Fri Aug 29 04:11:06 2003
@@ -14,6 +14,7 @@
 #define SEMOP		 1
 #define SEMGET		 2
 #define SEMCTL		 3
+#define SEMTIMEDOP	 4
 #define MSGSND		11
 #define MSGRCV		12
 #define MSGGET		13
diff -Nru a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h
--- a/include/asm-ppc/irq.h	Thu Jul  3 09:56:35 2003
+++ b/include/asm-ppc/irq.h	Thu Aug 28 05:31:04 2003
@@ -71,8 +71,8 @@
 	return (irq);
 }
 
-#elif defined(CONFIG_440)
-#include <asm/ibm440.h>
+#elif defined(CONFIG_44x)
+#include <asm/ibm44x.h>
 
 #define	NR_UIC_IRQS	32
 #define	NR_IRQS		((NR_UIC_IRQS * NR_UICS) + NR_BOARD_IRQS)
diff -Nru a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h
--- a/include/asm-ppc/mmu.h	Thu Jul  3 09:56:35 2003
+++ b/include/asm-ppc/mmu.h	Thu Aug 28 05:31:04 2003
@@ -10,6 +10,18 @@
 
 #ifndef __ASSEMBLY__
 
+/*
+ * Define physical address type.  Machines using split size
+ * virtual/physical addressing like 32-bit virtual / 36-bit
+ * physical need a larger than native word size type. -Matt
+ */
+#ifdef CONFIG_PTE_64BIT
+typedef unsigned long long phys_addr_t;
+extern phys_addr_t fixup_bigphys_addr(phys_addr_t, phys_addr_t);
+#else
+typedef unsigned long phys_addr_t;
+#endif
+
 /* Default "unsigned long" context */
 typedef unsigned long mm_context_t;
 
@@ -325,6 +337,55 @@
 #define TLB_I           0x00000004      /* Caching is inhibited */
 #define TLB_M           0x00000002      /* Memory is coherent */
 #define TLB_G           0x00000001      /* Memory is guarded from prefetch */
+
+/*
+ * PPC44x support
+ */
+#define PPC44x_MMUCR_TID	0x000000ff	
+#define PPC44x_MMUCR_STS	0x00010000
+
+#define	PPC44x_TLB_PAGEID	0
+#define	PPC44x_TLB_XLAT		1
+#define	PPC44x_TLB_ATTRIB	2
+
+/* Page identification fields */
+#define PPC44x_TLB_EPN_MASK	0xfffffc00      /* Effective Page Number */
+#define	PPC44x_TLB_VALID	0x00000200      /* Valid flag */
+#define PPC44x_TLB_TS		0x00000100	/* Translation address space */
+#define PPC44x_TLB_PAGESZ_MASK	0x000000f0
+#define PPC44x_TLB_PAGESZ(x)	(x << 4)
+#define PPC44x_PAGESZ_1K	0
+#define PPC44x_PAGESZ_4K	1
+#define PPC44x_PAGESZ_16K	2
+#define PPC44x_PAGESZ_64K	3
+#define PPC44x_PAGESZ_256K	4
+#define PPC44x_PAGESZ_1M	5
+#define PPC44x_PAGESZ_16M	7
+#define	PPC44x_PAGESZ_256M	9
+
+/* Translation fields */
+#define PPC44x_TLB_RPN_MASK	0xfffffc00      /* Real Page Number */
+#define	PPC44x_TLB_ERPN_MASK	0x0000000f
+
+/* Storage attribute and access control fields */
+#define PPC44x_TLB_ATTR_MASK	0x0000ff80
+#define PPC44x_TLB_U0		0x00008000      /* User 0 */
+#define PPC44x_TLB_U1		0x00004000      /* User 1 */
+#define PPC44x_TLB_U2		0x00002000      /* User 2 */
+#define PPC44x_TLB_U3		0x00001000      /* User 3 */
+#define PPC44x_TLB_W		0x00000800      /* Caching is write-through */
+#define PPC44x_TLB_I		0x00000400      /* Caching is inhibited */
+#define PPC44x_TLB_M		0x00000200      /* Memory is coherent */
+#define PPC44x_TLB_G		0x00000100      /* Memory is guarded */
+#define PPC44x_TLB_E		0x00000080      /* Memory is guarded */
+
+#define PPC44x_TLB_PERM_MASK	0x0000003f
+#define PPC44x_TLB_UX		0x00000020      /* User execution */
+#define PPC44x_TLB_UW		0x00000010      /* User write */
+#define PPC44x_TLB_UR		0x00000008      /* User read */
+#define PPC44x_TLB_SX		0x00000004      /* Super execution */
+#define PPC44x_TLB_SW		0x00000002      /* Super write */
+#define PPC44x_TLB_SR		0x00000001      /* Super read */
 
 #endif /* _PPC_MMU_H_ */
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h
--- a/include/asm-ppc/ocp.h	Thu Jun 19 05:23:14 2003
+++ b/include/asm-ppc/ocp.h	Thu Aug 28 05:31:04 2003
@@ -40,6 +40,7 @@
 #include <linux/config.h>
 #include <linux/devfs_fs_kernel.h>
 
+#include <asm/mmu.h>
 #include <asm/ocp_ids.h>
 #include <asm/rwsem.h>
 #include <asm/semaphore.h>
@@ -103,7 +104,7 @@
 	unsigned int	vendor;
 	unsigned int	function;
 	int		index;
-	unsigned long	paddr;
+	phys_addr_t	paddr;
 	int	  	irq;
 	unsigned long	pm;
 	void		*additions;
diff -Nru a/include/asm-ppc/page.h b/include/asm-ppc/page.h
--- a/include/asm-ppc/page.h	Thu Jul  3 09:56:35 2003
+++ b/include/asm-ppc/page.h	Thu Aug 28 04:35:00 2003
@@ -4,7 +4,11 @@
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
-#define PAGE_MASK	(~(PAGE_SIZE-1))
+/*
+ * Subtle: this is an int (not an unsigned long) and so it
+ * gets extended to 64 bits the way want (i.e. with 1s).  -- paulus
+ */
+#define PAGE_MASK	(~((1 << PAGE_SHIFT) - 1))
 
 #ifdef __KERNEL__
 #include <linux/config.h>
@@ -14,6 +18,20 @@
 #define KERNELBASE	PAGE_OFFSET
 
 #ifndef __ASSEMBLY__
+/*
+ * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
+ * physical addressing.  For now this just the IBM PPC440.
+ */
+#ifdef CONFIG_PTE_64BIT
+typedef unsigned long long pte_basic_t;
+#define PTE_SHIFT	(PAGE_SHIFT - 3)	/* 512 ptes per page */
+#define PTE_FMT		"%16Lx"
+#else
+typedef unsigned long pte_basic_t;
+#define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
+#define PTE_FMT		"%.8lx"
+#endif
+
 #include <asm/system.h> /* for xmon definition */
 
 #ifdef CONFIG_XMON
@@ -35,7 +53,7 @@
 /*
  * These are used to make use of C type-checking..
  */
-typedef struct { unsigned long pte; } pte_t;
+typedef struct { pte_basic_t pte; } pte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
diff -Nru a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
--- a/include/asm-ppc/pci.h	Thu Jul  3 09:56:35 2003
+++ b/include/asm-ppc/pci.h	Thu Aug 28 03:51:50 2003
@@ -2,6 +2,14 @@
 #define __PPC_PCI_H
 #ifdef __KERNEL__
 
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+struct pci_dev;
+
 /* Values for the `which' argument to sys_pciconfig_iobase syscall.  */
 #define IOBASE_BRIDGE_NUMBER	0
 #define IOBASE_MEMORY		1
@@ -43,18 +51,12 @@
 extern unsigned long pci_phys_to_bus(unsigned long pa, int busnr);
 extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
 
-/* Dynamic DMA Mapping stuff, stolen from i386
- * 	++ajoshi
+/*
+ * Dynamic DMA Mapping stuff
+ * Originally stolen from i386 by ajoshi and updated by paulus
+ * Non-consistent cache support by Dan Malek
  */
 
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <asm/scatterlist.h>
-#include <asm/io.h>
-
-struct pci_dev;
-
 /* The PCI address space does equal the physical memory
  * address space.  The networking and block device layers use
  * this boolean for bounce buffer decisions.
@@ -91,8 +93,8 @@
 static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size, int direction)
 {
-	if (direction == PCI_DMA_NONE)
-		BUG();
+	BUG_ON(direction == PCI_DMA_NONE);
+	consistent_sync(ptr, size, direction);
 	return virt_to_bus(ptr);
 }
 
@@ -117,10 +119,11 @@
  * to pci_map_single, but takes a struct page instead of a virtual address
  */
 static inline dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
-				      unsigned long offset, size_t size, int direction)
+				      unsigned long offset, size_t size,
+				      int direction)
 {
-	if (direction == PCI_DMA_NONE)
-		BUG();
+	BUG_ON(direction == PCI_DMA_NONE);
+	consistent_sync_page(page, offset, size, direction);
 	return (page - mem_map) * PAGE_SIZE + PCI_DRAM_OFFSET + offset;
 }
 
@@ -136,7 +139,8 @@
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
  * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
+ * and length.  They are obtained via sg_dma_{address,len}(SG),
+ * defined in <asm/scatterlist.h>.
  *
  * NOTE: An implementation may be able to use a smaller number of
  *       DMA address/length pairs than there are SG table elements.
@@ -164,10 +168,15 @@
 		else if (!sg[i].address && !sg[i].page)
 			BUG();
 
-		if (sg[i].address)
+		if (sg[i].address) {
+			consistent_sync(sg[i].address, sg[i].length, direction);
 			sg[i].dma_address = virt_to_bus(sg[i].address);
-		else
+		} else {
+			consistent_sync_page(sg[i].page, sg[i].offset,
+					     sg[i].length, direction);
 			sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset;
+		}
+		sg[i].dma_length = sg[i].length;
 	}
 
 	return nents;
@@ -180,8 +189,7 @@
 static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 				int nents, int direction)
 {
-	if (direction == PCI_DMA_NONE)
-		BUG();
+	BUG_ON(direction == PCI_DMA_NONE);
 	/* nothing to do */
 }
 
@@ -198,9 +206,9 @@
 				       dma_addr_t dma_handle,
 				       size_t size, int direction)
 {
-	if (direction == PCI_DMA_NONE)
-		BUG();
-	/* nothing to do */
+	BUG_ON(direction == PCI_DMA_NONE);
+
+	consistent_sync(bus_to_virt(dma_handle), size, direction);
 }
 
 /* Make physical memory consistent for a set of streaming
@@ -213,9 +221,17 @@
 				   struct scatterlist *sg,
 				   int nelems, int direction)
 {
-	if (direction == PCI_DMA_NONE)
-		BUG();
-	/* nothing to do */
+	int i;
+
+	BUG_ON(direction == PCI_DMA_NONE);
+
+	for (i = 0; i < nelems; i++, sg++) {
+		if (sg->address)
+			consistent_sync(sg->address, sg->length, direction);
+		else
+			consistent_sync_page(sg->page, sg->offset,
+					sg->length, direction);
+	}
 }
 
 /* Return whether the given PCI device DMA address mask can
@@ -257,14 +273,6 @@
 {
 	/* Nothing to do. */
 }
-
-/* These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns.
- */
-#define sg_dma_address(sg)	((sg)->dma_address)
-#define sg_dma_len(sg)		((sg)->length)
 
 /* Return the index of the PCI controller for device PDEV. */
 extern int pci_controller_num(struct pci_dev *pdev);
diff -Nru a/include/asm-ppc/pgalloc.h b/include/asm-ppc/pgalloc.h
--- a/include/asm-ppc/pgalloc.h	Tue Feb 11 12:37:32 2003
+++ b/include/asm-ppc/pgalloc.h	Thu Aug 28 04:35:00 2003
@@ -6,6 +6,13 @@
 #include <linux/threads.h>
 #include <asm/processor.h>
 
+#ifdef CONFIG_PTE_64BIT
+/* 44x uses an 8kB pgdir because it has 8-byte Linux PTEs. */
+#define PGDIR_ORDER	1
+#else
+#define PGDIR_ORDER	0
+#endif
+
 /*
  * This is handled very differently on the PPC since out page tables
  * are all 0's and I want to be able to use these zero'd pages elsewhere
@@ -56,7 +63,7 @@
 {
 	pgd_t *ret;
 
-	if ((ret = (pgd_t *)__get_free_page(GFP_KERNEL)) != NULL)
+	if ((ret = (pgd_t *)__get_free_pages(GFP_KERNEL, PGDIR_ORDER)) != NULL)
 		clear_page(ret);
 	return ret;
 }
diff -Nru a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
--- a/include/asm-ppc/pgtable.h	Thu Jul  3 09:56:35 2003
+++ b/include/asm-ppc/pgtable.h	Thu Aug 28 05:31:04 2003
@@ -154,13 +154,23 @@
  * and ITLB, respectively (see "mmu.h" for definitions).
  */
 
-/* PMD_SHIFT determines the size of the area mapped by the second-level page tables */
-#define PMD_SHIFT	22
+/*
+ * The normal case is that PTEs are 32-bits and we have a 1-page
+ * 1024-entry pgdir pointing to 1-page 1024-entry PTE pages.  -- paulus
+ *
+ * For any >32-bit physical address platform, we can use the following
+ * two level page table layout where the pgdir is 8KB and the MS 13 bits
+ * are an index to the second level table.  The combined pgdir/pmd first
+ * level has 2048 entries and the second level has 512 64-bit PTE entries.
+ * -Matt
+ */
+/* PMD_SHIFT determines the size of the area mapped by the PTE pages */
+#define PMD_SHIFT	(PAGE_SHIFT + PTE_SHIFT)
 #define PMD_SIZE	(1UL << PMD_SHIFT)
 #define PMD_MASK	(~(PMD_SIZE-1))
 
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT	22
+/* PGDIR_SHIFT determines what a top-level page table entry can map */
+#define PGDIR_SHIFT	PMD_SHIFT
 #define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
@@ -168,9 +178,10 @@
  * entries per page directory level: our page-table tree is two-level, so
  * we don't really have any PMD directory.
  */
-#define PTRS_PER_PTE	1024
+#define PTRS_PER_PTE	(1 << PTE_SHIFT)
 #define PTRS_PER_PMD	1
-#define PTRS_PER_PGD	1024
+#define PTRS_PER_PGD	(1 << (32 - PGDIR_SHIFT))
+
 #define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
 #define FIRST_USER_PGD_NR	0
 
@@ -178,7 +189,7 @@
 #define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
 
 #define pte_ERROR(e) \
-	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+	printk("%s:%d: bad pte "PTE_FMT".\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
 	printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
 #define pgd_ERROR(e) \
@@ -202,7 +213,11 @@
  * of RAM.  -- Cort
  */
 #define VMALLOC_OFFSET (0x1000000) /* 16M */
+#ifdef CONFIG_44x
+#define VMALLOC_START (((_ALIGN((long)high_memory, PPC44x_PIN_SIZE) + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#else
 #define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#endif
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END	ioremap_bot
 
@@ -252,6 +267,44 @@
 #define _PAGE_ACCESSED	0x400	/* software: R: page referenced */
 #define _PMD_PRESENT	PAGE_MASK
 
+#elif defined(CONFIG_44x)
+/*
+ * Definitions for PPC44x
+ *
+ * Because of the 3 word TLB entries to support 36-bit addressing,
+ * the attribute are difficult to map in such a fashion that they
+ * are easily loaded during exception processing.  I decided to
+ * organize the entry so the ERPN is the only portion in the
+ * upper word of the PTE and the attribute bits below are packed
+ * in as sensibly as they can be in the area below a 4KB page size
+ * oriented RPN.  This at least makes it easy to load the RPN and
+ * ERPN fields in the TLB. -Matt
+ *
+ * Note that these bits preclude future use of a page size
+ * less than 4KB.
+ */
+#define _PAGE_PRESENT	0x00000001		/* S: PTE valid */
+#define	_PAGE_RW	0x00000002		/* S: Write permission */
+#define	_PAGE_DIRTY	0x00000004		/* S: Page dirty */
+#define _PAGE_ACCESSED	0x00000008		/* S: Page referenced */
+#define _PAGE_HWWRITE	0x00000010		/* H: Dirty & RW */
+#define _PAGE_HWEXEC	0x00000020		/* H: Execute permission */
+#define	_PAGE_USER	0x00000040		/* S: User page */
+#define	_PAGE_ENDIAN	0x00000080		/* H: E bit */
+#define	_PAGE_GUARDED	0x00000100		/* H: G bit */
+#define	_PAGE_COHERENT	0x00000200		/* H: M bit */
+#define _PAGE_FILE	0x00000400		/* S: nonlinear file mapping */
+#define	_PAGE_NO_CACHE	0x00000400		/* H: I bit */
+#define	_PAGE_WRITETHRU	0x00000800		/* H: W bit */
+
+/* TODO: Add large page lowmem mapping support */
+#define _PMD_PRESENT	0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD	(~PAGE_MASK)
+
+/* ERPN in a PTE never gets cleared, ignore it */
+#define _PTE_NONE_MASK 0xffffffff00000000ULL
+
 #elif defined(CONFIG_8xx)
 /* Definitions for 8xx embedded chips. */
 #define _PAGE_PRESENT	0x0001	/* Page is valid */
@@ -271,6 +324,16 @@
 #define _PAGE_DIRTY	0x0200	/* software: page changed */
 #define _PAGE_USER	0x0800	/* One of the PP bits, the other is USER&~RW */
 
+/*
+ * The 8xx TLB miss handler allegedly sets _PAGE_ACCESSED in the PTE
+ * for an address even if _PAGE_PRESENT is not set, as a performance
+ * optimization.  This is a bug if you ever want to use swap unless
+ * _PAGE_ACCESSED is 2, which it isn't, or unless you have 8xx-specific
+ * definitions for __swp_entry etc. below, which would be gross.
+ *  -- paulus
+ */
+#define _PTE_NONE_MASK	_PAGE_ACCESSED
+
 #else /* CONFIG_6xx */
 /* Definitions for 60x, 740/750, etc. */
 #define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
@@ -284,21 +347,19 @@
 #define _PAGE_ACCESSED	0x100	/* R: page referenced */
 #define _PAGE_EXEC	0x200	/* software: i-cache coherency required */
 #define _PAGE_RW	0x400	/* software: user write access allowed */
+
+#define _PTE_NONE_MASK	_PAGE_HASHPTE
+
 #endif
 
-/* The non-standard PowerPC MMUs, which includes the 4xx and 8xx (and
- * mabe 603e) have TLB miss handlers that unconditionally set the
- * _PAGE_ACCESSED flag as a performance optimization.  This causes
- * problems for the page_none() macro, just like the HASHPTE flag does
- * for the standard PowerPC MMUs.  Depending upon the MMU configuration,
- * either HASHPTE or ACCESSED will have to be masked to give us a
- * proper pte_none() condition.
+/*
+ * Some bits are only used on some cpu families...
  */
 #ifndef _PAGE_HASHPTE
 #define _PAGE_HASHPTE	0
-#define _PTE_NONE_MASK _PAGE_ACCESSED
-#else
-#define _PTE_NONE_MASK _PAGE_HASHPTE
+#endif
+#ifndef _PTE_NONE_MASK
+#define _PTE_NONE_MASK	0
 #endif
 #ifndef _PAGE_SHARED
 #define _PAGE_SHARED	0
@@ -324,7 +385,16 @@
 #define _PAGE_BASE	_PAGE_PRESENT | _PAGE_ACCESSED
 #define _PAGE_WRENABLE	_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE
 
+/*
+ * 44x wants _PAGE_GUARDED on all kernel pages for various reasons.
+ * Allegedly that doesn't hurt performance.  -- paulus
+ */
+#ifdef CONFIG_44x
+#define _PAGE_KERNEL	_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED | _PAGE_HWEXEC | _PAGE_GUARDED
+#else
 #define _PAGE_KERNEL	_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED | _PAGE_HWEXEC
+#endif
+
 #define _PAGE_IO	_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED
 
 #define PAGE_NONE	__pgprot(_PAGE_BASE)
@@ -438,7 +508,7 @@
  * and a page entry and page directory to the page they refer to.
  */
 
-static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+static inline pte_t mk_pte_phys(phys_addr_t physpage, pgprot_t pgprot)
 {
 	pte_t pte;
 	pte_val(pte) = physpage | pgprot_val(pgprot);
@@ -463,6 +533,8 @@
  *
  * pte_update clears and sets bit atomically, and returns
  * the old pte value.
+ * The ((unsigned long)(p+1) - 4) hack is to get to the least-significant
+ * 32 bits of the PTE regardless of whether PTEs are 32 or 64 bits.
  */
 static inline unsigned long pte_update(pte_t *p, unsigned long clr,
 				       unsigned long set)
@@ -477,7 +549,7 @@
 "	stwcx.	%1,0,%3\n\
 	bne-	1b"
 	: "=&r" (old), "=&r" (tmp), "=m" (*p)
-	: "r" (p), "r" (clr), "r" (set), "m" (*p)
+	: "r" ((unsigned long)(p+1) - 4), "r" (clr), "r" (set), "m" (*p)
 	: "cc" );
 	return old;
 }
@@ -544,7 +616,8 @@
 	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 }
 
-extern pgd_t swapper_pg_dir[1024];
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
 extern void paging_init(void);
 
 /*
diff -Nru a/include/asm-ppc/ppc4xx_dma.h b/include/asm-ppc/ppc4xx_dma.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc/ppc4xx_dma.h	Thu Aug 28 21:21:26 2003
@@ -0,0 +1,593 @@
+/*
+ * include/asm-ppc/ppc4xx_dma.h
+ *
+ * IBM PPC4xx DMA engine library
+ *
+ * Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * Cleaned by Matt Porter <mporter@mvista.com>
+ *
+ * Original code by Armin Kuster <akuster@mvista.com>
+ * and Pete Popov <ppopov@mvista.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.
+ *
+ * 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASMPPC_PPC4xx_DMA_H
+#define __ASMPPC_PPC4xx_DMA_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/mmu.h>
+#include <asm/ibm4xx.h>
+
+#undef DEBUG_4xxDMA
+
+#define MAX_PPC4xx_DMA_CHANNELS		4
+
+/* in arch/ppc/kernel/setup.c -- Cort */
+extern unsigned long DMA_MODE_WRITE, DMA_MODE_READ;
+
+/* 
+ * Function return status codes
+ * These values are used to indicate whether or not the function
+ * call was successful, or a bad/invalid parameter was passed.
+ */
+#define DMA_STATUS_GOOD			0
+#define DMA_STATUS_BAD_CHANNEL		1
+#define DMA_STATUS_BAD_HANDLE		2
+#define DMA_STATUS_BAD_MODE		3
+#define DMA_STATUS_NULL_POINTER		4
+#define DMA_STATUS_OUT_OF_MEMORY	5
+#define DMA_STATUS_SGL_LIST_EMPTY	6
+#define DMA_STATUS_GENERAL_ERROR	7
+#define DMA_STATUS_CHANNEL_NOTFREE	8
+
+#define DMA_CHANNEL_BUSY		0x80000000
+
+/*
+ * These indicate status as returned from the DMA Status Register.
+ */
+#define DMA_STATUS_NO_ERROR	0
+#define DMA_STATUS_CS		1	/* Count Status        */
+#define DMA_STATUS_TS		2	/* Transfer Status     */
+#define DMA_STATUS_DMA_ERROR	3	/* DMA Error Occurred  */
+#define DMA_STATUS_DMA_BUSY	4	/* The channel is busy */
+
+
+/*
+ * DMA Channel Control Registers
+ */
+
+#ifdef CONFIG_44x
+#define	PPC4xx_DMA_64BIT
+#define DMA_CR_OFFSET 1
+#else
+#define DMA_CR_OFFSET 0
+#endif
+
+#define DMA_CE_ENABLE        (1<<31)	/* DMA Channel Enable */
+#define SET_DMA_CE_ENABLE(x) (((x)&0x1)<<31)
+#define GET_DMA_CE_ENABLE(x) (((x)&DMA_CE_ENABLE)>>31)
+
+#define DMA_CIE_ENABLE        (1<<30)	/* DMA Channel Interrupt Enable */
+#define SET_DMA_CIE_ENABLE(x) (((x)&0x1)<<30)
+#define GET_DMA_CIE_ENABLE(x) (((x)&DMA_CIE_ENABLE)>>30)
+
+#define DMA_TD                (1<<29)
+#define SET_DMA_TD(x)         (((x)&0x1)<<29)
+#define GET_DMA_TD(x)         (((x)&DMA_TD)>>29)
+
+#define DMA_PL                (1<<28)	/* Peripheral Location */
+#define SET_DMA_PL(x)         (((x)&0x1)<<28)
+#define GET_DMA_PL(x)         (((x)&DMA_PL)>>28)
+
+#define EXTERNAL_PERIPHERAL    0
+#define INTERNAL_PERIPHERAL    1
+
+#define SET_DMA_PW(x)     (((x)&0x3)<<(26-DMA_CR_OFFSET))	/* Peripheral Width */
+#define DMA_PW_MASK       SET_DMA_PW(3)
+#define   PW_8                 0
+#define   PW_16                1
+#define   PW_32                2
+#define   PW_64                3
+/* FIXME: Add PW_128 support for 440GP DMA block */
+#define GET_DMA_PW(x)     (((x)&DMA_PW_MASK)>>(26-DMA_CR_OFFSET))
+
+#define DMA_DAI           (1<<(25-DMA_CR_OFFSET))	/* Destination Address Increment */
+#define SET_DMA_DAI(x)    (((x)&0x1)<<(25-DMA_CR_OFFSET))
+
+#define DMA_SAI           (1<<(24-DMA_CR_OFFSET))	/* Source Address Increment */
+#define SET_DMA_SAI(x)    (((x)&0x1)<<(24-DMA_CR_OFFSET))
+
+#define DMA_BEN           (1<<(23-DMA_CR_OFFSET))	/* Buffer Enable */
+#define SET_DMA_BEN(x)    (((x)&0x1)<<(23-DMA_CR_OFFSET))
+
+#define SET_DMA_TM(x)     (((x)&0x3)<<(21-DMA_CR_OFFSET))	/* Transfer Mode */
+#define DMA_TM_MASK       SET_DMA_TM(3)
+#define   TM_PERIPHERAL        0	/* Peripheral */
+#define   TM_RESERVED          1	/* Reserved */
+#define   TM_S_MM              2	/* Memory to Memory */
+#define   TM_D_MM              3	/* Device Paced Memory to Memory */
+#define GET_DMA_TM(x)     (((x)&DMA_TM_MASK)>>(21-DMA_CR_OFFSET))
+
+#define SET_DMA_PSC(x)    (((x)&0x3)<<(19-DMA_CR_OFFSET))	/* Peripheral Setup Cycles */
+#define DMA_PSC_MASK      SET_DMA_PSC(3)
+#define GET_DMA_PSC(x)    (((x)&DMA_PSC_MASK)>>(19-DMA_CR_OFFSET))
+
+#define SET_DMA_PWC(x)    (((x)&0x3F)<<(13-DMA_CR_OFFSET))	/* Peripheral Wait Cycles */
+#define DMA_PWC_MASK      SET_DMA_PWC(0x3F)
+#define GET_DMA_PWC(x)    (((x)&DMA_PWC_MASK)>>(13-DMA_CR_OFFSET))
+
+#define SET_DMA_PHC(x)    (((x)&0x7)<<(10-DMA_CR_OFFSET))	/* Peripheral Hold Cycles */
+#define DMA_PHC_MASK      SET_DMA_PHC(0x7)
+#define GET_DMA_PHC(x)    (((x)&DMA_PHC_MASK)>>(10-DMA_CR_OFFSET))
+
+#define DMA_ETD_OUTPUT     (1<<(9-DMA_CR_OFFSET))	/* EOT pin is a TC output */
+#define SET_DMA_ETD(x)     (((x)&0x1)<<(9-DMA_CR_OFFSET))
+
+#define DMA_TCE_ENABLE     (1<<(8-DMA_CR_OFFSET))
+#define SET_DMA_TCE(x)     (((x)&0x1)<<(8-DMA_CR_OFFSET))
+
+#define DMA_DEC            (1<<(2)	/* Address Decrement */
+#define SET_DMA_DEC(x)     (((x)&0x1)<<2)
+#define GET_DMA_DEC(x)     (((x)&DMA_DEC)>>2)
+
+/*
+ * Transfer Modes
+ * These modes are defined in a way that makes it possible to
+ * simply "or" in the value in the control register.
+ */
+
+#define DMA_MODE_MM		(SET_DMA_TM(TM_S_MM))	/* memory to memory */
+
+				/* Device-paced memory to memory, */
+				/* device is at source address    */
+#define DMA_MODE_MM_DEVATSRC	(DMA_TD | SET_DMA_TM(TM_D_MM))
+
+				/* Device-paced memory to memory,      */
+				/* device is at destination address    */
+#define DMA_MODE_MM_DEVATDST	(SET_DMA_TM(TM_D_MM))
+
+/* 405gp/440gp */
+#define SET_DMA_PREFETCH(x)   (((x)&0x3)<<(4-DMA_CR_OFFSET))	/* Memory Read Prefetch */
+#define DMA_PREFETCH_MASK      SET_DMA_PREFETCH(3)
+#define   PREFETCH_1           0	/* Prefetch 1 Double Word */
+#define   PREFETCH_2           1
+#define   PREFETCH_4           2
+#define GET_DMA_PREFETCH(x) (((x)&DMA_PREFETCH_MASK)>>(4-DMA_CR_OFFSET))
+
+#define DMA_PCE            (1<<(3-DMA_CR_OFFSET))	/* Parity Check Enable */
+#define SET_DMA_PCE(x)     (((x)&0x1)<<(3-DMA_CR_OFFSET))
+#define GET_DMA_PCE(x)     (((x)&DMA_PCE)>>(3-DMA_CR_OFFSET))
+
+/* stb3x */
+
+#define DMA_ECE_ENABLE (1<<5)
+#define SET_DMA_ECE(x) (((x)&0x1)<<5)
+#define GET_DMA_ECE(x) (((x)&DMA_ECE_ENABLE)>>5)
+
+#define DMA_TCD_DISABLE	(1<<4)
+#define SET_DMA_TCD(x) (((x)&0x1)<<4)
+#define GET_DMA_TCD(x) (((x)&DMA_TCD_DISABLE)>>4)
+
+typedef uint32_t sgl_handle_t;
+
+#ifdef CONFIG_PPC4xx_EDMA
+
+#define SGL_LIST_SIZE 4096
+#define DMA_PPC4xx_SIZE SGL_LIST_SIZE
+
+#define SET_DMA_PRIORITY(x)   (((x)&0x3)<<(6-DMA_CR_OFFSET))	/* DMA Channel Priority */
+#define DMA_PRIORITY_MASK SET_DMA_PRIORITY(3)
+#define PRIORITY_LOW           0
+#define PRIORITY_MID_LOW       1
+#define PRIORITY_MID_HIGH      2
+#define PRIORITY_HIGH          3
+#define GET_DMA_PRIORITY(x) (((x)&DMA_PRIORITY_MASK)>>(6-DMA_CR_OFFSET))
+
+/* 
+ * DMA Polarity Configuration Register
+ */
+
+#define DMAReq0_ActiveLow (1<<31)
+#define DMAAck0_ActiveLow (1<<30)
+#define EOT0_ActiveLow    (1<<29)	/* End of Transfer      */
+
+#define DMAReq1_ActiveLow (1<<28)
+#define DMAAck1_ActiveLow (1<<27)
+#define EOT1_ActiveLow    (1<<26)
+
+#define DMAReq2_ActiveLow (1<<25)
+#define DMAAck2_ActiveLow (1<<24)
+#define EOT2_ActiveLow    (1<<23)
+
+#define DMAReq3_ActiveLow (1<<22)
+#define DMAAck3_ActiveLow (1<<21)
+#define EOT3_ActiveLow    (1<<20)
+
+/*
+ * DMA Sleep Mode Register
+ */
+#define SLEEP_MODE_ENABLE (1<<21)
+
+/*
+ * DMA Status Register
+ */
+#define DMA_CS0           (1<<31)	/* Terminal Count has been reached */
+#define DMA_CS1           (1<<30)
+#define DMA_CS2           (1<<29)
+#define DMA_CS3           (1<<28)
+
+#define DMA_TS0           (1<<27)	/* End of Transfer has been requested */
+#define DMA_TS1           (1<<26)
+#define DMA_TS2           (1<<25)
+#define DMA_TS3           (1<<24)
+
+#define DMA_CH0_ERR       (1<<23)	/* DMA Chanel 0 Error */
+#define DMA_CH1_ERR       (1<<22)
+#define DMA_CH2_ERR       (1<<21)
+#define DMA_CH3_ERR       (1<<20)
+
+#define DMA_IN_DMA_REQ0   (1<<19)	/* Internal DMA Request is pending */
+#define DMA_IN_DMA_REQ1   (1<<18)
+#define DMA_IN_DMA_REQ2   (1<<17)
+#define DMA_IN_DMA_REQ3   (1<<16)
+
+#define DMA_EXT_DMA_REQ0  (1<<15)	/* External DMA Request is pending */
+#define DMA_EXT_DMA_REQ1  (1<<14)
+#define DMA_EXT_DMA_REQ2  (1<<13)
+#define DMA_EXT_DMA_REQ3  (1<<12)
+
+#define DMA_CH0_BUSY      (1<<11)	/* DMA Channel 0 Busy */
+#define DMA_CH1_BUSY      (1<<10)
+#define DMA_CH2_BUSY       (1<<9)
+#define DMA_CH3_BUSY       (1<<8)
+
+#define DMA_SG0            (1<<7)	/* DMA Channel 0 Scatter/Gather in progress */
+#define DMA_SG1            (1<<6)
+#define DMA_SG2            (1<<5)
+#define DMA_SG3            (1<<4)
+
+/*
+ * DMA SG Command Register
+ */
+#define SSG0_ENABLE        (1<<31)	/* Start Scatter Gather */
+#define SSG1_ENABLE        (1<<30)
+#define SSG2_ENABLE        (1<<29)
+#define SSG3_ENABLE        (1<<28)
+#define SSG0_MASK_ENABLE   (1<<15)	/* Enable writing to SSG0 bit */
+#define SSG1_MASK_ENABLE   (1<<14)
+#define SSG2_MASK_ENABLE   (1<<13)
+#define SSG3_MASK_ENABLE   (1<<12)
+
+/*
+ * DMA Scatter/Gather Descriptor Bit fields 
+ */
+#define SG_LINK            (1<<31)	/* Link */
+#define SG_TCI_ENABLE      (1<<29)	/* Enable Terminal Count Interrupt */
+#define SG_ETI_ENABLE      (1<<28)	/* Enable End of Transfer Interrupt */
+#define SG_ERI_ENABLE      (1<<27)	/* Enable Error Interrupt */
+#define SG_COUNT_MASK       0xFFFF	/* Count Field */
+
+#define SET_DMA_CONTROL \
+ 		(SET_DMA_CIE_ENABLE(p_init->int_enable) | /* interrupt enable         */ \
+ 		SET_DMA_BEN(p_init->buffer_enable)     | /* buffer enable            */\
+		SET_DMA_ETD(p_init->etd_output)        | /* end of transfer pin      */ \
+	       	SET_DMA_TCE(p_init->tce_enable)        | /* terminal count enable    */ \
+                SET_DMA_PL(p_init->pl)                 | /* peripheral location      */ \
+                SET_DMA_DAI(p_init->dai)               | /* dest addr increment      */ \
+                SET_DMA_SAI(p_init->sai)               | /* src addr increment       */ \
+                SET_DMA_PRIORITY(p_init->cp)           |  /* channel priority        */ \
+                SET_DMA_PW(p_init->pwidth)             |  /* peripheral/bus width    */ \
+                SET_DMA_PSC(p_init->psc)               |  /* peripheral setup cycles */ \
+                SET_DMA_PWC(p_init->pwc)               |  /* peripheral wait cycles  */ \
+                SET_DMA_PHC(p_init->phc)               |  /* peripheral hold cycles  */ \
+                SET_DMA_PREFETCH(p_init->pf)              /* read prefetch           */)
+
+#define GET_DMA_POLARITY(chan) (DMAReq##chan##_ActiveLow | DMAAck##chan##_ActiveLow | EOT##chan##_ActiveLow)
+
+#elif defined(CONFIG_STBXXX_DMA)		/* stb03xxx */
+
+#define DMA_PPC4xx_SIZE	4096
+
+/*
+ * DMA Status Register
+ */
+
+#define SET_DMA_PRIORITY(x)   (((x)&0x00800001))	/* DMA Channel Priority */
+#define DMA_PRIORITY_MASK	0x00800001
+#define   PRIORITY_LOW         	0x00000000
+#define   PRIORITY_MID_LOW     	0x00000001
+#define   PRIORITY_MID_HIGH    	0x00800000
+#define   PRIORITY_HIGH        	0x00800001
+#define GET_DMA_PRIORITY(x) (((((x)&DMA_PRIORITY_MASK) &0x00800000) >> 22 ) | (((x)&DMA_PRIORITY_MASK) &0x00000001))
+
+#define DMA_CS0           (1<<31)	/* Terminal Count has been reached */
+#define DMA_CS1           (1<<30)
+#define DMA_CS2           (1<<29)
+#define DMA_CS3           (1<<28)
+
+#define DMA_TS0           (1<<27)	/* End of Transfer has been requested */
+#define DMA_TS1           (1<<26)
+#define DMA_TS2           (1<<25)
+#define DMA_TS3           (1<<24)
+
+#define DMA_CH0_ERR       (1<<23)	/* DMA Chanel 0 Error */
+#define DMA_CH1_ERR       (1<<22)
+#define DMA_CH2_ERR       (1<<21)
+#define DMA_CH3_ERR       (1<<20)
+
+#define DMA_CT0		  (1<<19)	/* Chained transfere */
+
+#define DMA_IN_DMA_REQ0   (1<<18)	/* Internal DMA Request is pending */
+#define DMA_IN_DMA_REQ1   (1<<17)
+#define DMA_IN_DMA_REQ2   (1<<16)
+#define DMA_IN_DMA_REQ3   (1<<15)
+
+#define DMA_EXT_DMA_REQ0  (1<<14)	/* External DMA Request is pending */
+#define DMA_EXT_DMA_REQ1  (1<<13)
+#define DMA_EXT_DMA_REQ2  (1<<12)
+#define DMA_EXT_DMA_REQ3  (1<<11)
+
+#define DMA_CH0_BUSY      (1<<10)	/* DMA Channel 0 Busy */
+#define DMA_CH1_BUSY      (1<<9)
+#define DMA_CH2_BUSY       (1<<8)
+#define DMA_CH3_BUSY       (1<<7)
+
+#define DMA_CT1            (1<<6)	/* Chained transfere */
+#define DMA_CT2            (1<<5)
+#define DMA_CT3            (1<<4)
+
+#define DMA_CH_ENABLE (1<<7)
+#define SET_DMA_CH(x) (((x)&0x1)<<7)
+#define GET_DMA_CH(x) (((x)&DMA_CH_ENABLE)>>7)
+
+/* STBx25xxx dma unique */
+/* enable device port on a dma channel 
+ * example ext 0 on dma 1
+ */
+
+#define	SSP0_RECV	15
+#define	SSP0_XMIT	14
+#define EXT_DMA_0	12
+#define	SC1_XMIT	11
+#define SC1_RECV	10
+#define EXT_DMA_2	9 
+#define	EXT_DMA_3	8 
+#define SERIAL2_XMIT	7
+#define SERIAL2_RECV	6
+#define SC0_XMIT 	5
+#define	SC0_RECV	4
+#define	SERIAL1_XMIT	3 
+#define SERIAL1_RECV	2
+#define	SERIAL0_XMIT	1
+#define SERIAL0_RECV	0
+
+#define DMA_CHAN_0	1
+#define DMA_CHAN_1	2
+#define DMA_CHAN_2	3
+#define DMA_CHAN_3	4
+
+/* end STBx25xx */
+
+/*
+ * Bit 30 must be one for Redwoods, otherwise transfers may receive errors.
+ */
+#define DMA_CR_MB0 0x2
+
+#define SET_DMA_CONTROL \
+       		(SET_DMA_CIE_ENABLE(p_init->int_enable) |  /* interrupt enable         */ \
+		SET_DMA_ETD(p_init->etd_output)        |  /* end of transfer pin      */ \
+		SET_DMA_TCE(p_init->tce_enable)        |  /* terminal count enable    */ \
+		SET_DMA_PL(p_init->pl)                 |  /* peripheral location      */ \
+		SET_DMA_DAI(p_init->dai)               |  /* dest addr increment      */ \
+		SET_DMA_SAI(p_init->sai)               |  /* src addr increment       */ \
+		SET_DMA_PRIORITY(p_init->cp)           |  /* channel priority        */  \
+		SET_DMA_PW(p_init->pwidth)             |  /* peripheral/bus width    */ \
+		SET_DMA_PSC(p_init->psc)               |  /* peripheral setup cycles */ \
+		SET_DMA_PWC(p_init->pwc)               |  /* peripheral wait cycles  */ \
+		SET_DMA_PHC(p_init->phc)               |  /* peripheral hold cycles  */ \
+		SET_DMA_TCD(p_init->tcd_disable)	  |  /* TC chain mode disable   */ \
+		SET_DMA_ECE(p_init->ece_enable)	  |  /* ECE chanin mode enable  */ \
+		SET_DMA_CH(p_init->ch_enable)	|    /* Chain enable 	        */ \
+		DMA_CR_MB0				/* must be one */)
+
+#define GET_DMA_POLARITY(chan) chan
+
+#endif
+
+typedef struct {
+	unsigned short in_use;	/* set when channel is being used, clr when
+				 * available.
+				 */
+	/* 
+	 * Valid polarity settings:
+	 *   DMAReq0_ActiveLow
+	 *   DMAAck0_ActiveLow
+	 *   EOT0_ActiveLow
+	 *
+	 *   DMAReq1_ActiveLow
+	 *   DMAAck1_ActiveLow
+	 *   EOT1_ActiveLow
+	 * 
+	 *   DMAReq2_ActiveLow
+	 *   DMAAck2_ActiveLow
+	 *   EOT2_ActiveLow
+	 *
+	 *   DMAReq3_ActiveLow 
+	 *   DMAAck3_ActiveLow
+	 *   EOT3_ActiveLow
+	 */
+	unsigned int polarity;
+
+	char buffer_enable;	/* Boolean: buffer enable            */
+	char tce_enable;	/* Boolean: terminal count enable    */
+	char etd_output;	/* Boolean: eot pin is a tc output   */
+	char pce;		/* Boolean: parity check enable      */
+
+	/*
+	 * Peripheral location:
+	 * INTERNAL_PERIPHERAL (UART0 on the 405GP)
+	 * EXTERNAL_PERIPHERAL
+	 */
+	char pl;		/* internal/external peripheral      */
+
+	/*
+	 * Valid pwidth settings:
+	 *   PW_8
+	 *   PW_16
+	 *   PW_32
+	 *   PW_64
+	 */
+	unsigned int pwidth;
+
+	char dai;		/* Boolean: dst address increment   */
+	char sai;		/* Boolean: src address increment   */
+
+	/*
+	 * Valid psc settings: 0-3
+	 */
+	unsigned int psc;	/* Peripheral Setup Cycles         */
+
+	/*
+	 * Valid pwc settings:
+	 * 0-63
+	 */
+	unsigned int pwc;	/* Peripheral Wait Cycles          */
+
+	/*
+	 * Valid phc settings:
+	 * 0-7
+	 */
+	unsigned int phc;	/* Peripheral Hold Cycles          */
+
+	/*
+	 * Valid cp (channel priority) settings:
+	 *   PRIORITY_LOW
+	 *   PRIORITY_MID_LOW
+	 *   PRIORITY_MID_HIGH
+	 *   PRIORITY_HIGH
+	 */
+	unsigned int cp;	/* channel priority                */
+
+	/*
+	 * Valid pf (memory read prefetch) settings:
+	 *
+	 *   PREFETCH_1
+	 *   PREFETCH_2
+	 *   PREFETCH_4
+	 */
+	unsigned int pf;	/* memory read prefetch            */
+
+	/*
+	 * Boolean: channel interrupt enable
+	 * NOTE: for sgl transfers, only the last descriptor will be setup to
+	 * interrupt.
+	 */
+	char int_enable;
+
+	char shift;		/* easy access to byte_count shift, based on */
+	/* the width of the channel                  */
+
+	uint32_t control;	/* channel control word                      */
+
+	/* These variabled are used ONLY in single dma transfers              */
+	unsigned int mode;	/* transfer mode                     */
+	phys_addr_t addr;
+	char ce;		/* channel enable */
+#ifdef CONFIG_STB03xxx
+	char ch_enable;
+	char tcd_disable;
+	char ece_enable;
+	char td;		/* transfer direction */
+#endif
+
+} ppc_dma_ch_t;
+
+/*
+ * PPC44x DMA implementations have a slightly different
+ * descriptor layout.  Probably moved about due to the
+ * change to 64-bit addresses and link pointer. I don't
+ * know why they didn't just leave control_count after
+ * the dst_addr.
+ */
+#ifdef PPC4xx_DMA_64BIT
+typedef struct {
+	uint32_t control;
+	uint32_t control_count;
+	phys_addr_t src_addr;
+	phys_addr_t dst_addr;
+	phys_addr_t next;
+} ppc_sgl_t;
+#else
+typedef struct {
+	uint32_t control;
+	phys_addr_t src_addr;
+	phys_addr_t dst_addr;
+	uint32_t control_count;
+	uint32_t next;
+} ppc_sgl_t;
+#endif
+
+typedef struct {
+	unsigned int dmanr;
+	uint32_t control;	/* channel ctrl word; loaded from each descrptr */
+	uint32_t sgl_control;	/* LK, TCI, ETI, and ERI bits in sgl descriptor */
+	dma_addr_t dma_addr;	/* dma (physical) address of this list          */
+	ppc_sgl_t *phead;
+	ppc_sgl_t *ptail;
+	uint32_t pad32[2];
+
+} sgl_list_info_t;
+
+typedef struct {
+	phys_addr_t *src_addr;
+	phys_addr_t *dst_addr;
+	phys_addr_t dma_src_addr;
+	phys_addr_t dma_dst_addr;
+} pci_alloc_desc_t;
+
+extern ppc_dma_ch_t dma_channels[];
+
+/*
+ * The DMA API are in ppc4xx_dma.c and ppc4xx_sgdma.c
+ */
+extern int ppc4xx_init_dma_channel(unsigned int, ppc_dma_ch_t *);
+extern int ppc4xx_get_channel_config(unsigned int, ppc_dma_ch_t *);
+extern int ppc4xx_set_channel_priority(unsigned int, unsigned int);
+extern unsigned int ppc4xx_get_peripheral_width(unsigned int);
+extern int ppc4xx_alloc_dma_handle(sgl_handle_t *, unsigned int, unsigned int);
+extern void ppc4xx_free_dma_handle(sgl_handle_t);
+extern int ppc4xx_get_dma_status(void);
+extern void ppc4xx_set_src_addr(int dmanr, phys_addr_t src_addr);
+extern void ppc4xx_set_dst_addr(int dmanr, phys_addr_t dst_addr);
+extern void ppc4xx_enable_dma(unsigned int dmanr);
+extern void ppc4xx_disable_dma(unsigned int dmanr);
+extern void ppc4xx_set_dma_count(unsigned int dmanr, unsigned int count);
+extern int ppc4xx_get_dma_residue(unsigned int dmanr);
+extern void ppc4xx_set_dma_addr2(unsigned int dmanr, phys_addr_t src_dma_addr,
+				 phys_addr_t dst_dma_addr);
+extern int ppc4xx_enable_dma_interrupt(unsigned int dmanr);
+extern int ppc4xx_disable_dma_interrupt(unsigned int dmanr);
+extern int ppc4xx_clr_dma_status(unsigned int dmanr);
+extern int ppc4xx_map_dma_port(unsigned int dmanr, unsigned int ocp_dma,short dma_chan);
+extern int ppc4xx_disable_dma_port(unsigned int dmanr, unsigned int ocp_dma,short dma_chan);
+extern int ppc4xx_set_dma_mode(unsigned int dmanr, unsigned int mode);
+
+/* These are in kernel/dma.c: */
+
+/* reserve a DMA channel */
+extern int request_dma(unsigned int dmanr, const char *device_id);
+/* release it again */
+extern void free_dma(unsigned int dmanr);
+#endif
+#endif				/* __KERNEL__ */
diff -Nru a/include/asm-ppc/ppc_asm.h b/include/asm-ppc/ppc_asm.h
--- a/include/asm-ppc/ppc_asm.h	Thu Jul  3 09:56:35 2003
+++ b/include/asm-ppc/ppc_asm.h	Thu Aug 28 05:31:04 2003
@@ -112,6 +112,12 @@
 	bdnz	0b
 #endif
 
+#ifdef CONFIG_BOOKE
+#define tophys(rd,rs)				\
+	mr      rd,rs
+#define tovirt(rd,rs)				\
+	mr      rd,rs
+#else /* CONFIG_BOOKE */
 /*
  * On APUS (Amiga PowerPC cpu upgrade board), we don't know the
  * physical base address of RAM at compile time.
@@ -129,6 +135,7 @@
 	.align  1;				\
 	.long   0b;				\
 	.previous
+#endif /* CONFIG_BOOKE */
 
 /*
  * On 64-bit cpus, we use the rfid instruction instead of rfi, but
diff -Nru a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h
--- a/include/asm-ppc/processor.h	Thu Jul 17 10:28:12 2003
+++ b/include/asm-ppc/processor.h	Fri Aug 29 03:56:51 2003
@@ -3,6 +3,12 @@
 #define __ASM_PPC_PROCESSOR_H
 
 /*
+ * The Book E definitions are hacked into here for 44x right
+ * now.  This whole thing needs regorganized (maybe per-core
+ * files) * so that it becomes readable. -Matt
+ */
+
+/*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
  */
@@ -45,6 +51,11 @@
 #define MSR_RI		(1<<1)		/* Recoverable Exception */
 #define MSR_LE		(1<<0) 		/* Little Endian */
 
+#ifdef CONFIG_BOOKE
+#define MSR_IS		MSR_IR		/* Instruction Space */
+#define MSR_DS		MSR_DR		/* Data Space */
+#endif
+
 #ifdef CONFIG_APUS_FAST_EXCEPT
 #define MSR_		MSR_ME|MSR_IP|MSR_RI
 #else
@@ -89,8 +100,13 @@
 #define	SPRN_CDBCR	0x3D7	/* Cache Debug Control Register */
 #define	SPRN_CTR	0x009	/* Count Register */
 #define	SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
+#ifdef CONFIG_BOOKE
+#define	SPRN_DAC1	0x13C	/* Book E Data Address Compare 1 */
+#define	SPRN_DAC2	0x13D	/* Book E Data Address Compare 2 */
+#else
 #define	SPRN_DAC1	0x3F6	/* Data Address Compare 1 */
 #define	SPRN_DAC2	0x3F7	/* Data Address Compare 2 */
+#endif /* CONFIG_BOOKE */
 #define	SPRN_DAR	0x013	/* Data Address Register */
 #define	SPRN_DBAT0L	0x219	/* Data BAT 0 Lower Register */
 #define	SPRN_DBAT0U	0x218	/* Data BAT 0 Upper Register */
@@ -109,7 +125,7 @@
 #define	SPRN_DBAT7L	0x23F	/* Data BAT 7 Lower Register */
 #define	SPRN_DBAT7U	0x23E	/* Data BAT 7 Upper Register */
 
-#define	SPRN_DBCR	0x3F2	/* Debug Control Regsiter */
+#define	SPRN_DBCR	0x3F2	/* Debug Control Register */
 #define	  DBCR_EDM	0x80000000
 #define	  DBCR_IDM	0x40000000
 #define	  DBCR_RST(x)	(((x) & 0x3) << 28)
@@ -142,7 +158,11 @@
 #define	  DBCR_SDA	0x00000004	/* Second DAC Enable */
 #define	  DBCR_JOI	0x00000002	/* JTAG Serial Outbound Int. Enable */
 #define	  DBCR_JII	0x00000001	/* JTAG Serial Inbound Int. Enable */
+#ifdef CONFIG_BOOKE
+#define	SPRN_DBCR0	0x134		/* Book E Debug Control Register 0 */
+#else
 #define	SPRN_DBCR0	0x3F2		/* Debug Control Register 0 */
+#endif /* CONFIG_BOOKE */
 #define   DBCR0_EDM         0x80000000  /* External Debug Mode             */
 #define   DBCR0_IDM         0x40000000  /* Internal Debug Mode             */
 #define   DBCR0_RST         0x30000000  /* all the bits in the RST field   */
@@ -165,10 +185,17 @@
 #define   DBCR0_IA12T       0x00008000  /* Instr Addr 1-2 range Toggle     */
 #define   DBCR0_IA34T       0x00004000  /* Instr Addr 3-4 range Toggle     */
 #define   DBCR0_FT          0x00000001  /* Freeze Timers on debug event    */
+#ifdef CONFIG_BOOKE
+#define	SPRN_DBCR1	0x135		/* Book E Debug Control Register 1 */
+#define	SPRN_DBSR	0x130		/* Book E Debug Status Register    */
+#define   DBSR_IC	    0x08000000	/* Book E Instruction Completion   */
+#define   DBSR_TIE	    0x01000000	/* Book E Trap Instruction debug Event*/
+#else /* CONFIG_BOOKE */
 #define	SPRN_DBCR1	0x3BD		/* Debug Control Register 1 */
 #define	SPRN_DBSR	0x3F0		/* Debug Status Register */
 #define   DBSR_IC	    0x80000000	/* Instruction Completion          */
 #define   DBSR_TIE	    0x10000000	/* Trap Instruction debug Event    */
+#endif /* CONFIG_BOOKE */
 #define	SPRN_DCCR	0x3FA	/* Data Cache Cacheability Register */
 #define	  DCCR_NOCACHE		0	/* Noncacheable */
 #define	  DCCR_CACHE		1	/* Cacheable */
@@ -176,7 +203,11 @@
 #define	SPRN_DCWR	0x3BA	/* Data Cache Write-thru Register */
 #define	  DCWR_COPY		0	/* Copy-back */
 #define	  DCWR_WRITE		1	/* Write-through */
+#ifdef CONFIG_BOOKE
+#define	SPRN_DEAR	0x03D	/* Book E Data Error Address Register */
+#else
 #define	SPRN_DEAR	0x3D5	/* Data Error Address Register */
+#endif /* CONFIG_BOOKE */
 #define	SPRN_DEC	0x016	/* Decrement Register */
 #define	SPRN_DER	0x095	/* Debug Enable Regsiter */
 #define   DER_RSTE	0x40000000	/* Reset Interrupt */
@@ -201,7 +232,11 @@
 #define	SPRN_DMISS	0x3D0		/* Data TLB Miss Register */
 #define	SPRN_DSISR	0x012		/* Data Storage Interrupt Status Register */
 #define	SPRN_EAR	0x11A		/* External Address Register */
+#ifdef CONFIG_BOOKE
+#define	SPRN_ESR	0x03E		/* Book E Exception Syndrome Register */
+#else
 #define	SPRN_ESR	0x3D4		/* Exception Syndrome Register */
+#endif /* CONFIG_BOOKE */
 #define	  ESR_IMCP	0x80000000	/* Instr. Machine Check - Protection */
 #define	  ESR_IMCN	0x40000000	/* Instr. Machine Check - Non-config */
 #define	  ESR_IMCB	0x20000000	/* Instr. Machine Check - Bus error */
@@ -261,8 +296,13 @@
 #define	  HID1_ABE	(1<<10)		/* 7450 Address Broadcast Enable */
 #define	SPRN_HID2	0x3F8	/* Hardware Implementation Register 2 */
 #define	SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
+#ifdef CONFIG_BOOKE
+#define	SPRN_IAC1	0x138	/* Book E Instruction Address Compare 1 */
+#define	SPRN_IAC2	0x139	/* Book E Instruction Address Compare 2 */
+#else
 #define	SPRN_IAC1	0x3F4	/* Instruction Address Compare 1 */
 #define	SPRN_IAC2	0x3F5	/* Instruction Address Compare 2 */
+#endif /* CONFIG_BOOKE */
 #define	SPRN_IBAT0L	0x211	/* Instruction BAT 0 Lower Register */
 #define	SPRN_IBAT0U	0x210	/* Instruction BAT 0 Upper Register */
 #define	SPRN_IBAT1L	0x213	/* Instruction BAT 1 Lower Register */
@@ -353,8 +393,13 @@
 #define	SPRN_PBL2	0x3FE	/* Protection Bound Lower 2 */
 #define	SPRN_PBU1	0x3FD	/* Protection Bound Upper 1 */
 #define	SPRN_PBU2	0x3FF	/* Protection Bound Upper 2 */
+#ifdef CONFIG_BOOKE
+#define	SPRN_PID	0x030	/* Book E Process ID */
+#define	SPRN_PIR	0x11E	/* Book E Processor Identification Register */
+#else
 #define	SPRN_PID	0x3B1	/* Process ID */
 #define	SPRN_PIR	0x3FF	/* Processor Identification Register */
+#endif /* CONFIG_BOOKE */
 #define	SPRN_PIT	0x3DB	/* Programmable Interval Timer */
 #define	SPRN_PMC1	0x3B9	/* Performance Counter Register 1 */
 #define	SPRN_PMC2	0x3BA	/* Performance Counter Register 2 */
@@ -379,6 +424,14 @@
 #define	SPRN_SPRG5	0x115	/* Special Purpose Register General 5 (4xx) */
 #define	SPRN_SPRG6	0x116	/* Special Purpose Register General 6 (4xx) */
 #define	SPRN_SPRG7	0x117	/* Special Purpose Register General 7 (4xx) */
+#define SPRG4R	SPRN_SPRG4R	/* Book E Supervisor Private Registers */
+#define SPRG5R	SPRN_SPRG5R
+#define SPRG6R	SPRN_SPRG6R
+#define SPRG7R	SPRN_SPRG7R
+#define SPRG4W	SPRN_SPRG4W
+#define SPRG5W	SPRN_SPRG5W
+#define SPRG6W	SPRN_SPRG6W
+#define SPRG7W	SPRN_SPRG7W
 #define	SPRN_SRR0	0x01A	/* Save/Restore Register 0 */
 #define	SPRN_SRR1	0x01B	/* Save/Restore Register 1 */
 #define	SPRN_SRR2	0x3DE	/* Save/Restore Register 2 */
@@ -392,7 +445,11 @@
 #define	SPRN_TBRU	0x10D	/* Time Base Read Upper Register (user, R/O) */
 #define	SPRN_TBWL	0x11C	/* Time Base Lower Register (super, R/W) */
 #define	SPRN_TBWU	0x11D	/* Time Base Upper Register (super, R/W) */
+#ifdef CONFIG_BOOKE
+#define	SPRN_TCR	0x154	/* Book E Timer Control Register */
+#else
 #define	SPRN_TCR	0x3DA	/* Timer Control Register */
+#endif /* CONFIG_BOOKE */
 #define	  TCR_WP(x)		(((x)&0x3)<<30)	/* WDT Period */
 #define	    WP_2_17		0		/* 2^17 clocks */
 #define	    WP_2_21		1		/* 2^21 clocks */
@@ -405,6 +462,7 @@
 #define	    WRC_SYSTEM		3		/* System reset will occur */
 #define	  TCR_WIE		0x08000000	/* WDT Interrupt Enable */
 #define	  TCR_PIE		0x04000000	/* PIT Interrupt Enable */
+#define	  TCR_DIE		TCR_PIE		/* DEC Interrupt Enable */
 #define	  TCR_FP(x)		(((x)&0x3)<<24)	/* FIT Period */
 #define	    FP_2_9		0		/* 2^9 clocks */
 #define	    FP_2_13		1		/* 2^13 clocks */
@@ -425,7 +483,11 @@
 #define	SPRN_THRM3	0x3FE	/* Thermal Management Register 3 */
 #define	  THRM3_E		(1<<0)
 #define	SPRN_TLBMISS	0x3D4	/* 980 7450 TLB Miss Register */
+#ifdef CONFIG_BOOKE
+#define	SPRN_TSR	0x150	/* Book E Timer Status Register */
+#else
 #define	SPRN_TSR	0x3D8	/* Timer Status Register */
+#endif /* CONFIG_BOOKE */
 #define	  TSR_ENW		0x80000000	/* Enable Next Watchdog */
 #define	  TSR_WIS		0x40000000	/* WDT Interrupt Status */
 #define	  TSR_WRS(x)		(((x)&0x3)<<28)	/* WDT Reset Status */
@@ -434,6 +496,7 @@
 #define	    WRS_CHIP		2		/* WDT forced chip reset */
 #define	    WRS_SYSTEM		3		/* WDT forced system reset */
 #define	  TSR_PIS		0x08000000	/* PIT Interrupt Status */
+#define	  TSR_DIS		TSR_PIS		/* DEC Interrupt Status */
 #define	  TSR_FIS		0x04000000	/* FIT Interrupt Status */
 #define	SPRN_UMMCR0	0x3A8	/* User Monitor Mode Control Register 0 */
 #define	SPRN_UMMCR1	0x3AC	/* User Monitor Mode Control Register 0 */
@@ -446,6 +509,45 @@
 #define	SPRN_XER	0x001	/* Fixed Point Exception Register */
 #define	SPRN_ZPR	0x3B0	/* Zone Protection Register */
 
+/* Book E definitions */
+#define SPRN_DECAR	0x036	/* Decrementer Auto Reload Register */
+#define SPRN_CSRR0	0x03A	/* Critical Save and Restore Register 0 */
+#define SPRN_CSRR1	0x03B	/* Critical Save and Restore Register 1 */
+#define	SPRN_IVPR	0x03F	/* Interrupt Vector Prefix Register */
+#define SPRN_USPRG0	0x100	/* User Special Purpose Register General 0 */
+#define	SPRN_SPRG4R	0x104	/* Special Purpose Register General 4 Read */
+#define	SPRN_SPRG5R	0x105	/* Special Purpose Register General 5 Read */
+#define	SPRN_SPRG6R	0x106	/* Special Purpose Register General 6 Read */
+#define	SPRN_SPRG7R	0x107	/* Special Purpose Register General 7 Read */
+#define	SPRN_SPRG4W	0x114	/* Special Purpose Register General 4 Write */
+#define	SPRN_SPRG5W	0x115	/* Special Purpose Register General 5 Write */
+#define	SPRN_SPRG6W	0x116	/* Special Purpose Register General 6 Write */
+#define	SPRN_SPRG7W	0x117	/* Special Purpose Register General 7 Write */
+#define SPRN_DBCR2	0x136	/* Debug Control Register 2 */
+#define	SPRN_IAC3	0x13A	/* Instruction Address Compare 3 */
+#define	SPRN_IAC4	0x13B	/* Instruction Address Compare 4 */
+#define SPRN_DVC1	0x13E	/* */
+#define SPRN_DVC2	0x13F	/* */
+#define SPRN_IVOR0	0x190	/* Interrupt Vector Offset Register 0 */
+#define SPRN_IVOR1	0x191	/* Interrupt Vector Offset Register 1 */
+#define SPRN_IVOR2	0x192	/* Interrupt Vector Offset Register 2 */
+#define SPRN_IVOR3	0x193	/* Interrupt Vector Offset Register 3 */
+#define SPRN_IVOR4	0x194	/* Interrupt Vector Offset Register 4 */
+#define SPRN_IVOR5	0x195	/* Interrupt Vector Offset Register 5 */
+#define SPRN_IVOR6	0x196	/* Interrupt Vector Offset Register 6 */
+#define SPRN_IVOR7	0x197	/* Interrupt Vector Offset Register 7 */
+#define SPRN_IVOR8	0x198	/* Interrupt Vector Offset Register 8 */
+#define SPRN_IVOR9	0x199	/* Interrupt Vector Offset Register 9 */
+#define SPRN_IVOR10	0x19a	/* Interrupt Vector Offset Register 10 */
+#define SPRN_IVOR11	0x19b	/* Interrupt Vector Offset Register 11 */
+#define SPRN_IVOR12	0x19c	/* Interrupt Vector Offset Register 12 */
+#define SPRN_IVOR13	0x19d	/* Interrupt Vector Offset Register 13 */
+#define SPRN_IVOR14	0x19e	/* Interrupt Vector Offset Register 14 */
+#define SPRN_IVOR15	0x19f	/* Interrupt Vector Offset Register 15 */
+#define SPRN_MMUCR	0x3b2	/* MMU Control Register */
+
+#define ESR_ST		0x00800000	/* Store Operation */
+
 /* Short-hand versions for a number of the above SPRNs */
 
 #define	CTR	SPRN_CTR	/* Counter Register */
@@ -559,6 +661,10 @@
 #define	PVR_403GCX	0x00201400
 #define	PVR_405GP	0x40110000
 #define	PVR_STB03XXX	0x40310000
+#define PVR_440GP_RB	0x40120440
+#define PVR_440GP_RC1	0x40120481
+#define PVR_440GP_RC2	0x40200481
+#define PVR_440GX_RC1	0x51b21850
 #define	PVR_601		0x00010000
 #define	PVR_602		0x00050000
 #define	PVR_603		0x00030000
@@ -716,6 +822,7 @@
 	vector128	vr[32];		/* Complete AltiVec set */
 	vector128	vscr;		/* AltiVec status */
 	unsigned long	vrsave;
+	int		used_vr;	/* set if process has used altivec */
 #endif /* CONFIG_ALTIVEC */
 #if defined(CONFIG_4xx)
 	/* Saved 4xx debug registers */
diff -Nru a/include/asm-ppc/scatterlist.h b/include/asm-ppc/scatterlist.h
--- a/include/asm-ppc/scatterlist.h	Tue Feb 11 12:37:32 2003
+++ b/include/asm-ppc/scatterlist.h	Thu Aug 28 03:51:50 2003
@@ -9,9 +9,12 @@
 				 * or NULL for highmem page */
 	struct page * page;	/* Location for highmem page, if any */
 	unsigned int offset;	/* for highmem, page offset */
+	unsigned int length;	/* length at address or page+offset */
 
-	dma_addr_t dma_address;	/* phys/bus dma address		 */
-	unsigned int length;	/* length			 */
+	dma_addr_t dma_address;	/* phys/bus dma address	*/
+	unsigned int dma_length; /* number of bytes mapped at dma_address */
+	/* Note that if we coalesce multiple scatterlist elements,
+	   dma_length can be different from length */
 };
 
 /*
@@ -22,7 +25,7 @@
  * is 0.
  */
 #define sg_dma_address(sg)      ((sg)->dma_address)
-#define sg_dma_len(sg)          ((sg)->length)
+#define sg_dma_len(sg)          ((sg)->dma_length)
 
 #endif /* !(_PPC_SCATTERLIST_H) */
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
--- a/include/asm-ppc/serial.h	Thu Jun 19 04:36:32 2003
+++ b/include/asm-ppc/serial.h	Thu Aug 28 05:31:04 2003
@@ -14,7 +14,7 @@
 #include <platforms/lopec_serial.h>
 #elif defined(CONFIG_SPRUCE)
 #include <platforms/spruce.h>
-#elif defined(CONFIG_40x)
+#elif defined(CONFIG_4xx)
 #include <asm/ibm4xx.h>
 #else
 
diff -Nru a/include/asm-ppc/sigcontext.h b/include/asm-ppc/sigcontext.h
--- a/include/asm-ppc/sigcontext.h	Tue Feb 11 12:37:32 2003
+++ b/include/asm-ppc/sigcontext.h	Fri Aug 29 03:56:51 2003
@@ -3,8 +3,7 @@
 
 #include <asm/ptrace.h>
 
-
-struct sigcontext_struct {
+struct sigcontext {
 	unsigned long	_unused[4];
 	int		signal;
 	unsigned long	handler;
diff -Nru a/include/asm-ppc/ucontext.h b/include/asm-ppc/ucontext.h
--- a/include/asm-ppc/ucontext.h	Tue Feb 11 12:37:32 2003
+++ b/include/asm-ppc/ucontext.h	Fri Aug 29 03:56:51 2003
@@ -1,14 +1,28 @@
 #ifndef _ASMPPC_UCONTEXT_H
 #define _ASMPPC_UCONTEXT_H
 
-/* Copied from i386. */
+#include <asm/elf.h>
+#include <asm/signal.h>
+
+struct mcontext {
+	elf_gregset_t	mc_gregs;
+	elf_fpregset_t	mc_fregs;
+	unsigned long	mc_pad[2];
+	elf_vrregset_t	mc_vregs __attribute__((__aligned__(16)));
+};
 
 struct ucontext {
-	unsigned long	  uc_flags;
-	struct ucontext  *uc_link;
-	stack_t		  uc_stack;
-	struct sigcontext_struct uc_mcontext;
-	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+	unsigned long	 uc_flags;
+	struct ucontext *uc_link;
+	stack_t		 uc_stack;
+	int		 uc_pad[7];
+	struct mcontext	*uc_regs;	/* backward compat */
+	sigset_t	 uc_oldsigmask;	/* backward compat */
+	int		 uc_pad2;
+	sigset_t	 uc_sigmask;
+	/* glibc has 1024-bit signal masks, ours are 64-bit */
+	int		 uc_maskext[30];
+	struct mcontext	 uc_mcontext;
 };
 
 #endif /* !_ASMPPC_UCONTEXT_H */
diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h	Thu Jul  3 09:56:35 2003
+++ b/include/asm-ppc/unistd.h	Fri Aug 29 03:56:51 2003
@@ -237,7 +237,25 @@
 #define __NR_io_getevents	229
 #define __NR_io_submit		230
 #define __NR_io_cancel		231
+#define __NR_set_tid_address	232
+#define __NR_fadvise64		233
+#define __NR_exit_group		234
+#define __NR_lookup_dcookie	235
+#define __NR_epoll_create	236
+#define __NR_epoll_ctl		237
+#define __NR_epoll_wait		238
+#define __NR_remap_file_pages	239
+#define __NR_timer_create	240
+#define __NR_timer_settime	241
+#define __NR_timer_gettime	242
+#define __NR_timer_getoverrun	243
+#define __NR_timer_delete	244
+#define __NR_clock_settime	245
+#define __NR_clock_gettime	246
+#define __NR_clock_getres	247
+#define __NR_clock_nanosleep	248
 #endif
+#define __NR_swapcontext	249
 
 #define __NR(n)	#n
 
diff -Nru a/include/asm-sparc/pgtsrmmu.h b/include/asm-sparc/pgtsrmmu.h
--- a/include/asm-sparc/pgtsrmmu.h	Tue Feb  5 09:39:47 2002
+++ b/include/asm-sparc/pgtsrmmu.h	Mon Jul 21 04:57:23 2003
@@ -9,6 +9,9 @@
 
 #include <asm/page.h>
 
+/* Number of contexts is implementation-dependent; 64k is the most we support */
+#define SRMMU_MAX_CONTEXTS    65536
+
 /* PMD_SHIFT determines the size of the area a second-level page table can map */
 #define SRMMU_PMD_SHIFT         18
 #define SRMMU_PMD_SIZE          (1UL << SRMMU_PMD_SHIFT)
diff -Nru a/include/asm-sparc/sfp-machine.h b/include/asm-sparc/sfp-machine.h
--- a/include/asm-sparc/sfp-machine.h	Tue Feb  5 09:39:48 2002
+++ b/include/asm-sparc/sfp-machine.h	Thu Aug 28 00:11:19 2003
@@ -77,9 +77,9 @@
 
 /* Some assembly to speed things up. */
 #define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
-  __asm__ ("addcc %r7,%8,%2
-	    addxcc %r5,%6,%1
-	    addx %r3,%4,%0"						\
+  __asm__ ("addcc %r7,%8,%2\n\t"					\
+	   "addxcc %r5,%6,%1\n\t"					\
+	   "addx %r3,%4,%0\n"						\
 	   : "=r" ((USItype)(r2)),					\
 	     "=&r" ((USItype)(r1)),					\
 	     "=&r" ((USItype)(r0))					\
@@ -92,9 +92,9 @@
 	   : "cc")
 
 #define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
-  __asm__ ("subcc %r7,%8,%2
-	    subxcc %r5,%6,%1
-	    subx %r3,%4,%0"						\
+  __asm__ ("subcc %r7,%8,%2\n\t"					\
+	    "subxcc %r5,%6,%1\n\t"					\
+	    "subx %r3,%4,%0\n"						\
 	   : "=r" ((USItype)(r2)),					\
 	     "=&r" ((USItype)(r1)),					\
 	     "=&r" ((USItype)(r0))					\
@@ -111,11 +111,11 @@
     /* We need to fool gcc,  as we need to pass more than 10		\
        input/outputs.  */						\
     register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2");		\
-    __asm__ __volatile__ ("
-	    addcc %r8,%9,%1
-	    addxcc %r6,%7,%0
-	    addxcc %r4,%5,%%g2
-	    addx %r2,%3,%%g1"						\
+    __asm__ __volatile__ (						\
+	    "addcc %r8,%9,%1\n\t"					\
+	    "addxcc %r6,%7,%0\n\t"					\
+	    "addxcc %r4,%5,%%g2\n\t"					\
+	    "addx %r2,%3,%%g1\n\t"					\
 	   : "=&r" ((USItype)(r1)),					\
 	     "=&r" ((USItype)(r0))					\
 	   : "%rJ" ((USItype)(x3)),					\
@@ -136,11 +136,11 @@
     /* We need to fool gcc,  as we need to pass more than 10		\
        input/outputs.  */						\
     register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2");		\
-    __asm__ __volatile__ ("
-	    subcc %r8,%9,%1
-	    subxcc %r6,%7,%0
-	    subxcc %r4,%5,%%g2
-	    subx %r2,%3,%%g1"						\
+    __asm__ __volatile__ (						\
+	    "subcc %r8,%9,%1\n\t"					\
+	    "subxcc %r6,%7,%0\n\t"					\
+	    "subxcc %r4,%5,%%g2\n\t"					\
+	    "subx %r2,%3,%%g1\n\t"					\
 	   : "=&r" ((USItype)(r1)),					\
 	     "=&r" ((USItype)(r0))					\
 	   : "%rJ" ((USItype)(x3)),					\
@@ -161,10 +161,10 @@
 #define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0) __FP_FRAC_SUB_4(x3,x2,x1,x0,x3,x2,x1,x0,y3,y2,y1,y0)
 
 #define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)					\
-  __asm__ ("addcc %3,%4,%3
-	    addxcc %2,%%g0,%2
-	    addxcc %1,%%g0,%1
-	    addx %0,%%g0,%0"						\
+  __asm__ ("addcc %3,%4,%3\n\t"						\
+	   "addxcc %2,%%g0,%2\n\t"					\
+	   "addxcc %1,%%g0,%1\n\t"					\
+	   "addx %0,%%g0,%0\n\t"					\
 	   : "=&r" ((USItype)(x3)),					\
 	     "=&r" ((USItype)(x2)),					\
 	     "=&r" ((USItype)(x1)),					\
diff -Nru a/include/asm-sparc64/asi.h b/include/asm-sparc64/asi.h
--- a/include/asm-sparc64/asi.h	Sun Aug 18 21:37:30 2002
+++ b/include/asm-sparc64/asi.h	Mon Aug  4 00:37:03 2003
@@ -36,10 +36,12 @@
 #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_QUAD_LDD_PHYS	0x34 /* (III+) PADDR, qword load		*/
 #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_QUAD_LDD_PHYS_L	0x3c /* (III+) PADDR, qword load, little endian	*/
 #define ASI_SRAM_FAST_INIT	0x40 /* (III+) Fast SRAM init			*/
 #define ASI_DCACHE_INVALIDATE	0x42 /* (III) DCache Invalidate diag		*/
 #define ASI_DCACHE_UTAG		0x43 /* (III) DCache uTag diag			*/
@@ -51,6 +53,7 @@
 #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_JBUS_CONFIG		0x4a /* (IIIi) JBUS Config Register		*/
 #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		*/
diff -Nru a/include/asm-sparc64/chafsr.h b/include/asm-sparc64/chafsr.h
--- a/include/asm-sparc64/chafsr.h	Tue Feb  5 10:11:34 2002
+++ b/include/asm-sparc64/chafsr.h	Mon Aug  4 00:14:22 2003
@@ -4,10 +4,54 @@
 
 /* Cheetah Asynchronous Fault Status register, ASI=0x4C VA<63:0>=0x0 */
 
+/* Comments indicate which processor variants on which the bit definition
+ * is valid.  Codes are:
+ * ch	-->	cheetah
+ * ch+	-->	cheetah plus
+ * jp	-->	jalapeno
+ */
+
 /* All bits of this register except M_SYNDROME and E_SYNDROME are
  * read, write 1 to clear.  M_SYNDROME and E_SYNDROME are read-only.
  */
 
+/* Software bit set by linux trap handlers to indicate that the trap was
+ * signalled at %tl >= 1.
+ */
+#define CHAFSR_TL1		(1UL << 63UL) /* n/a */
+
+/* Unmapped error from system bus for prefetch queue or
+ * store queue read operation
+ */
+#define CHPAFSR_DTO		(1UL << 59UL) /* ch+ */
+
+/* Bus error from system bus for prefetch queue or store queue
+ * read operation
+ */
+#define CHPAFSR_DBERR		(1UL << 58UL) /* ch+ */
+
+/* Hardware corrected E-cache Tag ECC error */
+#define CHPAFSR_THCE		(1UL << 57UL) /* ch+ */
+/* System interface protocol error, hw timeout caused */
+#define JPAFSR_JETO		(1UL << 57UL) /* jp */
+
+/* SW handled correctable E-cache Tag ECC error */
+#define CHPAFSR_TSCE		(1UL << 56UL) /* ch+ */
+/* Parity error on system snoop results */
+#define JPAFSR_SCE		(1UL << 56UL) /* jp */
+
+/* Uncorrectable E-cache Tag ECC error */
+#define CHPAFSR_TUE		(1UL << 55UL) /* ch+ */
+/* System interface protocol error, illegal command detected */
+#define JPAFSR_JEIC		(1UL << 55UL) /* jp */
+
+/* Uncorrectable system bus data ECC error due to prefetch
+ * or store fill request
+ */
+#define CHPAFSR_DUE		(1UL << 54UL) /* ch+ */
+/* System interface protocol error, illegal ADTYPE detected */
+#define JPAFSR_JEIT		(1UL << 54UL) /* jp */
+
 /* Multiple errors of the same type have occurred.  This bit is set when
  * an uncorrectable error or a SW correctable error occurs and the status
  * bit to report that error is already set.  When multiple errors of
@@ -22,12 +66,12 @@
  * subunit will be logged.  All errors in subsequent 16-byte subunits
  * from the same 64-byte transaction are ignored.
  */
-#define CHAFSR_ME		0x0020000000000000
+#define CHAFSR_ME		(1UL << 53UL) /* ch,ch+,jp */
 
 /* Privileged state error has occurred.  This is a capture of PSTATE.PRIV
  * at the time the error is detected.
  */
-#define CHAFSR_PRIV		0x0010000000000000
+#define CHAFSR_PRIV		(1UL << 52UL) /* ch,ch+,jp */
 
 /* The following bits 51 (CHAFSR_PERR) to 33 (CHAFSR_CE) are sticky error
  * bits and record the most recently detected errors.  Bits accumulate
@@ -38,74 +82,123 @@
  * pin when this event occurs and it also logs a specific cause code
  * into a JTAG scannable flop.
  */
-#define CHAFSR_PERR		0x0008000000000000
+#define CHAFSR_PERR		(1UL << 51UL) /* ch,ch+,jp */
 
 /* Internal processor error.  The processor asserts its' ERROR
  * pin when this event occurs and it also logs a specific cause code
  * into a JTAG scannable flop.
  */
-#define CHAFSR_IERR		0x0004000000000000
+#define CHAFSR_IERR		(1UL << 50UL) /* ch,ch+,jp */
 
 /* System request parity error on incoming address */
-#define CHAFSR_ISAP		0x0002000000000000
+#define CHAFSR_ISAP		(1UL << 49UL) /* ch,ch+,jp */
 
 /* HW Corrected system bus MTAG ECC error */
-#define CHAFSR_EMC		0x0001000000000000
+#define CHAFSR_EMC		(1UL << 48UL) /* ch,ch+ */
+/* Parity error on L2 cache tag SRAM */
+#define JPAFSR_ETP		(1UL << 48UL) /* jp */
 
 /* Uncorrectable system bus MTAG ECC error */
-#define CHAFSR_EMU		0x0000800000000000
+#define CHAFSR_EMU		(1UL << 47UL) /* ch,ch+ */
+/* Out of range memory error has occurred */
+#define JPAFSR_OM		(1UL << 47UL) /* jp */
 
 /* HW Corrected system bus data ECC error for read of interrupt vector */
-#define CHAFSR_IVC		0x0000400000000000
+#define CHAFSR_IVC		(1UL << 46UL) /* ch,ch+ */
+/* Error due to unsupported store */
+#define JPAFSR_UMS		(1UL << 46UL) /* jp */
 
 /* Uncorrectable system bus data ECC error for read of interrupt vector */
-#define CHAFSR_IVU		0x0000200000000000
+#define CHAFSR_IVU		(1UL << 45UL) /* ch,ch+,jp */
 
 /* Unmappeed error from system bus */
-#define CHAFSR_TO		0x0000100000000000
+#define CHAFSR_TO		(1UL << 44UL) /* ch,ch+,jp */
 
 /* Bus error response from system bus */
-#define CHAFSR_BERR		0x0000080000000000
+#define CHAFSR_BERR		(1UL << 43UL) /* ch,ch+,jp */
 
 /* SW Correctable E-cache ECC error for instruction fetch or data access
  * other than block load.
  */
-#define CHAFSR_UCC		0x0000040000000000
+#define CHAFSR_UCC		(1UL << 42UL) /* ch,ch+,jp */
 
 /* Uncorrectable E-cache ECC error for instruction fetch or data access
  * other than block load.
  */
-#define CHAFSR_UCU		0x0000020000000000
+#define CHAFSR_UCU		(1UL << 41UL) /* ch,ch+,jp */
 
 /* Copyout HW Corrected ECC error */
-#define CHAFSR_CPC		0x0000010000000000
+#define CHAFSR_CPC		(1UL << 40UL) /* ch,ch+,jp */
 
 /* Copyout Uncorrectable ECC error */
-#define CHAFSR_CPU		0x0000008000000000
+#define CHAFSR_CPU		(1UL << 39UL) /* ch,ch+,jp */
 
 /* HW Corrected ECC error from E-cache for writeback */
-#define CHAFSR_WDC		0x0000004000000000
+#define CHAFSR_WDC		(1UL << 38UL) /* ch,ch+,jp */
 
 /* Uncorrectable ECC error from E-cache for writeback */
-#define CHAFSR_WDU		0x0000002000000000
+#define CHAFSR_WDU		(1UL << 37UL) /* ch,ch+,jp */
 
 /* HW Corrected ECC error from E-cache for store merge or block load */
-#define CHAFSR_EDC		0x0000001000000000
+#define CHAFSR_EDC		(1UL << 36UL) /* ch,ch+,jp */
 
 /* Uncorrectable ECC error from E-cache for store merge or block load */
-#define CHAFSR_EDU		0x0000000800000000
+#define CHAFSR_EDU		(1UL << 35UL) /* ch,ch+,jp */
 
 /* Uncorrectable system bus data ECC error for read of memory or I/O */
-#define CHAFSR_UE		0x0000000400000000
+#define CHAFSR_UE		(1UL << 34UL) /* ch,ch+,jp */
 
 /* HW Corrected system bus data ECC error for read of memory or I/O */
-#define CHAFSR_CE		0x0000000200000000
+#define CHAFSR_CE		(1UL << 33UL) /* ch,ch+,jp */
+
+/* Uncorrectable ECC error from remote cache/memory */
+#define JPAFSR_RUE		(1UL << 32UL) /* jp */
+
+/* Correctable ECC error from remote cache/memory */
+#define JPAFSR_RCE		(1UL << 31UL) /* jp */
+
+/* JBUS parity error on returned read data */
+#define JPAFSR_BP		(1UL << 30UL) /* jp */
+
+/* JBUS parity error on data for writeback or block store */
+#define JPAFSR_WBP		(1UL << 29UL) /* jp */
+
+/* Foreign read to DRAM incurring correctable ECC error */
+#define JPAFSR_FRC		(1UL << 28UL) /* jp */
+
+/* Foreign read to DRAM incurring uncorrectable ECC error */
+#define JPAFSR_FRU		(1UL << 27UL) /* jp */
 
 #define CHAFSR_ERRORS		(CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP | CHAFSR_EMC | \
 				 CHAFSR_EMU | CHAFSR_IVC | CHAFSR_IVU | CHAFSR_TO | \
 				 CHAFSR_BERR | CHAFSR_UCC | CHAFSR_UCU | CHAFSR_CPC | \
 				 CHAFSR_CPU | CHAFSR_WDC | CHAFSR_WDU | CHAFSR_EDC | \
 				 CHAFSR_EDU | CHAFSR_UE | CHAFSR_CE)
+#define CHPAFSR_ERRORS		(CHPAFSR_DTO | CHPAFSR_DBERR | CHPAFSR_THCE | \
+				 CHPAFSR_TSCE | CHPAFSR_TUE | CHPAFSR_DUE | \
+				 CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP | CHAFSR_EMC | \
+				 CHAFSR_EMU | CHAFSR_IVC | CHAFSR_IVU | CHAFSR_TO | \
+				 CHAFSR_BERR | CHAFSR_UCC | CHAFSR_UCU | CHAFSR_CPC | \
+				 CHAFSR_CPU | CHAFSR_WDC | CHAFSR_WDU | CHAFSR_EDC | \
+				 CHAFSR_EDU | CHAFSR_UE | CHAFSR_CE)
+#define JPAFSR_ERRORS		(JPAFSR_JETO | JPAFSR_SCE | JPAFSR_JEIC | \
+				 JPAFSR_JEIT | CHAFSR_PERR | CHAFSR_IERR | \
+				 CHAFSR_ISAP | JPAFSR_ETP | JPAFSR_OM | \
+				 JPAFSR_UMS | CHAFSR_IVU | CHAFSR_TO | \
+				 CHAFSR_BERR | CHAFSR_UCC | CHAFSR_UCU | \
+				 CHAFSR_CPC | CHAFSR_CPU | CHAFSR_WDC | \
+				 CHAFSR_WDU | CHAFSR_EDC | CHAFSR_EDU | \
+				 CHAFSR_UE | CHAFSR_CE | JPAFSR_RUE | \
+				 JPAFSR_RCE | JPAFSR_BP | JPAFSR_WBP | \
+				 JPAFSR_FRC | JPAFSR_FRU)
+
+/* Active JBUS request signal when error occurred */
+#define JPAFSR_JBREQ		(0x7UL << 24UL) /* jp */
+#define JPAFSR_JBREQ_SHIFT	24UL
+
+/* L2 cache way information */
+#define JPAFSR_ETW		(0x3UL << 22UL) /* jp */
+#define JPAFSR_ETW_SHIFT	22UL
 
 /* System bus MTAG ECC syndrome.  This field captures the status of the
  * first occurrence of the highest-priority error according to the M_SYND
@@ -113,8 +206,12 @@
  * for which the M_SYND is reported, is cleared, the contents of the M_SYND
  * field will be unchanged by will be unfrozen for further error capture.
  */
-#define CHAFSR_M_SYNDROME	0x00000000000f0000
-#define CHAFSR_M_SYNDROME_SHIFT	16
+#define CHAFSR_M_SYNDROME	(0xfUL << 16UL) /* ch,ch+,jp */
+#define CHAFSR_M_SYNDROME_SHIFT	16UL
+
+/* Agenid Id of the foreign device causing the UE/CE errors */
+#define JPAFSR_AID		(0x1fUL << 9UL) /* jp */
+#define JPAFSR_AID_SHIFT	9UL
 
 /* System bus or E-cache data ECC syndrome.  This field captures the status
  * of the first occurrence of the highest-priority error according to the
@@ -122,8 +219,8 @@
  * error for which the E_SYND is reported, is cleare, the contents of the E_SYND
  * field will be unchanged but will be unfrozen for further error capture.
  */
-#define CHAFSR_E_SYNDROME	0x00000000000001ff
-#define CHAFSR_E_SYNDROME_SHIFT	0
+#define CHAFSR_E_SYNDROME	(0x1ffUL << 0UL) /* ch,ch+,jp */
+#define CHAFSR_E_SYNDROME_SHIFT	0UL
 
 /* The AFSR must be explicitly cleared by software, it is not cleared automatically
  * by a read.  Writes to bits <51:33> with bits set will clear the corresponding
@@ -141,10 +238,5 @@
  * and ready for another event, even though AFSR.CE is still set.  The same rules
  * also apply to the M_SYNDROME and E_SYNDROME fields of the AFSR.
  */
-
-/* Software bit set by linux trap handlers to indicate that the trap was
- * signalled at %tl >= 1.
- */
-#define CHAFSR_TL1		0x8000000000000000
 
 #endif /* _SPARC64_CHAFSR_H */
diff -Nru a/include/asm-sparc64/head.h b/include/asm-sparc64/head.h
--- a/include/asm-sparc64/head.h	Thu Apr  3 15:14:24 2003
+++ b/include/asm-sparc64/head.h	Mon Jul 21 08:35:22 2003
@@ -9,16 +9,27 @@
 #define	PTREGS_OFF	(STACK_BIAS + STACKFRAME_SZ)
 
 #define __CHEETAH_ID	0x003e0014
+#define __JALAPENO_ID	0x003e0016
 
 #define CHEETAH_MANUF		0x003e
 #define CHEETAH_IMPL		0x0014
 #define CHEETAH_PLUS_IMPL	0x0015
+#define JALAPENO_IMPL		0x0016
 
 #define BRANCH_IF_CHEETAH_BASE(tmp1,tmp2,label)	\
 	rdpr	%ver, %tmp1;			\
 	sethi	%hi(__CHEETAH_ID), %tmp2;	\
 	srlx	%tmp1, 32, %tmp1;		\
 	or	%tmp2, %lo(__CHEETAH_ID), %tmp2;\
+	cmp	%tmp1, %tmp2;			\
+	be,pn	%icc, label;			\
+	 nop;
+
+#define BRANCH_IF_JALAPENO(tmp1,tmp2,label)	\
+	rdpr	%ver, %tmp1;			\
+	sethi	%hi(__JALAPENO_ID), %tmp2;	\
+	srlx	%tmp1, 32, %tmp1;		\
+	or	%tmp2, %lo(__JALAPENO_ID), %tmp2;\
 	cmp	%tmp1, %tmp2;			\
 	be,pn	%icc, label;			\
 	 nop;
diff -Nru a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
--- a/include/asm-sparc64/io.h	Tue Feb  5 06:10:22 2002
+++ b/include/asm-sparc64/io.h	Tue Aug  5 00:21:13 2003
@@ -413,7 +413,7 @@
  */
 #define ioremap(__offset, __size)	((void *)(__offset))
 #define ioremap_nocache(X,Y)		ioremap((X),(Y))
-#define iounmap(__addr)			do { } while(0)
+#define iounmap(__addr)			do { (void)(__addr); } while(0)
 
 /* Similarly for SBUS. */
 #define sbus_ioremap(__res, __offset, __size, __name) \
diff -Nru a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h
--- a/include/asm-sparc64/irq.h	Tue Mar 18 20:45:47 2003
+++ b/include/asm-sparc64/irq.h	Mon Jul 21 08:35:22 2003
@@ -76,6 +76,7 @@
 /* IMAP/ICLR register defines */
 #define IMAP_VALID		0x80000000	/* IRQ Enabled		*/
 #define IMAP_TID_UPA		0x7c000000	/* UPA TargetID		*/
+#define IMAP_TID_JBUS		0x7c000000	/* JBUS TargetID	*/
 #define IMAP_AID_SAFARI		0x7c000000	/* Safari AgentID	*/
 #define IMAP_NID_SAFARI		0x03e00000	/* Safari NodeID	*/
 #define IMAP_IGN		0x000007c0	/* IRQ Group Number	*/
diff -Nru a/include/asm-sparc64/isa.h b/include/asm-sparc64/isa.h
--- a/include/asm-sparc64/isa.h	Tue Feb  5 10:16:18 2002
+++ b/include/asm-sparc64/isa.h	Wed Jul 23 08:37:36 2003
@@ -32,6 +32,11 @@
 #define linux_prom_isa_ranges linux_prom_ebus_ranges
 	struct linux_prom_isa_ranges	isa_ranges[PROMREG_MAX];
 	int			num_isa_ranges;
+#define linux_prom_isa_intmap	linux_prom_ebus_intmap
+	struct linux_prom_isa_intmap	isa_intmap[PROMREG_MAX];
+	int			num_isa_intmap;
+#define linux_prom_isa_intmask	linux_prom_ebus_intmask
+	struct linux_prom_isa_intmap	isa_intmask;
 };
 
 extern struct isa_bridge	*isa_chain;
diff -Nru a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
--- a/include/asm-sparc64/pbm.h	Mon Feb  4 23:44:27 2002
+++ b/include/asm-sparc64/pbm.h	Sat Aug  2 17:45:01 2003
@@ -128,6 +128,25 @@
 	/* PCI controller we sit under. */
 	struct pci_controller_info	*parent;
 
+	/* Physical address base of controller registers. */
+	unsigned long			controller_regs;
+
+	/* Physical address base of PBM registers. */
+	unsigned long			pbm_regs;
+
+	/* Opaque 32-bit system bus Port ID. */
+	u32				portid;
+
+	/* Chipset version information. */
+	int				chip_type;
+#define PBM_CHIP_TYPE_SABRE		1
+#define PBM_CHIP_TYPE_PSYCHO		2
+#define PBM_CHIP_TYPE_SCHIZO		3
+#define PBM_CHIP_TYPE_SCHIZO_PLUS	4
+#define PBM_CHIP_TYPE_TOMATILLO		5
+	int				chip_version;
+	int				chip_revision;
+
 	/* Name used for top-level resources. */
 	char				name[64];
 
@@ -139,6 +158,7 @@
 	struct linux_prom_pci_intmap	pbm_intmap[PROM_PCIIMAP_MAX];
 	int				num_pbm_intmap;
 	struct linux_prom_pci_intmask	pbm_intmask;
+	u64				ino_bitmap;
 
 	/* PBM I/O and Memory space resources. */
 	struct resource			io_space;
@@ -169,12 +189,6 @@
 struct pci_controller_info {
 	/* List of all PCI controllers. */
 	struct pci_controller_info	*next;
-
-	/* Physical address base of controller registers. */
-	unsigned long			controller_regs;
-
-	/* Opaque 32-bit system bus Port ID. */
-	u32				portid;
 
 	/* Each controller gets a unique index, used mostly for
 	 * error logging purposes.
diff -Nru a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
--- a/include/asm-sparc64/smp.h	Sun Aug 18 21:37:30 2002
+++ b/include/asm-sparc64/smp.h	Mon Jul 21 08:35:22 2003
@@ -87,11 +87,19 @@
 extern __inline__ int hard_smp_processor_id(void)
 {
 	if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		unsigned long safari_config;
-		__asm__ __volatile__("ldxa [%%g0] %1, %0"
-				     : "=r" (safari_config)
-				     : "i" (ASI_SAFARI_CONFIG));
-		return ((safari_config >> 17) & 0x3ff);
+		unsigned long cfg, ver;
+		__asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+		if ((ver >> 32) == 0x003e0016) {
+			__asm__ __volatile__("ldxa [%%g0] %1, %0"
+					     : "=r" (cfg)
+					     : "i" (ASI_JBUS_CONFIG));
+			return ((cfg >> 17) & 0x1f);
+		} else {
+			__asm__ __volatile__("ldxa [%%g0] %1, %0"
+					     : "=r" (cfg)
+					     : "i" (ASI_SAFARI_CONFIG));
+			return ((cfg >> 17) & 0x3ff);
+		}
 	} else if (this_is_starfire != 0) {
 		return starfire_hard_smp_processor_id();
 	} else {
diff -Nru a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
--- a/include/asm-x86_64/io_apic.h	Sat Aug  9 13:32:28 2003
+++ b/include/asm-x86_64/io_apic.h	Fri Aug 22 03:29:25 2003
@@ -148,6 +148,6 @@
 extern int io_apic_get_unique_id (int ioapic, int apic_id);
 extern int io_apic_get_version (int ioapic);
 extern int io_apic_get_redir_entries (int ioapic);
-extern int io_apic_set_pci_routing (int ioapic, int pin, int irq);
+extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int);
 
 #endif
diff -Nru a/include/linux/agp_backend.h b/include/linux/agp_backend.h
--- a/include/linux/agp_backend.h	Mon Jul 14 05:05:58 2003
+++ b/include/linux/agp_backend.h	Tue Jul 15 02:30:11 2003
@@ -55,6 +55,8 @@
 	INTEL_I855_PM,
 	INTEL_I860,
 	INTEL_I865_G,
+	INTEL_I7205,
+	INTEL_I7505,
 	VIA_GENERIC,
 	VIA_VP3,
 	VIA_MVP3,
diff -Nru a/include/linux/console.h b/include/linux/console.h
--- a/include/linux/console.h	Mon Dec 30 09:58:44 2002
+++ b/include/linux/console.h	Sun Jul 21 05:25:42 2002
@@ -113,6 +113,7 @@
 extern void release_console_sem(void);
 extern void console_conditional_schedule(void);
 extern void console_unblank(void);
+extern void disable_console_blank(void);
 
 /* VESA Blanking Levels */
 #define VESA_NO_BLANKING        0
diff -Nru a/include/linux/ethtool.h b/include/linux/ethtool.h
--- a/include/linux/ethtool.h	Fri Jul 18 16:37:35 2003
+++ b/include/linux/ethtool.h	Mon Aug 25 14:24:22 2003
@@ -97,7 +97,7 @@
 	u32	rx_max_coalesced_frames;
 
 	/* Same as above two parameters, except that these values
-	 * apply while an IRQ is being services by the host.  Not
+	 * apply while an IRQ is being serviced by the host.  Not
 	 * all cards support this feature and the values are ignored
 	 * in that case.
 	 */
@@ -119,7 +119,7 @@
 	u32	tx_max_coalesced_frames;
 
 	/* Same as above two parameters, except that these values
-	 * apply while an IRQ is being services by the host.  Not
+	 * apply while an IRQ is being serviced by the host.  Not
 	 * all cards support this feature and the values are ignored
 	 * in that case.
 	 */
@@ -248,6 +248,101 @@
 	u32	cmd;		/* ETHTOOL_GSTATS */
 	u32	n_stats;	/* number of u64's being returned */
 	u64	data[0];
+};
+
+struct net_device;
+
+/* Some generic methods drivers may use in their ethtool_ops */
+u32 ethtool_op_get_link(struct net_device *dev);
+u32 ethtool_op_get_tx_csum(struct net_device *dev);
+u32 ethtool_op_get_sg(struct net_device *dev);
+int ethtool_op_set_sg(struct net_device *dev, u32 data);
+
+/**
+ * &ethtool_ops - Alter and report network device settings
+ * get_settings: Get device-specific settings
+ * set_settings: Set device-specific settings
+ * get_drvinfo: Report driver information
+ * get_regs: Get device registers
+ * get_wol: Report whether Wake-on-Lan is enabled
+ * set_wol: Turn Wake-on-Lan on or off
+ * get_msglevel: Report driver message level
+ * set_msglevel: Set driver message level
+ * nway_reset: Restart autonegotiation
+ * get_link: Get link status
+ * get_eeprom: Read data from the device EEPROM
+ * set_eeprom: Write data to the device EEPROM
+ * get_coalesce: Get interrupt coalescing parameters
+ * set_coalesce: Set interrupt coalescing parameters
+ * get_ringparam: Report ring sizes
+ * set_ringparam: Set ring sizes
+ * get_pauseparam: Report pause parameters
+ * set_pauseparam: Set pause paramters
+ * get_rx_csum: Report whether receive checksums are turned on or off
+ * set_rx_csum: Turn receive checksum on or off
+ * get_tx_csum: Report whether transmit checksums are turned on or off
+ * set_tx_csum: Turn transmit checksums on or off
+ * get_sg: Report whether scatter-gather is enabled
+ * set_sg: Turn scatter-gather on or off
+ * self_test: Run specified self-tests
+ * get_strings: Return a set of strings that describe the requested objects 
+ * phys_id: Identify the device
+ * get_stats: Return statistics about the device
+ *
+ * Description:
+ *
+ * get_settings:
+ *	@get_settings is passed an &ethtool_cmd to fill in.  It returns
+ *	an negative errno or zero.
+ *
+ * set_settings:
+ *	@set_settings is passed an &ethtool_cmd and should attempt to set
+ *	all the settings this device supports.  It may return an error value
+ *	if something goes wrong (otherwise 0).
+ *
+ * get_eeprom:
+ *	Should fill in the magic field.  Don't need to check len for zero
+ *	or wraparound but must check offset + len < size.  Fill in the data
+ *	argument with the eeprom values from offset to offset + len.  Update
+ *	len to the amount read.  Returns an error or zero.
+ *
+ * set_eeprom:
+ *	Should validate the magic field.  Don't need to check len for zero
+ *	or wraparound but must check offset + len < size.  Update len to
+ *	the amount written.  Returns an error or zero.
+ */
+struct ethtool_ops {
+	int	(*get_settings)(struct net_device *, struct ethtool_cmd *);
+	int	(*set_settings)(struct net_device *, struct ethtool_cmd *);
+	void	(*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
+	int	(*get_regs_len)(struct net_device *);
+	void	(*get_regs)(struct net_device *, struct ethtool_regs *, void *);
+	void	(*get_wol)(struct net_device *, struct ethtool_wolinfo *);
+	int	(*set_wol)(struct net_device *, struct ethtool_wolinfo *);
+	u32	(*get_msglevel)(struct net_device *);
+	void	(*set_msglevel)(struct net_device *, u32);
+	int	(*nway_reset)(struct net_device *);
+	u32	(*get_link)(struct net_device *);
+	int	(*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
+	int	(*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
+	int	(*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
+	int	(*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
+	void	(*get_ringparam)(struct net_device *, struct ethtool_ringparam *);
+	int	(*set_ringparam)(struct net_device *, struct ethtool_ringparam *);
+	void	(*get_pauseparam)(struct net_device *, struct ethtool_pauseparam*);
+	int	(*set_pauseparam)(struct net_device *, struct ethtool_pauseparam*);
+	u32	(*get_rx_csum)(struct net_device *);
+	int	(*set_rx_csum)(struct net_device *, u32);
+	u32	(*get_tx_csum)(struct net_device *);
+	int	(*set_tx_csum)(struct net_device *, u32);
+	u32	(*get_sg)(struct net_device *);
+	int	(*set_sg)(struct net_device *, u32);
+	int	(*self_test_count)(struct net_device *);
+	void	(*self_test)(struct net_device *, struct ethtool_test *, u64 *);
+	void	(*get_strings)(struct net_device *, u32 stringset, u8 *);
+	int	(*phys_id)(struct net_device *, u32);
+	int	(*get_stats_count)(struct net_device *);
+	void	(*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);
 };
 
 /* CMDs currently supported */
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Sun Jun 29 09:27:44 2003
+++ b/include/linux/ide.h	Sun Aug 17 03:49:50 2003
@@ -1003,6 +1003,7 @@
 	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
 	unsigned	highmem    : 1;	/* can do full 32-bit dma */
 	unsigned	no_dsc     : 1;	/* 0 default, 1 dsc_overlap disabled */
+	unsigned	sata	   : 1; /* 0 PATA, 1 SATA */
 
 	void		*hwif_data;	/* extra hwif data */
 } ide_hwif_t;
@@ -1331,9 +1332,10 @@
 extern int ide_xlate_1024(kdev_t, int, int, const char *);
 
 /*
- * Convert kdev_t structure into ide_drive_t * one.
+ * Convert kdev_t structure into ide_drive_t * one. If force is set the
+ * non present drives can be opened.
  */
-extern ide_drive_t *get_info_ptr(kdev_t i_rdev);
+extern ide_drive_t *ide_info_ptr(kdev_t i_rdev, int force);
 
 /*
  * Return the current idea about the total capacity of this drive.
@@ -1349,12 +1351,6 @@
 extern ide_startstop_t ide_do_reset(ide_drive_t *);
 
 /*
- * Re-Start an operation for an IDE interface.
- * The caller should return immediately after invoking this.
- */
-extern int restart_request(ide_drive_t *, struct request *);
-
-/*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
 extern void ide_init_drive_cmd(struct request *);
@@ -1721,6 +1717,12 @@
 #endif
 
 extern void hwif_unregister(ide_hwif_t *);
+
+extern void ide_probe_reset(ide_hwif_t *);
+extern void ide_tune_drives(ide_hwif_t *);
+extern int ide_wait_hwif_ready(ide_hwif_t *);
+extern u8 ide_probe_for_drive(ide_drive_t *);
+
 
 extern void export_ide_init_queue(ide_drive_t *);
 extern u8 export_probe_for_drive(ide_drive_t *);
diff -Nru a/include/linux/interrupt.h b/include/linux/interrupt.h
--- a/include/linux/interrupt.h	Wed Dec 11 10:08:18 2002
+++ b/include/linux/interrupt.h	Fri Aug  1 17:13:37 2003
@@ -12,6 +12,12 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
+/* For 2.6.x compatibility */
+typedef void irqreturn_t;
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define IRQ_RETVAL(x)
+
 struct irqaction {
 	void (*handler)(int, void *, struct pt_regs *);
 	unsigned long flags;
diff -Nru a/include/linux/ipv6.h b/include/linux/ipv6.h
--- a/include/linux/ipv6.h	Tue Feb  5 09:39:41 2002
+++ b/include/linux/ipv6.h	Sat Aug  9 01:13:10 2003
@@ -70,7 +70,7 @@
 	__u32			bitmap;		/* strict/loose bit map */
 	struct in6_addr		addr[0];
 
-#define rt0_type		rt_hdr.type;
+#define rt0_type		rt_hdr.type
 };
 
 /*
diff -Nru a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h
--- a/include/linux/ipv6_route.h	Tue Feb  5 09:39:41 2002
+++ b/include/linux/ipv6_route.h	Wed Jul 23 03:02:34 2003
@@ -25,6 +25,7 @@
 #define RTF_DEFAULT	0x00010000	/* default - learned via ND	*/
 #define RTF_ALLONLINK	0x00020000	/* fallback, no routers on link	*/
 #define RTF_ADDRCONF	0x00040000	/* addrconf route - RA		*/
+#define RTF_PREFIX_RT	0x00080000	/* A prefix only route - RA	*/
 
 #define RTF_NONEXTHOP	0x00200000	/* route with no nexthop	*/
 #define RTF_EXPIRES	0x00400000
diff -Nru a/include/linux/list.h b/include/linux/list.h
--- a/include/linux/list.h	Tue Sep 17 17:10:44 2002
+++ b/include/linux/list.h	Wed Aug 27 14:26:38 2003
@@ -227,6 +227,19 @@
 	     pos = list_entry(pos->member.next, typeof(*pos), member),	\
 		     prefetch(pos->member.next))
 
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
 #endif /* __KERNEL__ || _LVM_H_INCLUDE */
 
 #endif
diff -Nru a/include/linux/lvm.h b/include/linux/lvm.h
--- a/include/linux/lvm.h	Thu Jul 25 06:46:01 2002
+++ b/include/linux/lvm.h	Mon Mar 10 06:55:46 2003
@@ -80,8 +80,8 @@
 #ifndef _LVM_H_INCLUDE
 #define _LVM_H_INCLUDE
 
-#define LVM_RELEASE_NAME "1.0.5+"
-#define LVM_RELEASE_DATE "22/07/2002"
+#define LVM_RELEASE_NAME "1.0.7"
+#define LVM_RELEASE_DATE "28/03/2003"
 
 #define	_LVM_KERNEL_H_VERSION	"LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")"
 
@@ -94,7 +94,7 @@
 #define	LVM_TOTAL_RESET
 
 #ifdef __KERNEL__
-#undef LVM_HD_NAME /* display nice names in /proc/partitions */
+#undef LVM_HD_NAME		/* display nice names in /proc/partitions */
 
 /* lots of debugging output (see driver source)
    #define DEBUG_LVM_GET_INFO
@@ -118,7 +118,7 @@
    causes problems on some platforms. It's not nice but then
    neither is the alternative. */
 struct list_head {
-        struct list_head *next, *prev;
+	struct list_head *next, *prev;
 };
 #define __KERNEL__
 #include <linux/kdev_t.h>
@@ -258,9 +258,9 @@
 #define	LVM_PE_T_MAX		( ( 1 << ( sizeof ( uint16_t) * 8)) - 2)
 
 #define	LVM_LV_SIZE_MAX(a)	( ( long long) LVM_PE_T_MAX * (a)->pe_size > ( long long) 1024*1024/SECTOR_SIZE*1024*1024 ? ( long long) 1024*1024/SECTOR_SIZE*1024*1024 : ( long long) LVM_PE_T_MAX * (a)->pe_size)
-#define	LVM_MIN_PE_SIZE		( 8192L / SECTOR_SIZE) /* 8 KB in sectors */
+#define	LVM_MIN_PE_SIZE		( 8192L / SECTOR_SIZE)	/* 8 KB in sectors */
 #define	LVM_MAX_PE_SIZE		( 16L * 1024L * 1024L / SECTOR_SIZE * 1024)	/* 16GB in sectors */
-#define	LVM_DEFAULT_PE_SIZE	( 4096L * 1024 / SECTOR_SIZE)	/* 4 MB in sectors */
+#define	LVM_DEFAULT_PE_SIZE	( 32768L * 1024 / SECTOR_SIZE)	/* 32 MB in sectors */
 #define	LVM_DEFAULT_STRIPE_SIZE	16L	/* 16 KB  */
 #define	LVM_MIN_STRIPE_SIZE	( PAGE_SIZE/SECTOR_SIZE)	/* PAGESIZE in sectors */
 #define	LVM_MAX_STRIPE_SIZE	( 512L * 1024 / SECTOR_SIZE)	/* 512 KB in sectors */
@@ -416,9 +416,9 @@
 typedef struct lv_block_exception_v1 {
 	struct list_head hash;
 	uint32_t rsector_org;
-	kdev_t   rdev_org;
+	kdev_t rdev_org;
 	uint32_t rsector_new;
-	kdev_t   rdev_new;
+	kdev_t rdev_new;
 } lv_block_exception_t;
 
 /* disk stored pe information */
@@ -462,7 +462,7 @@
 	uint pe_stale;		/* for future use */
 	pe_disk_t *pe;		/* HM */
 	struct block_device *bd;
-	char pv_uuid[UUID_LEN+1];
+	char pv_uuid[UUID_LEN + 1];
 
 #ifndef __KERNEL__
 	uint32_t pe_start;	/* in sectors */
@@ -473,7 +473,7 @@
 /* disk */
 typedef struct pv_disk_v2 {
 	uint8_t id[2];		/* Identifier */
-	uint16_t version;		/* HM lvm version */
+	uint16_t version;	/* HM lvm version */
 	lvm_disk_data_t pv_on_disk;
 	lvm_disk_data_t vg_on_disk;
 	lvm_disk_data_t pv_uuidlist_on_disk;
@@ -486,14 +486,14 @@
 	uint32_t pv_number;
 	uint32_t pv_status;
 	uint32_t pv_allocatable;
-	uint32_t pv_size;		/* HM */
+	uint32_t pv_size;	/* HM */
 	uint32_t lv_cur;
 	uint32_t pe_size;
 	uint32_t pe_total;
 	uint32_t pe_allocated;
-	
+
 	/* new in struct version 2 */
-	uint32_t pe_start;	        /* in sectors */
+	uint32_t pe_start;	/* in sectors */
 
 } pv_disk_t;
 
@@ -567,8 +567,8 @@
 	uint32_t lv_snapshot_hash_table_size;
 	uint32_t lv_snapshot_hash_mask;
 	wait_queue_head_t lv_snapshot_wait;
-	int	lv_snapshot_use_rate;
-	struct vg_v3	*vg;
+	int lv_snapshot_use_rate;
+	struct vg_v3 *vg;
 
 	uint lv_allocated_snapshot_le;
 #else
@@ -582,14 +582,14 @@
 	uint8_t vg_name[NAME_LEN];
 	uint32_t lv_access;
 	uint32_t lv_status;
-	uint32_t lv_open;		/* HM */
-	uint32_t lv_dev;		/* HM */
+	uint32_t lv_open;	/* HM */
+	uint32_t lv_dev;	/* HM */
 	uint32_t lv_number;	/* HM */
 	uint32_t lv_mirror_copies;	/* for future use */
 	uint32_t lv_recovery;	/*       "        */
 	uint32_t lv_schedule;	/*       "        */
 	uint32_t lv_size;
-	uint32_t lv_snapshot_minor;/* minor number of original */
+	uint32_t lv_snapshot_minor;	/* minor number of original */
 	uint16_t lv_chunk_size;	/* chunk size of snapshot */
 	uint16_t dummy;
 	uint32_t lv_allocated_le;
@@ -626,7 +626,7 @@
 	struct proc_dir_entry *proc;
 	pv_t *pv[ABS_MAX_PV + 1];	/* physical volume struct pointers */
 	lv_t *lv[ABS_MAX_LV + 1];	/* logical  volume struct pointers */
-	char vg_uuid[UUID_LEN+1];	/* volume group UUID */
+	char vg_uuid[UUID_LEN + 1];	/* volume group UUID */
 #ifdef __KERNEL__
 	struct proc_dir_entry *vg_dir_pde;
 	struct proc_dir_entry *lv_subdir_pde;
@@ -640,20 +640,20 @@
 /* disk */
 typedef struct vg_disk_v2 {
 	uint8_t vg_uuid[UUID_LEN];	/* volume group UUID */
-	uint8_t vg_name_dummy[NAME_LEN-UUID_LEN];	/* rest of v1 VG name */
+	uint8_t vg_name_dummy[NAME_LEN - UUID_LEN];	/* rest of v1 VG name */
 	uint32_t vg_number;	/* volume group number */
 	uint32_t vg_access;	/* read/write */
 	uint32_t vg_status;	/* active or not */
-	uint32_t lv_max;		/* maximum logical volumes */
-	uint32_t lv_cur;		/* current logical volumes */
-	uint32_t lv_open;		/* open    logical volumes */
-	uint32_t pv_max;		/* maximum physical volumes */
-	uint32_t pv_cur;		/* current physical volumes FU */
-	uint32_t pv_act;		/* active physical volumes */
+	uint32_t lv_max;	/* maximum logical volumes */
+	uint32_t lv_cur;	/* current logical volumes */
+	uint32_t lv_open;	/* open    logical volumes */
+	uint32_t pv_max;	/* maximum physical volumes */
+	uint32_t pv_cur;	/* current physical volumes FU */
+	uint32_t pv_act;	/* active physical volumes */
 	uint32_t dummy;
 	uint32_t vgda;		/* volume group descriptor arrays FU */
-	uint32_t pe_size;		/* physical extent size in sectors */
-	uint32_t pe_total;		/* total of physical extents */
+	uint32_t pe_size;	/* physical extent size in sectors */
+	uint32_t pe_total;	/* total of physical extents */
 	uint32_t pe_allocated;	/* allocated physical extents */
 	uint32_t pvg_total;	/* physical volume groups FU */
 } vg_disk_t;
@@ -712,40 +712,44 @@
 
 /* Request structure LV_SNAPSHOT_USE_RATE */
 typedef struct {
-	int	block;
-	int	rate;
+	int block;
+	int rate;
 } lv_snapshot_use_rate_req_t;
 
 
 
 /* useful inlines */
-static inline ulong round_up(ulong n, ulong size) {
+static inline ulong round_up(ulong n, ulong size)
+{
 	size--;
 	return (n + size) & ~size;
 }
 
-static inline ulong div_up(ulong n, ulong size) {
+static inline ulong div_up(ulong n, ulong size)
+{
 	return round_up(n, size) / size;
 }
 
 /* FIXME: nasty capital letters */
-static int inline LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg_t *vg, lv_t *lv) {
+static int inline LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg_t * vg, lv_t * lv)
+{
 	return vg->pe_size / lv->lv_chunk_size;
 }
 
-static int inline LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg_t *vg, lv_t *lv) {
+static int inline LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg_t * vg, lv_t * lv)
+{
 	ulong chunks = vg->pe_size / lv->lv_chunk_size;
 	ulong entry_size = sizeof(lv_COW_table_disk_t);
 	ulong chunk_size = lv->lv_chunk_size * SECTOR_SIZE;
 	ulong entries = (vg->pe_size * SECTOR_SIZE) /
-		(entry_size + chunk_size);
+	    (entry_size + chunk_size);
 
-	if(chunks < 2)
+	if (chunks < 2)
 		return 0;
 
-	for(; entries; entries--)
-		if((div_up(entries * entry_size, chunk_size) + entries) <=
-		   chunks)
+	for (; entries; entries--)
+		if ((div_up(entries * entry_size, chunk_size) + entries) <=
+		    chunks)
 			break;
 
 	return entries;
@@ -753,4 +757,3 @@
 
 
 #endif				/* #ifndef _LVM_H_INCLUDE */
-
diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h	Thu Jun 19 14:22:53 2003
+++ b/include/linux/netdevice.h	Tue Aug 26 14:15:07 2003
@@ -41,6 +41,11 @@
 
 struct divert_blk;
 struct vlan_group;
+struct ethtool_ops;
+
+					/* source back-compat hook */
+#define SET_ETHTOOL_OPS(netdev,ops) \
+	( (netdev)->ethtool_ops = (ops) )
 
 #define HAVE_ALLOC_NETDEV		/* feature macro: alloc_xxxdev
 					   functions are available. */
@@ -290,6 +295,8 @@
 	 * See <net/iw_handler.h> for details. Jean II */
 	struct iw_handler_def *	wireless_handlers;
 
+	struct ethtool_ops *ethtool_ops;
+
 	/*
 	 * This marks the end of the "visible" part of the structure. All
 	 * fields hereafter are internal to the system, and may change at
@@ -601,6 +608,7 @@
 #define HAVE_NETIF_RECEIVE_SKB 1
 extern int		netif_receive_skb(struct sk_buff *skb);
 extern int		dev_ioctl(unsigned int cmd, void *);
+extern int		dev_ethtool(struct ifreq *);
 extern int		dev_change_flags(struct net_device *, unsigned);
 extern void		dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
 
@@ -789,6 +797,7 @@
 	local_irq_save(flags);
 	if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) BUG();
 	list_del(&dev->poll_list);
+	smp_mb__before_clear_bit();
 	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
 	local_irq_restore(flags);
 }
@@ -801,6 +810,8 @@
 extern void		fc_setup(struct net_device *dev);
 extern void		fc_freedev(struct net_device *dev);
 /* Support for loadable net-drivers */
+extern struct net_device *alloc_netdev(int sizeof_priv, const char *name,
+				       void (*setup)(struct net_device *));
 extern int		register_netdev(struct net_device *dev);
 extern void		unregister_netdev(struct net_device *dev);
 /* Functions used for multicast support */
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Thu Jun 26 03:39:58 2003
+++ b/include/linux/pci.h	Sun Aug 31 06:52:15 2003
@@ -520,6 +520,32 @@
 	int  (*enable_wake) (struct pci_dev *dev, u32 state, int enable);   /* Enable wake event */
 };
 
+/**
+ * PCI_DEVICE - macro used to describe a specific pci device
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device.  The subvendor and subdevice fields will be set to
+ * PCI_ANY_ID.
+ */
+#define PCI_DEVICE(vend,dev) \
+	.vendor = (vend), .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+/**
+ * PCI_DEVICE_CLASS - macro used to describe a specific pci device class
+ * @dev_class: the class, subclass, prog-if triple for this device
+ * @dev_class_mask: the class mask for this device
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI class.  The vendor, device, subvendor, and subdevice 
+ * fields will be set to PCI_ANY_ID.
+ */
+#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \
+	.class = (dev_class), .class_mask = (dev_class_mask), \
+	.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
 
 /* these external functions are only available when PCI support is enabled */
 #ifdef CONFIG_PCI
@@ -602,7 +628,7 @@
 #define HAVE_PCI_SET_MWI
 int pci_set_mwi(struct pci_dev *dev);
 void pci_clear_mwi(struct pci_dev *dev);
-int pdev_set_mwi(struct pci_dev *dev);
+int pci_generic_prep_mwi(struct pci_dev *dev);
 int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_assign_resource(struct pci_dev *dev, int i);
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Tue Aug 19 23:09:15 2003
+++ b/include/linux/pci_ids.h	Sun Aug 31 01:20:32 2003
@@ -810,6 +810,7 @@
 #define PCI_DEVICE_ID_SUN_SCHIZO	0x8001
 #define PCI_DEVICE_ID_SUN_SABRE		0xa000
 #define PCI_DEVICE_ID_SUN_HUMMINGBIRD	0xa001
+#define PCI_DEVICE_ID_SUN_TOMATILLO	0xa801
 
 #define PCI_VENDOR_ID_CMD		0x1095
 #define PCI_DEVICE_ID_SII_1210SA	0x0240
@@ -841,6 +842,7 @@
 
 #define PCI_VENDOR_ID_SGI		0x10a9
 #define PCI_DEVICE_ID_SGI_IOC3		0x0003
+#define PCI_DEVICE_ID_SGI_IOC4		0x100a
 
 #define PCI_VENDOR_ID_ACC		0x10aa
 #define PCI_DEVICE_ID_ACC_2056		0x0000
@@ -1187,6 +1189,8 @@
 #define PCI_DEVICE_ID_SYSKONNECT_TR	0x4200
 #define PCI_DEVICE_ID_SYSKONNECT_GE	0x4300
 #define PCI_DEVICE_ID_SYSKONNECT_YU	0x4320
+#define PCI_DEVICE_ID_SYSKONNECT_9DXX	0x4400
+#define PCI_DEVICE_ID_SYSKONNECT_9MXX	0x4500
 
 #define PCI_VENDOR_ID_VMIC		0x114a
 #define PCI_DEVICE_ID_VMIC_VME		0x7587
@@ -1649,13 +1653,18 @@
 #define PCI_DEVICE_ID_TIGON3_5704	0x1648
 #define PCI_DEVICE_ID_TIGON3_5702FE	0x164d
 #define PCI_DEVICE_ID_TIGON3_5705	0x1653
+#define PCI_DEVICE_ID_TIGON3_5705_2	0x1654
 #define PCI_DEVICE_ID_TIGON3_5705M	0x165d
+#define PCI_DEVICE_ID_TIGON3_5705M_2	0x165e
 #define PCI_DEVICE_ID_TIGON3_5782	0x1696
+#define PCI_DEVICE_ID_TIGON3_5788	0x169c
 #define PCI_DEVICE_ID_TIGON3_5702X	0x16a6
 #define PCI_DEVICE_ID_TIGON3_5703X	0x16a7
 #define PCI_DEVICE_ID_TIGON3_5704S	0x16a8
 #define PCI_DEVICE_ID_TIGON3_5702A3	0x16c6
 #define PCI_DEVICE_ID_TIGON3_5703A3	0x16c7
+#define PCI_DEVICE_ID_TIGON3_5901	0x170d
+#define PCI_DEVICE_ID_TIGON3_5901_2	0x170e
 
 #define PCI_VENDOR_ID_SYBA		0x1592
 #define PCI_DEVICE_ID_SYBA_2P_EPP	0x0782
@@ -1672,7 +1681,9 @@
 
 #define PCI_VENDOR_ID_ALTIMA		0x173b
 #define PCI_DEVICE_ID_ALTIMA_AC1000	0x03e8
+#define PCI_DEVICE_ID_ALTIMA_AC1001	0x03e9
 #define PCI_DEVICE_ID_ALTIMA_AC9100	0x03ea
+#define PCI_DEVICE_ID_ALTIMA_AC1003	0x03eb
 
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
diff -Nru a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
--- a/include/linux/pkt_sched.h	Thu Jul 18 23:30:42 2002
+++ b/include/linux/pkt_sched.h	Thu Aug 21 15:09:19 2003
@@ -45,7 +45,7 @@
 
 struct tc_estimator
 {
-	char		interval;
+	signed char	interval;
 	unsigned char	ewma_log;
 };
 
diff -Nru a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
--- a/include/linux/rtnetlink.h	Tue Jun  3 22:03:51 2003
+++ b/include/linux/rtnetlink.h	Wed Jul 23 03:02:34 2003
@@ -167,6 +167,7 @@
 #define RTM_F_NOTIFY		0x100	/* Notify user of route change	*/
 #define RTM_F_CLONED		0x200	/* This route is cloned		*/
 #define RTM_F_EQUALIZE		0x400	/* Multipath equalizer: NI	*/
+#define RTM_F_PREFIX		0x800	/* Prefix addresses		*/
 
 /* Reserved table identifiers */
 
diff -Nru a/include/linux/seq_file.h b/include/linux/seq_file.h
--- a/include/linux/seq_file.h	Tue Mar 19 08:08:32 2002
+++ b/include/linux/seq_file.h	Mon Aug 25 09:34:39 2003
@@ -2,7 +2,15 @@
 #define _LINUX_SEQ_FILE_H
 #ifdef __KERNEL__
 
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/semaphore.h>
+
 struct seq_operations;
+struct file;
+struct vfsmount;
+struct dentry;
+struct inode;
 
 struct seq_file {
 	char *buf;
@@ -52,5 +60,10 @@
 int seq_printf(struct seq_file *, const char *, ...)
 	__attribute__ ((format (printf,2,3)));
 
+int seq_path(struct seq_file *, struct vfsmount *, struct dentry *, char *);
+
+int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
+int single_release(struct inode *, struct file *);
+int seq_release_private(struct inode *, struct file *);
 #endif
 #endif
diff -Nru a/include/linux/sisfb.h b/include/linux/sisfb.h
--- a/include/linux/sisfb.h	Sun Jun 29 09:27:44 2003
+++ b/include/linux/sisfb.h	Fri Aug 29 04:29:08 2003
@@ -39,9 +39,9 @@
 #define VB_CHRONTEL             0x02000000
 #define VB_301LV                0x04000000  	
 #define VB_302LV                0x08000000  	
-#define VB_TRUMPION		0x10000000     
-#define VB_VIDEOBRIDGE		(VB_301|VB_301B|VB_302B|VB_301LV|VB_302LV| \
-				 VB_LVDS|VB_CHRONTEL|VB_TRUMPION)
+#define VB_301C			0x10000000     
+#define VB_VIDEOBRIDGE		(VB_301|VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV| \
+				 VB_LVDS|VB_CHRONTEL)
 #define VB_SISBRIDGE            (VB_301|VB_301B|VB_302B|VB_301LV|VB_302LV)
 #define VB_SINGLE_MODE          0x20000000   	 /* CRT1 or CRT2; determined by VB_DISPTYPE_CRTx */
 #define VB_DISPMODE_SINGLE	VB_SINGLE_MODE 	 
@@ -88,6 +88,7 @@
 	SIS_740,
 	SIS_330,
 	SIS_660,
+	SIS_760,
 	MAX_SIS_CHIP
 } SIS_CHIP_TYPE;
 
@@ -243,7 +244,10 @@
 	unsigned long sisfb_vbflags;
 	unsigned long sisfb_currentvbflags;
 
-	char reserved[227]; 		/* for future use */
+	int sisfb_scalelcd;
+	unsigned long sisfb_specialtiming;
+
+	char reserved[219]; 		/* for future use */
 };
 
 #ifdef __KERNEL__
diff -Nru a/include/linux/sonypi.h b/include/linux/sonypi.h
--- a/include/linux/sonypi.h	Fri Feb 21 02:22:44 2003
+++ b/include/linux/sonypi.h	Tue Aug 26 04:52:33 2003
@@ -94,6 +94,8 @@
 #define SONYPI_EVENT_MEMORYSTICK_INSERT		54
 #define SONYPI_EVENT_MEMORYSTICK_EJECT		55
 #define SONYPI_EVENT_ANYBUTTON_RELEASED		56
+#define SONYPI_EVENT_BATTERY_INSERT		57
+#define SONYPI_EVENT_BATTERY_REMOVE		58
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT		_IOR('v', 0, __u8)
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Tue Jun 24 14:11:29 2003
+++ b/include/linux/sysctl.h	Wed Aug 13 11:57:54 2003
@@ -127,6 +127,7 @@
  	KERN_CORE_PATTERN=56,	/* string: pattern for core-files */
 	KERN_PPC_L3CR=57,       /* l3cr register on PPC */
 	KERN_EXCEPTION_TRACE=58, /* boolean: exception trace */
+ 	KERN_CORE_SETUID=59,	/* int: set to allow core dumps of setuid apps */
 };
 
 
@@ -146,6 +147,7 @@
 	VM_MAX_MAP_COUNT=11,	/* int: Maximum number of active map areas */
 	VM_MIN_READAHEAD=12,    /* Min file readahead */
 	VM_MAX_READAHEAD=13,    /* Max file readahead */
+	VM_PAGEBUF=17,		/* struct: Control pagebuf parameters */
 };
 
 
diff -Nru a/include/linux/threads.h b/include/linux/threads.h
--- a/include/linux/threads.h	Tue Feb  5 06:10:16 2002
+++ b/include/linux/threads.h	Thu Jun  6 06:45:40 2002
@@ -9,9 +9,9 @@
  */
  
 #ifdef CONFIG_SMP
-#define NR_CPUS	32		/* Max processors that can be running in SMP */
+#define NR_CPUS	CONFIG_NR_CPUS
 #else
-#define NR_CPUS 1
+#define NR_CPUS	1
 #endif
 
 #define MIN_THREADS_LEFT_FOR_ROOT 4
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Thu Feb 20 03:02:21 2003
+++ b/include/linux/usb.h	Wed Aug 21 11:20:19 2002
@@ -865,6 +865,7 @@
 	struct usb_device *children[USB_MAXCHILDREN];
 };
 
+extern int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum);
 extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
 extern struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum);
 
@@ -873,6 +874,7 @@
 extern void usb_scan_devices(void);
 
 /* used these for multi-interface device registration */
+extern int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned int ifnum);
 extern void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv);
 extern int usb_interface_claimed(struct usb_interface *iface);
 extern void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface);
diff -Nru a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
--- a/include/linux/usbdevice_fs.h	Mon Feb  4 23:42:04 2002
+++ b/include/linux/usbdevice_fs.h	Wed Aug 21 11:47:32 2002
@@ -142,6 +142,8 @@
 #define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
 #define USBDEVFS_RESET             _IO('U', 20)
 #define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)
+#define USBDEVFS_DISCONNECT        _IO('U', 22)
+#define USBDEVFS_CONNECT           _IO('U', 23)
 
 /* --------------------------------------------------------------------- */
 
diff -Nru a/include/linux/wm97xx.h b/include/linux/wm97xx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/wm97xx.h	Fri Jul 25 06:11:58 2003
@@ -0,0 +1,96 @@
+  
+/*
+ * Register bits for Wolfson WM97xx series of codecs
+ */
+ 
+#ifndef _WM97XX_H_
+#define _WM97XX_H_
+
+#include <linux/ac97_codec.h>	/* AC97 control layer */
+
+/*
+ * WM97xx AC97 Touchscreen registers
+ */
+#define AC97_WM97XX_DIGITISER1		0x76
+#define AC97_WM97XX_DIGITISER2		0x78
+#define AC97_WM97XX_DIGITISER_RD	0x7a
+
+/*
+ * WM97xx register bits
+ */
+#define WM97XX_POLL			0x8000		/* initiate a polling measurement */
+#define WM97XX_ADCSEL_X		0x1000		/* x coord measurement */
+#define WM97XX_ADCSEL_Y		0x2000		/* y coord measurement */
+#define WM97XX_ADCSEL_PRES	0x3000		/* pressure measurement */
+#define WM97XX_COO			0x0800		/* enable coordinate mode */
+#define WM97XX_CTC			0x0400		/* enable continuous mode */
+#define WM97XX_CM_RATE_93	0x0000		/* 93.75Hz continuous rate */
+#define WM97XX_CM_RATE_187	0x0100		/* 187.5Hz continuous rate */
+#define WM97XX_CM_RATE_375	0x0200		/* 375Hz continuous rate */
+#define WM97XX_CM_RATE_750	0x0300		/* 750Hz continuous rate */
+#define WM97XX_CM_RATE_8K	0x00f0		/* 8kHz continuous rate */
+#define WM97XX_CM_RATE_12K	0x01f0		/* 12kHz continuous rate */
+#define WM97XX_CM_RATE_24K	0x02f0		/* 24kHz continuous rate */
+#define WM97XX_CM_RATE_48K	0x03f0		/* 48kHz continuous rate */
+#define WM97XX_DELAY(i)		((i << 4) & 0x00f0)	/* sample delay times */
+#define WM97XX_SLEN			0x0008		/* slot read back enable */
+#define WM97XX_SLT(i)		((i - 5) & 0x7)	/* touchpanel slot selection (5-11) */
+#define WM97XX_PRP_DETW		0x4000		/* pen detect on, digitiser off, wake up */
+#define WM97XX_PRP_DET		0x8000		/* pen detect on, digitiser off, no wake up */
+#define WM97XX_PRP_DET_DIG	0xc000		/* pen detect on, digitiser on */
+#define WM97XX_RPR			0x2000		/* wake up on pen down */
+#define WM97XX_PEN_DOWN     0x8000     /* pen is down */
+
+/* WM9712 Bits */
+#define WM9712_45W			0x1000		/* set for 5-wire touchscreen */
+#define WM9712_PDEN			0x0800		/* measure only when pen down */
+#define WM9712_WAIT			0x0200		/* wait until adc is read before next sample */
+#define WM9712_PIL			0x0100		/* current used for pressure measurement. set 400uA else 200uA */ 
+#define WM9712_MASK_HI		0x0040		/* hi on mask pin (47) stops conversions */
+#define WM9712_MASK_EDGE	0x0080		/* rising/falling edge on pin delays sample */
+#define	WM9712_MASK_SYNC	0x00c0		/* rising/falling edge on mask initiates sample */
+#define WM9712_RPU(i)		(i&0x3f)	/* internal pull up on pen detect (64k / rpu) */
+#define WM9712_ADCSEL_COMP1	0x4000		/* COMP1/AUX1 measurement (pin29) */
+#define WM9712_ADCSEL_COMP2	0x5000		/* COMP2/AUX2 measurement (pin30) */
+#define WM9712_ADCSEL_BMON	0x6000		/* BMON/AUX3 measurement (pin31) */
+#define WM9712_ADCSEL_WIPER	0x7000		/* WIPER/AUX4 measurement (pin12) */
+#define WM9712_PD(i)		(0x1 << i)  /* power management */ 
+
+/* WM9712 Registers */
+#define AC97_WM9712_POWER			0x24
+#define AC97_WM9712_REV				0x58
+
+/* WM9705 Bits */
+#define WM9705_PDEN			0x1000		/* measure only when pen is down */
+#define WM9705_PINV			0x0800		/* inverts sense of pen down output */
+#define WM9705_BSEN			0x0400		/* BUSY flag enable, pin47 is 1 when busy */
+#define WM9705_BINV			0x0200		/* invert BUSY (pin47) output */
+#define WM9705_WAIT			0x0100		/* wait until adc is read before next sample */
+#define WM9705_PIL			0x0080		/* current used for pressure measurement. set 400uA else 200uA */ 
+#define WM9705_PHIZ			0x0040		/* set PHONE and PCBEEP inputs to high impedance */
+#define WM9705_MASK_HI		0x0010		/* hi on mask stops conversions */
+#define WM9705_MASK_EDGE	0x0020		/* rising/falling edge on pin delays sample */
+#define	WM9705_MASK_SYNC	0x0030		/* rising/falling edge on mask initiates sample */
+#define WM9705_PDD(i)		(i & 0x000f) /* pen detect comparator threshold */
+#define WM9705_ADCSEL_BMON	0x4000		/* BMON measurement */
+#define WM9705_ADCSEL_AUX	0x5000		/* AUX measurement */
+#define WM9705_ADCSEL_PHONE	0x6000		/* PHONE measurement */
+#define WM9705_ADCSEL_PCBEEP 0x7000		/* PCBEEP measurement */
+
+/* AUX ADC ID's */
+#define TS_COMP1			0x0
+#define TS_COMP2			0x1
+#define TS_BMON				0x2
+#define TS_WIPER			0x3
+
+/* ID numbers */
+#define WM97XX_ID1			0x574d
+#define WM9712_ID2			0x4c12
+#define WM9705_ID2			0x4c05
+
+#define AC97_LINK_FRAME		21			/* time in uS for AC97 link frame */
+
+void register_touchscreen_codec(struct ac97_codec *codec);
+void unregister_touchscreen_codec(struct ac97_codec *codec);
+
+#endif
diff -Nru a/include/net/ip_vs.h b/include/net/ip_vs.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/net/ip_vs.h	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,932 @@
+/*
+ *      IP Virtual Server
+ *      data structure and functionality definitions
+ */
+
+#ifndef _IP_VS_H
+#define _IP_VS_H
+
+#include <asm/types.h>          /* For __uXX types */
+
+#define IP_VS_VERSION_CODE            0x01000A
+#define NVERSION(version)                       \
+	(version >> 16) & 0xFF,                 \
+	(version >> 8) & 0xFF,                  \
+	version & 0xFF
+
+/*
+ *      Virtual Service Flags
+ */
+#define IP_VS_SVC_F_PERSISTENT        0x0001    /* persistent port */
+#define IP_VS_SVC_F_HASHED            0x0002    /* hashed entry */
+
+/*
+ *      Destination Server Flags
+ */
+#define IP_VS_DEST_F_AVAILABLE        0x0001    /* Available tag */
+
+/*
+ *      IPVS sync daemon states
+ */
+#define IP_VS_STATE_NONE    0           /* daemon is stopped */
+#define IP_VS_STATE_MASTER  1           /* started as master */
+#define IP_VS_STATE_BACKUP  2           /* started as backup */
+
+/*
+ *      IPVS socket options
+ */
+#define IP_VS_BASE_CTL		(64+1024+64)		/* base */
+
+#define IP_VS_SO_SET_NONE	IP_VS_BASE_CTL	        /* just peek */
+#define IP_VS_SO_SET_INSERT	(IP_VS_BASE_CTL+1)
+#define IP_VS_SO_SET_ADD	(IP_VS_BASE_CTL+2)
+#define IP_VS_SO_SET_EDIT	(IP_VS_BASE_CTL+3)
+#define IP_VS_SO_SET_DEL	(IP_VS_BASE_CTL+4)
+#define IP_VS_SO_SET_FLUSH	(IP_VS_BASE_CTL+5)
+#define IP_VS_SO_SET_LIST	(IP_VS_BASE_CTL+6)
+#define IP_VS_SO_SET_ADDDEST	(IP_VS_BASE_CTL+7)
+#define IP_VS_SO_SET_DELDEST	(IP_VS_BASE_CTL+8)
+#define IP_VS_SO_SET_EDITDEST	(IP_VS_BASE_CTL+9)
+#define IP_VS_SO_SET_TIMEOUTS	(IP_VS_BASE_CTL+10)
+#define IP_VS_SO_SET_STARTDAEMON (IP_VS_BASE_CTL+11)
+#define IP_VS_SO_SET_STOPDAEMON (IP_VS_BASE_CTL+12)
+#define IP_VS_SO_SET_RESTORE    (IP_VS_BASE_CTL+13)
+#define IP_VS_SO_SET_SAVE       (IP_VS_BASE_CTL+14)
+#define IP_VS_SO_SET_ZERO	(IP_VS_BASE_CTL+15)
+#define IP_VS_SO_SET_MAX	IP_VS_SO_SET_ZERO
+
+#define IP_VS_SO_GET_VERSION	IP_VS_BASE_CTL
+#define IP_VS_SO_GET_INFO	(IP_VS_BASE_CTL+1)
+#define IP_VS_SO_GET_SERVICES	(IP_VS_BASE_CTL+2)
+#define IP_VS_SO_GET_SERVICE	(IP_VS_BASE_CTL+3)
+#define IP_VS_SO_GET_DESTS	(IP_VS_BASE_CTL+4)
+#define IP_VS_SO_GET_DEST	(IP_VS_BASE_CTL+5)	/* not used now */
+#define IP_VS_SO_GET_TIMEOUTS	(IP_VS_BASE_CTL+6)
+#define IP_VS_SO_GET_DAEMON	(IP_VS_BASE_CTL+7)
+#define IP_VS_SO_GET_MAX	IP_VS_SO_GET_DAEMON
+
+
+/*
+ *      IPVS Connection Flags
+ */
+#define IP_VS_CONN_F_FWD_MASK         0x0007    /* mask for the fwd methods */
+#define IP_VS_CONN_F_MASQ	      0x0000    /* masquerading */
+#define IP_VS_CONN_F_LOCALNODE	      0x0001    /* local node */
+#define IP_VS_CONN_F_TUNNEL	      0x0002    /* tunneling */
+#define IP_VS_CONN_F_DROUTE           0x0003    /* direct routing */
+#define IP_VS_CONN_F_BYPASS           0x0004    /* cache bypass */
+#define IP_VS_CONN_F_HASHED	      0x0040	/* hashed entry */
+#define IP_VS_CONN_F_NOOUTPUT         0x0080    /* no output packets */
+#define IP_VS_CONN_F_INACTIVE         0x0100    /* not established */
+#define IP_VS_CONN_F_OUT_SEQ          0x0200    /* must do output seq adjust */
+#define IP_VS_CONN_F_IN_SEQ           0x0400    /* must do input seq adjust */
+#define IP_VS_CONN_F_SEQ_MASK         0x0600    /* in/out sequence mask */
+#define IP_VS_CONN_F_NO_CPORT         0x0800    /* no client port set yet */
+
+/* Move it to better place one day, for now keep it unique */
+#define NFC_IPVS_PROPERTY	0x10000
+
+#define IP_VS_SCHEDNAME_MAXLEN         16
+#define IP_VS_IFNAME_MAXLEN            16
+
+struct ip_vs_rule_user {
+	/* global options */
+	int             tcp_timeout;    /* timeout values */
+	int             tcp_fin_timeout;
+	int             udp_timeout;
+	int             state;          /* sync daemon state */
+	char            mcast_ifn[IP_VS_IFNAME_MAXLEN];
+					/* multicast interface name */
+
+	/* virtual service options */
+	u_int16_t	protocol;
+	u_int32_t	vaddr;          /* virtual address */
+	u_int16_t	vport;
+	u_int32_t       vfwmark;        /* firwall mark of virtual service*/
+	char            sched_name[IP_VS_SCHEDNAME_MAXLEN];
+	unsigned	vs_flags;       /* virtual service flags */
+	unsigned        timeout;        /* persistent timeout in ticks */
+	u_int32_t	netmask;        /* persistent netmask */
+
+	/* destination specific options */
+	u_int32_t	daddr;          /* destination address */
+	u_int16_t	dport;
+	unsigned        conn_flags;     /* destination flags */
+	int             weight;         /* destination weight */
+};
+
+
+/*
+ *	IPVS statistics object (for user space)
+ */
+struct ip_vs_stats_user
+{
+	__u32                   conns;          /* connections scheduled */
+	__u32                   inpkts;         /* incoming packets */
+	__u32                   outpkts;        /* outgoing packets */
+	__u64                   inbytes;        /* incoming bytes */
+	__u64                   outbytes;       /* outgoing bytes */
+
+	__u32			cps;		/* current connection rate */
+	__u32			inpps;		/* current in packet rate */
+	__u32			outpps;		/* current out packet rate */
+	__u32			inbps;		/* current in byte rate */
+	__u32			outbps;		/* current out byte rate */
+};
+
+
+/* The argument to IP_VS_SO_GET_INFO */
+struct ip_vs_getinfo {
+	/* version number */
+	unsigned int	version;
+
+	/* size of connection hash table */
+	unsigned int	size;
+
+	/* number of virtual services */
+	unsigned int	num_services;
+};
+
+/* The argument to IP_VS_SO_GET_SERVICE */
+struct ip_vs_service_user {
+	/* which service: user fills this in */
+	u_int16_t	protocol;
+	u_int32_t	addr;           /* virtual address */
+	u_int16_t	port;
+	u_int32_t       fwmark;         /* firwall mark of virtual service */
+
+	/* service options */
+	char            sched_name[IP_VS_SCHEDNAME_MAXLEN];
+	unsigned	flags;          /* virtual service flags */
+	unsigned        timeout;        /* persistent timeout in ticks */
+	u_int32_t	netmask;        /* persistent netmask */
+
+	/* number of real servers */
+	unsigned int    num_dests;
+
+	/* statistics */
+	struct ip_vs_stats_user stats;
+};
+
+struct ip_vs_dest_user {
+	u_int32_t	addr;           /* destination address */
+	u_int16_t	port;
+	unsigned	flags;		/* destination flags */
+	int		weight;         /* destination weight */
+	u_int32_t	activeconns;	/* active connections */
+	u_int32_t	inactconns;	/* inactive connections */
+
+	/* statistics */
+	struct ip_vs_stats_user stats;
+};
+
+/* The argument to IP_VS_SO_GET_DESTS */
+struct ip_vs_get_dests {
+	/* which service: user fills this in */
+	u_int16_t	protocol;
+	u_int32_t	addr;           /* virtual address */
+	u_int16_t	port;
+	u_int32_t       fwmark;         /* firwall mark of virtual service */
+
+	/* number of real servers */
+	unsigned int    num_dests;
+
+	/* the real servers */
+	struct ip_vs_dest_user entrytable[0];
+};
+
+/* The argument to IP_VS_SO_GET_SERVICES */
+struct ip_vs_get_services {
+	/* number of virtual services */
+	unsigned int num_services;
+
+	/* service table */
+	struct ip_vs_service_user entrytable[0];
+};
+
+/* The argument to IP_VS_SO_GET_TIMEOUTS */
+struct ip_vs_timeout_user {
+	int             tcp_timeout;
+	int             tcp_fin_timeout;
+	int             udp_timeout;
+};
+
+/* The argument to IP_VS_SO_GET_DAEMON */
+struct ip_vs_daemon_user {
+	int	state;				/* sync daemon state */
+	char	mcast_ifn[IP_VS_IFNAME_MAXLEN];	/* multicast interface name */
+};
+
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/list.h>                 /* for struct list_head */
+#include <linux/spinlock.h>             /* for struct rwlock_t */
+#include <linux/skbuff.h>               /* for struct sk_buff */
+#include <linux/ip.h>                   /* for struct iphdr */
+#include <asm/atomic.h>                 /* for struct atomic_t */
+#include <linux/netdevice.h>		/* for struct neighbour; */
+#include <net/dst.h>			/* for struct dst_entry */
+#include <net/route.h>			/* for ip_route_output */
+#include <net/tcp.h>
+#include <net/udp.h>
+
+
+#ifdef CONFIG_IP_VS_DEBUG
+extern int ip_vs_get_debug_level(void);
+#define IP_VS_DBG(level, msg...)			\
+    do {						\
+	    if (level <= ip_vs_get_debug_level())	\
+		    printk(KERN_DEBUG "IPVS: " msg);	\
+    } while (0)
+#define IP_VS_DBG_RL(msg...)				\
+    do {						\
+	    if (net_ratelimit())			\
+		    printk(KERN_DEBUG "IPVS: " msg);	\
+    } while (0)
+#else	/* NO DEBUGGING at ALL */
+#define IP_VS_DBG(level, msg...)  do {} while (0)
+#define IP_VS_DBG_RL(msg...)  do {} while (0)
+#endif
+
+#define IP_VS_BUG() BUG()
+#define IP_VS_ERR(msg...) printk(KERN_ERR "IPVS: " msg)
+#define IP_VS_INFO(msg...) printk(KERN_INFO "IPVS: " msg)
+#define IP_VS_WARNING(msg...) \
+	printk(KERN_WARNING "IPVS: " msg)
+#define IP_VS_ERR_RL(msg...)				\
+    do {						\
+	    if (net_ratelimit())			\
+		    printk(KERN_ERR "IPVS: " msg);	\
+    } while (0)
+
+#ifdef CONFIG_IP_VS_DEBUG
+#define EnterFunction(level)						\
+    do {								\
+	    if (level <= ip_vs_get_debug_level())			\
+		    printk(KERN_DEBUG "Enter: %s, %s line %i\n",	\
+			   __FUNCTION__, __FILE__, __LINE__);		\
+    } while (0)
+#define LeaveFunction(level)                                            \
+    do {                                                                \
+	    if (level <= ip_vs_get_debug_level())                       \
+			printk(KERN_DEBUG "Leave: %s, %s line %i\n",    \
+			       __FUNCTION__, __FILE__, __LINE__);       \
+    } while (0)
+#else
+#define EnterFunction(level)   do {} while (0)
+#define LeaveFunction(level)   do {} while (0)
+#endif
+
+
+/*
+ *      The port number of FTP service (in network order).
+ */
+#define FTPPORT  __constant_htons(21)
+#define FTPDATA  __constant_htons(20)
+
+
+/*
+ *      IPVS sysctl variables under the /proc/sys/net/ipv4/vs/
+ */
+#define NET_IPV4_VS              21
+
+enum {
+	NET_IPV4_VS_DEBUG_LEVEL=1,
+	NET_IPV4_VS_AMEMTHRESH=2,
+	NET_IPV4_VS_AMDROPRATE=3,
+	NET_IPV4_VS_DROP_ENTRY=4,
+	NET_IPV4_VS_DROP_PACKET=5,
+	NET_IPV4_VS_SECURE_TCP=6,
+	NET_IPV4_VS_TO_ES=7,
+	NET_IPV4_VS_TO_SS=8,
+	NET_IPV4_VS_TO_SR=9,
+	NET_IPV4_VS_TO_FW=10,
+	NET_IPV4_VS_TO_TW=11,
+	NET_IPV4_VS_TO_CL=12,
+	NET_IPV4_VS_TO_CW=13,
+	NET_IPV4_VS_TO_LA=14,
+	NET_IPV4_VS_TO_LI=15,
+	NET_IPV4_VS_TO_SA=16,
+	NET_IPV4_VS_TO_UDP=17,
+	NET_IPV4_VS_TO_ICMP=18,
+	NET_IPV4_VS_LBLC_EXPIRE=19,
+	NET_IPV4_VS_LBLCR_EXPIRE=20,
+	NET_IPV4_VS_CACHE_BYPASS=22,
+	NET_IPV4_VS_EXPIRE_NODEST_CONN=23,
+	NET_IPV4_VS_SYNC_THRESHOLD=24,
+	NET_IPV4_VS_NAT_ICMP_SEND=25,
+	NET_IPV4_VS_LAST
+};
+
+
+/*
+ *      IPVS State Values
+ */
+enum {
+	IP_VS_S_NONE = 0,
+	IP_VS_S_ESTABLISHED,
+	IP_VS_S_SYN_SENT,
+	IP_VS_S_SYN_RECV,
+	IP_VS_S_FIN_WAIT,
+	IP_VS_S_TIME_WAIT,
+	IP_VS_S_CLOSE,
+	IP_VS_S_CLOSE_WAIT,
+	IP_VS_S_LAST_ACK,
+	IP_VS_S_LISTEN,
+	IP_VS_S_SYNACK,
+	IP_VS_S_UDP,
+	IP_VS_S_ICMP,
+	IP_VS_S_LAST
+};
+
+
+struct ip_vs_timeout_table {
+	atomic_t refcnt;
+	int scale;
+	int timeout[IP_VS_S_LAST+1];
+};
+
+
+/*
+ *	Transport protocol header
+ */
+union ip_vs_tphdr {
+	unsigned char *raw;
+	struct udphdr *uh;
+	struct tcphdr *th;
+	struct icmphdr *icmph;
+	__u16 *portp;
+};
+
+
+/*
+ *	Delta sequence info structure
+ *	Each ip_vs_conn has 2 (output AND input seq. changes).
+ *      Only used in the VS/NAT.
+ */
+struct ip_vs_seq {
+	__u32           init_seq;       /* Add delta from this seq */
+	__u32           delta;          /* Delta in sequence numbers */
+	__u32           previous_delta; /* Delta in sequence numbers
+					   before last resized pkt */
+};
+
+
+/*
+ *	IPVS statistics object
+ */
+struct ip_vs_stats
+{
+	__u32                   conns;          /* connections scheduled */
+	__u32                   inpkts;         /* incoming packets */
+	__u32                   outpkts;        /* outgoing packets */
+	__u64                   inbytes;        /* incoming bytes */
+	__u64                   outbytes;       /* outgoing bytes */
+
+	__u32			cps;		/* current connection rate */
+	__u32			inpps;		/* current in packet rate */
+	__u32			outpps;		/* current out packet rate */
+	__u32			inbps;		/* current in byte rate */
+	__u32			outbps;		/* current out byte rate */
+
+	spinlock_t              lock;           /* spin lock */
+};
+
+
+/*
+ *	IP_VS structure allocated for each dynamically scheduled connection
+ */
+struct ip_vs_conn {
+	struct list_head        c_list;         /* hashed list heads */
+
+	/* Protocol, addresses and port numbers */
+	__u32                   caddr;          /* client address */
+	__u32                   vaddr;          /* virtual address */
+	__u32                   daddr;          /* destination address */
+	__u16                   cport;
+	__u16                   vport;
+	__u16                   dport;
+	__u16                   protocol;       /* Which protocol (TCP/UDP) */
+
+	/* counter and timer */
+	atomic_t		refcnt;		/* reference count */
+	struct timer_list	timer;		/* Expiration timer */
+	volatile unsigned long	timeout;	/* timeout */
+	struct ip_vs_timeout_table *timeout_table;
+
+	/* Flags and state transition */
+	spinlock_t              lock;           /* lock for state transition */
+	volatile __u16          flags;          /* status flags */
+	volatile __u16          state;          /* state info */
+
+	/* Control members */
+	struct ip_vs_conn       *control;       /* Master control connection */
+	atomic_t                n_control;      /* Number of controlled ones */
+	struct ip_vs_dest       *dest;          /* real server */
+	atomic_t                in_pkts;        /* incoming packet counter */
+
+	/* packet transmitter for different forwarding methods */
+	int (*packet_xmit)(struct sk_buff *skb, struct ip_vs_conn *cp);
+
+	/* Note: we can group the following members into a structure,
+	   in order to save more space, and the following members are
+	   only used in VS/NAT anyway */
+	struct ip_vs_app        *app;           /* bound ip_vs_app object */
+	void                    *app_data;      /* Application private data */
+	struct ip_vs_seq        in_seq;         /* incoming seq. struct */
+	struct ip_vs_seq        out_seq;        /* outgoing seq. struct */
+};
+
+
+/*
+ *	The information about the virtual service offered to the net
+ *	and the forwarding entries
+ */
+struct ip_vs_service {
+	struct list_head	s_list;   /* for normal service table */
+	struct list_head	f_list;   /* for fwmark-based service table */
+	atomic_t		refcnt;   /* reference counter */
+	atomic_t		usecnt;   /* use counter */
+
+	__u16			protocol; /* which protocol (TCP/UDP) */
+	__u32			addr;	  /* IP address for virtual service */
+	__u16			port;	  /* port number for the service */
+	__u32                   fwmark;   /* firewall mark of the service */
+	unsigned		flags;	  /* service status flags */
+	unsigned		timeout;  /* persistent timeout in ticks */
+	__u32			netmask;  /* grouping granularity */
+
+	struct list_head	destinations;  /* real server d-linked list */
+	__u32			num_dests;     /* number of servers */
+	struct ip_vs_stats      stats;         /* statistics for the service */
+
+	/* for scheduling */
+	struct ip_vs_scheduler	*scheduler;    /* bound scheduler object */
+	rwlock_t		sched_lock;    /* lock sched_data */
+	void			*sched_data;   /* scheduler application data */
+};
+
+
+/*
+ *	The real server destination forwarding entry
+ *	with ip address, port number, and so on.
+ */
+struct ip_vs_dest {
+	struct list_head	n_list;   /* for the dests in the service */
+	struct list_head	d_list;   /* for table with all the dests */
+
+	__u32			addr;	  /* IP address of real server */
+	__u16			port;	  /* port number of the service */
+	unsigned		flags;	  /* dest status flags */
+	atomic_t		weight;	  /* server weight */
+	atomic_t		conn_flags;	/* flags to copy to conn */
+	atomic_t		activeconns;	/* active connections */
+	atomic_t		inactconns;     /* inactive connections */
+	atomic_t		refcnt;	        /* reference counter */
+	struct ip_vs_stats      stats;          /* statistics */
+
+	/* for destination cache */
+	spinlock_t		dst_lock;	/* lock dst_cache */
+	struct dst_entry	*dst_cache;	/* destination cache entry */
+	u32			dst_rtos;	/* RT_TOS(tos) for dst */
+
+	/* for virtual service */
+	struct ip_vs_service    *svc;     /* service that it belongs to */
+	__u16			protocol; /* which protocol (TCP/UDP) */
+	__u32			vaddr;	  /* IP address for virtual service */
+	__u16			vport;	  /* port number for the service */
+	__u32                   vfwmark;  /* firewall mark of the service */
+};
+
+
+/*
+ *	The scheduler object
+ */
+struct ip_vs_scheduler {
+	struct list_head        n_list;   /* d-linked list head */
+	char			*name;    /* scheduler name */
+	atomic_t                refcnt;   /* reference counter */
+	struct module		*module;  /* THIS_MODULE/NULL */
+
+	/* scheduler initializing service */
+	int (*init_service)(struct ip_vs_service *svc);
+	/* scheduling service finish */
+	int (*done_service)(struct ip_vs_service *svc);
+	/* scheduler updating service */
+	int (*update_service)(struct ip_vs_service *svc);
+
+	/* selecting a server from the given service */
+	struct ip_vs_dest* (*schedule)(struct ip_vs_service *svc,
+				       struct iphdr *iph);
+};
+
+
+/*
+ *	The application module object
+ */
+struct ip_vs_app
+{
+	struct list_head        n_list;   /* d-linked list head */
+	char                    *name;    /* name of application module */
+	unsigned                type;     /* type = proto<<16 | port
+					     (host byte order)*/
+	struct module		*module;  /* THIS_MODULE/NULL */
+
+	/* ip_vs_app initializer */
+	int (*init_conn)(struct ip_vs_app *, struct ip_vs_conn *);
+	/* ip_vs_app finish */
+	int (*done_conn)(struct ip_vs_app *, struct ip_vs_conn *);
+	/* output hook */
+	int (*pkt_out)(struct ip_vs_app *,
+		       struct ip_vs_conn *, struct sk_buff *);
+	/* input hook */
+	int (*pkt_in)(struct ip_vs_app *,
+		      struct ip_vs_conn *, struct sk_buff *);
+};
+
+
+/*
+ *      IPVS core functions
+ *      (from ip_vs_core.c)
+ */
+extern const char *ip_vs_proto_name(unsigned proto);
+extern unsigned int check_for_ip_vs_out(struct sk_buff **skb_p,
+					int (*okfn)(struct sk_buff *));
+
+
+/*
+ *     ip_vs_conn handling functions
+ *     (from ip_vs_conn.c)
+ */
+
+/*
+ *     IPVS connection entry hash table
+ */
+#ifndef CONFIG_IP_VS_TAB_BITS
+#define CONFIG_IP_VS_TAB_BITS   12
+#endif
+/* make sure that IP_VS_CONN_TAB_BITS is located in [8, 20] */
+#if CONFIG_IP_VS_TAB_BITS < 8
+#define IP_VS_CONN_TAB_BITS	8
+#endif
+#if CONFIG_IP_VS_TAB_BITS > 20
+#define IP_VS_CONN_TAB_BITS	20
+#endif
+#if 8 <= CONFIG_IP_VS_TAB_BITS && CONFIG_IP_VS_TAB_BITS <= 20
+#define IP_VS_CONN_TAB_BITS	CONFIG_IP_VS_TAB_BITS
+#endif
+#define IP_VS_CONN_TAB_SIZE     (1 << IP_VS_CONN_TAB_BITS)
+#define IP_VS_CONN_TAB_MASK     (IP_VS_CONN_TAB_SIZE - 1)
+
+#define VS_STATE_INPUT	        0
+#define VS_STATE_OUTPUT	        4
+#define VS_STATE_INPUT_ONLY	8
+
+extern struct ip_vs_timeout_table vs_timeout_table;
+extern struct ip_vs_timeout_table vs_timeout_table_dos;
+
+extern struct ip_vs_conn *ip_vs_conn_in_get
+(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+extern struct ip_vs_conn *ip_vs_conn_out_get
+(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+
+/* put back the conn without restarting its timer */
+static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
+{
+	atomic_dec(&cp->refcnt);
+}
+extern void ip_vs_conn_put(struct ip_vs_conn *cp);
+
+extern struct ip_vs_conn *
+ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
+	       __u32 daddr, __u16 dport, unsigned flags,
+	       struct ip_vs_dest *dest);
+extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
+
+extern const char * ip_vs_state_name(int state);
+extern int ip_vs_set_state(struct ip_vs_conn *cp, int state_off,
+			   struct iphdr *iph, void *tp);
+extern int ip_vs_conn_listen(struct ip_vs_conn *cp);
+extern int ip_vs_check_template(struct ip_vs_conn *ct);
+extern void ip_vs_secure_tcp_set(int on);
+extern void ip_vs_random_dropentry(void);
+extern int ip_vs_conn_init(void);
+extern void ip_vs_conn_cleanup(void);
+
+static inline void ip_vs_control_del(struct ip_vs_conn *cp)
+{
+	struct ip_vs_conn *ctl_cp = cp->control;
+	if (!ctl_cp) {
+		IP_VS_ERR("request control DEL for uncontrolled: "
+			  "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+			  NIPQUAD(cp->caddr),ntohs(cp->cport),
+			  NIPQUAD(cp->vaddr),ntohs(cp->vport));
+		return;
+	}
+
+	IP_VS_DBG(7, "DELeting control for: "
+		  "cp.dst=%d.%d.%d.%d:%d ctl_cp.dst=%d.%d.%d.%d:%d\n",
+		  NIPQUAD(cp->caddr),ntohs(cp->cport),
+		  NIPQUAD(ctl_cp->caddr),ntohs(ctl_cp->cport));
+
+	cp->control = NULL;
+	if (atomic_read(&ctl_cp->n_control) == 0) {
+		IP_VS_ERR("BUG control DEL with n=0 : "
+			  "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+			  NIPQUAD(cp->caddr),ntohs(cp->cport),
+			  NIPQUAD(cp->vaddr),ntohs(cp->vport));
+		return;
+	}
+	atomic_dec(&ctl_cp->n_control);
+}
+
+static inline void
+ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp)
+{
+	if (cp->control) {
+		IP_VS_ERR("request control ADD for already controlled: "
+			  "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+			  NIPQUAD(cp->caddr),ntohs(cp->cport),
+			  NIPQUAD(cp->vaddr),ntohs(cp->vport));
+		ip_vs_control_del(cp);
+	}
+
+	IP_VS_DBG(7, "ADDing control for: "
+		  "cp.dst=%d.%d.%d.%d:%d ctl_cp.dst=%d.%d.%d.%d:%d\n",
+		  NIPQUAD(cp->caddr),ntohs(cp->cport),
+		  NIPQUAD(ctl_cp->caddr),ntohs(ctl_cp->cport));
+
+	cp->control = ctl_cp;
+	atomic_inc(&ctl_cp->n_control);
+}
+
+
+/*
+ *      IPVS application functions
+ *      (from ip_vs_app.c)
+ */
+#define IP_VS_APP_MAX_PORTS  8
+extern int register_ip_vs_app(struct ip_vs_app *mapp,
+			      unsigned short proto, __u16 port);
+extern int unregister_ip_vs_app(struct ip_vs_app *mapp);
+extern struct ip_vs_app * ip_vs_bind_app(struct ip_vs_conn *cp);
+extern int ip_vs_unbind_app(struct ip_vs_conn *cp);
+extern int ip_vs_app_pkt_out(struct ip_vs_conn *, struct sk_buff *skb);
+extern int ip_vs_app_pkt_in(struct ip_vs_conn *, struct sk_buff *skb);
+extern int ip_vs_skb_replace(struct sk_buff *skb, int pri,
+			     char *o_buf, int o_len, char *n_buf, int n_len);
+extern int ip_vs_app_init(void);
+extern void ip_vs_app_cleanup(void);
+
+
+/*
+ *      Registering/unregistering scheduler functions
+ *      (from ip_vs_sched.c)
+ */
+extern int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler);
+extern int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler);
+extern int ip_vs_bind_scheduler(struct ip_vs_service *svc,
+				struct ip_vs_scheduler *scheduler);
+extern int ip_vs_unbind_scheduler(struct ip_vs_service *svc);
+extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name);
+extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler);
+
+
+/*
+ *      IPVS control data and functions
+ *      (from ip_vs_ctl.c)
+ */
+extern int sysctl_ip_vs_cache_bypass;
+extern int sysctl_ip_vs_expire_nodest_conn;
+extern int sysctl_ip_vs_sync_threshold;
+extern int sysctl_ip_vs_nat_icmp_send;
+extern struct ip_vs_stats ip_vs_stats;
+
+extern struct ip_vs_service *ip_vs_service_get(__u32 fwmark,
+					       __u16 protocol,
+					       __u32 vaddr, __u16 vport);
+static inline void ip_vs_service_put(struct ip_vs_service *svc)
+{
+	atomic_dec(&svc->usecnt);
+}
+
+extern struct ip_vs_dest *
+ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport);
+extern void ip_vs_random_dropentry(void);
+extern int ip_vs_control_init(void);
+extern void ip_vs_control_cleanup(void);
+
+
+/*
+ *      IPVS sync daemon data and function prototypes
+ *      (from ip_vs_sync.c)
+ */
+extern volatile int ip_vs_sync_state;
+extern char ip_vs_mcast_ifn[IP_VS_IFNAME_MAXLEN];
+extern int start_sync_thread(int state, char *mcast_ifn);
+extern int stop_sync_thread(void);
+extern void ip_vs_sync_conn(struct ip_vs_conn *cp);
+
+
+/*
+ *      IPVS rate estimator prototypes (from ip_vs_est.c)
+ */
+extern int ip_vs_new_estimator(struct ip_vs_stats *stats);
+extern void ip_vs_kill_estimator(struct ip_vs_stats *stats);
+extern void ip_vs_zero_estimator(struct ip_vs_stats *stats);
+
+
+/*
+ *	This is a simple mechanism to ignore packets when
+ *	we are loaded. Just set ip_vs_drop_rate to 'n' and
+ *	we start to drop 1/rate of the packets
+ */
+extern int ip_vs_drop_rate;
+extern int ip_vs_drop_counter;
+
+static __inline__ int ip_vs_todrop(void)
+{
+	if (!ip_vs_drop_rate) return 0;
+	if (--ip_vs_drop_counter > 0) return 0;
+	ip_vs_drop_counter = ip_vs_drop_rate;
+	return 1;
+}
+
+
+/*
+ *      ip_vs_fwd_tag returns the forwarding tag of the connection
+ */
+#define IP_VS_FWD_METHOD(cp)  (cp->flags & IP_VS_CONN_F_FWD_MASK)
+
+extern __inline__ char ip_vs_fwd_tag(struct ip_vs_conn *cp)
+{
+	char fwd;
+
+	switch (IP_VS_FWD_METHOD(cp)) {
+	case IP_VS_CONN_F_MASQ:
+		fwd = 'M'; break;
+	case IP_VS_CONN_F_LOCALNODE:
+		fwd = 'L'; break;
+	case IP_VS_CONN_F_TUNNEL:
+		fwd = 'T'; break;
+	case IP_VS_CONN_F_DROUTE:
+		fwd = 'R'; break;
+	case IP_VS_CONN_F_BYPASS:
+		fwd = 'B'; break;
+	default:
+		fwd = '?'; break;
+	}
+	return fwd;
+}
+
+
+/*
+ *	transport layer header checking
+ */
+extern inline int ip_vs_header_check(struct sk_buff *skb, int proto, int ihl)
+{
+	int len;
+
+	switch (proto) {
+	case IPPROTO_TCP:
+		len = ihl + sizeof(struct tcphdr);
+		/* we don't care about TCP options */
+		break;
+	case IPPROTO_UDP:
+		len = ihl + sizeof(struct udphdr);
+		break;
+	default:
+		len = 0;
+	}
+
+	/* guarantee protocol header available in skb data area */
+	if (!pskb_may_pull(skb, len))
+		return -1;
+	else
+		return 0;
+}
+
+
+/*
+ *      Destination cache
+ */
+static inline void
+__ip_vs_dst_set(struct ip_vs_dest *dest, u32 rtos, struct dst_entry *dst)
+{
+	struct dst_entry *old_dst;
+
+	old_dst = dest->dst_cache;
+	dest->dst_cache = dst;
+	dest->dst_rtos = rtos;
+	dst_release(old_dst);
+}
+
+static inline void
+__ip_vs_dst_reset(struct ip_vs_dest *dest)
+{
+	struct dst_entry *old_dst;
+
+	old_dst = dest->dst_cache;
+	dest->dst_cache = NULL;
+	dst_release(old_dst);
+}
+
+static inline struct dst_entry *
+__ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos, u32 cookie)
+{
+	struct dst_entry *dst = dest->dst_cache;
+
+	if (!dst)
+		return NULL;
+	if ((dst->obsolete || rtos != dest->dst_rtos) &&
+	    dst->ops->check(dst, cookie) == NULL) {
+		dest->dst_cache = 0;
+		return NULL;
+	}
+	dst_hold(dst);
+	return dst;
+}
+
+static inline struct rtable *
+__ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos)
+{
+	struct rtable *rt;			/* Route to the other host */
+	struct ip_vs_dest *dest = cp->dest;
+
+	if (dest) {
+		spin_lock(&dest->dst_lock);
+		if (!(rt = (struct rtable *)
+		      __ip_vs_dst_check(dest, rtos, 0))) {
+			if (ip_route_output(&rt, dest->addr, 0, rtos, 0)) {
+				spin_unlock(&dest->dst_lock);
+				IP_VS_DBG_RL("ip_route_output error, "
+					     "dest: %u.%u.%u.%u\n",
+					     NIPQUAD(dest->addr));
+				return NULL;
+			}
+			__ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst));
+			IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n",
+				  NIPQUAD(dest->addr),
+				  atomic_read(&rt->u.dst.__refcnt), rtos);
+		}
+		spin_unlock(&dest->dst_lock);
+	} else {
+		if (ip_route_output(&rt, cp->daddr, 0, rtos, 0)) {
+			IP_VS_DBG_RL("ip_route_output error, dest: "
+				     "%u.%u.%u.%u\n", NIPQUAD(cp->daddr));
+			return NULL;
+		}
+	}
+
+	return rt;
+}
+
+static inline u16 ip_vs_check_diff(u32 old, u32 new, u16 oldsum)
+{
+	u32 diff[2] = { old, new };
+
+	return csum_fold(csum_partial((char *) diff, sizeof(diff),
+				      oldsum ^ 0xFFFF));
+}
+
+static inline void ip_vs_fast_check_update(union ip_vs_tphdr *h,
+	u32 oldip, u32 newip, u16 oldport, u16 newport, u8 protocol)
+{
+	u16 *checkp;
+
+	if (protocol == IPPROTO_TCP)
+		checkp = &h->th->check;
+	else
+		checkp = &h->uh->check;
+	*checkp = ip_vs_check_diff(~oldip, newip,
+				   ip_vs_check_diff(oldport ^ 0xFFFF,
+						    newport, *checkp));
+	if (!*checkp && protocol == IPPROTO_UDP)
+		*checkp = 0xFFFF;
+}
+
+static inline int
+ip_vs_skb_cow(struct sk_buff *skb, unsigned int headroom,
+	      struct iphdr **iph_p, unsigned char **t_p)
+{
+	int delta = (headroom > 16 ? headroom : 16) - skb_headroom(skb);
+
+	if (delta < 0)
+		delta = 0;
+
+	if (delta || skb_cloned(skb)) {
+		if (pskb_expand_head(skb, (delta+15)&~15, 0, GFP_ATOMIC))
+			return -ENOMEM;
+
+		/* skb data changed, update pointers */
+		*iph_p = skb->nh.iph;
+		*t_p = (char*) (*iph_p) + (*iph_p)->ihl * 4;
+	}
+	return 0;
+}
+
+#endif /* __KERNEL__ */
+
+#endif	/* _IP_VS_H */
diff -Nru a/include/net/neighbour.h b/include/net/neighbour.h
--- a/include/net/neighbour.h	Tue Feb  5 09:39:48 2002
+++ b/include/net/neighbour.h	Tue Aug 19 12:44:36 2003
@@ -180,6 +180,7 @@
 extern void			neigh_destroy(struct neighbour *neigh);
 extern int			__neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
 extern int			neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp);
+extern void			neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
 extern int			neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
 extern int			neigh_resolve_output(struct sk_buff *skb);
 extern int			neigh_connected_output(struct sk_buff *skb);
diff -Nru a/include/net/pkt_sched.h b/include/net/pkt_sched.h
--- a/include/net/pkt_sched.h	Tue Jul  8 18:53:06 2003
+++ b/include/net/pkt_sched.h	Sat Aug  2 23:13:10 2003
@@ -212,12 +212,16 @@
 
 #if PSCHED_CLOCK_SOURCE == PSCHED_JIFFIES
 
-#if HZ == 100
+#if HZ < 96
+#define PSCHED_JSCALE 14
+#elif HZ >= 96 && HZ < 192
 #define PSCHED_JSCALE 13
-#elif HZ == 1024
+#elif HZ >= 192 && HZ < 384
+#define PSCHED_JSCALE 12
+#elif HZ >= 384 && HZ < 768
+#define PSCHED_JSCALE 11
+#elif HZ >= 768
 #define PSCHED_JSCALE 10
-#else
-#define PSCHED_JSCALE 0
 #endif
 
 #define PSCHED_EXPORTLIST_2
diff -Nru a/include/scsi/scsi.h b/include/scsi/scsi.h
--- a/include/scsi/scsi.h	Tue Aug  6 07:41:52 2002
+++ b/include/scsi/scsi.h	Thu Aug 28 19:20:12 2003
@@ -78,6 +78,7 @@
 #define MODE_SENSE_10         0x5a
 #define PERSISTENT_RESERVE_IN 0x5e
 #define PERSISTENT_RESERVE_OUT 0x5f
+#define REPORT_LUNS           0xa0
 #define MOVE_MEDIUM           0xa5
 #define READ_12               0xa8
 #define WRITE_12              0xaa
@@ -88,8 +89,29 @@
 #define READ_ELEMENT_STATUS   0xb8
 #define SEND_VOLUME_TAG       0xb6
 #define WRITE_LONG_2          0xea
+#define READ_16               0x88
+#define WRITE_16              0x8a
+#define SERVICE_ACTION_IN     0x9e
+/* values for service action in */
+#define SAI_READ_CAPACITY_16  0x10
 
 #define SCSI_RETRY_10(c) ((c) == READ_6 || (c) == WRITE_6 || (c) == SEEK_6)
+
+/*
+ *  SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
+ *  T10/1561-D Revision 4 Draft dated 7th November 2002.
+ */
+#define SAM_STAT_GOOD            0x00
+#define SAM_STAT_CHECK_CONDITION 0x02
+#define SAM_STAT_CONDITION_MET   0x04
+#define SAM_STAT_BUSY            0x08
+#define SAM_STAT_INTERMEDIATE    0x10
+#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
+#define SAM_STAT_RESERVATION_CONFLICT 0x18
+#define SAM_STAT_COMMAND_TERMINATED 0x22        /* obsolete in SAM-3 */
+#define SAM_STAT_TASK_SET_FULL   0x28
+#define SAM_STAT_ACA_ACTIVE      0x30
+#define SAM_STAT_TASK_ABORTED    0x40
 
 /*
  *  Status codes
diff -Nru a/init/do_mounts.c b/init/do_mounts.c
--- a/init/do_mounts.c	Mon Jul 21 13:13:12 2003
+++ b/init/do_mounts.c	Thu Jul 10 06:46:36 2003
@@ -360,6 +360,7 @@
 				flags |= MS_RDONLY;
 				goto retry;
 			case -EINVAL:
+		        case -EBUSY:
 				continue;
 		}
 	        /*
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Wed Aug 14 13:52:09 2002
+++ b/init/main.c	Thu Aug 28 18:20:46 2003
@@ -26,6 +26,7 @@
 #include <linux/hdreg.h>
 #include <linux/iobuf.h>
 #include <linux/bootmem.h>
+#include <linux/file.h>
 #include <linux/tty.h>
 
 #include <asm/io.h>
@@ -424,9 +425,6 @@
 #ifdef CONFIG_PROC_FS
 	proc_root_init();
 #endif
-#if defined(CONFIG_SYSVIPC)
-	ipc_init();
-#endif
 	check_bugs();
 	printk("POSIX conformance testing by UNIFIX\n");
 
@@ -436,6 +434,9 @@
 	 *	make syscalls (and thus be locked).
 	 */
 	smp_init();
+#if defined(CONFIG_SYSVIPC)
+	ipc_init();
+#endif
 	rest_init();
 }
 
@@ -548,6 +549,7 @@
 
 static int init(void * unused)
 {
+	struct files_struct *files;
 	lock_kernel();
 	do_basic_setup();
 
@@ -560,7 +562,17 @@
 	 */
 	free_initmem();
 	unlock_kernel();
-
+	
+	/*
+	 * Right now we are a thread sharing with a ton of kernel
+	 * stuff. We don't want to end up in user space in that state
+	 */
+	 
+	files = current->files;
+	if(unshare_files())
+		panic("unshare");
+	put_files_struct(files);
+	
 	if (open("/dev/console", O_RDWR, 0) < 0)
 		printk("Warning: unable to open an initial console.\n");
 
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Sun Jun 29 08:09:23 2003
+++ b/kernel/fork.c	Fri Apr  5 10:07:17 2002
@@ -266,6 +266,7 @@
 {
 	BUG_ON(mm == &init_mm);
 	pgd_free(mm->pgd);
+	check_pgt_cache();
 	destroy_context(mm);
 	free_mm(mm);
 }
@@ -746,7 +747,8 @@
 		goto bad_fork_cleanup_fs;
 	if (copy_mm(clone_flags, p))
 		goto bad_fork_cleanup_sighand;
-	if (copy_namespace(clone_flags, p))
+	retval = copy_namespace(clone_flags, p);
+	if (retval)
 		goto bad_fork_cleanup_mm;
 	retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
 	if (retval)
diff -Nru a/kernel/panic.c b/kernel/panic.c
--- a/kernel/panic.c	Mon Aug 27 17:43:39 2001
+++ b/kernel/panic.c	Thu Aug 28 12:07:01 2003
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/sysrq.h>
 #include <linux/interrupt.h>
+#include <linux/console.h>
 
 asmlinkage void sys_sync(void);	/* it's really int */
 
@@ -31,6 +32,8 @@
 
 __setup("panic=", panic_setup);
 
+int machine_paniced; 
+
 /**
  *	panic - halt the system
  *	@fmt: The text string to print
@@ -49,6 +52,11 @@
         unsigned long caller = (unsigned long) __builtin_return_address(0);
 #endif
 
+#ifdef CONFIG_VT
+	disable_console_blank();
+#endif
+	machine_paniced = 1;
+	
 	bust_spinlocks(1);
 	va_start(args, fmt);
 	vsprintf(buf, fmt, args);
diff -Nru a/kernel/printk.c b/kernel/printk.c
--- a/kernel/printk.c	Fri Jun 27 04:39:07 2003
+++ b/kernel/printk.c	Fri Aug 29 15:53:12 2003
@@ -29,6 +29,7 @@
 
 #include <asm/uaccess.h>
 
+#if !defined(CONFIG_LOG_BUF_SHIFT) || (CONFIG_LOG_BUF_SHIFT == 0)
 #if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64)
 #define LOG_BUF_LEN	(65536)
 #elif defined(CONFIG_ARCH_S390)
@@ -37,6 +38,9 @@
 #define LOG_BUF_LEN	(32768)
 #else	
 #define LOG_BUF_LEN	(16384)			/* This must be a power of two */
+#endif
+#else /* CONFIG_LOG_BUF_SHIFT */
+#define LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
 #endif
 
 #define LOG_BUF_MASK	(LOG_BUF_LEN-1)
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Mon Jul 14 04:54:22 2003
+++ b/kernel/sysctl.c	Sat Aug 30 06:07:58 2003
@@ -49,6 +49,7 @@
 extern int max_queued_signals;
 extern int sysrq_enabled;
 extern int core_uses_pid;
+extern int core_setuid_ok;
 extern char core_pattern[];
 extern int cad_pid;
 
@@ -176,6 +177,8 @@
 	 0644, NULL, &proc_dointvec},
 	{KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
 	 0644, NULL, &proc_dointvec},
+	{KERN_CORE_USES_PID, "core_setuid_ok", &core_setuid_ok, sizeof(int),
+	0644, NULL, &proc_dointvec},
 	{KERN_CORE_PATTERN, "core_pattern", core_pattern, 64,
 	 0644, NULL, &proc_dostring, &sysctl_string},
 	{KERN_TAINTED, "tainted", &tainted, sizeof(int),
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Mon Aug  4 07:47:00 2003
+++ b/mm/filemap.c	Fri Aug  8 05:42:54 2003
@@ -3007,7 +3007,7 @@
 	}
 
 	/* FIXME: this is for backwards compatibility with 2.4 */
-	if (!S_ISBLK(inode->i_mode) && file->f_flags & O_APPEND)
+	if (!S_ISBLK(inode->i_mode) && (file->f_flags & O_APPEND))
 		*ppos = pos = inode->i_size;
 
 	/*
@@ -3238,7 +3238,7 @@
 	if (err != 0 || count == 0)
 		goto out;
 
-	if (!file->f_flags & O_DIRECT)
+	if (!(file->f_flags & O_DIRECT))
 		BUG();
 
 	remove_suid(inode);
@@ -3259,7 +3259,7 @@
 	 * Sync the fs metadata but not the minor inode changes and
 	 * of course not the data as we did direct DMA for the IO.
 	 */
-	if (written >= 0 && file->f_flags & O_SYNC)
+	if (written >= 0 && (file->f_flags & O_SYNC))
 		status = generic_osync_inode(inode, OSYNC_METADATA);
 
 	err = written ? written : status;
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Wed Jun  4 09:52:46 2003
+++ b/mm/memory.c	Fri Apr  5 10:06:57 2002
@@ -1414,6 +1414,7 @@
 		 */
 		if (!pgd_none(*pgd)) {
 			pmd_free(new);
+			check_pgt_cache();
 			goto out;
 		}
 	}
@@ -1448,6 +1449,7 @@
 			 */
 			if (!pmd_none(*pmd)) {
 				pte_free(new);
+				check_pgt_cache();
 				goto out;
 			}
 		}
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Wed Nov 27 10:04:37 2002
+++ b/mm/slab.c	Tue Jun  3 15:47:41 2003
@@ -1784,8 +1784,9 @@
 		full_free = 0;
 		p = searchp->slabs_free.next;
 		while (p != &searchp->slabs_free) {
-			slabp = list_entry(p, slab_t, list);
 #if DEBUG
+			slabp = list_entry(p, slab_t, list);
+
 			if (slabp->inuse)
 				BUG();
 #endif
diff -Nru a/net/8021q/vlan.c b/net/8021q/vlan.c
--- a/net/8021q/vlan.c	Wed Nov 20 12:31:42 2002
+++ b/net/8021q/vlan.c	Tue Aug 19 12:45:45 2003
@@ -533,7 +533,9 @@
 	    
 	grp->vlan_devices[VLAN_ID] = new_dev;
 
-	vlan_proc_add_dev(new_dev); /* create it's proc entry */
+	if (vlan_proc_add_dev(new_dev)<0)/* create it's proc entry */
+            	printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",
+					                 new_dev->name);
 
 	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
 		real_dev->vlan_rx_add_vid(real_dev, VLAN_ID);
diff -Nru a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
--- a/net/8021q/vlan_dev.c	Wed Nov 20 12:31:42 2002
+++ b/net/8021q/vlan_dev.c	Mon Jul 28 16:27:44 2003
@@ -171,7 +171,7 @@
 
 #ifdef VLAN_DEBUG
 		printk(VLAN_DBG "%s: dropping skb: %p because came in on wrong device, dev: %s  real_dev: %s, skb_dev: %s\n",
-			__FUNCTION__ skb, dev->name, 
+			__FUNCTION__, skb, dev->name, 
 			VLAN_DEV_INFO(skb->dev)->real_dev->name, 
 			skb->dev->name);
 #endif
diff -Nru a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
--- a/net/8021q/vlanproc.c	Thu Apr  3 07:01:02 2003
+++ b/net/8021q/vlanproc.c	Tue Aug 19 12:45:45 2003
@@ -204,8 +204,10 @@
 #endif
 
 	/** NOTE:  This will consume the memory pointed to by dent, it seems. */
-	remove_proc_entry(VLAN_DEV_INFO(vlandev)->dent->name, proc_vlan_dir);
-	VLAN_DEV_INFO(vlandev)->dent = NULL;
+	if (VLAN_DEV_INFO(vlandev)->dent) {
+		remove_proc_entry(VLAN_DEV_INFO(vlandev)->dent->name, proc_vlan_dir);
+		VLAN_DEV_INFO(vlandev)->dent = NULL;
+	}
 
 	return 0;
 }
diff -Nru a/net/Makefile b/net/Makefile
--- a/net/Makefile	Thu Mar 14 02:52:17 2002
+++ b/net/Makefile	Mon Aug 11 22:36:41 2003
@@ -46,6 +46,10 @@
 subdir-$(CONFIG_ECONET)		+= econet
 subdir-$(CONFIG_VLAN_8021Q)           += 8021q
 
+ifeq ($(CONFIG_NETFILTER),y)
+  mod-subdirs += ipv4/ipvs
+  subdir-$(CONFIG_IP_VS) += ipv4/ipvs
+endif
 
 obj-y	:= socket.o $(join $(subdir-y), $(patsubst %,/%.o,$(notdir $(subdir-y))))
 ifeq ($(CONFIG_NET),y)
diff -Nru a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c	Fri Jul 11 23:06:42 2003
+++ b/net/atm/common.c	Tue Jul 29 22:34:21 2003
@@ -84,7 +84,7 @@
 
 #ifdef CONFIG_ATM_CLIP_MODULE
 EXPORT_SYMBOL(atm_clip_ops);
-EXPORT_SYMBOL(atm_clip_ops_mutex);
+EXPORT_SYMBOL(try_atm_clip_ops);
 EXPORT_SYMBOL(atm_clip_ops_set);
 #endif
 #endif
diff -Nru a/net/core/Makefile b/net/core/Makefile
--- a/net/core/Makefile	Thu Mar 28 07:39:58 2002
+++ b/net/core/Makefile	Mon Aug 25 14:24:22 2003
@@ -21,7 +21,8 @@
 
 obj-$(CONFIG_FILTER) += filter.o
 
-obj-$(CONFIG_NET) += dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o
+obj-$(CONFIG_NET) +=	dev.o ethtool.o dev_mcast.o dst.o neighbour.o \
+			rtnetlink.o utils.o
 
 obj-$(CONFIG_NETFILTER) += netfilter.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
diff -Nru a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c	Fri May 23 10:59:51 2003
+++ b/net/core/dev.c	Mon Aug 25 14:24:22 2003
@@ -1588,6 +1588,7 @@
 	*budget -= work;
 
 	list_del(&blog_dev->poll_list);
+	smp_mb__before_clear_bit();
 	clear_bit(__LINK_STATE_RX_SCHED, &blog_dev->state);
 
 	if (queue->throttle) {
@@ -2198,7 +2199,6 @@
 			    cmd == SIOCBONDSLAVEINFOQUERY ||
 			    cmd == SIOCBONDINFOQUERY ||
 			    cmd == SIOCBONDCHANGEACTIVE ||
-			    cmd == SIOCETHTOOL ||
 			    cmd == SIOCGMIIPHY ||
 			    cmd == SIOCGMIIREG ||
 			    cmd == SIOCSMIIREG ||
@@ -2294,6 +2294,20 @@
 			}
 			return ret;
 
+		case SIOCETHTOOL:
+			dev_load(ifr.ifr_name);
+			rtnl_lock();
+			ret = dev_ethtool(&ifr);
+			rtnl_unlock();
+			if (!ret) {
+				if (colon)
+					*colon = ':';
+				if (copy_to_user(arg, &ifr,
+						 sizeof(struct ifreq)))
+					ret = -EFAULT;
+			}
+			return ret;
+
 		/*
 		 *	These ioctl calls:
 		 *	- require superuser power.
@@ -2301,7 +2315,6 @@
 		 *	- return a value
 		 */
 		 
-		case SIOCETHTOOL:
 		case SIOCGMIIPHY:
 		case SIOCGMIIREG:
 			if (!capable(CAP_NET_ADMIN))
diff -Nru a/net/core/ethtool.c b/net/core/ethtool.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/core/ethtool.c	Wed Aug 27 14:55:32 2003
@@ -0,0 +1,673 @@
+/*
+ * net/core/ethtool.c - Ethtool ioctl handler
+ * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
+ *
+ * This file is where we call all the ethtool_ops commands to get
+ * the information ethtool needs.  We fall back to calling do_ioctl()
+ * for drivers which haven't been converted to ethtool_ops yet.
+ *
+ * It's GPL, stupid.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <asm/uaccess.h>
+
+/* 
+ * Some useful ethtool_ops methods that're device independent.
+ * If we find that all drivers want to do the same thing here,
+ * we can turn these into dev_() function calls.
+ */
+
+u32 ethtool_op_get_link(struct net_device *dev)
+{
+	return netif_carrier_ok(dev) ? 1 : 0;
+}
+
+u32 ethtool_op_get_tx_csum(struct net_device *dev)
+{
+	return (dev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+u32 ethtool_op_get_sg(struct net_device *dev)
+{
+	return (dev->features & NETIF_F_SG) != 0;
+}
+
+int ethtool_op_set_sg(struct net_device *dev, u32 data)
+{
+	if (data)
+		dev->features |= NETIF_F_SG;
+	else
+		dev->features &= ~NETIF_F_SG;
+
+	return 0;
+}
+
+/* Handlers for each ethtool command */
+
+static int ethtool_get_settings(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_cmd cmd = { ETHTOOL_GSET };
+	int err;
+
+	if (!dev->ethtool_ops->get_settings)
+		return -EOPNOTSUPP;
+
+	err = dev->ethtool_ops->get_settings(dev, &cmd);
+	if (err < 0)
+		return err;
+
+	if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_settings(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_cmd cmd;
+
+	if (!dev->ethtool_ops->set_settings)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+		return -EFAULT;
+
+	return dev->ethtool_ops->set_settings(dev, &cmd);
+}
+
+static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_drvinfo info;
+	struct ethtool_ops *ops = dev->ethtool_ops;
+
+	if (!ops->get_drvinfo)
+		return -EOPNOTSUPP;
+
+	memset(&info, 0, sizeof(info));
+	info.cmd = ETHTOOL_GDRVINFO;
+	ops->get_drvinfo(dev, &info);
+
+	if (ops->self_test_count)
+		info.testinfo_len = ops->self_test_count(dev);
+	if (ops->get_stats_count)
+		info.n_stats = ops->get_stats_count(dev);
+	if (ops->get_regs_len)
+		info.regdump_len = ops->get_regs_len(dev);
+	/* XXX: eeprom? */
+
+	if (copy_to_user(useraddr, &info, sizeof(info)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_get_regs(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_regs regs;
+	struct ethtool_ops *ops = dev->ethtool_ops;
+	void *regbuf;
+	int reglen, ret;
+
+	if (!ops->get_regs || !ops->get_regs_len)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&regs, useraddr, sizeof(regs)))
+		return -EFAULT;
+
+	reglen = ops->get_regs_len(dev);
+	if (regs.len > reglen)
+		regs.len = reglen;
+
+	regbuf = kmalloc(reglen, GFP_USER);
+	if (!regbuf)
+		return -ENOMEM;
+
+	ops->get_regs(dev, &regs, regbuf);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &regs, sizeof(regs)))
+		goto out;
+	useraddr += offsetof(struct ethtool_regs, data);
+	if (copy_to_user(useraddr, regbuf, reglen))
+		goto out;
+	ret = 0;
+
+ out:
+	kfree(regbuf);
+	return ret;
+}
+
+static int ethtool_get_wol(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
+
+	if (!dev->ethtool_ops->get_wol)
+		return -EOPNOTSUPP;
+
+	dev->ethtool_ops->get_wol(dev, &wol);
+
+	if (copy_to_user(useraddr, &wol, sizeof(wol)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_wol(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_wolinfo wol;
+
+	if (!dev->ethtool_ops->set_wol)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&wol, useraddr, sizeof(wol)))
+		return -EFAULT;
+
+	return dev->ethtool_ops->set_wol(dev, &wol);
+}
+
+static int ethtool_get_msglevel(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+
+	if (!dev->ethtool_ops->get_msglevel)
+		return -EOPNOTSUPP;
+
+	edata.data = dev->ethtool_ops->get_msglevel(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_msglevel(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!dev->ethtool_ops->set_msglevel)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	dev->ethtool_ops->set_msglevel(dev, edata.data);
+	return 0;
+}
+
+static int ethtool_nway_reset(struct net_device *dev)
+{
+	if (!dev->ethtool_ops->nway_reset)
+		return -EOPNOTSUPP;
+
+	return dev->ethtool_ops->nway_reset(dev);
+}
+
+static int ethtool_get_link(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GLINK };
+
+	if (!dev->ethtool_ops->get_link)
+		return -EOPNOTSUPP;
+
+	edata.data = dev->ethtool_ops->get_link(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_get_eeprom(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_eeprom eeprom;
+	u8 *data;
+	int len, ret;
+
+	if (!dev->ethtool_ops->get_eeprom)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
+		return -EFAULT;
+
+	len = eeprom.len;
+	/* Check for wrap and zero */
+	if (eeprom.offset + len <= eeprom.offset)
+		return -EINVAL;
+
+	data = kmalloc(len, GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	if (copy_from_user(data, useraddr + sizeof(eeprom), len))
+		return -EFAULT;
+
+	ret = dev->ethtool_ops->get_eeprom(dev, &eeprom, data);
+	if (!ret)
+		goto out;
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
+		goto out;
+	if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
+		goto out;
+	ret = 0;
+
+ out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_set_eeprom(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_eeprom eeprom;
+	u8 *data;
+	int len, ret;
+
+	if (!dev->ethtool_ops->set_eeprom)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
+		return -EFAULT;
+
+	len = eeprom.len;
+	/* Check for wrap and zero */
+	if (eeprom.offset + len <= eeprom.offset)
+		return -EINVAL;
+
+	data = kmalloc(len, GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	if (copy_from_user(data, useraddr + sizeof(eeprom), len))
+		return -EFAULT;
+
+	ret = dev->ethtool_ops->set_eeprom(dev, &eeprom, data);
+	if (ret)
+		goto out;
+
+	if (copy_to_user(useraddr + sizeof(eeprom), data, len))
+		ret = -EFAULT;
+
+ out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_get_coalesce(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE };
+
+	if (!dev->ethtool_ops->get_coalesce)
+		return -EOPNOTSUPP;
+
+	dev->ethtool_ops->get_coalesce(dev, &coalesce);
+
+	if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_coalesce(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_coalesce coalesce;
+
+	if (!dev->ethtool_ops->get_coalesce)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
+		return -EFAULT;
+
+	return dev->ethtool_ops->set_coalesce(dev, &coalesce);
+}
+
+static int ethtool_get_ringparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM };
+
+	if (!dev->ethtool_ops->get_ringparam)
+		return -EOPNOTSUPP;
+
+	dev->ethtool_ops->get_ringparam(dev, &ringparam);
+
+	if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_ringparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_ringparam ringparam;
+
+	if (!dev->ethtool_ops->get_ringparam)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
+		return -EFAULT;
+
+	return dev->ethtool_ops->set_ringparam(dev, &ringparam);
+}
+
+static int ethtool_get_pauseparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
+
+	if (!dev->ethtool_ops->get_pauseparam)
+		return -EOPNOTSUPP;
+
+	dev->ethtool_ops->get_pauseparam(dev, &pauseparam);
+
+	if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_pauseparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_pauseparam pauseparam;
+
+	if (!dev->ethtool_ops->get_pauseparam)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
+		return -EFAULT;
+
+	return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
+}
+
+static int ethtool_get_rx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GRXCSUM };
+
+	if (!dev->ethtool_ops->get_rx_csum)
+		return -EOPNOTSUPP;
+
+	edata.data = dev->ethtool_ops->get_rx_csum(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_rx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!dev->ethtool_ops->set_rx_csum)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	dev->ethtool_ops->set_rx_csum(dev, edata.data);
+	return 0;
+}
+
+static int ethtool_get_tx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GTXCSUM };
+
+	if (!dev->ethtool_ops->get_tx_csum)
+		return -EOPNOTSUPP;
+
+	edata.data = dev->ethtool_ops->get_tx_csum(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_tx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!dev->ethtool_ops->set_tx_csum)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return dev->ethtool_ops->set_tx_csum(dev, edata.data);
+}
+
+static int ethtool_get_sg(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GSG };
+
+	if (!dev->ethtool_ops->get_sg)
+		return -EOPNOTSUPP;
+
+	edata.data = dev->ethtool_ops->get_sg(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_sg(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!dev->ethtool_ops->set_sg)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return dev->ethtool_ops->set_sg(dev, edata.data);
+}
+
+static int ethtool_self_test(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_test test;
+	struct ethtool_ops *ops = dev->ethtool_ops;
+	u64 *data;
+	int ret;
+
+	if (!ops->self_test || !ops->self_test_count)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&test, useraddr, sizeof(test)))
+		return -EFAULT;
+
+	test.len = ops->self_test_count(dev);
+	data = kmalloc(test.len * sizeof(u64), GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ops->self_test(dev, &test, data);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &test, sizeof(test)))
+		goto out;
+	useraddr += sizeof(test);
+	if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
+		goto out;
+	ret = 0;
+
+ out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_get_strings(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_gstrings gstrings;
+	struct ethtool_ops *ops = dev->ethtool_ops;
+	u8 *data;
+	int ret;
+
+	if (!ops->get_strings)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
+		return -EFAULT;
+
+	switch (gstrings.string_set) {
+	case ETH_SS_TEST:
+		if (!ops->self_test_count)
+			return -EOPNOTSUPP;
+		gstrings.len = ops->self_test_count(dev);
+		break;
+	case ETH_SS_STATS:
+		if (!ops->get_stats_count)
+			return -EOPNOTSUPP;
+		gstrings.len = ops->get_stats_count(dev);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ops->get_strings(dev, gstrings.string_set, data);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
+		goto out;
+	useraddr += sizeof(gstrings);
+	if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
+		goto out;
+	ret = 0;
+
+ out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_phys_id(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_value id;
+
+	if (!dev->ethtool_ops->phys_id)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&id, useraddr, sizeof(id)))
+		return -EFAULT;
+
+	return dev->ethtool_ops->phys_id(dev, id.data);
+}
+
+static int ethtool_get_stats(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_stats stats;
+	struct ethtool_ops *ops = dev->ethtool_ops;
+	u64 *data;
+	int ret;
+
+	if (!ops->get_ethtool_stats || !ops->get_stats_count)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&stats, useraddr, sizeof(stats)))
+		return -EFAULT;
+
+	stats.n_stats = ops->get_stats_count(dev);
+	data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ops->get_ethtool_stats(dev, &stats, data);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &stats, sizeof(stats)))
+		goto out;
+	useraddr += sizeof(stats);
+	if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
+		goto out;
+	ret = 0;
+
+ out:
+	kfree(data);
+	return ret;
+}
+
+/* The main entry point in this file.  Called from net/core/dev.c */
+
+int dev_ethtool(struct ifreq *ifr)
+{
+	struct net_device *dev = __dev_get_by_name(ifr->ifr_name);
+	void *useraddr = (void *) ifr->ifr_data;
+	u32 ethcmd;
+
+	/*
+	 * XXX: This can be pushed down into the ethtool_* handlers that
+	 * need it.  Keep existing behaviour for the moment.
+	 */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (!dev || !netif_device_present(dev))
+		return -ENODEV;
+
+	if (!dev->ethtool_ops)
+		goto ioctl;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GSET:
+		return ethtool_get_settings(dev, useraddr);
+	case ETHTOOL_SSET:
+		return ethtool_set_settings(dev, useraddr);
+	case ETHTOOL_GDRVINFO:
+		return ethtool_get_drvinfo(dev, useraddr);
+	case ETHTOOL_GREGS:
+		return ethtool_get_regs(dev, useraddr);
+	case ETHTOOL_GWOL:
+		return ethtool_get_wol(dev, useraddr);
+	case ETHTOOL_SWOL:
+		return ethtool_set_wol(dev, useraddr);
+	case ETHTOOL_GMSGLVL:
+		return ethtool_get_msglevel(dev, useraddr);
+	case ETHTOOL_SMSGLVL:
+		return ethtool_set_msglevel(dev, useraddr);
+	case ETHTOOL_NWAY_RST:
+		return ethtool_nway_reset(dev);
+	case ETHTOOL_GLINK:
+		return ethtool_get_link(dev, useraddr);
+	case ETHTOOL_GEEPROM:
+		return ethtool_get_eeprom(dev, useraddr);
+	case ETHTOOL_SEEPROM:
+		return ethtool_set_eeprom(dev, useraddr);
+	case ETHTOOL_GCOALESCE:
+		return ethtool_get_coalesce(dev, useraddr);
+	case ETHTOOL_SCOALESCE:
+		return ethtool_set_coalesce(dev, useraddr);
+	case ETHTOOL_GRINGPARAM:
+		return ethtool_get_ringparam(dev, useraddr);
+	case ETHTOOL_SRINGPARAM:
+		return ethtool_set_ringparam(dev, useraddr);
+	case ETHTOOL_GPAUSEPARAM:
+		return ethtool_get_pauseparam(dev, useraddr);
+	case ETHTOOL_SPAUSEPARAM:
+		return ethtool_set_pauseparam(dev, useraddr);
+	case ETHTOOL_GRXCSUM:
+		return ethtool_get_rx_csum(dev, useraddr);
+	case ETHTOOL_SRXCSUM:
+		return ethtool_set_rx_csum(dev, useraddr);
+	case ETHTOOL_GTXCSUM:
+		return ethtool_get_tx_csum(dev, useraddr);
+	case ETHTOOL_STXCSUM:
+		return ethtool_set_tx_csum(dev, useraddr);
+	case ETHTOOL_GSG:
+		return ethtool_get_sg(dev, useraddr);
+	case ETHTOOL_SSG:
+		return ethtool_set_sg(dev, useraddr);
+	case ETHTOOL_TEST:
+		return ethtool_self_test(dev, useraddr);
+	case ETHTOOL_GSTRINGS:
+		return ethtool_get_strings(dev, useraddr);
+	case ETHTOOL_PHYS_ID:
+		return ethtool_phys_id(dev, useraddr);
+	case ETHTOOL_GSTATS:
+		return ethtool_get_stats(dev, useraddr);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+ ioctl:
+	if (dev->do_ioctl)
+		return dev->do_ioctl(dev, ifr, SIOCETHTOOL);
+	return -EOPNOTSUPP;
+}
diff -Nru a/net/core/neighbour.c b/net/core/neighbour.c
--- a/net/core/neighbour.c	Wed Jun 11 23:24:41 2003
+++ b/net/core/neighbour.c	Tue Aug 19 12:44:36 2003
@@ -50,6 +50,7 @@
 static void neigh_app_notify(struct neighbour *n);
 #endif
 static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
 
 static int neigh_glbl_allocs;
 static struct neigh_table *neigh_tables;
@@ -167,6 +168,33 @@
 		dev_put(skb->dev);
 		kfree_skb(skb);
 	}
+}
+
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
+{
+	int i;
+
+	write_lock_bh(&tbl->lock);
+
+	for (i=0; i <= NEIGH_HASHMASK; i++) {
+		struct neighbour *n, **np;
+
+		np = &tbl->hash_buckets[i];
+		while ((n = *np) != NULL) {
+			if (dev && n->dev != dev) {
+				np = &n->next;
+				continue;
+			}
+			*np = n->next;
+			write_lock_bh(&n->lock);
+			n->dead = 1;
+			neigh_del_timer(n);
+			write_unlock_bh(&n->lock);
+			neigh_release(n);
+		}
+	}
+
+        write_unlock_bh(&tbl->lock);
 }
 
 int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
diff -Nru a/net/core/pktgen.c b/net/core/pktgen.c
--- a/net/core/pktgen.c	Sat Aug 31 06:13:55 2002
+++ b/net/core/pktgen.c	Mon Jul 21 09:05:03 2003
@@ -46,6 +46,9 @@
  * Also moved to /proc/net/pktgen/ 
  * --ro 
  *
+ * Fix refcount off by one if first packet fails, potential null deref, 
+ * memleak 030710- KJP
+ *
  * See Documentation/networking/pktgen.txt for how to use this.
  */
 
@@ -84,9 +87,9 @@
 #define cycles()	((u32)get_cycles())
 
 
-#define VERSION "pktgen version 1.2"
+#define VERSION "pktgen version 1.3"
 static char version[] __initdata = 
-  "pktgen.c: v1.2: Packet Generator for packet performance testing.\n";
+  "pktgen.c: v1.3: Packet Generator for packet performance testing.\n";
 
 /* Used to help with determining the pkts on receive */
 
@@ -613,12 +616,11 @@
                                 kfree_skb(skb);
                                 skb = fill_packet(odev, info);
                                 if (skb == NULL) {
-                                        break;
+					goto out_reldev;
                                 }
                                 fp++;
                                 fp_tmp = 0; /* reset counter */
                         }
-                        atomic_inc(&skb->users);
                 }
 
                 nr_frags = skb_shinfo(skb)->nr_frags;
@@ -626,7 +628,11 @@
 		spin_lock_bh(&odev->xmit_lock);
 		if (!netif_queue_stopped(odev)) {
 
+			atomic_inc(&skb->users);
+
 			if (odev->hard_start_xmit(skb, odev)) {
+
+				atomic_dec(&skb->users);
 				if (net_ratelimit()) {
                                    printk(KERN_INFO "Hard xmit error\n");
                                 }
@@ -731,15 +737,15 @@
 			     (unsigned long long) info->errors
 			     );
 	}
-        
+
+	kfree_skb(skb);
+
 out_reldev:
         if (odev) {
                 dev_put(odev);
                 odev = NULL;
         }
 
-        /* TODO:  Is this worth printing out (other than for debug?) */
-        printk("fp = %llu\n", (unsigned long long) fp);
 	return;
 
 }
@@ -955,7 +961,8 @@
 	if (len < 0)
 		return len;
 	memset(name, 0, sizeof(name));
-	copy_from_user(name, &user_buffer[i], len);
+	if (copy_from_user(name, &user_buffer[i], len))
+		return -EFAULT;
 	i += len;
   
 	max = count -i;
@@ -1085,18 +1092,20 @@
 		if (len < 0)
 			return len;
 		memset(info->outdev, 0, sizeof(info->outdev));
-		copy_from_user(info->outdev, &user_buffer[i], len);
+		if (copy_from_user(info->outdev, &user_buffer[i], len))
+			return -EFAULT;
 		i += len;
 		sprintf(result, "OK: odev=%s", info->outdev);
 		return count;
 	}
 	if (!strcmp(name, "flag")) {
                 char f[32];
-                memset(f, 0, 32);
 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
 		if (len < 0)
 			return len;
-		copy_from_user(f, &user_buffer[i], len);
+                memset(f, 0, 32);
+		if (copy_from_user(f, &user_buffer[i], len))
+			return -EFAULT;
 		i += len;
                 if (strcmp(f, "IPSRC_RND") == 0) {
                         info->flags |= F_IPSRC_RND;
@@ -1148,7 +1157,8 @@
 		if (len < 0)
 			return len;
 		memset(info->dst_min, 0, sizeof(info->dst_min));
-		copy_from_user(info->dst_min, &user_buffer[i], len);
+		if (copy_from_user(info->dst_min, &user_buffer[i], len))
+			return -EFAULT;
 		if(debug)
 			printk("pg: dst_min set to: %s\n", info->dst_min);
 		i += len;
@@ -1160,7 +1170,8 @@
 		if (len < 0)
 			return len;
 		memset(info->dst_max, 0, sizeof(info->dst_max));
-		copy_from_user(info->dst_max, &user_buffer[i], len);
+		if (copy_from_user(info->dst_max, &user_buffer[i], len))
+			return -EFAULT;
 		if(debug)
 			printk("pg: dst_max set to: %s\n", info->dst_max);
 		i += len;
@@ -1172,7 +1183,8 @@
 		if (len < 0)
 			return len;
 		memset(info->src_min, 0, sizeof(info->src_min));
-		copy_from_user(info->src_min, &user_buffer[i], len);
+		if (copy_from_user(info->src_min, &user_buffer[i], len))
+			return -EFAULT;
 		if(debug)
 			printk("pg: src_min set to: %s\n", info->src_min);
 		i += len;
@@ -1184,7 +1196,8 @@
 		if (len < 0)
 			return len;
 		memset(info->src_max, 0, sizeof(info->src_max));
-		copy_from_user(info->src_max, &user_buffer[i], len);
+		if (copy_from_user(info->src_max, &user_buffer[i], len))
+			return -EFAULT;
 		if(debug)
 			printk("pg: src_max set to: %s\n", info->src_max);
 		i += len;
@@ -1199,7 +1212,8 @@
 		if (len < 0)
 			return len;
 		memset(valstr, 0, sizeof(valstr));
-		copy_from_user(valstr, &user_buffer[i], len);
+		if (copy_from_user(valstr, &user_buffer[i], len))
+			return -EFAULT;
 		i += len;
 
 		for(*m = 0;*v && m < info->dst_mac + 6; v++) {
@@ -1231,7 +1245,8 @@
 		if (len < 0)
 			return len;
 		memset(valstr, 0, sizeof(valstr));
-		copy_from_user(valstr, &user_buffer[i], len);
+		if (copy_from_user(valstr, &user_buffer[i], len))
+			return -EFAULT;
 		i += len;
 
 		for(*m = 0;*v && m < info->src_mac + 6; v++) {
diff -Nru a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
--- a/net/core/sysctl_net_core.c	Wed Aug  7 09:17:09 2002
+++ b/net/core/sysctl_net_core.c	Tue Jul 22 23:38:44 2003
@@ -55,7 +55,7 @@
 	 &netdev_max_backlog, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
 	{NET_CORE_NO_CONG_THRESH, "no_cong_thresh",
-	 &no_cong, sizeof(int), 0644, NULL,
+	 &no_cong_thresh, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
 	{NET_CORE_NO_CONG, "no_cong",
 	 &no_cong, sizeof(int), 0644, NULL,
diff -Nru a/net/ipv4/Config.in b/net/ipv4/Config.in
--- a/net/ipv4/Config.in	Thu May 22 19:02:34 2003
+++ b/net/ipv4/Config.in	Mon Aug 11 22:36:41 2003
@@ -43,3 +43,6 @@
 if [ "$CONFIG_NETFILTER" != "n" ]; then
    source net/ipv4/netfilter/Config.in
 fi
+if [ "$CONFIG_NETFILTER" != "n" ]; then
+   source net/ipv4/ipvs/Config.in
+fi
diff -Nru a/net/ipv4/arp.c b/net/ipv4/arp.c
--- a/net/ipv4/arp.c	Thu Jun 26 23:03:01 2003
+++ b/net/ipv4/arp.c	Tue Aug 19 12:44:36 2003
@@ -1212,6 +1212,26 @@
 }
 #endif
 
+static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	switch (event) {
+	case NETDEV_CHANGEADDR:
+		neigh_changeaddr(&arp_tbl, dev);
+		rt_cache_flush(0);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+struct notifier_block arp_netdev_notifier = {
+	.notifier_call = arp_netdev_event,
+};
+
 /* Note, that it is not on notifier chain.
    It is necessary, that this routine was called after route cache will be
    flushed.
@@ -1243,6 +1263,7 @@
 #ifdef CONFIG_SYSCTL
 	neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
 #endif
+	register_netdevice_notifier(&arp_netdev_notifier);
 }
 
 
diff -Nru a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c	Mon Feb  3 00:04:36 2003
+++ b/net/ipv4/devinet.c	Sat Aug  9 20:49:50 2003
@@ -883,6 +883,7 @@
 	unsigned char	 *b = skb->tail;
 
 	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));
+	if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;
 	ifm = NLMSG_DATA(nlh);
 	ifm->ifa_family = AF_INET;
 	ifm->ifa_prefixlen = ifa->ifa_prefixlen;
diff -Nru a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
--- a/net/ipv4/ipconfig.c	Mon Jul 21 13:15:50 2003
+++ b/net/ipv4/ipconfig.c	Mon Aug 25 13:38:23 2003
@@ -124,14 +124,14 @@
 
 int ic_host_name_set __initdata = 0;		/* Host name set by us? */
 
-u32 ic_myaddr __initdata = INADDR_NONE;		/* My IP address */
-u32 ic_netmask __initdata = INADDR_NONE;	/* Netmask for local subnet */
-u32 ic_gateway __initdata = INADDR_NONE;	/* Gateway IP address */
+u32 ic_myaddr = INADDR_NONE;		/* My IP address */
+u32 ic_netmask = INADDR_NONE;	/* Netmask for local subnet */
+u32 ic_gateway = INADDR_NONE;	/* Gateway IP address */
 
-u32 ic_servaddr __initdata = INADDR_NONE;	/* Boot server IP address */
+u32 ic_servaddr = INADDR_NONE;	/* Boot server IP address */
 
-u32 root_server_addr __initdata = INADDR_NONE;	/* Address of NFS server */
-u8 root_server_path[256] __initdata = { 0, };	/* Path to mount as root */
+u32 root_server_addr = INADDR_NONE;	/* Address of NFS server */
+u8 root_server_path[256] = { 0, };	/* Path to mount as root */
 
 /* Persistent data: */
 
diff -Nru a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
--- a/net/ipv4/ipmr.c	Fri Oct  4 17:47:23 2002
+++ b/net/ipv4/ipmr.c	Sat Aug  2 23:08:22 2003
@@ -1096,6 +1096,7 @@
 
 	skb->h.ipiph = skb->nh.iph;
 	skb->nh.iph = iph;
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 #ifdef CONFIG_NETFILTER
 	nf_conntrack_put(skb->nfct);
 	skb->nfct = NULL;
@@ -1104,7 +1105,11 @@
 
 static inline int ipmr_forward_finish(struct sk_buff *skb)
 {
+	struct ip_options *opt = &(IPCB(skb)->opt);
 	struct dst_entry *dst = skb->dst;
+
+	if (unlikely(opt->optlen))
+		ip_forward_options(skb);
 
 	if (skb->len <= dst->pmtu)
 		return dst->output(skb);
diff -Nru a/net/ipv4/ipvs/Config.in b/net/ipv4/ipvs/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/Config.in	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,26 @@
+#
+# IP VS configuration
+#
+mainmenu_option next_comment
+comment '  IP: Virtual Server Configuration'
+
+tristate 'virtual server support (EXPERIMENTAL)' CONFIG_IP_VS
+if [ "$CONFIG_IP_VS" != "n" ]; then
+  bool '  IP virtual server debugging' CONFIG_IP_VS_DEBUG
+  int '  IPVS connection table size (the Nth power of 2)' CONFIG_IP_VS_TAB_BITS 12
+  comment 'IPVS scheduler'
+  dep_tristate '  round-robin scheduling' CONFIG_IP_VS_RR $CONFIG_IP_VS
+  dep_tristate '  weighted round-robin scheduling' CONFIG_IP_VS_WRR $CONFIG_IP_VS
+  dep_tristate '  least-connection scheduling scheduling' CONFIG_IP_VS_LC $CONFIG_IP_VS
+  dep_tristate '  weighted least-connection scheduling' CONFIG_IP_VS_WLC $CONFIG_IP_VS
+  dep_tristate '  locality-based least-connection scheduling' CONFIG_IP_VS_LBLC $CONFIG_IP_VS
+  dep_tristate '  locality-based least-connection with replication scheduling' CONFIG_IP_VS_LBLCR $CONFIG_IP_VS
+  dep_tristate '  destination hashing scheduling' CONFIG_IP_VS_DH $CONFIG_IP_VS
+  dep_tristate '  source hashing scheduling' CONFIG_IP_VS_SH $CONFIG_IP_VS
+  dep_tristate '  shortest expected delay scheduling' CONFIG_IP_VS_SED $CONFIG_IP_VS
+  dep_tristate '  never queue scheduling' CONFIG_IP_VS_NQ $CONFIG_IP_VS
+  comment 'IPVS application helper'
+  dep_tristate '  FTP protocol helper' CONFIG_IP_VS_FTP $CONFIG_IP_VS
+fi
+
+endmenu
diff -Nru a/net/ipv4/ipvs/Makefile b/net/ipv4/ipvs/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/Makefile	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,43 @@
+#
+# Makefile for the IPVS modules on top of IPv4.
+#
+# 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 :=	ipvs.o
+
+export-objs :=	ip_vs_core.o ip_vs_app.o
+
+ip_vs-objs :=	ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \
+		ip_vs_app.o ip_vs_sync.o ip_vs_est.o
+
+ifeq ($(CONFIG_IP_VS),y)
+  obj-y := $(ip_vs-objs)
+else
+  ifeq ($(CONFIG_IP_VS),m)
+    obj-m := ip_vs.o
+  endif
+endif
+
+# IPVS schedulers
+obj-$(CONFIG_IP_VS_RR) += ip_vs_rr.o
+obj-$(CONFIG_IP_VS_WRR) += ip_vs_wrr.o
+obj-$(CONFIG_IP_VS_LC) += ip_vs_lc.o
+obj-$(CONFIG_IP_VS_WLC) += ip_vs_wlc.o
+obj-$(CONFIG_IP_VS_LBLC) += ip_vs_lblc.o
+obj-$(CONFIG_IP_VS_LBLCR) += ip_vs_lblcr.o
+obj-$(CONFIG_IP_VS_DH) += ip_vs_dh.o
+obj-$(CONFIG_IP_VS_SH) += ip_vs_sh.o
+obj-$(CONFIG_IP_VS_SED) += ip_vs_sed.o
+obj-$(CONFIG_IP_VS_NQ) += ip_vs_nq.o
+
+# IPVS application helpers
+obj-$(CONFIG_IP_VS_FTP) += ip_vs_ftp.o
+
+include $(TOPDIR)/Rules.make
+
+ip_vs.o: $(ip_vs-objs)
+	$(LD) $(LD_RFLAG) -r -o $@ $(ip_vs-objs)
diff -Nru a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_app.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,508 @@
+/*
+ * IPVS         Application module
+ *
+ * Version:     $Id: ip_vs_app.c,v 1.14 2001/11/23 14:34:10 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              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.
+ *
+ * Most code here is taken from ip_masq_app.c in kernel 2.2. The difference
+ * is that ip_vs_app module handles the reverse direction (incoming requests
+ * and outgoing responses). The ip_vs_app modules are only used for VS/NAT.
+ *
+ *		IP_MASQ_APP application masquerading module
+ *
+ * Author:	Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+#include <net/ip_vs.h>
+
+#define IP_VS_APP_TAB_SIZE  16          /* must be power of 2 */
+
+#define IP_VS_APP_HASH(proto, port) ((port^proto) & (IP_VS_APP_TAB_SIZE-1))
+#define IP_VS_APP_TYPE(proto, port) (proto<<16 | port)
+#define IP_VS_APP_PORT(type)        (type & 0xffff)
+#define IP_VS_APP_PROTO(type)       ((type>>16) & 0x00ff)
+
+
+EXPORT_SYMBOL(register_ip_vs_app);
+EXPORT_SYMBOL(unregister_ip_vs_app);
+
+
+/*
+ *	will hold ipvs app. hashed list heads
+ */
+static struct list_head ip_vs_app_base[IP_VS_APP_TAB_SIZE];
+
+/* lock for ip_vs_app table */
+static rwlock_t __ip_vs_app_lock = RW_LOCK_UNLOCKED;
+
+
+/*
+ *	ip_vs_app registration routine
+ *	port: host byte order.
+ */
+int register_ip_vs_app(struct ip_vs_app *vapp,
+		       unsigned short proto, __u16 port)
+{
+	unsigned hash;
+
+	if (!vapp) {
+		IP_VS_ERR("register_ip_vs_app(): NULL arg\n");
+		return -EINVAL;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	vapp->type = IP_VS_APP_TYPE(proto, port);
+	hash = IP_VS_APP_HASH(proto, port);
+
+	write_lock_bh(&__ip_vs_app_lock);
+	list_add(&vapp->n_list, &ip_vs_app_base[hash]);
+	write_unlock_bh(&__ip_vs_app_lock);
+
+	return 0;
+}
+
+
+/*
+ *	ip_vs_app unregistration routine.
+ */
+int unregister_ip_vs_app(struct ip_vs_app *vapp)
+{
+	if (!vapp) {
+		IP_VS_ERR("unregister_ip_vs_app(): NULL arg\n");
+		return -EINVAL;
+	}
+
+	write_lock_bh(&__ip_vs_app_lock);
+	list_del(&vapp->n_list);
+	write_unlock_bh(&__ip_vs_app_lock);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+/*
+ *	get ip_vs_app object by its proto and port (net byte order).
+ */
+static struct ip_vs_app * ip_vs_app_get(unsigned short proto, __u16 port)
+{
+	struct list_head *e;
+	struct ip_vs_app *vapp;
+	unsigned hash;
+	unsigned type;
+
+	port = ntohs(port);
+	type = IP_VS_APP_TYPE(proto, port);
+	hash = IP_VS_APP_HASH(proto, port);
+
+	read_lock_bh(&__ip_vs_app_lock);
+
+	list_for_each(e, &ip_vs_app_base[hash]) {
+		vapp = list_entry(e, struct ip_vs_app, n_list);
+
+		/*
+		 * Test and MOD_INC_USE_COUNT atomically
+		 */
+		if (vapp->module && !try_inc_mod_count(vapp->module)) {
+			/*
+			 * This application module is just deleted
+			 */
+			continue;
+		}
+		if (type == vapp->type) {
+			read_unlock_bh(&__ip_vs_app_lock);
+			return vapp;
+		}
+
+		if (vapp->module)
+			__MOD_DEC_USE_COUNT(vapp->module);
+	}
+
+	read_unlock_bh(&__ip_vs_app_lock);
+	return NULL;
+}
+
+
+/*
+ *	Bind ip_vs_conn to its ip_vs_app based on proto and dport,
+ *	and call the ip_vs_app constructor.
+ */
+struct ip_vs_app * ip_vs_bind_app(struct ip_vs_conn *cp)
+{
+	struct ip_vs_app *vapp;
+
+	/* no need to bind app if its forwarding method is not NAT */
+	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
+		return NULL;
+
+	if (cp->protocol != IPPROTO_TCP && cp->protocol != IPPROTO_UDP)
+		return NULL;
+
+	/*
+	 *	don't allow binding if already bound
+	 */
+	if (cp->app != NULL) {
+		IP_VS_ERR("ip_vs_bind_app(): "
+			  "called for already bound object.\n");
+		return cp->app;
+	}
+
+	vapp = ip_vs_app_get(cp->protocol, cp->vport);
+
+	if (vapp != NULL) {
+		cp->app = vapp;
+
+		if (vapp->init_conn)
+			vapp->init_conn(vapp, cp);
+	}
+	return vapp;
+}
+
+
+/*
+ *	Unbind cp from type object and call cp destructor (does not kfree()).
+ */
+int ip_vs_unbind_app(struct ip_vs_conn *cp)
+{
+	struct ip_vs_app *vapp = cp->app;
+
+	if (cp->protocol != IPPROTO_TCP && cp->protocol != IPPROTO_UDP)
+		return 0;
+
+	if (vapp != NULL) {
+		if (vapp->done_conn)
+			vapp->done_conn(vapp, cp);
+		cp->app = NULL;
+		if (vapp->module)
+			__MOD_DEC_USE_COUNT(vapp->module);
+	}
+	return (vapp != NULL);
+}
+
+
+/*
+ *	Fixes th->seq based on ip_vs_seq info.
+ */
+static inline void vs_fix_seq(const struct ip_vs_seq *vseq, struct tcphdr *th)
+{
+	__u32 seq = ntohl(th->seq);
+
+	/*
+	 *	Adjust seq with delta-offset for all packets after
+	 *	the most recent resized pkt seq and with previous_delta offset
+	 *	for all packets	before most recent resized pkt seq.
+	 */
+	if (vseq->delta || vseq->previous_delta) {
+		if(after(seq, vseq->init_seq)) {
+			th->seq = htonl(seq + vseq->delta);
+			IP_VS_DBG(9, "vs_fix_seq(): added delta (%d) to seq\n",
+				  vseq->delta);
+		} else {
+			th->seq = htonl(seq + vseq->previous_delta);
+			IP_VS_DBG(9, "vs_fix_seq(): added previous_delta "
+				  "(%d) to seq\n", vseq->previous_delta);
+		}
+	}
+}
+
+
+/*
+ *	Fixes th->ack_seq based on ip_vs_seq info.
+ */
+static inline void
+vs_fix_ack_seq(const struct ip_vs_seq *vseq, struct tcphdr *th)
+{
+	__u32 ack_seq = ntohl(th->ack_seq);
+
+	/*
+	 * Adjust ack_seq with delta-offset for
+	 * the packets AFTER most recent resized pkt has caused a shift
+	 * for packets before most recent resized pkt, use previous_delta
+	 */
+	if (vseq->delta || vseq->previous_delta) {
+		/* since ack_seq is the number of octet that is expected
+		   to receive next, so compare it with init_seq+delta */
+		if(after(ack_seq, vseq->init_seq+vseq->delta)) {
+			th->ack_seq = htonl(ack_seq - vseq->delta);
+			IP_VS_DBG(9, "vs_fix_ack_seq(): subtracted delta "
+				  "(%d) from ack_seq\n", vseq->delta);
+
+		} else {
+			th->ack_seq = htonl(ack_seq - vseq->previous_delta);
+			IP_VS_DBG(9, "vs_fix_ack_seq(): subtracted "
+				  "previous_delta (%d) from ack_seq\n",
+				  vseq->previous_delta);
+		}
+	}
+}
+
+
+/*
+ *	Updates ip_vs_seq if pkt has been resized
+ *	Assumes already checked proto==IPPROTO_TCP and diff!=0.
+ */
+static inline void vs_seq_update(struct ip_vs_conn *cp, struct ip_vs_seq *vseq,
+				 unsigned flag, __u32 seq, int diff)
+{
+	/* spinlock is to keep updating cp->flags atomic */
+	spin_lock(&cp->lock);
+	if ( !(cp->flags & flag) || after(seq, vseq->init_seq)) {
+		vseq->previous_delta = vseq->delta;
+		vseq->delta += diff;
+		vseq->init_seq = seq;
+		cp->flags |= flag;
+	}
+	spin_unlock(&cp->lock);
+}
+
+
+/*
+ *	Output pkt hook. Will call bound ip_vs_app specific function
+ *	called by ip_vs_out(), assumes previously checked cp!=NULL
+ *	returns (new - old) skb->len diff.
+ */
+int ip_vs_app_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb)
+{
+	struct ip_vs_app *vapp;
+	int diff;
+	struct iphdr *iph;
+	struct tcphdr *th;
+	__u32 seq;
+
+	/*
+	 *	check if application module is bound to
+	 *	this ip_vs_conn.
+	 */
+	if ((vapp = cp->app) == NULL)
+		return 0;
+
+	iph = skb->nh.iph;
+	th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+
+	/*
+	 *	Remember seq number in case this pkt gets resized
+	 */
+	seq = ntohl(th->seq);
+
+	/*
+	 *	Fix seq stuff if flagged as so.
+	 */
+	if (cp->protocol == IPPROTO_TCP) {
+		if (cp->flags & IP_VS_CONN_F_OUT_SEQ)
+			vs_fix_seq(&cp->out_seq, th);
+		if (cp->flags & IP_VS_CONN_F_IN_SEQ)
+			vs_fix_ack_seq(&cp->in_seq, th);
+	}
+
+	/*
+	 *	Call private output hook function
+	 */
+	if (vapp->pkt_out == NULL)
+		return 0;
+
+	diff = vapp->pkt_out(vapp, cp, skb);
+
+	/*
+	 *	Update ip_vs seq stuff if len has changed.
+	 */
+	if (diff != 0 && cp->protocol == IPPROTO_TCP)
+		vs_seq_update(cp, &cp->out_seq,
+			      IP_VS_CONN_F_OUT_SEQ, seq, diff);
+
+	return diff;
+}
+
+
+/*
+ *	Input pkt hook. Will call bound ip_vs_app specific function
+ *	called by ip_fw_demasquerade(), assumes previously checked cp!=NULL.
+ *	returns (new - old) skb->len diff.
+ */
+int ip_vs_app_pkt_in(struct ip_vs_conn *cp, struct sk_buff *skb)
+{
+	struct ip_vs_app *vapp;
+	int diff;
+	struct iphdr *iph;
+	struct tcphdr *th;
+	__u32 seq;
+
+	/*
+	 *	check if application module is bound to
+	 *	this ip_vs_conn.
+	 */
+	if ((vapp = cp->app) == NULL)
+		return 0;
+
+	iph = skb->nh.iph;
+	th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+
+	/*
+	 *	Remember seq number in case this pkt gets resized
+	 */
+	seq = ntohl(th->seq);
+
+	/*
+	 *	Fix seq stuff if flagged as so.
+	 */
+	if (cp->protocol == IPPROTO_TCP) {
+		if (cp->flags & IP_VS_CONN_F_IN_SEQ)
+			vs_fix_seq(&cp->in_seq, th);
+		if (cp->flags & IP_VS_CONN_F_OUT_SEQ)
+			vs_fix_ack_seq(&cp->out_seq, th);
+	}
+
+	/*
+	 *	Call private input hook function
+	 */
+	if (vapp->pkt_in == NULL)
+		return 0;
+
+	diff = vapp->pkt_in(vapp, cp, skb);
+
+	/*
+	 *	Update ip_vs seq stuff if len has changed.
+	 */
+	if (diff != 0 && cp->protocol == IPPROTO_TCP)
+		vs_seq_update(cp, &cp->in_seq,
+			      IP_VS_CONN_F_IN_SEQ, seq, diff);
+
+	return diff;
+}
+
+
+/*
+ *	/proc/net/ip_vs_app entry function
+ */
+static int ip_vs_app_getinfo(char *buffer, char **start, off_t offset,
+			     int length)
+{
+	off_t pos=0;
+	int len=0;
+	char temp[64];
+	int idx;
+	struct ip_vs_app *vapp;
+	struct list_head *e;
+
+	pos = 64;
+	if (pos > offset) {
+		len += sprintf(buffer+len, "%-63s\n",
+			       "prot port    usecnt name");
+	}
+
+	read_lock_bh(&__ip_vs_app_lock);
+	for (idx=0 ; idx < IP_VS_APP_TAB_SIZE; idx++) {
+		list_for_each (e, &ip_vs_app_base[idx]) {
+			vapp = list_entry(e, struct ip_vs_app, n_list);
+
+			pos += 64;
+			if (pos <= offset)
+				continue;
+			sprintf(temp, "%-3s  %-7u %-6d %-17s",
+				ip_vs_proto_name(IP_VS_APP_PROTO(vapp->type)),
+				IP_VS_APP_PORT(vapp->type),
+				vapp->module?GET_USE_COUNT(vapp->module):0,
+				vapp->name);
+			len += sprintf(buffer+len, "%-63s\n", temp);
+			if (pos >= offset+length)
+				goto done;
+		}
+	}
+  done:
+	read_unlock_bh(&__ip_vs_app_lock);
+
+	*start = buffer+len-(pos-offset);       /* Start of wanted data */
+	len = pos-offset;
+	if (len > length)
+		len = length;
+	if (len < 0)
+		len = 0;
+	return len;
+}
+
+
+/*
+ *	Replace a segment of data with a new segment
+ */
+int ip_vs_skb_replace(struct sk_buff *skb, int pri,
+		      char *o_buf, int o_len, char *n_buf, int n_len)
+{
+	struct iphdr *iph;
+	int diff;
+	int o_offset;
+	int o_left;
+
+	EnterFunction(9);
+
+	diff = n_len - o_len;
+	o_offset = o_buf - (char *)skb->data;
+	/* The length of left data after o_buf+o_len in the skb data */
+	o_left = skb->len - (o_offset + o_len);
+
+	if (diff <= 0) {
+		memmove(o_buf + n_len, o_buf + o_len, o_left);
+		memcpy(o_buf, n_buf, n_len);
+		skb_trim(skb, skb->len + diff);
+	} else if (diff <= skb_tailroom(skb)) {
+		skb_put(skb, diff);
+		memmove(o_buf + n_len, o_buf + o_len, o_left);
+		memcpy(o_buf, n_buf, n_len);
+	} else {
+		if (pskb_expand_head(skb, skb_headroom(skb), diff, pri))
+			return -ENOMEM;
+		skb_put(skb, diff);
+		memmove(skb->data + o_offset + n_len,
+			skb->data + o_offset + o_len, o_left);
+		memcpy(skb->data + o_offset, n_buf, n_len);
+	}
+
+	/* must update the iph total length here */
+	iph = skb->nh.iph;
+	iph->tot_len = htons(skb->len);
+
+	LeaveFunction(9);
+	return 0;
+}
+
+
+int ip_vs_app_init(void)
+{
+	int idx;
+
+	for (idx=0 ; idx < IP_VS_APP_TAB_SIZE; idx++) {
+		INIT_LIST_HEAD(&ip_vs_app_base[idx]);
+	}
+
+	/* we will replace it with proc_net_ipvs_create() soon */
+	proc_net_create("ip_vs_app", 0, ip_vs_app_getinfo);
+	return 0;
+}
+
+void ip_vs_app_cleanup(void)
+{
+	proc_net_remove("ip_vs_app");
+}
diff -Nru a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_conn.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,1563 @@
+/*
+ * IPVS         An implementation of the IP virtual server support for the
+ *              LINUX operating system.  IPVS is now implemented as a module
+ *              over the Netfilter framework. IPVS can be used to build a
+ *              high-performance and highly available server based on a
+ *              cluster of servers.
+ *
+ * Version:     $Id: ip_vs_conn.c,v 1.28.2.5 2003/08/09 13:27:08 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              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 IPVS code for kernel 2.2 was done by Wensong Zhang and Peter Kese,
+ * with changes/fixes from Julian Anastasov, Lars Marowsky-Bree, Horms
+ * and others. Many code here is taken from IP MASQ code of kernel 2.2.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/compiler.h>
+#include <linux/vmalloc.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>                  /* for tcphdr */
+#include <linux/in.h>
+#include <linux/proc_fs.h>              /* for proc_net_* */
+#include <asm/softirq.h>                /* for local_bh_* */
+#include <net/ip.h>
+#include <net/tcp.h>                    /* for csum_tcpudp_magic */
+#include <net/udp.h>
+#include <net/icmp.h>                   /* for icmp_send */
+#include <net/route.h>                  /* for ip_route_output */
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/jhash.h>
+#include <linux/random.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *  Connection hash table: for input and output packets lookups of IPVS
+ */
+static struct list_head *ip_vs_conn_tab;
+
+/* SLAB cache for IPVS connections */
+static kmem_cache_t *ip_vs_conn_cachep;
+
+/* counter for current IPVS connections */
+static atomic_t ip_vs_conn_count = ATOMIC_INIT(0);
+
+/* counter for no-client-port connections */
+static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0);
+
+/* random value for IPVS connection hash */
+static unsigned int ip_vs_conn_rnd;
+
+/*
+ *  Fine locking granularity for big connection hash table
+ */
+#define CT_LOCKARRAY_BITS  4
+#define CT_LOCKARRAY_SIZE  (1<<CT_LOCKARRAY_BITS)
+#define CT_LOCKARRAY_MASK  (CT_LOCKARRAY_SIZE-1)
+
+struct ip_vs_aligned_lock
+{
+	rwlock_t	l;
+} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+
+/* lock array for conn table */
+struct ip_vs_aligned_lock
+__ip_vs_conntbl_lock_array[CT_LOCKARRAY_SIZE] __cacheline_aligned;
+
+static inline void ct_read_lock(unsigned key)
+{
+	read_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_read_unlock(unsigned key)
+{
+	read_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_write_lock(unsigned key)
+{
+	write_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_write_unlock(unsigned key)
+{
+	write_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_read_lock_bh(unsigned key)
+{
+	read_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_read_unlock_bh(unsigned key)
+{
+	read_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_write_lock_bh(unsigned key)
+{
+	write_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+static inline void ct_write_unlock_bh(unsigned key)
+{
+	write_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+}
+
+
+/*
+ *	Returns hash value for IPVS connection entry
+ */
+static unsigned
+ip_vs_conn_hashkey(unsigned proto, __u32 addr, __u16 port)
+{
+	return jhash_3words(addr, port, proto, ip_vs_conn_rnd)
+		& IP_VS_CONN_TAB_MASK;
+}
+
+
+/*
+ *	Hashes ip_vs_conn in ip_vs_conn_tab by proto,addr,port.
+ *	returns bool success.
+ */
+static int ip_vs_conn_hash(struct ip_vs_conn *cp)
+{
+	unsigned hash;
+
+	if (cp->flags & IP_VS_CONN_F_HASHED) {
+		IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	/* Hash by protocol, client address and port */
+	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
+
+	ct_write_lock(hash);
+
+	list_add(&cp->c_list, &ip_vs_conn_tab[hash]);
+	cp->flags |= IP_VS_CONN_F_HASHED;
+	atomic_inc(&cp->refcnt);
+
+	ct_write_unlock(hash);
+
+	return 1;
+}
+
+
+/*
+ *	UNhashes ip_vs_conn from ip_vs_conn_tab.
+ *	returns bool success.
+ */
+static int ip_vs_conn_unhash(struct ip_vs_conn *cp)
+{
+	unsigned hash;
+
+	if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
+		IP_VS_ERR("ip_vs_conn_unhash(): request for unhash flagged, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	/* unhash it and decrease its reference counter */
+	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
+	ct_write_lock(hash);
+
+	list_del(&cp->c_list);
+	cp->flags &= ~IP_VS_CONN_F_HASHED;
+	atomic_dec(&cp->refcnt);
+
+	ct_write_unlock(hash);
+
+	return 1;
+}
+
+
+/*
+ *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
+ *  Called for pkts coming from OUTside-to-INside.
+ *	s_addr, s_port: pkt source address (foreign host)
+ *	d_addr, d_port: pkt dest address (load balancer)
+ */
+static inline struct ip_vs_conn *__ip_vs_conn_in_get
+(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+	unsigned hash;
+	struct ip_vs_conn *cp;
+	struct list_head *l,*e;
+
+	hash = ip_vs_conn_hashkey(protocol, s_addr, s_port);
+	l = &ip_vs_conn_tab[hash];
+
+	ct_read_lock(hash);
+
+	for (e=l->next; e!=l; e=e->next) {
+		cp = list_entry(e, struct ip_vs_conn, c_list);
+		if (s_addr==cp->caddr && s_port==cp->cport &&
+		    d_port==cp->vport && d_addr==cp->vaddr &&
+		    protocol==cp->protocol) {
+			/* HIT */
+			atomic_inc(&cp->refcnt);
+			ct_read_unlock(hash);
+			return cp;
+		}
+	}
+
+	ct_read_unlock(hash);
+
+	return NULL;
+}
+
+struct ip_vs_conn *ip_vs_conn_in_get
+(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+	struct ip_vs_conn *cp;
+
+	cp = __ip_vs_conn_in_get(protocol, s_addr, s_port, d_addr, d_port);
+	if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
+		cp = __ip_vs_conn_in_get(protocol, s_addr, 0, d_addr, d_port);
+
+	IP_VS_DBG(7, "lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
+		  ip_vs_proto_name(protocol),
+		  NIPQUAD(s_addr), ntohs(s_port),
+		  NIPQUAD(d_addr), ntohs(d_port),
+		  cp?"hit":"not hit");
+
+	return cp;
+}
+
+
+/*
+ *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
+ *  Called for pkts coming from inside-to-OUTside.
+ *	s_addr, s_port: pkt source address (inside host)
+ *	d_addr, d_port: pkt dest address (foreign host)
+ */
+struct ip_vs_conn *ip_vs_conn_out_get
+(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+	unsigned hash;
+	struct ip_vs_conn *cp, *ret=NULL;
+	struct list_head *l,*e;
+
+	/*
+	 *	Check for "full" addressed entries
+	 */
+	hash = ip_vs_conn_hashkey(protocol, d_addr, d_port);
+	l = &ip_vs_conn_tab[hash];
+
+	ct_read_lock(hash);
+
+	for (e=l->next; e!=l; e=e->next) {
+		cp = list_entry(e, struct ip_vs_conn, c_list);
+		if (d_addr == cp->caddr && d_port == cp->cport &&
+		    s_port == cp->dport && s_addr == cp->daddr &&
+		    protocol == cp->protocol) {
+			/* HIT */
+			atomic_inc(&cp->refcnt);
+			ret = cp;
+			break;
+		}
+	}
+
+	ct_read_unlock(hash);
+
+	IP_VS_DBG(7, "lookup/out %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
+		  ip_vs_proto_name(protocol),
+		  NIPQUAD(s_addr), ntohs(s_port),
+		  NIPQUAD(d_addr), ntohs(d_port),
+		  ret?"hit":"not hit");
+
+	return ret;
+}
+
+
+/*
+ *      Put back the conn and restart its timer with its timeout
+ */
+void ip_vs_conn_put(struct ip_vs_conn *cp)
+{
+	/* reset it expire in its timeout */
+	mod_timer(&cp->timer, jiffies+cp->timeout);
+
+	__ip_vs_conn_put(cp);
+}
+
+
+/*
+ *	Timeout table[state]
+ */
+struct ip_vs_timeout_table vs_timeout_table = {
+	ATOMIC_INIT(0),	/* refcnt */
+	0,		/* scale  */
+	{
+		[IP_VS_S_NONE]          =	30*60*HZ,
+		[IP_VS_S_ESTABLISHED]	=	15*60*HZ,
+		[IP_VS_S_SYN_SENT]	=	2*60*HZ,
+		[IP_VS_S_SYN_RECV]	=	1*60*HZ,
+		[IP_VS_S_FIN_WAIT]	=	2*60*HZ,
+		[IP_VS_S_TIME_WAIT]	=	2*60*HZ,
+		[IP_VS_S_CLOSE]         =	10*HZ,
+		[IP_VS_S_CLOSE_WAIT]	=	60*HZ,
+		[IP_VS_S_LAST_ACK]	=	30*HZ,
+		[IP_VS_S_LISTEN]	=	2*60*HZ,
+		[IP_VS_S_SYNACK]	=	120*HZ,
+		[IP_VS_S_UDP]		=	5*60*HZ,
+		[IP_VS_S_ICMP]          =	1*60*HZ,
+		[IP_VS_S_LAST]          =	2*HZ,
+	},	/* timeout */
+};
+
+
+struct ip_vs_timeout_table vs_timeout_table_dos = {
+	ATOMIC_INIT(0),	/* refcnt */
+	0,		/* scale  */
+	{
+		[IP_VS_S_NONE]          =	15*60*HZ,
+		[IP_VS_S_ESTABLISHED]	=	8*60*HZ,
+		[IP_VS_S_SYN_SENT]	=	60*HZ,
+		[IP_VS_S_SYN_RECV]	=	10*HZ,
+		[IP_VS_S_FIN_WAIT]	=	60*HZ,
+		[IP_VS_S_TIME_WAIT]	=	60*HZ,
+		[IP_VS_S_CLOSE]         =	10*HZ,
+		[IP_VS_S_CLOSE_WAIT]	=	60*HZ,
+		[IP_VS_S_LAST_ACK]	=	30*HZ,
+		[IP_VS_S_LISTEN]	=	2*60*HZ,
+		[IP_VS_S_SYNACK]	=	100*HZ,
+		[IP_VS_S_UDP]		=	3*60*HZ,
+		[IP_VS_S_ICMP]          =	1*60*HZ,
+		[IP_VS_S_LAST]          =	2*HZ,
+	},	/* timeout */
+};
+
+
+/*
+ *	Timeout table to use for the VS entries
+ *	If NULL we use the default table (vs_timeout_table).
+ *	Under flood attack we switch to vs_timeout_table_dos
+ */
+
+static struct ip_vs_timeout_table *ip_vs_timeout_table = &vs_timeout_table;
+
+static const char * state_name_table[IP_VS_S_LAST+1] = {
+	[IP_VS_S_NONE]          =	"NONE",
+	[IP_VS_S_ESTABLISHED]	=	"ESTABLISHED",
+	[IP_VS_S_SYN_SENT]	=	"SYN_SENT",
+	[IP_VS_S_SYN_RECV]	=	"SYN_RECV",
+	[IP_VS_S_FIN_WAIT]	=	"FIN_WAIT",
+	[IP_VS_S_TIME_WAIT]	=	"TIME_WAIT",
+	[IP_VS_S_CLOSE]         =	"CLOSE",
+	[IP_VS_S_CLOSE_WAIT]	=	"CLOSE_WAIT",
+	[IP_VS_S_LAST_ACK]	=	"LAST_ACK",
+	[IP_VS_S_LISTEN]	=	"LISTEN",
+	[IP_VS_S_SYNACK]	=	"SYNACK",
+	[IP_VS_S_UDP]		=	"UDP",
+	[IP_VS_S_ICMP]          =	"ICMP",
+	[IP_VS_S_LAST]          =	"BUG!",
+};
+
+#define sNO IP_VS_S_NONE
+#define sES IP_VS_S_ESTABLISHED
+#define sSS IP_VS_S_SYN_SENT
+#define sSR IP_VS_S_SYN_RECV
+#define sFW IP_VS_S_FIN_WAIT
+#define sTW IP_VS_S_TIME_WAIT
+#define sCL IP_VS_S_CLOSE
+#define sCW IP_VS_S_CLOSE_WAIT
+#define sLA IP_VS_S_LAST_ACK
+#define sLI IP_VS_S_LISTEN
+#define sSA IP_VS_S_SYNACK
+
+struct vs_tcp_states_t {
+	int next_state[IP_VS_S_LAST];	/* should be _LAST_TCP */
+};
+
+const char * ip_vs_state_name(int state)
+{
+	if (state >= IP_VS_S_LAST)
+		return "ERR!";
+	return state_name_table[state] ? state_name_table[state] : "?";
+}
+
+static struct vs_tcp_states_t vs_tcp_states [] = {
+/*	INPUT */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }},
+/*fin*/ {{sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI, sTW }},
+/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
+/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sSR }},
+
+/*	OUTPUT */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI, sSR }},
+/*fin*/ {{sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI, sTW }},
+/*ack*/ {{sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES, sES }},
+/*rst*/ {{sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL, sCL }},
+
+/*	INPUT-ONLY */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }},
+/*fin*/ {{sCL, sFW, sSS, sTW, sFW, sTW, sCL, sCW, sLA, sLI, sTW }},
+/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
+/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
+};
+
+static struct vs_tcp_states_t vs_tcp_states_dos [] = {
+/*	INPUT */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSA }},
+/*fin*/ {{sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI, sSA }},
+/*ack*/ {{sCL, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI, sSA }},
+/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
+
+/*	OUTPUT */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSS, sES, sSS, sSA, sSS, sSS, sSS, sSS, sSS, sLI, sSA }},
+/*fin*/ {{sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI, sTW }},
+/*ack*/ {{sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES, sES }},
+/*rst*/ {{sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL, sCL }},
+
+/*	INPUT-ONLY */
+/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA	*/
+/*syn*/ {{sSA, sES, sES, sSR, sSA, sSA, sSA, sSA, sSA, sSA, sSA }},
+/*fin*/ {{sCL, sFW, sSS, sTW, sFW, sTW, sCL, sCW, sLA, sLI, sTW }},
+/*ack*/ {{sCL, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
+/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},
+};
+
+static struct vs_tcp_states_t *ip_vs_state_table = vs_tcp_states;
+
+void ip_vs_secure_tcp_set(int on)
+{
+	if (on) {
+		ip_vs_state_table = vs_tcp_states_dos;
+		ip_vs_timeout_table = &vs_timeout_table_dos;
+	} else {
+		ip_vs_state_table = vs_tcp_states;
+		ip_vs_timeout_table = &vs_timeout_table;
+	}
+}
+
+
+static inline int vs_tcp_state_idx(struct tcphdr *th, int state_off)
+{
+	/*
+	 *	[0-3]: input states, [4-7]: output, [8-11] input only states.
+	 */
+	if (th->rst)
+		return state_off+3;
+	if (th->syn)
+		return state_off+0;
+	if (th->fin)
+		return state_off+1;
+	if (th->ack)
+		return state_off+2;
+	return -1;
+}
+
+
+static inline int vs_set_state_timeout(struct ip_vs_conn *cp, int state)
+{
+	struct ip_vs_timeout_table *vstim = cp->timeout_table;
+
+	/*
+	 *	Use default timeout table if no specific for this entry
+	 */
+	if (!vstim)
+		vstim = &vs_timeout_table;
+
+	cp->timeout = vstim->timeout[cp->state=state];
+
+	if (vstim->scale) {
+		int scale = vstim->scale;
+
+		if (scale<0)
+			cp->timeout >>= -scale;
+		else if (scale > 0)
+			cp->timeout <<= scale;
+	}
+
+	return state;
+}
+
+
+static inline int
+vs_tcp_state(struct ip_vs_conn *cp, int state_off, struct tcphdr *th)
+{
+	int state_idx;
+	int new_state = IP_VS_S_CLOSE;
+
+	/*
+	 *    Update state offset to INPUT_ONLY if necessary
+	 *    or delete NO_OUTPUT flag if output packet detected
+	 */
+	if (cp->flags & IP_VS_CONN_F_NOOUTPUT) {
+		if (state_off == VS_STATE_OUTPUT)
+			cp->flags &= ~IP_VS_CONN_F_NOOUTPUT;
+		else
+			state_off = VS_STATE_INPUT_ONLY;
+	}
+
+	if ((state_idx = vs_tcp_state_idx(th, state_off)) < 0) {
+		IP_VS_DBG(8, "vs_tcp_state_idx(%d)=%d!!!\n",
+			  state_off, state_idx);
+		goto tcp_state_out;
+	}
+
+	new_state = ip_vs_state_table[state_idx].next_state[cp->state];
+
+  tcp_state_out:
+	if (new_state != cp->state) {
+		struct ip_vs_dest *dest = cp->dest;
+
+		IP_VS_DBG(8, "%s %s [%c%c%c%c] %u.%u.%u.%u:%d->"
+			  "%u.%u.%u.%u:%d state: %s->%s cnt:%d\n",
+			  ip_vs_proto_name(cp->protocol),
+			  (state_off==VS_STATE_OUTPUT)?"output ":"input ",
+			  th->syn? 'S' : '.',
+			  th->fin? 'F' : '.',
+			  th->ack? 'A' : '.',
+			  th->rst? 'R' : '.',
+			  NIPQUAD(cp->daddr), ntohs(cp->dport),
+			  NIPQUAD(cp->caddr), ntohs(cp->cport),
+			  ip_vs_state_name(cp->state),
+			  ip_vs_state_name(new_state),
+			  atomic_read(&cp->refcnt));
+		if (dest) {
+			if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
+			    (new_state != IP_VS_S_ESTABLISHED)) {
+				atomic_dec(&dest->activeconns);
+				atomic_inc(&dest->inactconns);
+				cp->flags |= IP_VS_CONN_F_INACTIVE;
+			} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
+				   (new_state == IP_VS_S_ESTABLISHED)) {
+				atomic_inc(&dest->activeconns);
+				atomic_dec(&dest->inactconns);
+				cp->flags &= ~IP_VS_CONN_F_INACTIVE;
+			}
+		}
+	}
+
+	return vs_set_state_timeout(cp, new_state);
+}
+
+
+/*
+ *	Handle state transitions
+ */
+int ip_vs_set_state(struct ip_vs_conn *cp,
+		    int state_off, struct iphdr *iph, void *tp)
+{
+	int ret;
+
+	spin_lock(&cp->lock);
+	switch (iph->protocol) {
+	case IPPROTO_TCP:
+		ret = vs_tcp_state(cp, state_off, tp);
+		break;
+	case IPPROTO_UDP:
+		ret = vs_set_state_timeout(cp, IP_VS_S_UDP);
+		break;
+	case IPPROTO_ICMP:
+		ret = vs_set_state_timeout(cp, IP_VS_S_ICMP);
+		break;
+	default:
+		ret = -1;
+	}
+	spin_unlock(&cp->lock);
+
+	return ret;
+}
+
+
+/*
+ *	Set LISTEN timeout. (ip_vs_conn_put will setup timer)
+ */
+int ip_vs_conn_listen(struct ip_vs_conn *cp)
+{
+	vs_set_state_timeout(cp, IP_VS_S_LISTEN);
+	return cp->timeout;
+}
+
+
+/*
+ *      Bypass transmitter
+ *      Let packets bypass the destination when the destination is not
+ *      available, it may be only used in transparent cache cluster.
+ */
+static int ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp)
+{
+	struct rtable *rt;			/* Route to the other host */
+	struct iphdr  *iph = skb->nh.iph;
+	u8     tos = iph->tos;
+	int    mtu;
+
+	EnterFunction(10);
+
+	if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(tos), 0)) {
+		IP_VS_DBG_RL("ip_vs_bypass_xmit(): ip_route_output error, "
+			     "dest: %u.%u.%u.%u\n", NIPQUAD(iph->daddr));
+		goto tx_error_icmp;
+	}
+
+	/* MTU checking */
+	mtu = rt->u.dst.pmtu;
+	if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) {
+		ip_rt_put(rt);
+		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
+		IP_VS_DBG_RL("ip_vs_bypass_xmit(): frag needed\n");
+		goto tx_error;
+	}
+
+	/* update checksum because skb might be defragmented */
+	ip_send_check(iph);
+
+	if (unlikely(skb_headroom(skb) < rt->u.dst.dev->hard_header_len)) {
+		if (skb_cow(skb, rt->u.dst.dev->hard_header_len)) {
+			ip_rt_put(rt);
+			IP_VS_ERR_RL("ip_vs_bypass_xmit(): no memory\n");
+			goto tx_error;
+		}
+	}
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+#ifdef CONFIG_NETFILTER_DEBUG
+	skb->nf_debug = 1 << NF_IP_LOCAL_OUT;
+#endif /* CONFIG_NETFILTER_DEBUG */
+	skb->nfcache |= NFC_IPVS_PROPERTY;
+	ip_send(skb);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	kfree_skb(skb);
+	return NF_STOLEN;
+}
+
+
+/*
+ *      NULL transmitter (do nothing except return NF_ACCEPT)
+ */
+static int ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp)
+{
+	return NF_ACCEPT;
+}
+
+
+/*
+ *      NAT transmitter (only for outside-to-inside nat forwarding)
+ */
+static int ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp)
+{
+	struct rtable *rt;		/* Route to the other host */
+	struct iphdr  *iph;
+	union ip_vs_tphdr h;
+	int ihl;
+	unsigned short size;
+	int mtu;
+
+	EnterFunction(10);
+
+	/*
+	 * If it has ip_vs_app helper, the helper may change the payload,
+	 * so it needs full checksum checking and checksum calculation.
+	 * If not, only the header (such as IP address and port number)
+	 * will be changed, so it is fast to do incremental checksum update,
+	 * and let the destination host  do final checksum checking.
+	 */
+
+	if (cp->app && skb_is_nonlinear(skb)
+	    && skb_linearize(skb, GFP_ATOMIC) != 0)
+		return NF_DROP;
+
+	iph = skb->nh.iph;
+	ihl = iph->ihl << 2;
+	h.raw = (char*) iph + ihl;
+	size = ntohs(iph->tot_len) - ihl;
+
+	/* do TCP/UDP checksum checking if it has application helper */
+	if (cp->app && (iph->protocol != IPPROTO_UDP || h.uh->check != 0)) {
+		switch (skb->ip_summed) {
+		case CHECKSUM_NONE:
+			skb->csum = csum_partial(h.raw, size, 0);
+
+		case CHECKSUM_HW:
+			if (csum_tcpudp_magic(iph->saddr, iph->daddr, size,
+					      iph->protocol, skb->csum)) {
+				IP_VS_DBG_RL("Incoming failed %s checksum "
+					     "from %d.%d.%d.%d (size=%d)!\n",
+					     ip_vs_proto_name(iph->protocol),
+					     NIPQUAD(iph->saddr),
+					     size);
+				goto tx_error;
+			}
+			break;
+		default:
+			/* CHECKSUM_UNNECESSARY */
+			break;
+		}
+	}
+
+	/*
+	 *  Check if it is no_cport connection ...
+	 */
+	if (cp->flags & IP_VS_CONN_F_NO_CPORT) {
+		atomic_dec(&ip_vs_conn_no_cport_cnt);
+		ip_vs_conn_unhash(cp);
+		cp->flags &= ~IP_VS_CONN_F_NO_CPORT;
+		cp->cport = h.portp[0];
+		/* hash on new dport */
+		ip_vs_conn_hash(cp);
+
+		IP_VS_DBG(10, "filled cport=%d\n", ntohs(cp->dport));
+	}
+
+	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = rt->u.dst.pmtu;
+	if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) {
+		ip_rt_put(rt);
+		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
+		IP_VS_DBG_RL("ip_vs_nat_xmit(): frag needed\n");
+		goto tx_error;
+	}
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* copy-on-write the packet before mangling it */
+	if (ip_vs_skb_cow(skb, rt->u.dst.dev->hard_header_len, &iph, &h.raw))
+		return NF_DROP;
+
+	/* mangle the packet */
+	iph->daddr = cp->daddr;
+	h.portp[1] = cp->dport;
+
+	/*
+	 *	Attempt ip_vs_app call.
+	 *	will fix ip_vs_conn and iph ack_seq stuff
+	 */
+	if (ip_vs_app_pkt_in(cp, skb) != 0) {
+		/* skb data has probably changed, update pointers */
+		iph = skb->nh.iph;
+		h.raw = (char*) iph + ihl;
+		size = skb->len - ihl;
+	}
+
+	/*
+	 *	Adjust TCP/UDP checksums
+	 */
+	if (!cp->app && (iph->protocol != IPPROTO_UDP || h.uh->check != 0)) {
+		/* Only port and addr are changed, do fast csum update */
+		ip_vs_fast_check_update(&h, cp->vaddr, cp->daddr,
+					cp->vport, cp->dport, iph->protocol);
+		if (skb->ip_summed == CHECKSUM_HW)
+			skb->ip_summed = CHECKSUM_NONE;
+	} else {
+		/* full checksum calculation */
+		switch (iph->protocol) {
+		case IPPROTO_TCP:
+			h.th->check = 0;
+			h.th->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+							size, iph->protocol,
+							csum_partial(h.raw, size, 0));
+			break;
+		case IPPROTO_UDP:
+			h.uh->check = 0;
+			h.uh->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+							size, iph->protocol,
+							csum_partial(h.raw, size, 0));
+			if (h.uh->check == 0)
+				h.uh->check = 0xFFFF;
+			break;
+		}
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	}
+	ip_send_check(iph);
+
+	IP_VS_DBG(10, "NAT to %u.%u.%u.%u:%d\n",
+		  NIPQUAD(iph->daddr), ntohs(h.portp[1]));
+
+	/* FIXME: when application helper enlarges the packet and the length
+	   is larger than the MTU of outgoing device, there will be still
+	   MTU problem. */
+
+#ifdef CONFIG_NETFILTER_DEBUG
+	skb->nf_debug = 1 << NF_IP_LOCAL_OUT;
+#endif /* CONFIG_NETFILTER_DEBUG */
+	skb->nfcache |= NFC_IPVS_PROPERTY;
+	ip_send(skb);
+
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	kfree_skb(skb);
+	return NF_STOLEN;
+}
+
+
+/*
+ *   IP Tunneling transmitter
+ *
+ *   This function encapsulates the packet in a new IP packet, its
+ *   destination will be set to cp->daddr. Most code of this function
+ *   is taken from ipip.c.
+ *
+ *   It is used in VS/TUN cluster. The load balancer selects a real
+ *   server from a cluster based on a scheduling algorithm,
+ *   encapsulates the request packet and forwards it to the selected
+ *   server. For example, all real servers are configured with
+ *   "ifconfig tunl0 <Virtual IP Address> up". When the server receives
+ *   the encapsulated packet, it will decapsulate the packet, processe
+ *   the request and return the response packets directly to the client
+ *   without passing the load balancer. This can greatly increase the
+ *   scalability of virtual server.
+ */
+static int ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp)
+{
+	struct rtable *rt;			/* Route to the other host */
+	struct net_device *tdev;		/* Device to other host */
+	struct iphdr  *old_iph = skb->nh.iph;
+	u8     tos = old_iph->tos;
+	u16    df = old_iph->frag_off;
+	struct iphdr  *iph;			/* Our new IP header */
+	int    max_headroom;			/* The extra header space needed */
+	int    mtu;
+
+	EnterFunction(10);
+
+	if (skb->protocol != __constant_htons(ETH_P_IP)) {
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): protocol error, "
+			     "ETH_P_IP: %d, skb protocol: %d\n",
+			     __constant_htons(ETH_P_IP), skb->protocol);
+		goto tx_error;
+	}
+
+	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(tos))))
+		goto tx_error_icmp;
+
+	tdev = rt->u.dst.dev;
+
+	mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+	if (mtu < 68) {
+		ip_rt_put(rt);
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): mtu less than 68\n");
+		goto tx_error;
+	}
+	if (skb->dst && mtu < skb->dst->pmtu)
+		skb->dst->pmtu = mtu;
+
+	df |= (old_iph->frag_off&__constant_htons(IP_DF));
+
+	if ((old_iph->frag_off&__constant_htons(IP_DF))
+	    && mtu < ntohs(old_iph->tot_len)) {
+		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
+		ip_rt_put(rt);
+		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): frag needed\n");
+		goto tx_error;
+	}
+
+	/* update checksum because skb might be defragmented */
+	ip_send_check(old_iph);
+
+	skb->h.raw = skb->nh.raw;
+
+	/*
+	 * Okay, now see if we can stuff it in the buffer as-is.
+	 */
+	max_headroom = (((tdev->hard_header_len+15)&~15)+sizeof(struct iphdr));
+
+	if (skb_headroom(skb) < max_headroom
+	    || skb_cloned(skb) || skb_shared(skb)) {
+		struct sk_buff *new_skb =
+			skb_realloc_headroom(skb, max_headroom);
+		if (!new_skb) {
+			ip_rt_put(rt);
+			kfree_skb(skb);
+			IP_VS_ERR_RL("ip_vs_tunnel_xmit(): no memory\n");
+			return -EINVAL;
+		}
+		kfree_skb(skb);
+		skb = new_skb;
+		old_iph = skb->nh.iph;
+	}
+
+	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/*
+	 *	Push down and install the IPIP header.
+	 */
+	iph			=	skb->nh.iph;
+	iph->version		=	4;
+	iph->ihl		=	sizeof(struct iphdr)>>2;
+	iph->frag_off		=	df;
+	iph->protocol		=	IPPROTO_IPIP;
+	iph->tos		=	tos;
+	iph->daddr		=	rt->rt_dst;
+	iph->saddr		=	rt->rt_src;
+	iph->ttl		=	old_iph->ttl;
+	iph->tot_len		=	htons(skb->len);
+	ip_select_ident(iph, &rt->u.dst, NULL);
+	ip_send_check(iph);
+
+	skb->ip_summed = CHECKSUM_NONE;
+#ifdef CONFIG_NETFILTER_DEBUG
+	skb->nf_debug = 1 << NF_IP_LOCAL_OUT;
+#endif /* CONFIG_NETFILTER_DEBUG */
+	skb->nfcache |= NFC_IPVS_PROPERTY;
+	ip_send(skb);
+
+	LeaveFunction(10);
+
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	kfree_skb(skb);
+	return NF_STOLEN;
+}
+
+
+/*
+ *      Direct Routing transmitter
+ */
+static int ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp)
+{
+	struct rtable *rt;			/* Route to the other host */
+	struct iphdr  *iph = skb->nh.iph;
+	int    mtu;
+
+	EnterFunction(10);
+
+	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = rt->u.dst.pmtu;
+	if ((iph->frag_off&__constant_htons(IP_DF)) && skb->len > mtu) {
+		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
+		ip_rt_put(rt);
+		IP_VS_DBG_RL("ip_vs_dr_xmit(): frag needed\n");
+		goto tx_error;
+	}
+
+	/* update checksum because skb might be defragmented */
+	ip_send_check(iph);
+
+	if (unlikely(skb_headroom(skb) < rt->u.dst.dev->hard_header_len)) {
+		if (skb_cow(skb, rt->u.dst.dev->hard_header_len)) {
+			ip_rt_put(rt);
+			IP_VS_ERR_RL("ip_vs_dr_xmit(): no memory\n");
+			goto tx_error;
+		}
+	}
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+#ifdef CONFIG_NETFILTER_DEBUG
+	skb->nf_debug = 1 << NF_IP_LOCAL_OUT;
+#endif /* CONFIG_NETFILTER_DEBUG */
+	skb->nfcache |= NFC_IPVS_PROPERTY;
+	ip_send(skb);
+
+#if 0000
+	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
+		do_ip_send);
+#endif
+	LeaveFunction(10);
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	kfree_skb(skb);
+	return NF_STOLEN;
+}
+
+
+/*
+ *  Bind a connection entry with the corresponding packet_xmit.
+ *  Called by ip_vs_conn_new.
+ */
+static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp)
+{
+	switch (IP_VS_FWD_METHOD(cp)) {
+	case IP_VS_CONN_F_MASQ:
+		cp->packet_xmit = ip_vs_nat_xmit;
+		break;
+
+	case IP_VS_CONN_F_TUNNEL:
+		cp->packet_xmit = ip_vs_tunnel_xmit;
+		break;
+
+	case IP_VS_CONN_F_DROUTE:
+		cp->packet_xmit = ip_vs_dr_xmit;
+		break;
+
+	case IP_VS_CONN_F_LOCALNODE:
+		cp->packet_xmit = ip_vs_null_xmit;
+		break;
+
+	case IP_VS_CONN_F_BYPASS:
+		cp->packet_xmit = ip_vs_bypass_xmit;
+		break;
+	}
+}
+
+
+/*
+ *  Bind a connection entry with a virtual service destination
+ *  Called just after a new connection entry is created.
+ */
+static inline void
+ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
+{
+	/* if dest is NULL, then return directly */
+	if (!dest)
+		return;
+
+	/* Increase the refcnt counter of the dest */
+	atomic_inc(&dest->refcnt);
+
+	/* Bind with the destination and its corresponding transmitter */
+	cp->flags |= atomic_read(&dest->conn_flags);
+	cp->dest = dest;
+
+	IP_VS_DBG(9, "Bind-dest %s c:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
+		  "d:%u.%u.%u.%u:%d fwd:%c s:%s flg:%X cnt:%d destcnt:%d\n",
+		  ip_vs_proto_name(cp->protocol),
+		  NIPQUAD(cp->caddr), ntohs(cp->cport),
+		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
+		  NIPQUAD(cp->daddr), ntohs(cp->dport),
+		  ip_vs_fwd_tag(cp), ip_vs_state_name(cp->state),
+		  cp->flags, atomic_read(&cp->refcnt),
+		  atomic_read(&dest->refcnt));
+}
+
+
+/*
+ *  Unbind a connection entry with its VS destination
+ *  Called by the ip_vs_conn_expire function.
+ */
+static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
+{
+	struct ip_vs_dest *dest = cp->dest;
+
+	/* if dest is NULL, then return directly */
+	if (!dest)
+		return;
+
+	IP_VS_DBG(9, "Unbind-dest %s c:%u.%u.%u.%u:%d "
+		  "v:%u.%u.%u.%u:%d d:%u.%u.%u.%u:%d fwd:%c "
+		  "s:%s flg:%X cnt:%d destcnt:%d",
+		  ip_vs_proto_name(cp->protocol),
+		  NIPQUAD(cp->caddr), ntohs(cp->cport),
+		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
+		  NIPQUAD(cp->daddr), ntohs(cp->dport),
+		  ip_vs_fwd_tag(cp), ip_vs_state_name(cp->state),
+		  cp->flags, atomic_read(&cp->refcnt),
+		  atomic_read(&dest->refcnt));
+
+	/*
+	 * Decrease the inactconns or activeconns counter
+	 * if it is not a connection template ((cp->cport!=0)
+	 *   || (cp->flags & IP_VS_CONN_F_NO_CPORT)).
+	 */
+	if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+		if (cp->flags & IP_VS_CONN_F_INACTIVE) {
+			atomic_dec(&dest->inactconns);
+		} else {
+			atomic_dec(&dest->activeconns);
+		}
+	}
+
+	/*
+	 * Simply decrease the refcnt of the dest, because the
+	 * dest will be either in service's destination list
+	 * or in the trash.
+	 */
+	atomic_dec(&dest->refcnt);
+}
+
+
+/*
+ *  Checking if the destination of a connection template is available.
+ *  If available, return 1, otherwise invalidate this connection
+ *  template and return 0.
+ */
+int ip_vs_check_template(struct ip_vs_conn *ct)
+{
+	struct ip_vs_dest *dest = ct->dest;
+
+	/*
+	 * Checking the dest server status.
+	 */
+	if ((dest == NULL) ||
+	    !(dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+		IP_VS_DBG(9, "check_template: dest not available for "
+			  "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d "
+			  "-> d:%u.%u.%u.%u:%d\n",
+			  ip_vs_proto_name(ct->protocol),
+			  NIPQUAD(ct->caddr), ntohs(ct->cport),
+			  NIPQUAD(ct->vaddr), ntohs(ct->vport),
+			  NIPQUAD(ct->daddr), ntohs(ct->dport));
+
+		/*
+		 * Invalidate the connection template
+		 */
+		ip_vs_conn_unhash(ct);
+		ct->dport = 65535;
+		ct->vport = 65535;
+		ct->cport = 0;
+		ip_vs_conn_hash(ct);
+
+		/*
+		 * Simply decrease the refcnt of the template,
+		 * don't restart its timer.
+		 */
+		atomic_dec(&ct->refcnt);
+		return 0;
+	}
+	return 1;
+}
+
+
+static inline void
+ip_vs_timeout_attach(struct ip_vs_conn *cp, struct ip_vs_timeout_table *vstim)
+{
+	atomic_inc(&vstim->refcnt);
+	cp->timeout_table = vstim;
+}
+
+static inline void ip_vs_timeout_detach(struct ip_vs_conn *cp)
+{
+	struct ip_vs_timeout_table *vstim = cp->timeout_table;
+
+	if (!vstim)
+		return;
+	cp->timeout_table = NULL;
+	atomic_dec(&vstim->refcnt);
+}
+
+
+static void ip_vs_conn_expire(unsigned long data)
+{
+	struct ip_vs_conn *cp = (struct ip_vs_conn *)data;
+
+	if (cp->timeout_table)
+		cp->timeout = cp->timeout_table->timeout[IP_VS_S_TIME_WAIT];
+	else
+		cp->timeout = vs_timeout_table.timeout[IP_VS_S_TIME_WAIT];
+
+	/*
+	 *	hey, I'm using it
+	 */
+	atomic_inc(&cp->refcnt);
+
+	/*
+	 *	do I control anybody?
+	 */
+	if (atomic_read(&cp->n_control))
+		goto expire_later;
+
+	/*
+	 *	unhash it if it is hashed in the conn table
+	 */
+	ip_vs_conn_unhash(cp);
+
+	/*
+	 *	refcnt==1 implies I'm the only one referrer
+	 */
+	if (likely(atomic_read(&cp->refcnt) == 1)) {
+		/* make sure that there is no timer on it now */
+		if (timer_pending(&cp->timer))
+			del_timer(&cp->timer);
+
+		/* does anybody control me? */
+		if (cp->control)
+			ip_vs_control_del(cp);
+
+		ip_vs_unbind_dest(cp);
+		ip_vs_unbind_app(cp);
+		ip_vs_timeout_detach(cp);
+		if (cp->flags & IP_VS_CONN_F_NO_CPORT)
+			atomic_dec(&ip_vs_conn_no_cport_cnt);
+		atomic_dec(&ip_vs_conn_count);
+
+		kmem_cache_free(ip_vs_conn_cachep, cp);
+		return;
+	}
+
+	/* hash it back to the table */
+	ip_vs_conn_hash(cp);
+
+  expire_later:
+	IP_VS_DBG(7, "delayed: refcnt-1=%d conn.n_control=%d\n",
+		  atomic_read(&cp->refcnt)-1,
+		  atomic_read(&cp->n_control));
+
+	ip_vs_conn_put(cp);
+}
+
+
+void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
+{
+	cp->timeout = 0;
+	mod_timer(&cp->timer, jiffies);
+	__ip_vs_conn_put(cp);
+}
+
+/*
+ *  Create a new connection entry and hash it into the ip_vs_conn_tab.
+ */
+struct ip_vs_conn *
+ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
+	       __u32 daddr, __u16 dport, unsigned flags,
+	       struct ip_vs_dest *dest)
+{
+	struct ip_vs_conn *cp;
+
+	cp = kmem_cache_alloc(ip_vs_conn_cachep, GFP_ATOMIC);
+	if (cp == NULL) {
+		IP_VS_ERR_RL("ip_vs_conn_new: no memory available.\n");
+		return NULL;
+	}
+
+	memset(cp, 0, sizeof(*cp));
+	INIT_LIST_HEAD(&cp->c_list);
+	init_timer(&cp->timer);
+	cp->timer.data     = (unsigned long)cp;
+	cp->timer.function = ip_vs_conn_expire;
+	ip_vs_timeout_attach(cp, ip_vs_timeout_table);
+	cp->protocol	   = proto;
+	cp->caddr	   = caddr;
+	cp->cport	   = cport;
+	cp->vaddr	   = vaddr;
+	cp->vport	   = vport;
+	cp->daddr          = daddr;
+	cp->dport          = dport;
+	cp->flags	   = flags;
+	cp->app_data	   = NULL;
+	cp->control	   = NULL;
+	cp->lock           = SPIN_LOCK_UNLOCKED;
+
+	atomic_set(&cp->n_control, 0);
+	atomic_set(&cp->in_pkts, 0);
+
+	atomic_inc(&ip_vs_conn_count);
+	if (flags & IP_VS_CONN_F_NO_CPORT)
+		atomic_inc(&ip_vs_conn_no_cport_cnt);
+
+	/* Bind its application helper (only for VS/NAT) if any */
+	ip_vs_bind_app(cp);
+
+	/* Bind the connection with a destination server */
+	ip_vs_bind_dest(cp, dest);
+
+	/* Set its state and timeout */
+	vs_set_state_timeout(cp, IP_VS_S_NONE);
+
+	/* Bind its packet transmitter */
+	ip_vs_bind_xmit(cp);
+
+	/*
+	 * Set the entry is referenced by the current thread before hashing
+	 * it in the table, so that other thread run ip_vs_random_dropentry
+	 * but cannot drop this entry.
+	 */
+	atomic_set(&cp->refcnt, 1);
+
+	/* Hash it in the ip_vs_conn_tab finally */
+	ip_vs_conn_hash(cp);
+
+	return cp;
+}
+
+
+/*
+ *	/proc/net/ip_vs_conn entries
+ */
+static int
+ip_vs_conn_getinfo(char *buffer, char **start, off_t offset, int length)
+{
+	off_t pos=0;
+	int idx, len=0;
+	char temp[70];
+	struct ip_vs_conn *cp;
+	struct list_head *l, *e;
+
+	pos = 128;
+	if (pos > offset) {
+		len += sprintf(buffer+len, "%-127s\n",
+			       "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt State       Expires");
+	}
+
+	for(idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {
+		/*
+		 *	Lock is actually only need in next loop
+		 *	we are called from uspace: must stop bh.
+		 */
+		ct_read_lock_bh(idx);
+
+		l = &ip_vs_conn_tab[idx];
+		for (e=l->next; e!=l; e=e->next) {
+			cp = list_entry(e, struct ip_vs_conn, c_list);
+			pos += 128;
+			if (pos <= offset)
+				continue;
+			sprintf(temp,
+				"%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu",
+				ip_vs_proto_name(cp->protocol),
+				ntohl(cp->caddr), ntohs(cp->cport),
+				ntohl(cp->vaddr), ntohs(cp->vport),
+				ntohl(cp->daddr), ntohs(cp->dport),
+				ip_vs_state_name(cp->state),
+				(cp->timer.expires-jiffies)/HZ);
+			len += sprintf(buffer+len, "%-127s\n", temp);
+			if (pos >= offset+length) {
+				ct_read_unlock_bh(idx);
+				goto done;
+			}
+		}
+		ct_read_unlock_bh(idx);
+	}
+
+  done:
+	*start = buffer+len-(pos-offset);       /* Start of wanted data */
+	len = pos-offset;
+	if (len > length)
+		len = length;
+	if (len < 0)
+		len = 0;
+	return len;
+}
+
+
+/*
+ *      Randomly drop connection entries before running out of memory
+ */
+static inline int todrop_entry(struct ip_vs_conn *cp)
+{
+	/*
+	 * The drop rate array needs tuning for real environments.
+	 * Called from timer bh only => no locking
+	 */
+	static char todrop_rate[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
+	static char todrop_counter[9] = {0};
+	int i;
+
+	/* if the conn entry hasn't lasted for 60 seconds, don't drop it.
+	   This will leave enough time for normal connection to get
+	   through. */
+	if (cp->timeout+jiffies-cp->timer.expires < 60*HZ)
+		return 0;
+
+	/* Don't drop the entry if its number of incoming packets is not
+	   located in [0, 8] */
+	i = atomic_read(&cp->in_pkts);
+	if (i > 8 || i < 0) return 0;
+
+	if (!todrop_rate[i]) return 0;
+	if (--todrop_counter[i] > 0) return 0;
+
+	todrop_counter[i] = todrop_rate[i];
+	return 1;
+}
+
+
+void ip_vs_random_dropentry(void)
+{
+	int idx;
+	struct ip_vs_conn *cp;
+	struct list_head *l,*e;
+	struct ip_vs_conn *ct;
+
+	/*
+	 * Randomly scan 1/32 of the whole table every second
+	 */
+	for (idx=0; idx<(IP_VS_CONN_TAB_SIZE>>5); idx++) {
+		unsigned hash = net_random()&IP_VS_CONN_TAB_MASK;
+
+		/*
+		 *  Lock is actually needed in this loop.
+		 */
+		ct_write_lock(hash);
+
+		l = &ip_vs_conn_tab[hash];
+		for (e=l->next; e!=l; e=e->next) {
+			cp = list_entry(e, struct ip_vs_conn, c_list);
+			if (!cp->cport && !(cp->flags & IP_VS_CONN_F_NO_CPORT))
+				/* connection template */
+				continue;
+			switch(cp->state) {
+			case IP_VS_S_SYN_RECV:
+			case IP_VS_S_SYNACK:
+				break;
+
+			case IP_VS_S_ESTABLISHED:
+			case IP_VS_S_UDP:
+				if (todrop_entry(cp))
+					break;
+				continue;
+
+			default:
+				continue;
+			}
+
+			/*
+			 * Drop the entry, and drop its ct if not referenced
+			 */
+			atomic_inc(&cp->refcnt);
+			ct_write_unlock(hash);
+
+			if ((ct = cp->control))
+				atomic_inc(&ct->refcnt);
+			IP_VS_DBG(4, "del connection\n");
+			ip_vs_conn_expire_now(cp);
+			if (ct) {
+				IP_VS_DBG(4, "del conn template\n");
+				ip_vs_conn_expire_now(ct);
+			}
+			ct_write_lock(hash);
+		}
+		ct_write_unlock(hash);
+	}
+}
+
+
+/*
+ *      Flush all the connection entries in the ip_vs_conn_tab
+ */
+static void ip_vs_conn_flush(void)
+{
+	int idx;
+	struct ip_vs_conn *cp;
+	struct list_head *l,*e;
+	struct ip_vs_conn *ct;
+
+  flush_again:
+	for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) {
+		/*
+		 *  Lock is actually needed in this loop.
+		 */
+		ct_write_lock_bh(idx);
+
+		l = &ip_vs_conn_tab[idx];
+		for (e=l->next; e!=l; e=e->next) {
+			cp = list_entry(e, struct ip_vs_conn, c_list);
+			atomic_inc(&cp->refcnt);
+			ct_write_unlock(idx);
+
+			if ((ct = cp->control))
+				atomic_inc(&ct->refcnt);
+			IP_VS_DBG(4, "del connection\n");
+			ip_vs_conn_expire_now(cp);
+			if (ct) {
+				IP_VS_DBG(4, "del conn template\n");
+				ip_vs_conn_expire_now(ct);
+			}
+			ct_write_lock(idx);
+		}
+		ct_write_unlock_bh(idx);
+	}
+
+	/* the counter may be not NULL, because maybe some conn entries
+	   are run by slow timer handler or unhashed but still referred */
+	if (atomic_read(&ip_vs_conn_count) != 0) {
+		schedule();
+		goto flush_again;
+	}
+}
+
+
+int ip_vs_conn_init(void)
+{
+	int idx;
+
+	/*
+	 * Allocate the connection hash table and initialize its list heads
+	 */
+	ip_vs_conn_tab = vmalloc(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head));
+	if (!ip_vs_conn_tab)
+		return -ENOMEM;
+
+	IP_VS_INFO("Connection hash table configured "
+		   "(size=%d, memory=%ldKbytes)\n",
+		   IP_VS_CONN_TAB_SIZE,
+		   (long)(IP_VS_CONN_TAB_SIZE*sizeof(struct list_head))/1024);
+	IP_VS_DBG(0, "Each connection entry needs %d bytes at least\n",
+		  sizeof(struct ip_vs_conn));
+
+	for (idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {
+		INIT_LIST_HEAD(&ip_vs_conn_tab[idx]);
+	}
+
+	for (idx = 0; idx < CT_LOCKARRAY_SIZE; idx++)  {
+		__ip_vs_conntbl_lock_array[idx].l = RW_LOCK_UNLOCKED;
+	}
+
+	/* Allocate ip_vs_conn slab cache */
+	ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn",
+					      sizeof(struct ip_vs_conn), 0,
+					      SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!ip_vs_conn_cachep) {
+		vfree(ip_vs_conn_tab);
+		return -ENOMEM;
+	}
+
+	proc_net_create("ip_vs_conn", 0, ip_vs_conn_getinfo);
+
+	/* calculate the random value for connection hash */
+	get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd));
+
+	return 0;
+}
+
+void ip_vs_conn_cleanup(void)
+{
+	/* flush all the connection entries first */
+	ip_vs_conn_flush();
+
+	/* Release the empty cache */
+	kmem_cache_destroy(ip_vs_conn_cachep);
+	proc_net_remove("ip_vs_conn");
+	vfree(ip_vs_conn_tab);
+}
diff -Nru a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_core.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,1284 @@
+/*
+ * IPVS         An implementation of the IP virtual server support for the
+ *              LINUX operating system.  IPVS is now implemented as a module
+ *              over the Netfilter framework. IPVS can be used to build a
+ *              high-performance and highly available server based on a
+ *              cluster of servers.
+ *
+ * Version:     $Id: ip_vs_core.c,v 1.31.2.5 2003/07/29 14:37:12 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              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 IPVS code for kernel 2.2 was done by Wensong Zhang and Peter Kese,
+ * with changes/fixes from Julian Anastasov, Lars Marowsky-Bree, Horms
+ * and others.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/icmp.h>
+
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/icmp.h>                   /* for icmp_send */
+#include <net/route.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <net/ip_vs.h>
+
+
+EXPORT_SYMBOL(register_ip_vs_scheduler);
+EXPORT_SYMBOL(unregister_ip_vs_scheduler);
+EXPORT_SYMBOL(ip_vs_skb_replace);
+EXPORT_SYMBOL(ip_vs_proto_name);
+EXPORT_SYMBOL(ip_vs_conn_new);
+EXPORT_SYMBOL(ip_vs_conn_in_get);
+EXPORT_SYMBOL(ip_vs_conn_out_get);
+EXPORT_SYMBOL(ip_vs_conn_listen);
+EXPORT_SYMBOL(ip_vs_conn_put);
+#ifdef CONFIG_IP_VS_DEBUG
+EXPORT_SYMBOL(ip_vs_get_debug_level);
+#endif
+EXPORT_SYMBOL(check_for_ip_vs_out);
+
+
+/* ID used in ICMP lookups */
+#define icmp_id(icmph)          ((icmph->un).echo.id)
+
+const char *ip_vs_proto_name(unsigned proto)
+{
+	static char buf[20];
+
+	switch (proto) {
+	case IPPROTO_IP:
+		return "IP";
+	case IPPROTO_UDP:
+		return "UDP";
+	case IPPROTO_TCP:
+		return "TCP";
+	case IPPROTO_ICMP:
+		return "ICMP";
+	default:
+		sprintf(buf, "IP_%d", proto);
+		return buf;
+	}
+}
+
+
+static inline void
+ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest = cp->dest;
+	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+		spin_lock(&dest->stats.lock);
+		dest->stats.inpkts++;
+		dest->stats.inbytes += skb->len;
+		spin_unlock(&dest->stats.lock);
+
+		spin_lock(&dest->svc->stats.lock);
+		dest->svc->stats.inpkts++;
+		dest->svc->stats.inbytes += skb->len;
+		spin_unlock(&dest->svc->stats.lock);
+
+		spin_lock(&ip_vs_stats.lock);
+		ip_vs_stats.inpkts++;
+		ip_vs_stats.inbytes += skb->len;
+		spin_unlock(&ip_vs_stats.lock);
+	}
+}
+
+
+static inline void
+ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
+{
+	struct ip_vs_dest *dest = cp->dest;
+	if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+		spin_lock(&dest->stats.lock);
+		dest->stats.outpkts++;
+		dest->stats.outbytes += skb->len;
+		spin_unlock(&dest->stats.lock);
+
+		spin_lock(&dest->svc->stats.lock);
+		dest->svc->stats.outpkts++;
+		dest->svc->stats.outbytes += skb->len;
+		spin_unlock(&dest->svc->stats.lock);
+
+		spin_lock(&ip_vs_stats.lock);
+		ip_vs_stats.outpkts++;
+		ip_vs_stats.outbytes += skb->len;
+		spin_unlock(&ip_vs_stats.lock);
+	}
+}
+
+
+static inline void
+ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc)
+{
+	spin_lock(&cp->dest->stats.lock);
+	cp->dest->stats.conns++;
+	spin_unlock(&cp->dest->stats.lock);
+
+	spin_lock(&svc->stats.lock);
+	svc->stats.conns++;
+	spin_unlock(&svc->stats.lock);
+
+	spin_lock(&ip_vs_stats.lock);
+	ip_vs_stats.conns++;
+	spin_unlock(&ip_vs_stats.lock);
+}
+
+/*
+ *  IPVS persistent scheduling function
+ *  It creates a connection entry according to its template if exists,
+ *  or selects a server and creates a connection entry plus a template.
+ *  Locking: we are svc user (svc->refcnt), so we hold all dests too
+ */
+static struct ip_vs_conn *
+ip_vs_sched_persist(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct ip_vs_conn *cp = NULL;
+	struct ip_vs_dest *dest;
+	const __u16 *portp;
+	struct ip_vs_conn *ct;
+	__u16  dport;	 /* destination port to forward */
+	__u32  snet;	 /* source network of the client, after masking */
+
+	portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+
+	/* Mask saddr with the netmask to adjust template granularity */
+	snet = iph->saddr & svc->netmask;
+
+	IP_VS_DBG(6, "P-schedule: src %u.%u.%u.%u:%u dest %u.%u.%u.%u:%u "
+		  "mnet %u.%u.%u.%u\n",
+		  NIPQUAD(iph->saddr), ntohs(portp[0]),
+		  NIPQUAD(iph->daddr), ntohs(portp[1]),
+		  NIPQUAD(snet));
+
+	/*
+	 * As far as we know, FTP is a very complicated network protocol, and
+	 * it uses control connection and data connections. For active FTP,
+	 * FTP server initialize data connection to the client, its source port
+	 * is often 20. For passive FTP, FTP server tells the clients the port
+	 * that it passively listens to,  and the client issues the data
+	 * connection. In the tunneling or direct routing mode, the load
+	 * balancer is on the client-to-server half of connection, the port
+	 * number is unknown to the load balancer. So, a conn template like
+	 * <caddr, 0, vaddr, 0, daddr, 0> is created for persistent FTP
+	 * service, and a template like <caddr, 0, vaddr, vport, daddr, dport>
+	 * is created for other persistent services.
+	 */
+	if (portp[1] == svc->port) {
+		/* Check if a template already exists */
+		if (svc->port != FTPPORT)
+			ct = ip_vs_conn_in_get(iph->protocol, snet, 0,
+					       iph->daddr, portp[1]);
+		else
+			ct = ip_vs_conn_in_get(iph->protocol, snet, 0,
+					       iph->daddr, 0);
+
+		if (!ct || !ip_vs_check_template(ct)) {
+			/*
+			 * No template found or the dest of the connection
+			 * template is not available.
+			 */
+			dest = svc->scheduler->schedule(svc, iph);
+			if (dest == NULL) {
+				IP_VS_DBG(1, "P-schedule: no dest found.\n");
+				return NULL;
+			}
+
+			/*
+			 * Create a template like <protocol,caddr,0,
+			 * vaddr,vport,daddr,dport> for non-ftp service,
+			 * and <protocol,caddr,0,vaddr,0,daddr,0>
+			 * for ftp service.
+			 */
+			if (svc->port != FTPPORT)
+				ct = ip_vs_conn_new(iph->protocol,
+						    snet, 0,
+						    iph->daddr, portp[1],
+						    dest->addr, dest->port,
+						    0,
+						    dest);
+			else
+				ct = ip_vs_conn_new(iph->protocol,
+						    snet, 0,
+						    iph->daddr, 0,
+						    dest->addr, 0,
+						    0,
+						    dest);
+			if (ct == NULL)
+				return NULL;
+
+			ct->timeout = svc->timeout;
+		} else {
+			/* set destination with the found template */
+			dest = ct->dest;
+		}
+		dport = dest->port;
+	} else {
+		/*
+		 * Note: persistent fwmark-based services and persistent
+		 * port zero service are handled here.
+		 * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
+		 * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
+		 */
+		if (svc->fwmark)
+			ct = ip_vs_conn_in_get(IPPROTO_IP, snet, 0,
+					       htonl(svc->fwmark), 0);
+		else
+			ct = ip_vs_conn_in_get(iph->protocol, snet, 0,
+					       iph->daddr, 0);
+
+		if (!ct || !ip_vs_check_template(ct)) {
+			/*
+			 * If it is not persistent port zero, return NULL,
+			 * otherwise create a connection template.
+			 */
+			if (svc->port)
+				return NULL;
+
+			dest = svc->scheduler->schedule(svc, iph);
+			if (dest == NULL) {
+				IP_VS_DBG(1, "P-schedule: no dest found.\n");
+				return NULL;
+			}
+
+			/*
+			 * Create a template according to the service
+			 */
+			if (svc->fwmark)
+				ct = ip_vs_conn_new(IPPROTO_IP,
+						    snet, 0,
+						    htonl(svc->fwmark), 0,
+						    dest->addr, 0,
+						    0,
+						    dest);
+			else
+				ct = ip_vs_conn_new(iph->protocol,
+						    snet, 0,
+						    iph->daddr, 0,
+						    dest->addr, 0,
+						    0,
+						    dest);
+			if (ct == NULL)
+				return NULL;
+
+			ct->timeout = svc->timeout;
+		} else {
+			/* set destination with the found template */
+			dest = ct->dest;
+		}
+		dport = portp[1];
+	}
+
+	/*
+	 *    Create a new connection according to the template
+	 */
+	cp = ip_vs_conn_new(iph->protocol,
+			    iph->saddr, portp[0],
+			    iph->daddr, portp[1],
+			    dest->addr, dport,
+			    0,
+			    dest);
+	if (cp == NULL) {
+		ip_vs_conn_put(ct);
+		return NULL;
+	}
+
+	/*
+	 *    Increase the inactive connection counter
+	 *    because it is in Syn-Received
+	 *    state (inactive) when the connection is created.
+	 */
+	atomic_inc(&dest->inactconns);
+
+	/*
+	 *    Add its control
+	 */
+	ip_vs_control_add(cp, ct);
+
+	ip_vs_conn_put(ct);
+	return cp;
+}
+
+
+/*
+ *  IPVS main scheduling function
+ *  It selects a server according to the virtual service, and
+ *  creates a connection entry.
+ */
+static struct ip_vs_conn *
+ip_vs_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct ip_vs_conn *cp = NULL;
+	struct ip_vs_dest *dest;
+	const __u16 *portp;
+
+	/*
+	 *    Persistent service
+	 */
+	if (svc->flags & IP_VS_SVC_F_PERSISTENT)
+		return ip_vs_sched_persist(svc, iph);
+
+	/*
+	 *    Non-persistent service
+	 */
+	portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+	if (!svc->fwmark && portp[1] != svc->port) {
+		if (!svc->port)
+			IP_VS_ERR("Schedule: port zero only supported "
+				  "in persistent services, "
+				  "check your ipvs configuration\n");
+		return NULL;
+	}
+
+	dest = svc->scheduler->schedule(svc, iph);
+	if (dest == NULL) {
+		IP_VS_DBG(1, "Schedule: no dest found.\n");
+		return NULL;
+	}
+
+	/*
+	 *    Create a connection entry.
+	 */
+	cp = ip_vs_conn_new(iph->protocol,
+			    iph->saddr, portp[0],
+			    iph->daddr, portp[1],
+			    dest->addr, dest->port?dest->port:portp[1],
+			    0,
+			    dest);
+	if (cp == NULL)
+		return NULL;
+
+	/*
+	 *    Increase the inactive connection counter because it is in
+	 *    Syn-Received state (inactive) when the connection is created.
+	 */
+	atomic_inc(&dest->inactconns);
+
+	IP_VS_DBG(6, "Schedule fwd:%c s:%s c:%u.%u.%u.%u:%u v:%u.%u.%u.%u:%u "
+		  "d:%u.%u.%u.%u:%u flg:%X cnt:%d\n",
+		  ip_vs_fwd_tag(cp), ip_vs_state_name(cp->state),
+		  NIPQUAD(cp->caddr), ntohs(cp->cport),
+		  NIPQUAD(cp->vaddr), ntohs(cp->vport),
+		  NIPQUAD(cp->daddr), ntohs(cp->dport),
+		  cp->flags, atomic_read(&cp->refcnt));
+
+	return cp;
+}
+
+
+/*
+ *  Pass or drop the packet.
+ *  Called by ip_vs_in, when the virtual service is available but
+ *  no destination is available for a new connection.
+ */
+static int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb)
+{
+	struct iphdr *iph = skb->nh.iph;
+	__u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+
+	/* if it is fwmark-based service, the cache_bypass sysctl is up
+	   and the destination is RTN_UNICAST (and not local), then create
+	   a cache_bypass connection entry */
+	if (sysctl_ip_vs_cache_bypass && svc->fwmark
+	    && (inet_addr_type(iph->daddr) == RTN_UNICAST)) {
+		int ret;
+		struct ip_vs_conn *cp;
+
+		ip_vs_service_put(svc);
+
+		/* create a new connection entry */
+		IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");
+		cp = ip_vs_conn_new(iph->protocol,
+				    iph->saddr, portp[0],
+				    iph->daddr, portp[1],
+				    0, 0,
+				    IP_VS_CONN_F_BYPASS,
+				    NULL);
+		if (cp == NULL) {
+			kfree_skb(skb);
+			return NF_STOLEN;
+		}
+
+		/* statistics */
+		ip_vs_in_stats(cp, skb);
+
+		/* set state */
+		ip_vs_set_state(cp, VS_STATE_INPUT, iph, portp);
+
+		/* transmit the first SYN packet */
+		ret = cp->packet_xmit(skb, cp);
+
+		atomic_inc(&cp->in_pkts);
+		ip_vs_conn_put(cp);
+		return ret;
+	}
+
+	/*
+	 * When the virtual ftp service is presented, packets destined
+	 * for other services on the VIP may get here (except services
+	 * listed in the ipvs table), pass the packets, because it is
+	 * not ipvs job to decide to drop the packets.
+	 */
+	if ((svc->port == FTPPORT) && (portp[1] != FTPPORT)) {
+		ip_vs_service_put(svc);
+		return NF_ACCEPT;
+	}
+
+	ip_vs_service_put(svc);
+
+	/*
+	 * Notify the client that the destination is unreachable, and
+	 * release the socket buffer.
+	 * Since it is in IP layer, the TCP socket is not actually
+	 * created, the TCP RST packet cannot be sent, instead that
+	 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ
+	 */
+	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+	kfree_skb(skb);
+	return NF_STOLEN;
+}
+
+
+/*
+ *      It is hooked before NF_IP_PRI_NAT_SRC at the NF_IP_POST_ROUTING
+ *      chain, and is used for VS/NAT.
+ *      It detects packets for VS/NAT connections and sends the packets
+ *      immediately. This can avoid that iptable_nat mangles the packets
+ *      for VS/NAT.
+ */
+static unsigned int ip_vs_post_routing(unsigned int hooknum,
+				       struct sk_buff **skb_p,
+				       const struct net_device *in,
+				       const struct net_device *out,
+				       int (*okfn)(struct sk_buff *))
+{
+	struct sk_buff  *skb = *skb_p;
+
+	if (!(skb->nfcache & NFC_IPVS_PROPERTY))
+		return NF_ACCEPT;
+
+	/* The packet was sent from IPVS, exit this chain */
+	(*okfn)(skb);
+
+	return NF_STOLEN;
+}
+
+
+/*
+ *	Handle ICMP messages in the inside-to-outside direction (outgoing).
+ *	Find any that might be relevant, check against existing connections,
+ *	forward to the right destination host if relevant.
+ *	Currently handles error types - unreachable, quench, ttl exceeded.
+ *      (Only used in VS/NAT)
+ */
+static int ip_vs_out_icmp(struct sk_buff **skb_p)
+{
+	struct sk_buff	*skb   = *skb_p;
+	struct iphdr	*iph;
+	struct icmphdr	*icmph;
+	struct iphdr	*ciph;	/* The ip header contained within the ICMP */
+	__u16		*pptr;	/* port numbers from TCP/UDP contained header */
+	unsigned short	ihl;
+	unsigned short	len;
+	unsigned short	clen, csize;
+	struct ip_vs_conn *cp;
+
+	/* reassemble IP fragments, but will it happen in ICMP packets?? */
+	if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+		skb = ip_defrag(skb);
+		if (!skb)
+			return NF_STOLEN;
+		*skb_p = skb;
+	}
+
+	if (skb_is_nonlinear(skb)) {
+		if (skb_linearize(skb, GFP_ATOMIC) != 0)
+			return NF_DROP;
+		ip_send_check(skb->nh.iph);
+	}
+
+	iph = skb->nh.iph;
+	ihl = iph->ihl << 2;
+	icmph = (struct icmphdr *)((char *)iph + ihl);
+	len   = ntohs(iph->tot_len) - ihl;
+	if (len < sizeof(struct icmphdr))
+		return NF_DROP;
+
+	IP_VS_DBG(12, "outgoing ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",
+		  icmph->type, ntohs(icmp_id(icmph)),
+		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+
+	/*
+	 * Work through seeing if this is for us.
+	 * These checks are supposed to be in an order that means easy
+	 * things are checked first to speed up processing.... however
+	 * this means that some packets will manage to get a long way
+	 * down this stack and then be rejected, but that's life.
+	 */
+	if ((icmph->type != ICMP_DEST_UNREACH) &&
+	    (icmph->type != ICMP_SOURCE_QUENCH) &&
+	    (icmph->type != ICMP_TIME_EXCEEDED))
+		return NF_ACCEPT;
+
+	/* Now find the contained IP header */
+	clen = len - sizeof(struct icmphdr);
+	if (clen < sizeof(struct iphdr))
+		return NF_DROP;
+	ciph = (struct iphdr *) (icmph + 1);
+	csize = ciph->ihl << 2;
+	if (clen < csize)
+		return NF_DROP;
+
+	/* We are only interested ICMPs generated from TCP or UDP packets */
+	if (ciph->protocol != IPPROTO_UDP && ciph->protocol != IPPROTO_TCP)
+		return NF_ACCEPT;
+
+	/* Skip non-first embedded TCP/UDP fragments */
+	if (ciph->frag_off & __constant_htons(IP_OFFSET))
+		return NF_ACCEPT;
+
+	/* We need at least TCP/UDP ports here */
+	if (clen < csize + sizeof(struct udphdr))
+		return NF_DROP;
+
+	/*
+	 * Find the ports involved - this packet was
+	 * incoming so the ports are right way round
+	 * (but reversed relative to outer IP header!)
+	 */
+	pptr = (__u16 *)&(((char *)ciph)[csize]);
+
+	/* Ensure the checksum is correct */
+	if (ip_compute_csum((unsigned char *) icmph, len)) {
+		/* Failed checksum! */
+		IP_VS_DBG(1, "forward ICMP: failed checksum from %d.%d.%d.%d!\n",
+			  NIPQUAD(iph->saddr));
+		return NF_DROP;
+	}
+
+	IP_VS_DBG(11, "Handling outgoing ICMP for "
+		  "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n",
+		  NIPQUAD(ciph->saddr), ntohs(pptr[0]),
+		  NIPQUAD(ciph->daddr), ntohs(pptr[1]));
+
+	/* ciph content is actually <protocol, caddr, cport, daddr, dport> */
+	cp = ip_vs_conn_out_get(ciph->protocol, ciph->daddr, pptr[1],
+				ciph->saddr, pptr[0]);
+	if (!cp)
+		return NF_ACCEPT;
+
+	if (IP_VS_FWD_METHOD(cp) != 0) {
+		IP_VS_ERR("shouldn't reach here, because the box is on the"
+			  "half connection in the tun/dr module.\n");
+	}
+
+	/* Now we do real damage to this packet...! */
+	/* First change the source IP address, and recalc checksum */
+	iph->saddr = cp->vaddr;
+	ip_send_check(iph);
+
+	/* Now change the *dest* address in the contained IP */
+	ciph->daddr = cp->vaddr;
+	ip_send_check(ciph);
+
+	/* the TCP/UDP dest port - cannot redo check */
+	pptr[1] = cp->vport;
+
+	/* And finally the ICMP checksum */
+	icmph->checksum = 0;
+	icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	/* do the statistics and put it back */
+	ip_vs_out_stats(cp, skb);
+	ip_vs_conn_put(cp);
+
+	IP_VS_DBG(11, "Forwarding correct outgoing ICMP to "
+		  "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n",
+		  NIPQUAD(ciph->saddr), ntohs(pptr[0]),
+		  NIPQUAD(ciph->daddr), ntohs(pptr[1]));
+
+	skb->nfcache |= NFC_IPVS_PROPERTY;
+
+	return NF_ACCEPT;
+}
+
+
+/*
+ *	It is hooked at the NF_IP_FORWARD chain, used only for VS/NAT.
+ *	Check if outgoing packet belongs to the established ip_vs_conn,
+ *      rewrite addresses of the packet and send it on its way...
+ */
+static unsigned int ip_vs_out(unsigned int hooknum,
+			      struct sk_buff **skb_p,
+			      const struct net_device *in,
+			      const struct net_device *out,
+			      int (*okfn)(struct sk_buff *))
+{
+	struct sk_buff  *skb = *skb_p;
+	struct iphdr	*iph;
+	union ip_vs_tphdr h;
+	struct ip_vs_conn *cp;
+	int size;
+	int ihl;
+
+	EnterFunction(11);
+
+	if (skb->nfcache & NFC_IPVS_PROPERTY)
+		return NF_ACCEPT;
+
+	iph = skb->nh.iph;
+	if (iph->protocol == IPPROTO_ICMP)
+		return ip_vs_out_icmp(skb_p);
+
+	/* let it go if other IP protocols */
+	if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)
+		return NF_ACCEPT;
+
+	/* reassemble IP fragments */
+	if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+		skb = ip_defrag(skb);
+		if (!skb)
+			return NF_STOLEN;
+		iph = skb->nh.iph;
+		*skb_p = skb;
+	}
+
+	/* make sure that protocol header available in skb data area,
+	   note that skb data area may be reallocated. */
+	ihl = iph->ihl << 2;
+	if (ip_vs_header_check(skb, iph->protocol, ihl) == -1)
+		return NF_DROP;
+
+	iph = skb->nh.iph;
+	h.raw = (char*) iph + ihl;
+
+	/*
+	 *	Check if the packet belongs to an old entry
+	 */
+	cp = ip_vs_conn_out_get(iph->protocol, iph->saddr, h.portp[0],
+				iph->daddr, h.portp[1]);
+	if (!cp) {
+		if (sysctl_ip_vs_nat_icmp_send &&
+		    ip_vs_lookup_real_service(iph->protocol,
+					      iph->saddr, h.portp[0])) {
+			/*
+			 * Notify the real server: there is no existing
+			 * entry if it is not RST packet or not TCP packet.
+			 */
+			if (!h.th->rst || iph->protocol != IPPROTO_TCP) {
+				icmp_send(skb, ICMP_DEST_UNREACH,
+					  ICMP_PORT_UNREACH, 0);
+				kfree_skb(skb);
+				return NF_STOLEN;
+			}
+		}
+		IP_VS_DBG(12, "packet for %s %d.%d.%d.%d:%d "
+			  "continue traversal as normal.\n",
+			  ip_vs_proto_name(iph->protocol),
+			  NIPQUAD(iph->daddr),
+			  ntohs(h.portp[1]));
+		if (skb_is_nonlinear(skb))
+			ip_send_check(iph);
+		return NF_ACCEPT;
+	}
+
+	/*
+	 * If it has ip_vs_app helper, the helper may change the payload,
+	 * so it needs full checksum checking and checksum calculation.
+	 * If not, only the header (addr/port) is changed, so it is fast
+	 * to do incremental checksum update, and let the destination host
+	 * do final checksum checking.
+	 */
+
+	if (cp->app && skb_is_nonlinear(skb)) {
+		if (skb_linearize(skb, GFP_ATOMIC) != 0) {
+			ip_vs_conn_put(cp);
+			return NF_DROP;
+		}
+		iph = skb->nh.iph;
+		h.raw = (char*) iph + ihl;
+	}
+
+	size = skb->len - ihl;
+	IP_VS_DBG(11, "O-pkt: %s size=%d\n",
+		  ip_vs_proto_name(iph->protocol), size);
+
+	/* do TCP/UDP checksum checking if it has application helper */
+	if (cp->app && (iph->protocol != IPPROTO_UDP || h.uh->check != 0)) {
+		switch (skb->ip_summed) {
+		case CHECKSUM_NONE:
+			skb->csum = csum_partial(h.raw, size, 0);
+		case CHECKSUM_HW:
+			if (csum_tcpudp_magic(iph->saddr, iph->daddr, size,
+					      iph->protocol, skb->csum)) {
+				ip_vs_conn_put(cp);
+				IP_VS_DBG_RL("Outgoing failed %s checksum "
+					     "from %d.%d.%d.%d (size=%d)!\n",
+					     ip_vs_proto_name(iph->protocol),
+					     NIPQUAD(iph->saddr),
+					     size);
+				return NF_DROP;
+			}
+			break;
+		default:
+			/* CHECKSUM_UNNECESSARY */
+			break;
+		}
+	}
+
+	IP_VS_DBG(11, "Outgoing %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d\n",
+		  ip_vs_proto_name(iph->protocol),
+		  NIPQUAD(iph->saddr), ntohs(h.portp[0]),
+		  NIPQUAD(iph->daddr), ntohs(h.portp[1]));
+
+	/* mangle the packet */
+	iph->saddr = cp->vaddr;
+	h.portp[0] = cp->vport;
+
+	/*
+	 *	Call application helper if needed
+	 */
+	if (ip_vs_app_pkt_out(cp, skb) != 0) {
+		/* skb data has probably changed, update pointers */
+		iph = skb->nh.iph;
+		h.raw = (char*)iph + ihl;
+		size = skb->len - ihl;
+	}
+
+	/*
+	 *	Adjust TCP/UDP checksums
+	 */
+	if (!cp->app && (iph->protocol != IPPROTO_UDP || h.uh->check != 0)) {
+		/* Only port and addr are changed, do fast csum update */
+		ip_vs_fast_check_update(&h, cp->daddr, cp->vaddr,
+					cp->dport, cp->vport, iph->protocol);
+		if (skb->ip_summed == CHECKSUM_HW)
+			skb->ip_summed = CHECKSUM_NONE;
+	} else {
+		/* full checksum calculation */
+		switch (iph->protocol) {
+		case IPPROTO_TCP:
+			h.th->check = 0;
+			skb->csum = csum_partial(h.raw, size, 0);
+			h.th->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+							size, iph->protocol,
+							skb->csum);
+			IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%d)\n",
+				  ip_vs_proto_name(iph->protocol), h.th->check,
+				  (char*)&(h.th->check) - (char*)h.raw);
+			break;
+		case IPPROTO_UDP:
+			h.uh->check = 0;
+			skb->csum = csum_partial(h.raw, size, 0);
+			h.uh->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+							size, iph->protocol,
+							skb->csum);
+			if (h.uh->check == 0)
+				h.uh->check = 0xFFFF;
+			IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%d)\n",
+				  ip_vs_proto_name(iph->protocol), h.uh->check,
+				  (char*)&(h.uh->check) - (char*)h.raw);
+			break;
+		}
+	}
+	ip_send_check(iph);
+
+	ip_vs_out_stats(cp, skb);
+	ip_vs_set_state(cp, VS_STATE_OUTPUT, iph, h.portp);
+	ip_vs_conn_put(cp);
+
+	skb->nfcache |= NFC_IPVS_PROPERTY;
+
+	LeaveFunction(11);
+	return NF_ACCEPT;
+}
+
+
+/*
+ *      Check if the packet is for VS/NAT connections, then send it
+ *      immediately.
+ *      Called by ip_fw_compact to detect packets for VS/NAT before
+ *      they are changed by ipchains masquerading code.
+ */
+unsigned int check_for_ip_vs_out(struct sk_buff **skb_p,
+				 int (*okfn)(struct sk_buff *))
+{
+	unsigned int ret;
+
+	ret = ip_vs_out(NF_IP_FORWARD, skb_p, NULL, NULL, NULL);
+	if (ret != NF_ACCEPT) {
+		return ret;
+	} else {
+		/* send the packet immediately if it is already mangled
+		   by ip_vs_out */
+		if ((*skb_p)->nfcache & NFC_IPVS_PROPERTY) {
+			(*okfn)(*skb_p);
+			return NF_STOLEN;
+		}
+	}
+	return NF_ACCEPT;
+}
+
+
+/*
+ *	Handle ICMP messages in the outside-to-inside direction (incoming)
+ *	and sometimes in outgoing direction from ip_vs_forward_icmp.
+ *	Find any that might be relevant, check against existing connections,
+ *	forward to the right destination host if relevant.
+ *	Currently handles error types - unreachable, quench, ttl exceeded.
+ */
+static int ip_vs_in_icmp(struct sk_buff **skb_p)
+{
+	struct sk_buff	*skb   = *skb_p;
+	struct iphdr    *iph;
+	struct icmphdr  *icmph;
+	struct iphdr    *ciph;	/* The ip header contained within the ICMP */
+	__u16	        *pptr;	/* port numbers from TCP/UDP contained header */
+	unsigned short   len;
+	unsigned short	clen, csize;
+	struct ip_vs_conn *cp;
+	struct rtable *rt;			/* Route to the other host */
+	int    mtu;
+
+	if (skb_is_nonlinear(skb)) {
+		if (skb_linearize(skb, GFP_ATOMIC) != 0)
+			return NF_DROP;
+	}
+
+	iph = skb->nh.iph;
+	ip_send_check(iph);
+	icmph = (struct icmphdr *)((char *)iph + (iph->ihl << 2));
+	len = ntohs(iph->tot_len) - (iph->ihl<<2);
+	if (len < sizeof(struct icmphdr))
+		return NF_DROP;
+
+	IP_VS_DBG(12, "icmp in (%d,%d) %u.%u.%u.%u -> %u.%u.%u.%u\n",
+		  icmph->type, ntohs(icmp_id(icmph)),
+		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+
+	if ((icmph->type != ICMP_DEST_UNREACH) &&
+	    (icmph->type != ICMP_SOURCE_QUENCH) &&
+	    (icmph->type != ICMP_TIME_EXCEEDED))
+		return NF_ACCEPT;
+
+	/*
+	 * If we get here we have an ICMP error of one of the above 3 types
+	 * Now find the contained IP header
+	 */
+	clen = len - sizeof(struct icmphdr);
+	if (clen < sizeof(struct iphdr))
+		return NF_DROP;
+	ciph = (struct iphdr *) (icmph + 1);
+	csize = ciph->ihl << 2;
+	if (clen < csize)
+		return NF_DROP;
+
+	/* We are only interested ICMPs generated from TCP or UDP packets */
+	if (ciph->protocol != IPPROTO_UDP && ciph->protocol != IPPROTO_TCP)
+		return NF_ACCEPT;
+
+	/* Skip non-first embedded TCP/UDP fragments */
+	if (ciph->frag_off & __constant_htons(IP_OFFSET))
+		return NF_ACCEPT;
+
+	/* We need at least TCP/UDP ports here */
+	if (clen < csize + sizeof(struct udphdr))
+		return NF_DROP;
+
+	/* Ensure the checksum is correct */
+	if (ip_compute_csum((unsigned char *) icmph, len)) {
+		/* Failed checksum! */
+		IP_VS_ERR_RL("incoming ICMP: failed checksum from "
+			     "%d.%d.%d.%d!\n", NIPQUAD(iph->saddr));
+		return NF_DROP;
+	}
+
+	pptr = (__u16 *)&(((char *)ciph)[csize]);
+
+	IP_VS_DBG(11, "Handling incoming ICMP for "
+		  "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n",
+		  NIPQUAD(ciph->saddr), ntohs(pptr[0]),
+		  NIPQUAD(ciph->daddr), ntohs(pptr[1]));
+
+	/* This is pretty much what ip_vs_conn_in_get() does,
+	   except parameters are in the reverse order */
+	cp = ip_vs_conn_in_get(ciph->protocol,
+			       ciph->daddr, pptr[1],
+			       ciph->saddr, pptr[0]);
+	if (cp == NULL)
+		return NF_ACCEPT;
+
+	ip_vs_in_stats(cp, skb);
+
+	/* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
+	   forwarded directly here, because there is no need to
+	   translate address/port back */
+	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
+		int ret;
+		if (cp->packet_xmit)
+			ret = cp->packet_xmit(skb, cp);
+		else
+			ret = NF_ACCEPT;
+		atomic_inc(&cp->in_pkts);
+		ip_vs_conn_put(cp);
+		return ret;
+	}
+
+	/*
+	 * mangle and send the packet here
+	 */
+	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
+		goto tx_error_icmp;
+
+	/* MTU checking */
+	mtu = rt->u.dst.pmtu;
+	if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) {
+		ip_rt_put(rt);
+		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
+		IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");
+		goto tx_error;
+	}
+
+	/* drop old route */
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
+
+	/* copy-on-write the packet before mangling it */
+	if (ip_vs_skb_cow(skb, rt->u.dst.dev->hard_header_len,
+			  &iph, (unsigned char**)&icmph)) {
+		ip_vs_conn_put(cp);
+		return NF_DROP;
+	}
+	ciph = (struct iphdr *) (icmph + 1);
+	pptr = (__u16 *)&(((char *)ciph)[csize]);
+
+	/* The ICMP packet for VS/NAT must be written to correct addresses
+	   before being forwarded to the right server */
+
+	/* First change the dest IP address, and recalc checksum */
+	iph->daddr = cp->daddr;
+	ip_send_check(iph);
+
+	/* Now change the *source* address in the contained IP */
+	ciph->saddr = cp->daddr;
+	ip_send_check(ciph);
+
+	/* the TCP/UDP source port - cannot redo check */
+	pptr[0] = cp->dport;
+
+	/* And finally the ICMP checksum */
+	icmph->checksum = 0;
+	icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	IP_VS_DBG(11, "Forwarding incoming ICMP to "
+		  "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n",
+		  NIPQUAD(ciph->saddr), ntohs(pptr[0]),
+		  NIPQUAD(ciph->daddr), ntohs(pptr[1]));
+
+#ifdef CONFIG_NETFILTER_DEBUG
+	skb->nf_debug = 1 << NF_IP_LOCAL_OUT;
+#endif /* CONFIG_NETFILTER_DEBUG */
+	ip_send(skb);
+	ip_vs_conn_put(cp);
+	return NF_STOLEN;
+
+  tx_error_icmp:
+	dst_link_failure(skb);
+  tx_error:
+	dev_kfree_skb(skb);
+	ip_vs_conn_put(cp);
+	return NF_STOLEN;
+}
+
+
+/*
+ *	Check if it's for virtual services, look it up,
+ *	and send it on its way...
+ */
+static unsigned int ip_vs_in(unsigned int hooknum,
+			     struct sk_buff **skb_p,
+			     const struct net_device *in,
+			     const struct net_device *out,
+			     int (*okfn)(struct sk_buff *))
+{
+	struct sk_buff	*skb = *skb_p;
+	struct iphdr	*iph = skb->nh.iph;
+	union ip_vs_tphdr h;
+	struct ip_vs_conn *cp;
+	struct ip_vs_service *svc;
+	int ihl;
+	int ret;
+
+	/*
+	 *	Big tappo: only PACKET_HOST (nor loopback neither mcasts)
+	 *	... don't know why 1st test DOES NOT include 2nd (?)
+	 */
+	if (skb->pkt_type != PACKET_HOST || skb->dev == &loopback_dev) {
+		IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",
+			  skb->pkt_type,
+			  iph->protocol,
+			  NIPQUAD(iph->daddr));
+		return NF_ACCEPT;
+	}
+
+	if (iph->protocol == IPPROTO_ICMP)
+		return ip_vs_in_icmp(skb_p);
+
+	/* let it go if other IP protocols */
+	if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)
+		return NF_ACCEPT;
+
+	/* make sure that protocol header available in skb data area,
+	   note that skb data area may be reallocated. */
+	ihl = iph->ihl << 2;
+	if (ip_vs_header_check(skb, iph->protocol, ihl) == -1)
+		return NF_DROP;
+	iph = skb->nh.iph;
+	h.raw = (char*) iph + ihl;
+
+	/*
+	 * Check if the packet belongs to an existing connection entry
+	 */
+	cp = ip_vs_conn_in_get(iph->protocol, iph->saddr, h.portp[0],
+			       iph->daddr, h.portp[1]);
+
+	if (!cp &&
+	    (h.th->syn || (iph->protocol!=IPPROTO_TCP)) &&
+	    (svc = ip_vs_service_get(skb->nfmark, iph->protocol,
+				     iph->daddr, h.portp[1]))) {
+		if (ip_vs_todrop()) {
+			/*
+			 * It seems that we are very loaded.
+			 * We have to drop this packet :(
+			 */
+			ip_vs_service_put(svc);
+			return NF_DROP;
+		}
+
+		/*
+		 * Let the virtual server select a real server for the
+		 * incoming connection, and create a connection entry.
+		 */
+		cp = ip_vs_schedule(svc, iph);
+		if (!cp)
+			return ip_vs_leave(svc, skb);
+		ip_vs_conn_stats(cp, svc);
+		ip_vs_service_put(svc);
+	}
+
+	if (!cp) {
+		/* sorry, all this trouble for a no-hit :) */
+		IP_VS_DBG(12, "packet for %s %d.%d.%d.%d:%d continue "
+			  "traversal as normal.\n",
+			  ip_vs_proto_name(iph->protocol),
+			  NIPQUAD(iph->daddr),
+			  ntohs(h.portp[1]));
+		return NF_ACCEPT;
+	}
+
+	IP_VS_DBG(11, "Incoming %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d\n",
+		  ip_vs_proto_name(iph->protocol),
+		  NIPQUAD(iph->saddr), ntohs(h.portp[0]),
+		  NIPQUAD(iph->daddr), ntohs(h.portp[1]));
+
+	/* Check the server status */
+	if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+		/* the destination server is not availabe */
+
+		if (sysctl_ip_vs_expire_nodest_conn) {
+			/* try to expire the connection immediately */
+			ip_vs_conn_expire_now(cp);
+		} else {
+			/* don't restart its timer, and silently
+			   drop the packet. */
+			__ip_vs_conn_put(cp);
+		}
+		return NF_DROP;
+	}
+
+	ip_vs_in_stats(cp, skb);
+	ip_vs_set_state(cp, VS_STATE_INPUT, iph, h.portp);
+	if (cp->packet_xmit)
+		ret = cp->packet_xmit(skb, cp);
+	else {
+		IP_VS_DBG_RL("warning: packet_xmit is null");
+		ret = NF_ACCEPT;
+	}
+
+	/* increase its packet counter and check if it is needed
+	   to be synchronized */
+	atomic_inc(&cp->in_pkts);
+	if (ip_vs_sync_state == IP_VS_STATE_MASTER &&
+	    (cp->protocol != IPPROTO_TCP ||
+	     cp->state == IP_VS_S_ESTABLISHED) &&
+	    (atomic_read(&cp->in_pkts) % 50 == sysctl_ip_vs_sync_threshold))
+		ip_vs_sync_conn(cp);
+
+	ip_vs_conn_put(cp);
+	return ret;
+}
+
+
+/*
+ *	It is hooked at the NF_IP_FORWARD chain, in order to catch ICMP
+ *      packets destined for 0.0.0.0/0.
+ *      When fwmark-based virtual service is used, such as transparent
+ *      cache cluster, TCP packets can be marked and routed to ip_vs_in,
+ *      but ICMP destined for 0.0.0.0/0 cannot not be easily marked and
+ *      sent to ip_vs_in_icmp. So, catch them at the NF_IP_FORWARD chain
+ *      and send them to ip_vs_in_icmp.
+ */
+static unsigned int ip_vs_forward_icmp(unsigned int hooknum,
+				       struct sk_buff **skb_p,
+				       const struct net_device *in,
+				       const struct net_device *out,
+				       int (*okfn)(struct sk_buff *))
+{
+	struct sk_buff	*skb = *skb_p;
+	struct iphdr	*iph = skb->nh.iph;
+
+	if (iph->protocol != IPPROTO_ICMP)
+		return NF_ACCEPT;
+
+	if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+		skb = ip_defrag(skb);
+		if (!skb)
+			return NF_STOLEN;
+		*skb_p = skb;
+	}
+
+	return ip_vs_in_icmp(skb_p);
+}
+
+
+/* After packet filtering, forward packet through VS/DR, VS/TUN,
+   or VS/NAT(change destination), so that filtering rules can be
+   applied to IPVS. */
+static struct nf_hook_ops ip_vs_in_ops = {
+	{ NULL, NULL },
+	ip_vs_in, PF_INET, NF_IP_LOCAL_IN, 100
+};
+
+/* After packet filtering, change source only for VS/NAT */
+static struct nf_hook_ops ip_vs_out_ops = {
+	{ NULL, NULL },
+	ip_vs_out, PF_INET, NF_IP_FORWARD, 100
+};
+
+/* After packet filtering (but before ip_vs_out_icmp), catch icmp
+   destined for 0.0.0.0/0, which is for incoming IPVS connections */
+static struct nf_hook_ops ip_vs_forward_icmp_ops = {
+	{ NULL, NULL },
+	ip_vs_forward_icmp, PF_INET, NF_IP_FORWARD, 99
+};
+
+/* Before the netfilter connection tracking, exit from POST_ROUTING */
+static struct nf_hook_ops ip_vs_post_routing_ops = {
+	{ NULL, NULL },
+	ip_vs_post_routing, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC-1
+};
+
+
+/*
+ *	Initialize IP Virtual Server
+ */
+static int __init ip_vs_init(void)
+{
+	int ret;
+
+	ret = ip_vs_control_init();
+	if (ret < 0) {
+		IP_VS_ERR("can't setup control.\n");
+		goto cleanup_nothing;
+	}
+
+	ret = ip_vs_conn_init();
+	if (ret < 0) {
+		IP_VS_ERR("can't setup connection table.\n");
+		goto cleanup_control;
+	}
+
+	ret = ip_vs_app_init();
+	if (ret < 0) {
+		IP_VS_ERR("can't setup application helper.\n");
+		goto cleanup_conn;
+	}
+
+	ret = nf_register_hook(&ip_vs_in_ops);
+	if (ret < 0) {
+		IP_VS_ERR("can't register in hook.\n");
+		goto cleanup_app;
+	}
+	ret = nf_register_hook(&ip_vs_out_ops);
+	if (ret < 0) {
+		IP_VS_ERR("can't register out hook.\n");
+		goto cleanup_inops;
+	}
+	ret = nf_register_hook(&ip_vs_post_routing_ops);
+	if (ret < 0) {
+		IP_VS_ERR("can't register post_routing hook.\n");
+		goto cleanup_outops;
+	}
+	ret = nf_register_hook(&ip_vs_forward_icmp_ops);
+	if (ret < 0) {
+		IP_VS_ERR("can't register forward_icmp hook.\n");
+		goto cleanup_postroutingops;
+	}
+
+	IP_VS_INFO("ipvs loaded.\n");
+	return ret;
+
+  cleanup_postroutingops:
+	nf_unregister_hook(&ip_vs_post_routing_ops);
+  cleanup_outops:
+	nf_unregister_hook(&ip_vs_out_ops);
+  cleanup_inops:
+	nf_unregister_hook(&ip_vs_in_ops);
+  cleanup_app:
+	ip_vs_app_cleanup();
+  cleanup_conn:
+	ip_vs_conn_cleanup();
+  cleanup_control:
+	ip_vs_control_cleanup();
+  cleanup_nothing:
+	return ret;
+}
+
+static void __exit ip_vs_cleanup(void)
+{
+	nf_unregister_hook(&ip_vs_forward_icmp_ops);
+	nf_unregister_hook(&ip_vs_post_routing_ops);
+	nf_unregister_hook(&ip_vs_out_ops);
+	nf_unregister_hook(&ip_vs_in_ops);
+	ip_vs_app_cleanup();
+	ip_vs_conn_cleanup();
+	ip_vs_control_cleanup();
+	IP_VS_INFO("ipvs unloaded.\n");
+}
+
+module_init(ip_vs_init);
+module_exit(ip_vs_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_ctl.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,2154 @@
+/*
+ * IPVS         An implementation of the IP virtual server support for the
+ *              LINUX operating system.  IPVS is now implemented as a module
+ *              over the NetFilter framework. IPVS can be used to build a
+ *              high-performance and highly available server based on a
+ *              cluster of servers.
+ *
+ * Version:     $Id: ip_vs_ctl.c,v 1.30.2.3 2003/07/29 14:37:12 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *              Julian Anastasov <ja@ssi.bg>
+ *
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/timer.h>
+#include <linux/swap.h>
+#include <linux/proc_fs.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <net/ip.h>
+#include <net/sock.h>
+
+#include <asm/uaccess.h>
+
+#include <net/ip_vs.h>
+
+/* semaphore for IPVS sockopts. And, [gs]etsockopt may sleep. */
+static DECLARE_MUTEX(__ip_vs_mutex);
+
+/* lock for service table */
+rwlock_t __ip_vs_svc_lock = RW_LOCK_UNLOCKED;
+
+/* lock for table with the real services */
+static rwlock_t __ip_vs_rs_lock = RW_LOCK_UNLOCKED;
+
+/* lock for state and timeout tables */
+static rwlock_t __ip_vs_securetcp_lock = RW_LOCK_UNLOCKED;
+
+/* lock for drop entry handling */
+static spinlock_t __ip_vs_dropentry_lock = SPIN_LOCK_UNLOCKED;
+
+/* lock for drop packet handling */
+static spinlock_t __ip_vs_droppacket_lock = SPIN_LOCK_UNLOCKED;
+
+/* 1/rate drop and drop-entry variables */
+int ip_vs_drop_rate = 0;
+int ip_vs_drop_counter = 0;
+atomic_t ip_vs_dropentry = ATOMIC_INIT(0);
+
+/* number of virtual services */
+static int ip_vs_num_services = 0;
+
+/* sysctl variables */
+static int sysctl_ip_vs_drop_entry = 0;
+static int sysctl_ip_vs_drop_packet = 0;
+static int sysctl_ip_vs_secure_tcp = 0;
+static int sysctl_ip_vs_amemthresh = 2048;
+static int sysctl_ip_vs_am_droprate = 10;
+int sysctl_ip_vs_cache_bypass = 0;
+int sysctl_ip_vs_expire_nodest_conn = 0;
+int sysctl_ip_vs_sync_threshold = 3;
+int sysctl_ip_vs_nat_icmp_send = 0;
+
+#ifdef CONFIG_IP_VS_DEBUG
+static int sysctl_ip_vs_debug_level = 0;
+
+int ip_vs_get_debug_level(void)
+{
+	return sysctl_ip_vs_debug_level;
+}
+#endif
+
+/*
+ *	update_defense_level is called from timer bh and from sysctl.
+ */
+static void update_defense_level(void)
+{
+	struct sysinfo i;
+	int availmem;
+	int nomem;
+
+	/* we only count free and buffered memory (in pages) */
+	si_meminfo(&i);
+	availmem = i.freeram + i.bufferram;
+
+	nomem = (availmem < sysctl_ip_vs_amemthresh);
+
+	/* drop_entry */
+	spin_lock(&__ip_vs_dropentry_lock);
+	switch (sysctl_ip_vs_drop_entry) {
+	case 0:
+		atomic_set(&ip_vs_dropentry, 0);
+		break;
+	case 1:
+		if (nomem) {
+			atomic_set(&ip_vs_dropentry, 1);
+			sysctl_ip_vs_drop_entry = 2;
+		} else {
+			atomic_set(&ip_vs_dropentry, 0);
+		}
+		break;
+	case 2:
+		if (nomem) {
+			atomic_set(&ip_vs_dropentry, 1);
+		} else {
+			atomic_set(&ip_vs_dropentry, 0);
+			sysctl_ip_vs_drop_entry = 1;
+		};
+		break;
+	case 3:
+		atomic_set(&ip_vs_dropentry, 1);
+		break;
+	}
+	spin_unlock(&__ip_vs_dropentry_lock);
+
+	/* drop_packet */
+	spin_lock(&__ip_vs_droppacket_lock);
+	switch (sysctl_ip_vs_drop_packet) {
+	case 0:
+		ip_vs_drop_rate = 0;
+		break;
+	case 1:
+		if (nomem) {
+			ip_vs_drop_rate = ip_vs_drop_counter
+				= sysctl_ip_vs_amemthresh /
+				(sysctl_ip_vs_amemthresh - availmem);
+			sysctl_ip_vs_drop_packet = 2;
+		} else {
+			ip_vs_drop_rate = 0;
+		}
+		break;
+	case 2:
+		if (nomem) {
+			ip_vs_drop_rate = ip_vs_drop_counter
+				= sysctl_ip_vs_amemthresh /
+				(sysctl_ip_vs_amemthresh - availmem);
+		} else {
+			ip_vs_drop_rate = 0;
+			sysctl_ip_vs_drop_packet = 1;
+		}
+		break;
+	case 3:
+		ip_vs_drop_rate = sysctl_ip_vs_am_droprate;
+		break;
+	}
+	spin_unlock(&__ip_vs_droppacket_lock);
+
+	/* secure_tcp */
+	write_lock(&__ip_vs_securetcp_lock);
+	switch (sysctl_ip_vs_secure_tcp) {
+	case 0:
+		ip_vs_secure_tcp_set(0);
+		break;
+	case 1:
+		if (nomem) {
+			ip_vs_secure_tcp_set(1);
+			sysctl_ip_vs_secure_tcp = 2;
+		} else {
+			ip_vs_secure_tcp_set(0);
+		}
+		break;
+	case 2:
+		if (nomem) {
+			ip_vs_secure_tcp_set(1);
+		} else {
+			ip_vs_secure_tcp_set(0);
+			sysctl_ip_vs_secure_tcp = 1;
+		}
+		break;
+	case 3:
+		ip_vs_secure_tcp_set(1);
+		break;
+	}
+	write_unlock(&__ip_vs_securetcp_lock);
+}
+
+
+/*
+ *	Timer for checking the defense
+ */
+static struct timer_list defense_timer;
+#define DEFENSE_TIMER_PERIOD	1*HZ
+
+static void defense_timer_handler(unsigned long data)
+{
+	update_defense_level();
+	if (atomic_read(&ip_vs_dropentry))
+		ip_vs_random_dropentry();
+
+	mod_timer(&defense_timer, jiffies + DEFENSE_TIMER_PERIOD);
+}
+
+
+/*
+ *  Hash table: for virtual service lookups
+ */
+#define IP_VS_SVC_TAB_BITS 8
+#define IP_VS_SVC_TAB_SIZE (1 << IP_VS_SVC_TAB_BITS)
+#define IP_VS_SVC_TAB_MASK (IP_VS_SVC_TAB_SIZE - 1)
+
+/* the service table hashed by <protocol, addr, port> */
+static struct list_head ip_vs_svc_table[IP_VS_SVC_TAB_SIZE];
+/* the service table hashed by fwmark */
+static struct list_head ip_vs_svc_fwm_table[IP_VS_SVC_TAB_SIZE];
+
+/*
+ *  Hash table: for real service lookups
+ */
+#define IP_VS_RTAB_BITS 4
+#define IP_VS_RTAB_SIZE (1 << IP_VS_RTAB_BITS)
+#define IP_VS_RTAB_MASK (IP_VS_RTAB_SIZE - 1)
+
+static struct list_head ip_vs_rtable[IP_VS_RTAB_SIZE];
+
+/*
+ * Trash for destinations
+ */
+static LIST_HEAD(ip_vs_dest_trash);
+
+/*
+ * FTP & NULL virtual service counters
+ */
+static atomic_t ip_vs_ftpsvc_counter = ATOMIC_INIT(0);
+static atomic_t ip_vs_nullsvc_counter = ATOMIC_INIT(0);
+
+
+/*
+ *  Returns hash value for virtual service
+ */
+static __inline__ unsigned
+ip_vs_svc_hashkey(unsigned proto, __u32 addr, __u16 port)
+{
+	register unsigned porth = ntohs(port);
+
+	return (proto^ntohl(addr)^(porth>>IP_VS_SVC_TAB_BITS)^porth)
+		& IP_VS_SVC_TAB_MASK;
+}
+
+/*
+ *  Returns hash value of fwmark for virtual service lookup
+ */
+static __inline__ unsigned ip_vs_svc_fwm_hashkey(__u32 fwmark)
+{
+	return fwmark & IP_VS_SVC_TAB_MASK;
+}
+
+/*
+ *  Hashes ip_vs_service in the ip_vs_svc_table by <proto,addr,port>
+ *  or in the ip_vs_svc_fwm_table by fwmark.
+ *  Should be called with locked tables.
+ *  Returns bool success.
+ */
+static int ip_vs_svc_hash(struct ip_vs_service *svc)
+{
+	unsigned hash;
+
+	if (svc->flags & IP_VS_SVC_F_HASHED) {
+		IP_VS_ERR("ip_vs_svc_hash(): request for already hashed, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	if (svc->fwmark == 0) {
+		/*
+		 *  Hash it by <protocol,addr,port> in ip_vs_svc_table
+		 */
+		hash = ip_vs_svc_hashkey(svc->protocol, svc->addr, svc->port);
+		list_add(&svc->s_list, &ip_vs_svc_table[hash]);
+	} else {
+		/*
+		 *  Hash it by fwmark in ip_vs_svc_fwm_table
+		 */
+		hash = ip_vs_svc_fwm_hashkey(svc->fwmark);
+		list_add(&svc->f_list, &ip_vs_svc_fwm_table[hash]);
+	}
+
+	svc->flags |= IP_VS_SVC_F_HASHED;
+	/* increase its refcnt because it is referenced by the svc table */
+	atomic_inc(&svc->refcnt);
+	return 1;
+}
+
+
+/*
+ *  Unhashes ip_vs_service from ip_vs_svc_table/ip_vs_svc_fwm_table.
+ *  Should be called with locked tables.
+ *  Returns bool success.
+ */
+static int ip_vs_svc_unhash(struct ip_vs_service *svc)
+{
+	if (!(svc->flags & IP_VS_SVC_F_HASHED)) {
+		IP_VS_ERR("ip_vs_svc_unhash(): request for unhash flagged, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	if (svc->fwmark == 0) {
+		/*
+		 * Remove it from the ip_vs_svc_table table.
+		 */
+		list_del(&svc->s_list);
+	} else {
+		/*
+		 * Remove it from the ip_vs_svc_fwm_table table.
+		 */
+		list_del(&svc->f_list);
+	}
+
+	svc->flags &= ~IP_VS_SVC_F_HASHED;
+	atomic_dec(&svc->refcnt);
+	return 1;
+}
+
+
+/*
+ *  Get service by {proto,addr,port} in the service table.
+ */
+static __inline__ struct ip_vs_service *
+__ip_vs_service_get(__u16 protocol, __u32 vaddr, __u16 vport)
+{
+	unsigned hash;
+	struct ip_vs_service *svc;
+	struct list_head *l,*e;
+
+	/*
+	 *	Check for "full" addressed entries
+	 */
+	hash = ip_vs_svc_hashkey(protocol, vaddr, vport);
+
+	l = &ip_vs_svc_table[hash];
+	for (e=l->next; e!=l; e=e->next) {
+		svc = list_entry(e, struct ip_vs_service, s_list);
+		if ((svc->addr == vaddr)
+		    && (svc->port == vport)
+		    && (svc->protocol == protocol)) {
+			/* HIT */
+			atomic_inc(&svc->usecnt);
+			return svc;
+		}
+	}
+
+	return NULL;
+}
+
+
+/*
+ *  Get service by {fwmark} in the service table.
+ */
+static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark)
+{
+	unsigned hash;
+	struct ip_vs_service *svc;
+	struct list_head *l,*e;
+
+	/*
+	 *	Check for "full" addressed entries
+	 */
+	hash = ip_vs_svc_fwm_hashkey(fwmark);
+
+	l = &ip_vs_svc_fwm_table[hash];
+	for (e=l->next; e!=l; e=e->next) {
+		svc = list_entry(e, struct ip_vs_service, f_list);
+		if (svc->fwmark == fwmark) {
+			/* HIT */
+			atomic_inc(&svc->usecnt);
+			return svc;
+		}
+	}
+
+	return NULL;
+}
+
+struct ip_vs_service *
+ip_vs_service_get(__u32 fwmark, __u16 protocol, __u32 vaddr, __u16 vport)
+{
+	struct ip_vs_service *svc;
+
+	read_lock(&__ip_vs_svc_lock);
+
+	/*
+	 *	Check the table hashed by fwmark first
+	 */
+	if (fwmark && (svc = __ip_vs_svc_fwm_get(fwmark)))
+		goto out;
+
+	/*
+	 *	Check the table hashed by <protocol,addr,port>
+	 *	for "full" addressed entries
+	 */
+	svc = __ip_vs_service_get(protocol, vaddr, vport);
+
+	if (svc == NULL
+	    && protocol == IPPROTO_TCP
+	    && atomic_read(&ip_vs_ftpsvc_counter)
+	    && (vport == FTPDATA || ntohs(vport) >= PROT_SOCK)) {
+		/*
+		 * Check if ftp service entry exists, the packet
+		 * might belong to FTP data connections.
+		 */
+		svc = __ip_vs_service_get(protocol, vaddr, FTPPORT);
+	}
+
+	if (svc == NULL
+	    && atomic_read(&ip_vs_nullsvc_counter)) {
+		/*
+		 * Check if the catch-all port (port zero) exists
+		 */
+		svc = __ip_vs_service_get(protocol, vaddr, 0);
+	}
+
+  out:
+	read_unlock(&__ip_vs_svc_lock);
+
+	IP_VS_DBG(6, "lookup service: fwm %u %s %u.%u.%u.%u:%u %s\n",
+		  fwmark, ip_vs_proto_name(protocol),
+		  NIPQUAD(vaddr), ntohs(vport),
+		  svc?"hit":"not hit");
+
+	return svc;
+}
+
+
+static inline void
+__ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
+{
+	atomic_inc(&svc->refcnt);
+	dest->svc = svc;
+}
+
+static inline void
+__ip_vs_unbind_svc(struct ip_vs_dest *dest)
+{
+	struct ip_vs_service *svc = dest->svc;
+
+	dest->svc = NULL;
+	if (atomic_dec_and_test(&svc->refcnt))
+		kfree(svc);
+}
+
+/*
+ *  Returns hash value for real service
+ */
+static __inline__ unsigned ip_vs_rs_hashkey(__u32 addr, __u16 port)
+{
+	register unsigned porth = ntohs(port);
+
+	return (ntohl(addr)^(porth>>IP_VS_RTAB_BITS)^porth)
+		& IP_VS_RTAB_MASK;
+}
+
+/*
+ *  Hashes ip_vs_dest in ip_vs_rtable by proto,addr,port.
+ *  should be called with locked tables.
+ *  returns bool success.
+ */
+static int ip_vs_rs_hash(struct ip_vs_dest *dest)
+{
+	unsigned hash;
+
+	if (!list_empty(&dest->d_list)) {
+		return 0;
+	}
+
+	/*
+	 *	Hash by proto,addr,port,
+	 *	which are the parameters of the real service.
+	 */
+	hash = ip_vs_rs_hashkey(dest->addr, dest->port);
+	list_add(&dest->d_list, &ip_vs_rtable[hash]);
+
+	return 1;
+}
+
+/*
+ *  UNhashes ip_vs_dest from ip_vs_rtable.
+ *  should be called with locked tables.
+ *  returns bool success.
+ */
+static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
+{
+	/*
+	 * Remove it from the ip_vs_rtable table.
+	 */
+	if (!list_empty(&dest->d_list)) {
+		list_del(&dest->d_list);
+		INIT_LIST_HEAD(&dest->d_list);
+	}
+
+	return 1;
+}
+
+/*
+ *  Lookup real service by {proto,addr,port} in the real service table.
+ */
+struct ip_vs_dest *
+ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport)
+{
+	unsigned hash;
+	struct ip_vs_dest *dest;
+	struct list_head *l,*e;
+
+	/*
+	 *	Check for "full" addressed entries
+	 *	Return the first found entry
+	 */
+	hash = ip_vs_rs_hashkey(daddr, dport);
+
+	l = &ip_vs_rtable[hash];
+
+	read_lock(&__ip_vs_rs_lock);
+	for (e=l->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, d_list);
+		if ((dest->addr == daddr)
+		    && (dest->port == dport)
+		    && ((dest->protocol == protocol) ||
+			dest->vfwmark)) {
+			/* HIT */
+			read_unlock(&__ip_vs_rs_lock);
+			return dest;
+		}
+	}
+	read_unlock(&__ip_vs_rs_lock);
+
+	return NULL;
+}
+
+/*
+ *  Lookup destination by {addr,port} in the given service
+ */
+static struct ip_vs_dest *
+ip_vs_lookup_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
+{
+	struct ip_vs_dest *dest;
+	struct list_head *l, *e;
+
+	/*
+	 * Find the destination for the given service
+	 */
+	l = &svc->destinations;
+	for (e=l->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		if ((dest->addr == daddr) && (dest->port == dport)) {
+			/* HIT */
+			return dest;
+		}
+	}
+
+	return NULL;
+}
+
+
+/*
+ *  Lookup dest by {svc,addr,port} in the destination trash.
+ *  The destination trash is used to hold the destinations that are removed
+ *  from the service table but are still referenced by some conn entries.
+ *  The reason to add the destination trash is when the dest is temporary
+ *  down (either by administrator or by monitor program), the dest can be
+ *  picked back from the trash, the remaining connections to the dest can
+ *  continue, and the counting information of the dest is also useful for
+ *  scheduling.
+ */
+static struct ip_vs_dest *
+ip_vs_trash_get_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
+{
+	struct ip_vs_dest *dest;
+	struct list_head *l, *e;
+
+	/*
+	 * Find the destination in trash
+	 */
+	l = &ip_vs_dest_trash;
+
+	for (e=l->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
+			  "refcnt=%d\n",
+			  dest->vfwmark,
+			  NIPQUAD(dest->addr), ntohs(dest->port),
+			  atomic_read(&dest->refcnt));
+		if (dest->addr == daddr &&
+		    dest->port == dport &&
+		    dest->vfwmark == svc->fwmark &&
+		    dest->protocol == svc->protocol &&
+		    (svc->fwmark ||
+		     (dest->vaddr == svc->addr &&
+		      dest->vport == svc->port))) {
+			/* HIT */
+			return dest;
+		}
+
+		/*
+		 * Try to purge the destination from trash if not referenced
+		 */
+		if (atomic_read(&dest->refcnt) == 1) {
+			IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u "
+				  "from trash\n",
+				  dest->vfwmark,
+				  NIPQUAD(dest->addr), ntohs(dest->port));
+			e = e->prev;
+			list_del(&dest->n_list);
+			__ip_vs_dst_reset(dest);
+			__ip_vs_unbind_svc(dest);
+			kfree(dest);
+		}
+	}
+
+	return NULL;
+}
+
+
+/*
+ *  Clean up all the destinations in the trash
+ *  Called by the ip_vs_control_cleanup()
+ *
+ *  When the ip_vs_control_clearup is activated by ipvs module exit,
+ *  the service tables must have been flushed and all the connections
+ *  are expired, and the refcnt of each destination in the trash must
+ *  be 1, so we simply release them here.
+ */
+static void ip_vs_trash_cleanup(void)
+{
+	struct ip_vs_dest *dest;
+	struct list_head *l;
+
+	l = &ip_vs_dest_trash;
+
+	while (l->next != l) {
+		dest = list_entry(l->next, struct ip_vs_dest, n_list);
+		list_del(&dest->n_list);
+		__ip_vs_dst_reset(dest);
+		__ip_vs_unbind_svc(dest);
+		kfree(dest);
+	}
+}
+
+
+/*
+ *  Update a destination in the given service
+ */
+static void __ip_vs_update_dest(struct ip_vs_service *svc,
+				struct ip_vs_dest *dest,
+				struct ip_vs_rule_user *ur)
+{
+	int conn_flags;
+
+	/*
+	 *    Set the weight and the flags
+	 */
+	atomic_set(&dest->weight, ur->weight);
+
+	conn_flags = ur->conn_flags | IP_VS_CONN_F_INACTIVE;
+
+	/*
+	 *    Check if local node and update the flags
+	 */
+	if (inet_addr_type(ur->daddr) == RTN_LOCAL) {
+		conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
+			| IP_VS_CONN_F_LOCALNODE;
+	}
+
+	/*
+	 *    Set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading
+	 */
+	if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) {
+		conn_flags |= IP_VS_CONN_F_NOOUTPUT;
+	} else {
+		/*
+		 *    Put the real service in ip_vs_rtable if not present.
+		 *    For now only for NAT!
+		 */
+		write_lock_bh(&__ip_vs_rs_lock);
+		ip_vs_rs_hash(dest);
+		write_unlock_bh(&__ip_vs_rs_lock);
+	}
+	atomic_set(&dest->conn_flags, conn_flags);
+
+	/* bind the service */
+	if (!dest->svc) {
+		__ip_vs_bind_svc(dest, svc);
+	} else {
+		if (dest->svc != svc) {
+			__ip_vs_unbind_svc(dest);
+			__ip_vs_bind_svc(dest, svc);
+		}
+	}
+
+	/* set the dest status flags */
+	dest->flags |= IP_VS_DEST_F_AVAILABLE;
+}
+
+
+/*
+ *  Create a destination for the given service
+ */
+static int
+ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_rule_user *ur,
+	       struct ip_vs_dest **destp)
+{
+	struct ip_vs_dest *dest;
+	unsigned atype;
+
+	EnterFunction(2);
+
+	atype = inet_addr_type(ur->daddr);
+	if (atype != RTN_LOCAL && atype != RTN_UNICAST)
+		return -EINVAL;
+
+	*destp = dest = (struct ip_vs_dest*)
+		kmalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC);
+	if (dest == NULL) {
+		IP_VS_ERR("ip_vs_new_dest: kmalloc failed.\n");
+		return -ENOMEM;
+	}
+	memset(dest, 0, sizeof(struct ip_vs_dest));
+
+	dest->protocol = svc->protocol;
+	dest->vaddr = svc->addr;
+	dest->vport = svc->port;
+	dest->vfwmark = svc->fwmark;
+	dest->addr = ur->daddr;
+	dest->port = ur->dport;
+
+	atomic_set(&dest->activeconns, 0);
+	atomic_set(&dest->inactconns, 0);
+	atomic_set(&dest->refcnt, 0);
+
+	INIT_LIST_HEAD(&dest->d_list);
+	dest->dst_lock = SPIN_LOCK_UNLOCKED;
+	dest->stats.lock = SPIN_LOCK_UNLOCKED;
+	__ip_vs_update_dest(svc, dest, ur);
+	ip_vs_new_estimator(&dest->stats);
+
+	LeaveFunction(2);
+	return 0;
+}
+
+
+/*
+ *  Add a destination into an existing service
+ */
+static int ip_vs_add_dest(struct ip_vs_service *svc,
+			  struct ip_vs_rule_user *ur)
+{
+	struct ip_vs_dest *dest;
+	__u32 daddr = ur->daddr;
+	__u16 dport = ur->dport;
+	int ret;
+
+	EnterFunction(2);
+
+	if (ur->weight < 0) {
+		IP_VS_ERR("ip_vs_add_dest(): server weight less than zero\n");
+		return -ERANGE;
+	}
+
+	/*
+	 * Check if the dest already exists in the list
+	 */
+	dest = ip_vs_lookup_dest(svc, daddr, dport);
+	if (dest != NULL) {
+		IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
+		return -EEXIST;
+	}
+
+	/*
+	 * Check if the dest already exists in the trash and
+	 * is from the same service
+	 */
+	dest = ip_vs_trash_get_dest(svc, daddr, dport);
+	if (dest != NULL) {
+		IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
+			  "refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
+			  NIPQUAD(daddr), ntohs(dport),
+			  atomic_read(&dest->refcnt),
+			  dest->vfwmark,
+			  NIPQUAD(dest->vaddr),
+			  ntohs(dest->vport));
+		__ip_vs_update_dest(svc, dest, ur);
+
+		/*
+		 * Get the destination from the trash
+		 */
+		list_del(&dest->n_list);
+
+		ip_vs_new_estimator(&dest->stats);
+
+		write_lock_bh(&__ip_vs_svc_lock);
+
+		/*
+		 * Wait until all other svc users go away.
+		 */
+		while (atomic_read(&svc->usecnt) > 1) {};
+
+		list_add(&dest->n_list, &svc->destinations);
+		svc->num_dests++;
+
+		/* call the update_service function of its scheduler */
+		svc->scheduler->update_service(svc);
+
+		write_unlock_bh(&__ip_vs_svc_lock);
+		return 0;
+	}
+
+	/*
+	 * Allocate and initialize the dest structure
+	 */
+	ret = ip_vs_new_dest(svc, ur, &dest);
+	if (ret) {
+		return ret;
+	}
+
+	/*
+	 * Add the dest entry into the list
+	 */
+	atomic_inc(&dest->refcnt);
+
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	/*
+	 * Wait until all other svc users go away.
+	 */
+	while (atomic_read(&svc->usecnt) > 1) {};
+
+	list_add(&dest->n_list, &svc->destinations);
+	svc->num_dests++;
+
+	/* call the update_service function of its scheduler */
+	svc->scheduler->update_service(svc);
+
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	LeaveFunction(2);
+
+	return 0;
+}
+
+
+/*
+ *  Edit a destination in the given service
+ */
+static int ip_vs_edit_dest(struct ip_vs_service *svc,
+			   struct ip_vs_rule_user *ur)
+{
+	struct ip_vs_dest *dest;
+	__u32 daddr = ur->daddr;
+	__u16 dport = ur->dport;
+
+	EnterFunction(2);
+
+	if (ur->weight < 0) {
+		IP_VS_ERR("ip_vs_edit_dest(): server weight less than zero\n");
+		return -ERANGE;
+	}
+
+	/*
+	 *  Lookup the destination list
+	 */
+	dest = ip_vs_lookup_dest(svc, daddr, dport);
+	if (dest == NULL) {
+		IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
+		return -ENOENT;
+	}
+
+	__ip_vs_update_dest(svc, dest, ur);
+
+	/* call the update_service, because server weight may be changed */
+	svc->scheduler->update_service(svc);
+
+	LeaveFunction(2);
+
+	return 0;
+}
+
+
+/*
+ *  Delete a destination (must be already unlinked from the service)
+ */
+static void __ip_vs_del_dest(struct ip_vs_dest *dest)
+{
+	ip_vs_kill_estimator(&dest->stats);
+
+	/*
+	 *  Remove it from the d-linked list with the real services.
+	 */
+	write_lock_bh(&__ip_vs_rs_lock);
+	ip_vs_rs_unhash(dest);
+	write_unlock_bh(&__ip_vs_rs_lock);
+
+	/*
+	 *  Decrease the refcnt of the dest, and free the dest
+	 *  if nobody refers to it (refcnt=0). Otherwise, throw
+	 *  the destination into the trash.
+	 */
+	if (atomic_dec_and_test(&dest->refcnt)) {
+		__ip_vs_dst_reset(dest);
+		/* simply decrease svc->refcnt here, let the caller check
+		   and release the service if nobody refers to it.
+		   Only user context can release destination and service,
+		   and only one user context can update virtual service at a
+		   time, so the operation here is OK */
+		atomic_dec(&dest->svc->refcnt);
+		kfree(dest);
+	} else {
+		IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, refcnt=%d\n",
+			  NIPQUAD(dest->addr), ntohs(dest->port),
+			  atomic_read(&dest->refcnt));
+		list_add(&dest->n_list, &ip_vs_dest_trash);
+		atomic_inc(&dest->refcnt);
+	}
+}
+
+
+/*
+ *  Unlink a destination from the given service
+ */
+static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
+				struct ip_vs_dest *dest,
+				int svcupd)
+{
+	dest->flags &= ~IP_VS_DEST_F_AVAILABLE;
+
+	/*
+	 *  Remove it from the d-linked destination list.
+	 */
+	list_del(&dest->n_list);
+	svc->num_dests--;
+	if (svcupd) {
+		/*
+		 *  Call the update_service function of its scheduler
+		 */
+		svc->scheduler->update_service(svc);
+	}
+}
+
+
+/*
+ *  Delete a destination server in the given service
+ */
+static int ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_rule_user *ur)
+{
+	struct ip_vs_dest *dest;
+	__u32 daddr = ur->daddr;
+	__u16 dport = ur->dport;
+
+	EnterFunction(2);
+
+	dest = ip_vs_lookup_dest(svc, daddr, dport);
+	if (dest == NULL) {
+		IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
+		return -ENOENT;
+	}
+
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	/*
+	 *	Wait until all other svc users go away.
+	 */
+	while (atomic_read(&svc->usecnt) > 1) {};
+
+	/*
+	 *	Unlink dest from the service
+	 */
+	__ip_vs_unlink_dest(svc, dest, 1);
+
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	/*
+	 *	Delete the destination
+	 */
+	__ip_vs_del_dest(dest);
+
+	LeaveFunction(2);
+
+	return 0;
+}
+
+
+/*
+ *  Add a service into the service hash table
+ */
+static int
+ip_vs_add_service(struct ip_vs_rule_user *ur, struct ip_vs_service **svc_p)
+{
+	int ret = 0;
+	struct ip_vs_scheduler *sched;
+	struct ip_vs_service *svc = NULL;
+
+	MOD_INC_USE_COUNT;
+
+	/*
+	 * Lookup the scheduler, by 'ur->sched_name'
+	 */
+	sched = ip_vs_scheduler_get(ur->sched_name);
+	if (sched == NULL) {
+		IP_VS_INFO("Scheduler module ip_vs_%s.o not found\n",
+			   ur->sched_name);
+		ret = -ENOENT;
+		goto out_mod_dec;
+	}
+
+	svc = (struct ip_vs_service*)
+		kmalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
+	if (svc == NULL) {
+		IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n");
+		ret = -ENOMEM;
+		goto out_err;
+	}
+	memset(svc, 0, sizeof(struct ip_vs_service));
+
+	svc->protocol = ur->protocol;
+	svc->addr = ur->vaddr;
+	svc->port = ur->vport;
+	svc->fwmark = ur->vfwmark;
+	svc->flags = ur->vs_flags;
+	svc->timeout = ur->timeout * HZ;
+	svc->netmask = ur->netmask;
+
+	INIT_LIST_HEAD(&svc->destinations);
+	svc->sched_lock = RW_LOCK_UNLOCKED;
+	svc->stats.lock = SPIN_LOCK_UNLOCKED;
+
+	/*
+	 *    Bind the scheduler
+	 */
+	ret = ip_vs_bind_scheduler(svc, sched);
+	if (ret) {
+		goto out_err;
+	}
+
+	/*
+	 *    Update the virtual service counters
+	 */
+	if (svc->port == FTPPORT)
+		atomic_inc(&ip_vs_ftpsvc_counter);
+	else if (svc->port == 0)
+		atomic_inc(&ip_vs_nullsvc_counter);
+
+	/*
+	 *    I'm the first user of the service
+	 */
+	atomic_set(&svc->usecnt, 1);
+	atomic_set(&svc->refcnt, 0);
+
+	ip_vs_new_estimator(&svc->stats);
+	ip_vs_num_services++;
+
+	/*
+	 *    Hash the service into the service table
+	 */
+	write_lock_bh(&__ip_vs_svc_lock);
+	ip_vs_svc_hash(svc);
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	*svc_p = svc;
+	return 0;
+
+  out_err:
+	if (svc)
+		kfree(svc);
+	ip_vs_scheduler_put(sched);
+  out_mod_dec:
+	MOD_DEC_USE_COUNT;
+	return ret;
+}
+
+
+/*
+ *	Edit a service and bind it with a new scheduler
+ */
+static int ip_vs_edit_service(struct ip_vs_service *svc,
+			      struct ip_vs_rule_user *ur)
+{
+	struct ip_vs_scheduler *sched, *old_sched;
+	int ret = 0;
+
+	/*
+	 * Lookup the scheduler, by 'ur->sched_name'
+	 */
+	sched = ip_vs_scheduler_get(ur->sched_name);
+	if (sched == NULL) {
+		IP_VS_INFO("Scheduler module ip_vs_%s.o not found\n",
+			   ur->sched_name);
+		return -ENOENT;
+	}
+
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	/*
+	 * Wait until all other svc users go away.
+	 */
+	while (atomic_read(&svc->usecnt) > 1) {};
+
+	/*
+	 * Set the flags and timeout value
+	 */
+	svc->flags = ur->vs_flags | IP_VS_SVC_F_HASHED;
+	svc->timeout = ur->timeout * HZ;
+	svc->netmask = ur->netmask;
+
+	old_sched = svc->scheduler;
+	if (sched != old_sched) {
+		/*
+		 * Unbind the old scheduler
+		 */
+		if ((ret = ip_vs_unbind_scheduler(svc))) {
+			old_sched = sched;
+			goto out;
+		}
+
+		/*
+		 * Bind the new scheduler
+		 */
+		if ((ret = ip_vs_bind_scheduler(svc, sched))) {
+			/*
+			 * If ip_vs_bind_scheduler fails, restore the old
+			 * scheduler.
+			 * The main reason of failure is out of memory.
+			 *
+			 * The question is if the old scheduler can be
+			 * restored all the time. TODO: if it cannot be
+			 * restored some time, we must delete the service,
+			 * otherwise the system may crash.
+			 */
+			ip_vs_bind_scheduler(svc, old_sched);
+			old_sched = sched;
+		}
+	}
+
+  out:
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	if (old_sched)
+		ip_vs_scheduler_put(old_sched);
+
+	return ret;
+}
+
+
+/*
+ *  Delete a service from the service list
+ *  The service must be unlinked, unlocked and not referenced!
+ */
+static void __ip_vs_del_service(struct ip_vs_service *svc)
+{
+	struct list_head *l;
+	struct ip_vs_dest *dest;
+	struct ip_vs_scheduler *old_sched;
+
+	ip_vs_num_services--;
+	ip_vs_kill_estimator(&svc->stats);
+
+	/*
+	 *    Unbind scheduler
+	 */
+	old_sched = svc->scheduler;
+	ip_vs_unbind_scheduler(svc);
+	if (old_sched && old_sched->module)
+		__MOD_DEC_USE_COUNT(old_sched->module);
+
+	/*
+	 *    Unlink the whole destination list
+	 */
+	l = &svc->destinations;
+	while (l->next != l) {
+		dest = list_entry(l->next, struct ip_vs_dest, n_list);
+		__ip_vs_unlink_dest(svc, dest, 0);
+		__ip_vs_del_dest(dest);
+	}
+
+	/*
+	 *    Update the virtual service counters
+	 */
+	if (svc->port == FTPPORT)
+		atomic_dec(&ip_vs_ftpsvc_counter);
+	else if (svc->port == 0)
+		atomic_dec(&ip_vs_nullsvc_counter);
+
+	/*
+	 *    Free the service if nobody refers to it
+	 */
+	if (atomic_read(&svc->refcnt) == 0)
+		kfree(svc);
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ *  Delete a service from the service list
+ */
+static int ip_vs_del_service(struct ip_vs_service *svc)
+{
+	if (svc == NULL)
+		return -EEXIST;
+
+	/*
+	 * Unhash it from the service table
+	 */
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	ip_vs_svc_unhash(svc);
+
+	/*
+	 * Wait until all the svc users go away.
+	 */
+	while (atomic_read(&svc->usecnt) > 1) {};
+
+	__ip_vs_del_service(svc);
+
+	write_unlock_bh(&__ip_vs_svc_lock);
+
+	return 0;
+}
+
+
+/*
+ *  Flush all the virtual services
+ */
+static int ip_vs_flush(void)
+{
+	int idx;
+	struct ip_vs_service *svc;
+	struct list_head *l;
+
+	/*
+	 * Flush the service table hashed by <protocol,addr,port>
+	 */
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		l = &ip_vs_svc_table[idx];
+		while (l->next != l) {
+			svc = list_entry(l->next,struct ip_vs_service,s_list);
+			write_lock_bh(&__ip_vs_svc_lock);
+			ip_vs_svc_unhash(svc);
+			/*
+			 * Wait until all the svc users go away.
+			 */
+			while (atomic_read(&svc->usecnt) > 0) {};
+			__ip_vs_del_service(svc);
+			write_unlock_bh(&__ip_vs_svc_lock);
+		}
+	}
+
+	/*
+	 * Flush the service table hashed by fwmark
+	 */
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		l = &ip_vs_svc_fwm_table[idx];
+		while (l->next != l) {
+			svc = list_entry(l->next,struct ip_vs_service,f_list);
+			write_lock_bh(&__ip_vs_svc_lock);
+			ip_vs_svc_unhash(svc);
+			/*
+			 * Wait until all the svc users go away.
+			 */
+			while (atomic_read(&svc->usecnt) > 0) {};
+			__ip_vs_del_service(svc);
+			write_unlock_bh(&__ip_vs_svc_lock);
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ *  Zero counters in a service or all services
+ */
+static inline void
+__ip_vs_zero_stats(struct ip_vs_stats *stats)
+{
+	spin_lock_bh(&stats->lock);
+	memset(stats, 0, (char *)&stats->lock - (char *)stats);
+	spin_unlock_bh(&stats->lock);
+	ip_vs_zero_estimator(stats);
+}
+
+static int ip_vs_zero_service(struct ip_vs_service *svc)
+{
+	struct list_head *l;
+	struct ip_vs_dest *dest;
+
+	write_lock_bh(&__ip_vs_svc_lock);
+	list_for_each (l, &svc->destinations) {
+		dest = list_entry(l, struct ip_vs_dest, n_list);
+		__ip_vs_zero_stats(&dest->stats);
+	}
+	__ip_vs_zero_stats(&svc->stats);
+	write_unlock_bh(&__ip_vs_svc_lock);
+	return 0;
+}
+
+static int ip_vs_zero_all(void)
+{
+	int idx;
+	struct list_head *l;
+	struct ip_vs_service *svc;
+
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each (l, &ip_vs_svc_table[idx]) {
+			svc = list_entry(l, struct ip_vs_service, s_list);
+			ip_vs_zero_service(svc);
+		}
+	}
+
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each (l, &ip_vs_svc_fwm_table[idx]) {
+			svc = list_entry(l, struct ip_vs_service, f_list);
+			ip_vs_zero_service(svc);
+		}
+	}
+
+	__ip_vs_zero_stats(&ip_vs_stats);
+	return 0;
+}
+
+
+static int ip_vs_sysctl_defense_mode(ctl_table *ctl, int write,
+	struct file * filp, void *buffer, size_t *lenp)
+{
+	int *valp = ctl->data;
+	int val = *valp;
+	int ret;
+
+	ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+	if (write && (*valp != val)) {
+		if ((*valp < 0) || (*valp > 3)) {
+			/* Restore the correct value */
+			*valp = val;
+		} else {
+			local_bh_disable();
+			update_defense_level();
+			local_bh_enable();
+		}
+	}
+	return ret;
+}
+
+
+/*
+ *      IPVS sysctl table
+ */
+struct ip_vs_sysctl_table {
+	struct ctl_table_header *sysctl_header;
+	ctl_table vs_vars[NET_IPV4_VS_LAST];
+	ctl_table vs_dir[2];
+	ctl_table ipv4_dir[2];
+	ctl_table root_dir[2];
+};
+
+
+static struct ip_vs_sysctl_table ipv4_vs_table = {
+	NULL,
+	{{NET_IPV4_VS_AMEMTHRESH, "amemthresh",
+	  &sysctl_ip_vs_amemthresh, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
+#ifdef CONFIG_IP_VS_DEBUG
+	 {NET_IPV4_VS_DEBUG_LEVEL, "debug_level",
+	  &sysctl_ip_vs_debug_level, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
+#endif
+	 {NET_IPV4_VS_AMDROPRATE, "am_droprate",
+	  &sysctl_ip_vs_am_droprate, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
+	 {NET_IPV4_VS_DROP_ENTRY, "drop_entry",
+	  &sysctl_ip_vs_drop_entry, sizeof(int), 0644, NULL,
+	  &ip_vs_sysctl_defense_mode},
+	 {NET_IPV4_VS_DROP_PACKET, "drop_packet",
+	  &sysctl_ip_vs_drop_packet, sizeof(int), 0644, NULL,
+	  &ip_vs_sysctl_defense_mode},
+	 {NET_IPV4_VS_SECURE_TCP, "secure_tcp",
+	  &sysctl_ip_vs_secure_tcp, sizeof(int), 0644, NULL,
+	  &ip_vs_sysctl_defense_mode},
+	 {NET_IPV4_VS_TO_ES, "timeout_established",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_SS, "timeout_synsent",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_SR, "timeout_synrecv",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_FW, "timeout_finwait",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_TW, "timeout_timewait",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_TIME_WAIT],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_CL, "timeout_close",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_CW, "timeout_closewait",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_LA, "timeout_lastack",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_LI, "timeout_listen",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_SA, "timeout_synack",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_UDP, "timeout_udp",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_UDP],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_TO_ICMP, "timeout_icmp",
+	  &vs_timeout_table_dos.timeout[IP_VS_S_ICMP],
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {NET_IPV4_VS_CACHE_BYPASS, "cache_bypass",
+	  &sysctl_ip_vs_cache_bypass, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
+	 {NET_IPV4_VS_EXPIRE_NODEST_CONN, "expire_nodest_conn",
+	  &sysctl_ip_vs_expire_nodest_conn, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
+	 {NET_IPV4_VS_SYNC_THRESHOLD, "sync_threshold",
+	  &sysctl_ip_vs_sync_threshold, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
+	 {NET_IPV4_VS_NAT_ICMP_SEND, "nat_icmp_send",
+	  &sysctl_ip_vs_nat_icmp_send, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
+	 {0}},
+	{{NET_IPV4_VS, "vs", NULL, 0, 0555, ipv4_vs_table.vs_vars},
+	 {0}},
+	{{NET_IPV4, "ipv4", NULL, 0, 0555, ipv4_vs_table.vs_dir},
+	 {0}},
+	{{CTL_NET, "net", NULL, 0, 0555, ipv4_vs_table.ipv4_dir},
+	 {0}}
+};
+
+
+/*
+ *	Write the contents of the VS rule table to a PROCfs file.
+ *	(It is kept just for backward compatibility)
+ */
+static inline char *ip_vs_fwd_name(unsigned flags)
+{
+	char *fwd;
+
+	switch (flags & IP_VS_CONN_F_FWD_MASK) {
+	case IP_VS_CONN_F_LOCALNODE:
+		fwd = "Local";
+		break;
+	case IP_VS_CONN_F_TUNNEL:
+		fwd = "Tunnel";
+		break;
+	case IP_VS_CONN_F_DROUTE:
+		fwd = "Route";
+		break;
+	default:
+		fwd = "Masq";
+	}
+	return fwd;
+}
+
+static int ip_vs_get_info(char *buf, char **start, off_t offset, int length)
+{
+	int len=0;
+	off_t pos=0;
+	char temp[64], temp2[32];
+	int idx;
+	struct ip_vs_service *svc;
+	struct ip_vs_dest *dest;
+	struct list_head *l, *e, *p, *q;
+
+	/*
+	 * Note: since the length of the buffer is usually the multiple
+	 * of 512, it is good to use fixed record of the divisor of 512,
+	 * so that records won't be truncated at buffer boundary.
+	 */
+	pos = 192;
+	if (pos > offset) {
+		sprintf(temp,
+			"IP Virtual Server version %d.%d.%d (size=%d)",
+			NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE);
+		len += sprintf(buf+len, "%-63s\n", temp);
+		len += sprintf(buf+len, "%-63s\n",
+			       "Prot LocalAddress:Port Scheduler Flags");
+		len += sprintf(buf+len, "%-63s\n",
+			       "  -> RemoteAddress:Port Forward Weight ActiveConn InActConn");
+	}
+
+	read_lock_bh(&__ip_vs_svc_lock);
+
+	/* print the service table hashed by <protocol,addr,port> */
+	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		l = &ip_vs_svc_table[idx];
+		for (e=l->next; e!=l; e=e->next) {
+			svc = list_entry(e, struct ip_vs_service, s_list);
+			pos += 64;
+			if (pos > offset) {
+				if (svc->flags & IP_VS_SVC_F_PERSISTENT)
+					sprintf(temp2, "persistent %d %08X",
+						svc->timeout,
+						ntohl(svc->netmask));
+				else
+					temp2[0] = '\0';
+
+				sprintf(temp, "%s  %08X:%04X %s %s",
+					ip_vs_proto_name(svc->protocol),
+					ntohl(svc->addr),
+					ntohs(svc->port),
+					svc->scheduler->name, temp2);
+				len += sprintf(buf+len, "%-63s\n", temp);
+				if (len >= length)
+					goto done;
+			}
+
+			p = &svc->destinations;
+			for (q=p->next; q!=p; q=q->next) {
+				dest = list_entry(q, struct ip_vs_dest, n_list);
+				pos += 64;
+				if (pos <= offset)
+					continue;
+				sprintf(temp,
+					"  -> %08X:%04X      %-7s %-6d %-10d %-10d",
+					ntohl(dest->addr),
+					ntohs(dest->port),
+					ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
+					atomic_read(&dest->weight),
+					atomic_read(&dest->activeconns),
+					atomic_read(&dest->inactconns));
+				len += sprintf(buf+len, "%-63s\n", temp);
+				if (len >= length)
+					goto done;
+			}
+		}
+	}
+
+	/* print the service table hashed by fwmark */
+	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		l = &ip_vs_svc_fwm_table[idx];
+		for (e=l->next; e!=l; e=e->next) {
+			svc = list_entry(e, struct ip_vs_service, f_list);
+			pos += 64;
+			if (pos > offset) {
+				if (svc->flags & IP_VS_SVC_F_PERSISTENT)
+					sprintf(temp2, "persistent %d %08X",
+						svc->timeout,
+						ntohl(svc->netmask));
+				else
+					temp2[0] = '\0';
+
+				sprintf(temp, "FWM  %08X %s %s",
+					svc->fwmark,
+					svc->scheduler->name, temp2);
+				len += sprintf(buf+len, "%-63s\n", temp);
+				if (len >= length)
+					goto done;
+			}
+
+			p = &svc->destinations;
+			for (q=p->next; q!=p; q=q->next) {
+				dest = list_entry(q, struct ip_vs_dest, n_list);
+				pos += 64;
+				if (pos <= offset)
+					continue;
+				sprintf(temp,
+					"  -> %08X:%04X      %-7s %-6d %-10d %-10d",
+					ntohl(dest->addr),
+					ntohs(dest->port),
+					ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
+					atomic_read(&dest->weight),
+					atomic_read(&dest->activeconns),
+					atomic_read(&dest->inactconns));
+				len += sprintf(buf+len, "%-63s\n", temp);
+				if (len >= length)
+					goto done;
+			}
+		}
+	}
+
+  done:
+	read_unlock_bh(&__ip_vs_svc_lock);
+
+	*start = buf+len-(pos-offset);          /* Start of wanted data */
+	len = pos-offset;
+	if (len > length)
+		len = length;
+	if (len < 0)
+		len = 0;
+	return len;
+}
+
+
+struct ip_vs_stats ip_vs_stats;
+
+static int
+ip_vs_stats_get_info(char *buf, char **start, off_t offset, int length)
+{
+	int len=0;
+	off_t pos=0;
+	char temp[64];
+
+	pos += 320;
+	if (pos > offset) {
+		len += sprintf(buf+len, "%-63s\n%-63s\n",
+/*                              01234567 01234567 01234567 0123456701234567 0123456701234567 */
+			       "   Total Incoming Outgoing         Incoming         Outgoing",
+			       "   Conns  Packets  Packets            Bytes            Bytes");
+
+		spin_lock_bh(&ip_vs_stats.lock);
+		sprintf(temp, "%8X %8X %8X %8X%08X %8X%08X",
+			ip_vs_stats.conns,
+			ip_vs_stats.inpkts,
+			ip_vs_stats.outpkts,
+			(__u32)(ip_vs_stats.inbytes>>32),
+			(__u32)ip_vs_stats.inbytes,
+			(__u32)(ip_vs_stats.outbytes>>32),
+			(__u32)ip_vs_stats.outbytes);
+		len += sprintf(buf+len, "%-62s\n\n", temp);
+
+		len += sprintf(buf+len, "%-63s\n",
+/*                              01234567 01234567 01234567 0123456701234567 0123456701234567 */
+			       " Conns/s   Pkts/s   Pkts/s          Bytes/s          Bytes/s");
+		sprintf(temp, "%8X %8X %8X %16X %16X",
+			ip_vs_stats.cps,
+			ip_vs_stats.inpps,
+			ip_vs_stats.outpps,
+			ip_vs_stats.inbps,
+			ip_vs_stats.outbps);
+		len += sprintf(buf+len, "%-63s\n", temp);
+
+		spin_unlock_bh(&ip_vs_stats.lock);
+	}
+
+	*start = buf+len-(pos-offset);          /* Start of wanted data */
+	len = pos-offset;
+	if (len > length)
+		len = length;
+	if (len < 0)
+		len = 0;
+	return len;
+}
+
+
+/*
+ * Set timeout values for tcp tcpfin udp in the vs_timeout_table.
+ */
+static int ip_vs_set_timeouts(struct ip_vs_rule_user *u)
+{
+	IP_VS_DBG(2, "Setting timeout tcp:%d tcpfin:%d udp:%d\n",
+		  u->tcp_timeout,
+		  u->tcp_fin_timeout,
+		  u->udp_timeout);
+
+	if (u->tcp_timeout) {
+		vs_timeout_table.timeout[IP_VS_S_ESTABLISHED]
+			= u->tcp_timeout * HZ;
+	}
+
+	if (u->tcp_fin_timeout) {
+		vs_timeout_table.timeout[IP_VS_S_FIN_WAIT]
+			= u->tcp_fin_timeout * HZ;
+	}
+
+	if (u->udp_timeout) {
+		vs_timeout_table.timeout[IP_VS_S_UDP]
+			= u->udp_timeout * HZ;
+	}
+	return 0;
+}
+
+
+static int
+do_ip_vs_set_ctl(struct sock *sk, int cmd, void *user, unsigned int len)
+{
+	int ret;
+	struct ip_vs_rule_user *urule;
+	struct ip_vs_service *svc = NULL;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	/*
+	 * Check the size of mm, no overflow...
+	 * len > 128000 is a sanity check.
+	 */
+	if (len < sizeof(struct ip_vs_rule_user)) {
+		IP_VS_ERR("set_ctl: len %u < %u\n",
+			  len, sizeof(struct ip_vs_rule_user));
+		return -EINVAL;
+	} else if (len > 128000) {
+		IP_VS_ERR("set_ctl: len %u > 128000\n", len);
+		return -EINVAL;
+	} else if ((urule = kmalloc(len, GFP_KERNEL)) == NULL) {
+		IP_VS_ERR("set_ctl: no mem for len %u\n", len);
+		return -ENOMEM;
+	} else if (copy_from_user(urule, user, len) != 0) {
+		ret = -EFAULT;
+		goto out_free;
+	}
+
+	MOD_INC_USE_COUNT;
+	if (down_interruptible(&__ip_vs_mutex)) {
+		ret = -ERESTARTSYS;
+		goto out_dec;
+	}
+
+	if (cmd == IP_VS_SO_SET_FLUSH) {
+		/* Flush the virtual service */
+		ret = ip_vs_flush();
+		goto out_unlock;
+	} else if (cmd == IP_VS_SO_SET_TIMEOUTS) {
+		/* Set timeout values for (tcp tcpfin udp) */
+		ret = ip_vs_set_timeouts(urule);
+		goto out_unlock;
+	} else if (cmd == IP_VS_SO_SET_STARTDAEMON) {
+		ret = start_sync_thread(urule->state, urule->mcast_ifn);
+		goto out_unlock;
+	} else if (cmd == IP_VS_SO_SET_STOPDAEMON) {
+		ret = stop_sync_thread();
+		goto out_unlock;
+	} else if (cmd == IP_VS_SO_SET_ZERO) {
+		/* if no service address is set, zero counters in all */
+		if (!urule->vfwmark && !urule->vaddr && !urule->vport) {
+			ret = ip_vs_zero_all();
+			goto out_unlock;
+		}
+	}
+
+	/*
+	 * Check for valid protocol: TCP or UDP. Even for fwmark!=0
+	 */
+	if (urule->protocol!=IPPROTO_TCP && urule->protocol!=IPPROTO_UDP) {
+		IP_VS_INFO("vs_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s",
+			   ntohs(urule->protocol), NIPQUAD(urule->vaddr),
+			   ntohs(urule->vport), urule->sched_name);
+		ret = -EFAULT;
+		goto out_unlock;
+	}
+
+	/*
+	 * Lookup the exact service by <protocol, vaddr, vport> or fwmark
+	 */
+	if (urule->vfwmark == 0)
+		svc = __ip_vs_service_get(urule->protocol,
+					  urule->vaddr, urule->vport);
+	else
+		svc = __ip_vs_svc_fwm_get(urule->vfwmark);
+
+	if (cmd != IP_VS_SO_SET_ADD
+	    && (svc == NULL || svc->protocol != urule->protocol)) {
+		ret = -ESRCH;
+		goto out_unlock;
+	}
+
+	switch (cmd) {
+	case IP_VS_SO_SET_ADD:
+		if (svc != NULL)
+			ret = -EEXIST;
+		else
+			ret = ip_vs_add_service(urule, &svc);
+		break;
+	case IP_VS_SO_SET_EDIT:
+		ret = ip_vs_edit_service(svc, urule);
+		break;
+	case IP_VS_SO_SET_DEL:
+		ret = ip_vs_del_service(svc);
+		if (!ret)
+			goto out_unlock;
+		break;
+	case IP_VS_SO_SET_ADDDEST:
+		ret = ip_vs_add_dest(svc, urule);
+		break;
+	case IP_VS_SO_SET_EDITDEST:
+		ret = ip_vs_edit_dest(svc, urule);
+		break;
+	case IP_VS_SO_SET_DELDEST:
+		ret = ip_vs_del_dest(svc, urule);
+		break;
+	case IP_VS_SO_SET_ZERO:
+		ret = ip_vs_zero_service(svc);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (svc)
+		ip_vs_service_put(svc);
+
+  out_unlock:
+	up(&__ip_vs_mutex);
+  out_dec:
+	MOD_DEC_USE_COUNT;
+  out_free:
+	kfree(urule);
+	return ret;
+}
+
+
+static inline void
+__ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src)
+{
+	spin_lock_bh(&src->lock);
+	memcpy(dst, src, (char*)&src->lock - (char*)src);
+	spin_unlock_bh(&src->lock);
+}
+
+static inline int
+__ip_vs_get_service_entries(const struct ip_vs_get_services *get,
+			    struct ip_vs_get_services *uptr)
+{
+	int idx, count=0;
+	struct ip_vs_service *svc;
+	struct list_head *l;
+	struct ip_vs_service_user entry;
+	int ret = 0;
+
+	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each (l, &ip_vs_svc_table[idx]) {
+			if (count >= get->num_services)
+				goto out;
+			svc = list_entry(l, struct ip_vs_service, s_list);
+			entry.protocol = svc->protocol;
+			entry.addr = svc->addr;
+			entry.port = svc->port;
+			entry.fwmark = svc->fwmark;
+			strcpy(entry.sched_name, svc->scheduler->name);
+			entry.flags = svc->flags;
+			entry.timeout = svc->timeout / HZ;
+			entry.netmask = svc->netmask;
+			entry.num_dests = svc->num_dests;
+			__ip_vs_copy_stats(&entry.stats, &svc->stats);
+			if (copy_to_user(&uptr->entrytable[count],
+					 &entry, sizeof(entry))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			count++;
+		}
+	}
+
+	for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
+		list_for_each (l, &ip_vs_svc_fwm_table[idx]) {
+			if (count >= get->num_services)
+				goto out;
+			svc = list_entry(l, struct ip_vs_service, f_list);
+			entry.protocol = svc->protocol;
+			entry.addr = svc->addr;
+			entry.port = svc->port;
+			entry.fwmark = svc->fwmark;
+			strcpy(entry.sched_name, svc->scheduler->name);
+			entry.flags = svc->flags;
+			entry.timeout = svc->timeout / HZ;
+			entry.netmask = svc->netmask;
+			entry.num_dests = svc->num_dests;
+			__ip_vs_copy_stats(&entry.stats, &svc->stats);
+			if (copy_to_user(&uptr->entrytable[count],
+					 &entry, sizeof(entry))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			count++;
+		}
+	}
+ out:
+	return ret;
+}
+
+static inline int
+__ip_vs_get_dest_entries(const struct ip_vs_get_dests *get,
+			 struct ip_vs_get_dests *uptr)
+{
+	struct ip_vs_service *svc;
+	int ret = 0;
+
+	if (get->fwmark)
+		svc = __ip_vs_svc_fwm_get(get->fwmark);
+	else
+		svc = __ip_vs_service_get(get->protocol,
+					  get->addr, get->port);
+	if (svc) {
+		int count = 0;
+		struct ip_vs_dest *dest;
+		struct list_head *l, *e;
+		struct ip_vs_dest_user entry;
+
+		l = &svc->destinations;
+		for (e=l->next; e!=l; e=e->next) {
+			if (count >= get->num_dests)
+				break;
+			dest = list_entry(e, struct ip_vs_dest, n_list);
+			entry.addr = dest->addr;
+			entry.port = dest->port;
+			entry.flags = atomic_read(&dest->conn_flags);
+			entry.weight = atomic_read(&dest->weight);
+			entry.activeconns = atomic_read(&dest->activeconns);
+			entry.inactconns = atomic_read(&dest->inactconns);
+			__ip_vs_copy_stats(&entry.stats, &dest->stats);
+			if (copy_to_user(&uptr->entrytable[count],
+					 &entry, sizeof(entry))) {
+				ret = -EFAULT;
+				break;
+			}
+			count++;
+		}
+		ip_vs_service_put(svc);
+	} else
+		ret = -ESRCH;
+	return ret;
+}
+
+static inline void
+__ip_vs_get_timeouts(struct ip_vs_timeout_user *u)
+{
+	u->tcp_timeout = vs_timeout_table.timeout[IP_VS_S_ESTABLISHED] / HZ;
+	u->tcp_fin_timeout = vs_timeout_table.timeout[IP_VS_S_FIN_WAIT] / HZ;
+	u->udp_timeout = vs_timeout_table.timeout[IP_VS_S_UDP] / HZ;
+}
+
+static int
+do_ip_vs_get_ctl(struct sock *sk, int cmd, void *user, int *len)
+{
+	int ret = 0;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (down_interruptible(&__ip_vs_mutex))
+		return -ERESTARTSYS;
+
+	switch (cmd) {
+	case IP_VS_SO_GET_VERSION:
+	{
+		char buf[64];
+
+		sprintf(buf, "IP Virtual Server version %d.%d.%d (size=%d)",
+			NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE);
+		if (*len < strlen(buf)+1) {
+			ret = -EINVAL;
+			goto out;
+		}
+		if (copy_to_user(user, buf, strlen(buf)+1) != 0) {
+			ret = -EFAULT;
+			goto out;
+		}
+		*len = strlen(buf)+1;
+	}
+	break;
+
+	case IP_VS_SO_GET_INFO:
+	{
+		struct ip_vs_getinfo info;
+		info.version = IP_VS_VERSION_CODE;
+		info.size = IP_VS_CONN_TAB_SIZE;
+		info.num_services = ip_vs_num_services;
+		if (copy_to_user(user, &info, sizeof(info)) != 0)
+			ret = -EFAULT;
+	}
+	break;
+
+	case IP_VS_SO_GET_SERVICES:
+	{
+		struct ip_vs_get_services get;
+
+		if (*len < sizeof(get)) {
+			IP_VS_ERR("length: %u < %u\n", *len, sizeof(get));
+			ret = -EINVAL;
+			goto out;
+		}
+		if (copy_from_user(&get, user, sizeof(get))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		if (*len != (sizeof(get)+sizeof(struct ip_vs_service_user)*get.num_services)) {
+			IP_VS_ERR("length: %u != %u\n", *len,
+				  sizeof(get)+sizeof(struct ip_vs_service_user)*get.num_services);
+			ret = -EINVAL;
+			goto out;
+		}
+		ret = __ip_vs_get_service_entries(&get, user);
+	}
+	break;
+
+	case IP_VS_SO_GET_SERVICE:
+	{
+		struct ip_vs_service_user get;
+		struct ip_vs_service *svc;
+
+		if (*len != sizeof(get)) {
+			IP_VS_ERR("length: %u != %u\n", *len, sizeof(get));
+			ret = -EINVAL;
+			goto out;
+		}
+		if (copy_from_user(&get, user, sizeof(get))) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		if (get.fwmark)
+			svc = __ip_vs_svc_fwm_get(get.fwmark);
+		else
+			svc = __ip_vs_service_get(get.protocol,
+						  get.addr, get.port);
+		if (svc) {
+			strcpy(get.sched_name, svc->scheduler->name);
+			get.flags = svc->flags;
+			get.timeout = svc->timeout / HZ;
+			get.netmask = svc->netmask;
+			get.num_dests = svc->num_dests;
+			__ip_vs_copy_stats(&get.stats, &svc->stats);
+			if (copy_to_user(user, &get, *len) != 0)
+				ret = -EFAULT;
+			ip_vs_service_put(svc);
+		} else
+			ret = -ESRCH;
+	}
+	break;
+
+	case IP_VS_SO_GET_DESTS:
+	{
+		struct ip_vs_get_dests get;
+
+		if (*len < sizeof(get)) {
+			IP_VS_ERR("length: %u < %u\n", *len, sizeof(get));
+			ret = -EINVAL;
+			goto out;
+		}
+		if (copy_from_user(&get, user, sizeof(get))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		if (*len != (sizeof(get) +
+			     sizeof(struct ip_vs_dest_user)*get.num_dests)) {
+			IP_VS_ERR("length: %u != %u\n", *len,
+				  sizeof(get)+sizeof(struct ip_vs_dest_user)*get.num_dests);
+			ret = -EINVAL;
+			goto out;
+		}
+		ret = __ip_vs_get_dest_entries(&get, user);
+	}
+	break;
+
+	case IP_VS_SO_GET_TIMEOUTS:
+	{
+		struct ip_vs_timeout_user u;
+
+		if (*len < sizeof(u)) {
+			IP_VS_ERR("length: %u < %u\n", *len, sizeof(u));
+			ret = -EINVAL;
+			goto out;
+		}
+		__ip_vs_get_timeouts(&u);
+		if (copy_to_user(user, &u, sizeof(u)) != 0)
+			ret = -EFAULT;
+	}
+	break;
+
+	case IP_VS_SO_GET_DAEMON:
+	{
+		struct ip_vs_daemon_user u;
+
+		if (*len < sizeof(u)) {
+			IP_VS_ERR("length: %u < %u\n", *len, sizeof(u));
+			ret = -EINVAL;
+			goto out;
+		}
+		u.state = ip_vs_sync_state;
+		strcpy(u.mcast_ifn, ip_vs_mcast_ifn);
+		if (copy_to_user(user, &u, sizeof(u)) != 0)
+			ret = -EFAULT;
+	}
+	break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+  out:
+	up(&__ip_vs_mutex);
+	return ret;
+}
+
+
+static struct nf_sockopt_ops ip_vs_sockopts = {
+	{ NULL, NULL }, PF_INET,
+	IP_VS_BASE_CTL, IP_VS_SO_SET_MAX+1, do_ip_vs_set_ctl,
+	IP_VS_BASE_CTL, IP_VS_SO_GET_MAX+1, do_ip_vs_get_ctl
+};
+
+
+int ip_vs_control_init(void)
+{
+	int ret;
+	int idx;
+
+	EnterFunction(2);
+
+	ret = nf_register_sockopt(&ip_vs_sockopts);
+	if (ret) {
+		IP_VS_ERR("cannot register sockopt.\n");
+		return ret;
+	}
+
+	proc_net_create("ip_vs", 0, ip_vs_get_info);
+	proc_net_create("ip_vs_stats", 0, ip_vs_stats_get_info);
+
+	ipv4_vs_table.sysctl_header =
+		register_sysctl_table(ipv4_vs_table.root_dir, 0);
+	/*
+	 * Initilize ip_vs_svc_table, ip_vs_svc_fwm_table, ip_vs_rtable,
+	 * ip_vs_schedulers.
+	 */
+	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++)  {
+		INIT_LIST_HEAD(&ip_vs_svc_table[idx]);
+		INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);
+	}
+	for(idx = 0; idx < IP_VS_RTAB_SIZE; idx++)  {
+		INIT_LIST_HEAD(&ip_vs_rtable[idx]);
+	}
+
+	memset(&ip_vs_stats, 0, sizeof(ip_vs_stats));
+	ip_vs_stats.lock = SPIN_LOCK_UNLOCKED;
+	ip_vs_new_estimator(&ip_vs_stats);
+
+	/* Hook the defense timer */
+	init_timer(&defense_timer);
+	defense_timer.function = defense_timer_handler;
+	defense_timer.expires = jiffies + DEFENSE_TIMER_PERIOD;
+	add_timer(&defense_timer);
+
+	LeaveFunction(2);
+	return 0;
+}
+
+void ip_vs_control_cleanup(void)
+{
+	EnterFunction(2);
+	ip_vs_trash_cleanup();
+	del_timer_sync(&defense_timer);
+	ip_vs_kill_estimator(&ip_vs_stats);
+	unregister_sysctl_table(ipv4_vs_table.sysctl_header);
+	proc_net_remove("ip_vs_stats");
+	proc_net_remove("ip_vs");
+	nf_unregister_sockopt(&ip_vs_sockopts);
+	LeaveFunction(2);
+}
diff -Nru a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_dh.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,265 @@
+/*
+ * IPVS:        Destination Hashing scheduling module
+ *
+ * Version:     $Id: ip_vs_dh.c,v 1.4 2001/10/19 15:05:17 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@gnuchina.org>
+ *
+ *              Inspired by the consistent hashing scheduler patch from
+ *              Thomas Proell <proellt@gmx.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 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ *
+ */
+
+/*
+ * The dh algorithm is to select server by the hash key of destination IP
+ * address. The pseudo code is as follows:
+ *
+ *       n <- servernode[dest_ip];
+ *       if (n is dead) OR
+ *          (n is overloaded, such as n.conns>2*n.weight) then
+ *                 return NULL;
+ *
+ *       return n;
+ *
+ * Notes that servernode is a 256-bucket hash table that maps the hash
+ * index derived from packet destination IP address to the current server
+ * array. If the dh scheduler is used in cache cluster, it is good to
+ * combine it with cache_bypass feature. When the statically assigned
+ * server is dead or overloaded, the load balancer can bypass the cache
+ * server and send requests to the original server directly.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *      IPVS DH bucket
+ */
+struct ip_vs_dh_bucket {
+	struct ip_vs_dest       *dest;          /* real server (cache) */
+};
+
+/*
+ *     for IPVS DH entry hash table
+ */
+#ifndef CONFIG_IP_VS_DH_TAB_BITS
+#define CONFIG_IP_VS_DH_TAB_BITS        8
+#endif
+#define IP_VS_DH_TAB_BITS               CONFIG_IP_VS_DH_TAB_BITS
+#define IP_VS_DH_TAB_SIZE               (1 << IP_VS_DH_TAB_BITS)
+#define IP_VS_DH_TAB_MASK               (IP_VS_DH_TAB_SIZE - 1)
+
+
+/*
+ *	Returns hash value for IPVS DH entry
+ */
+static inline unsigned ip_vs_dh_hashkey(__u32 addr)
+{
+	return (ntohl(addr)*2654435761UL) & IP_VS_DH_TAB_MASK;
+}
+
+
+/*
+ *      Get ip_vs_dest associated with supplied parameters.
+ */
+static inline struct ip_vs_dest *
+ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __u32 addr)
+{
+	return (tbl[ip_vs_dh_hashkey(addr)]).dest;
+}
+
+
+/*
+ *      Assign all the hash buckets of the specified table with the service.
+ */
+static int
+ip_vs_dh_assign(struct ip_vs_dh_bucket *tbl, struct ip_vs_service *svc)
+{
+	int i;
+	struct ip_vs_dh_bucket *b;
+	struct list_head *p;
+	struct ip_vs_dest *dest;
+
+	b = tbl;
+	p = &svc->destinations;
+	for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
+		if (list_empty(p)) {
+			b->dest = NULL;
+		} else {
+			if (p == &svc->destinations)
+				p = p->next;
+
+			dest = list_entry(p, struct ip_vs_dest, n_list);
+			atomic_inc(&dest->refcnt);
+			b->dest = dest;
+
+			p = p->next;
+		}
+		b++;
+	}
+	return 0;
+}
+
+
+/*
+ *      Flush all the hash buckets of the specified table.
+ */
+static void ip_vs_dh_flush(struct ip_vs_dh_bucket *tbl)
+{
+	int i;
+	struct ip_vs_dh_bucket *b;
+
+	b = tbl;
+	for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
+		if (b->dest) {
+			atomic_dec(&b->dest->refcnt);
+			b->dest = NULL;
+		}
+		b++;
+	}
+}
+
+
+static int ip_vs_dh_init_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_dh_bucket *tbl;
+
+	/* allocate the DH table for this service */
+	tbl = kmalloc(sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE,
+		      GFP_ATOMIC);
+	if (tbl == NULL) {
+		IP_VS_ERR("ip_vs_dh_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	svc->sched_data = tbl;
+	IP_VS_DBG(6, "DH hash table (memory=%dbytes) allocated for "
+		  "current service\n",
+		  sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
+
+	/* assign the hash buckets with the updated service */
+	ip_vs_dh_assign(tbl, svc);
+
+	return 0;
+}
+
+
+static int ip_vs_dh_done_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_dh_bucket *tbl = svc->sched_data;
+
+	/* got to clean up hash buckets here */
+	ip_vs_dh_flush(tbl);
+
+	/* release the table itself */
+	kfree(svc->sched_data);
+	IP_VS_DBG(6, "DH hash table (memory=%dbytes) released\n",
+		  sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
+
+	return 0;
+}
+
+
+static int ip_vs_dh_update_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_dh_bucket *tbl = svc->sched_data;
+
+	/* got to clean up hash buckets here */
+	ip_vs_dh_flush(tbl);
+
+	/* assign the hash buckets with the updated service */
+	ip_vs_dh_assign(tbl, svc);
+
+	return 0;
+}
+
+
+/*
+ *      If the number of active connections is twice larger than its weight,
+ *      consider that the server is overloaded here.
+ */
+static inline int is_overloaded(struct ip_vs_dest *dest)
+{
+	if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)*2) {
+		return 1;
+	}
+	return 0;
+}
+
+
+/*
+ *      Destination hashing scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_dh_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct ip_vs_dest *dest;
+	struct ip_vs_dh_bucket *tbl;
+
+	IP_VS_DBG(6, "ip_vs_dh_schedule(): Scheduling...\n");
+
+	tbl = (struct ip_vs_dh_bucket *)svc->sched_data;
+	dest = ip_vs_dh_get(tbl, iph->daddr);
+	if (!dest
+	    || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
+	    || atomic_read(&dest->weight) <= 0
+	    || is_overloaded(dest)) {
+		return NULL;
+	}
+
+	IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
+		  "--> server %u.%u.%u.%u:%d\n",
+		  NIPQUAD(iph->daddr),
+		  NIPQUAD(dest->addr),
+		  ntohs(dest->port));
+
+	return dest;
+}
+
+
+/*
+ *      IPVS DH Scheduler structure
+ */
+static struct ip_vs_scheduler ip_vs_dh_scheduler =
+{
+	{0},                    /* n_list */
+	"dh",                   /* name */
+	ATOMIC_INIT(0),         /* refcnt */
+	THIS_MODULE,            /* this module */
+	ip_vs_dh_init_svc,      /* service initializer */
+	ip_vs_dh_done_svc,      /* service done */
+	ip_vs_dh_update_svc,    /* service updater */
+	ip_vs_dh_schedule,      /* select a server from the destination list */
+};
+
+
+static int __init ip_vs_dh_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_dh_scheduler.n_list);
+	return register_ip_vs_scheduler(&ip_vs_dh_scheduler);
+}
+
+
+static void __exit ip_vs_dh_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_dh_scheduler);
+}
+
+
+module_init(ip_vs_dh_init);
+module_exit(ip_vs_dh_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_est.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,200 @@
+/*
+ * ip_vs_est.c  Simple rate estimator for IPVS
+ *
+ * Version:     $Id: ip_vs_est.c,v 1.3.2.1 2003/07/29 14:37:13 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              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.
+ *
+ * Changes:
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <net/ip_vs.h>
+
+/*
+  This code is to estimate rate in a shorter interval (such as 8
+  seconds) for virtual services and real servers. For measure rate in a
+  long interval, it is easy to implement a user level daemon which
+  periodically reads those statistical counters and measure rate.
+
+  Currently, the measurement is activated by slow timer handler. Hope
+  this measurement will not introduce too much load.
+
+  We measure rate during the last 8 seconds every 2 seconds:
+
+    avgrate = avgrate*(1-W) + rate*W
+
+    where W = 2^(-2)
+
+  NOTES.
+
+  * The stored value for average bps is scaled by 2^5, so that maximal
+    rate is ~2.15Gbits/s, average pps and cps are scaled by 2^10.
+
+  * A lot code is taken from net/sched/estimator.c
+ */
+
+
+struct ip_vs_estimator
+{
+	struct ip_vs_estimator	*next;
+	struct ip_vs_stats	*stats;
+
+	u32			last_conns;
+	u32			last_inpkts;
+	u32			last_outpkts;
+	u64			last_inbytes;
+	u64			last_outbytes;
+
+	u32			cps;
+	u32			inpps;
+	u32			outpps;
+	u32			inbps;
+	u32			outbps;
+};
+
+
+static struct ip_vs_estimator *est_list = NULL;
+static rwlock_t est_lock = RW_LOCK_UNLOCKED;
+static struct timer_list est_timer;
+
+static void estimation_timer(unsigned long arg)
+{
+	struct ip_vs_estimator *e;
+	struct ip_vs_stats *s;
+	u32 n_conns;
+	u32 n_inpkts, n_outpkts;
+	u64 n_inbytes, n_outbytes;
+	u32 rate;
+
+	read_lock(&est_lock);
+	for (e = est_list; e; e = e->next) {
+		s = e->stats;
+
+		spin_lock(&s->lock);
+		n_conns = s->conns;
+		n_inpkts = s->inpkts;
+		n_outpkts = s->outpkts;
+		n_inbytes = s->inbytes;
+		n_outbytes = s->outbytes;
+
+		/* scaled by 2^10, but divided 2 seconds */
+		rate = (n_conns - e->last_conns)<<9;
+		e->last_conns = n_conns;
+		e->cps += ((long)rate - (long)e->cps)>>2;
+		s->cps = (e->cps+0x1FF)>>10;
+
+		rate = (n_inpkts - e->last_inpkts)<<9;
+		e->last_inpkts = n_inpkts;
+		e->inpps += ((long)rate - (long)e->inpps)>>2;
+		s->inpps = (e->inpps+0x1FF)>>10;
+
+		rate = (n_outpkts - e->last_outpkts)<<9;
+		e->last_outpkts = n_outpkts;
+		e->outpps += ((long)rate - (long)e->outpps)>>2;
+		s->outpps = (e->outpps+0x1FF)>>10;
+
+		rate = (n_inbytes - e->last_inbytes)<<4;
+		e->last_inbytes = n_inbytes;
+		e->inbps += ((long)rate - (long)e->inbps)>>2;
+		s->inbps = (e->inbps+0xF)>>5;
+
+		rate = (n_outbytes - e->last_outbytes)<<4;
+		e->last_outbytes = n_outbytes;
+		e->outbps += ((long)rate - (long)e->outbps)>>2;
+		s->outbps = (e->outbps+0xF)>>5;
+		spin_unlock(&s->lock);
+	}
+	read_unlock(&est_lock);
+	mod_timer(&est_timer, jiffies + 2*HZ);
+}
+
+int ip_vs_new_estimator(struct ip_vs_stats *stats)
+{
+	struct ip_vs_estimator *est;
+
+	est = kmalloc(sizeof(*est), GFP_KERNEL);
+	if (est == NULL)
+		return -ENOMEM;
+
+	memset(est, 0, sizeof(*est));
+	est->stats = stats;
+	est->last_conns = stats->conns;
+	est->cps = stats->cps<<10;
+
+	est->last_inpkts = stats->inpkts;
+	est->inpps = stats->inpps<<10;
+
+	est->last_outpkts = stats->outpkts;
+	est->outpps = stats->outpps<<10;
+
+	est->last_inbytes = stats->inbytes;
+	est->inbps = stats->inbps<<5;
+
+	est->last_outbytes = stats->outbytes;
+	est->outbps = stats->outbps<<5;
+
+	est->next = est_list;
+	if (est->next == NULL) {
+		init_timer(&est_timer);
+		est_timer.expires = jiffies + 2*HZ;
+		est_timer.function = estimation_timer;
+		add_timer(&est_timer);
+	}
+	write_lock_bh(&est_lock);
+	est_list = est;
+	write_unlock_bh(&est_lock);
+	return 0;
+}
+
+void ip_vs_kill_estimator(struct ip_vs_stats *stats)
+{
+	struct ip_vs_estimator *est, **pest;
+	int killed = 0;
+
+	write_lock_bh(&est_lock);
+	pest = &est_list;
+	while ((est=*pest) != NULL) {
+		if (est->stats != stats) {
+			pest = &est->next;
+			continue;
+		}
+		*pest = est->next;
+		kfree(est);
+		killed++;
+	}
+	if (killed && est_list == NULL)
+		del_timer_sync(&est_timer);
+	write_unlock_bh(&est_lock);
+}
+
+void ip_vs_zero_estimator(struct ip_vs_stats *stats)
+{
+	struct ip_vs_estimator *e;
+
+	write_lock_bh(&est_lock);
+	for (e = est_list; e; e = e->next) {
+		if (e->stats != stats)
+			continue;
+
+		/* set counters zero */
+		e->last_conns = 0;
+		e->last_inpkts = 0;
+		e->last_outpkts = 0;
+		e->last_inbytes = 0;
+		e->last_outbytes = 0;
+		e->cps = 0;
+		e->inpps = 0;
+		e->outpps = 0;
+		e->inbps = 0;
+		e->outbps = 0;
+	}
+	write_unlock_bh(&est_lock);
+}
diff -Nru a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_ftp.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,407 @@
+/*
+ * IP_VS        ftp application module
+ *
+ * Version:	$Id: ip_vs_ftp.c,v 1.12 2002/08/10 04:32:35 wensong Exp $
+ *
+ * Authors:	Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ * Changes:
+ *
+ *
+ *	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.
+ *
+ * Most code here is taken from ip_masq_ftp.c in kernel 2.2. The difference
+ * is that ip_vs_ftp module handles the reverse direction to ip_masq_ftp.
+ *
+ *		IP_MASQ_FTP ftp masquerading module
+ *
+ * Version:	@(#)ip_masq_ftp.c 0.04   02/05/96
+ *
+ * Author:	Wouter Gadeyne
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+
+#include <net/ip_vs.h>
+
+
+#define SERVER_STRING "227 Entering Passive Mode ("
+#define CLIENT_STRING "PORT "
+
+
+/*
+ * List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[IP_VS_APP_MAX_PORTS] = {21, 0};
+struct ip_vs_app *incarnations[IP_VS_APP_MAX_PORTS];
+
+/*
+ *	Debug level
+ */
+#ifdef CONFIG_IP_VS_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(IP_VS_APP_MAX_PORTS) "i");
+
+/*	Dummy variable */
+static int ip_vs_ftp_pasv;
+
+
+static int
+ip_vs_ftp_init_conn(struct ip_vs_app *vapp, struct ip_vs_conn *cp)
+{
+	return 0;
+}
+
+
+static int
+ip_vs_ftp_done_conn(struct ip_vs_app *vapp, struct ip_vs_conn *cp)
+{
+	return 0;
+}
+
+
+/*
+ * Get <addr,port> from the string "xxx.xxx.xxx.xxx,ppp,ppp", started
+ * with the "pattern" and terminated with the "term" character.
+ * <addr,port> is in network order.
+ */
+static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
+				  const char *pattern, size_t plen, char term,
+				  __u32 *addr, __u16 *port,
+				  char **start, char **end)
+{
+	unsigned char p1,p2,p3,p4,p5,p6;
+
+	while (data < data_limit) {
+		if (strnicmp(data, pattern, plen) != 0) {
+			data++;
+			continue;
+		}
+		*start = data+plen;
+		p1 = simple_strtoul(data+plen, &data, 10);
+		if (*data != ',')
+			continue;
+		p2 = simple_strtoul(data+1, &data, 10);
+		if (*data != ',')
+			continue;
+		p3 = simple_strtoul(data+1, &data, 10);
+		if (*data != ',')
+			continue;
+		p4 = simple_strtoul(data+1, &data, 10);
+		if (*data != ',')
+			continue;
+		p5 = simple_strtoul(data+1, &data, 10);
+		if (*data != ',')
+			continue;
+		p6 = simple_strtoul(data+1, &data, 10);
+		if (*data != term)
+			continue;
+
+		*end = data;
+		*addr = (p4<<24) | (p3<<16) | (p2<<8) | p1;
+		*port = (p6<<8) | p5;
+		return 1;
+	}
+	return 0;
+}
+
+
+/*
+ * Look at outgoing ftp packets to catch the response to a PASV command
+ * from the server (inside-to-outside).
+ * When we see one, we build a connection entry with the client address,
+ * client port 0 (unknown at the moment), the server address and the
+ * server port.  Mark the current connection entry as a control channel
+ * of the new entry. All this work is just to make the data connection
+ * can be scheduled to the right server later.
+ *
+ * The outgoing packet should be something like
+ *   "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)".
+ * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number.
+ */
+static int ip_vs_ftp_out(struct ip_vs_app *vapp,
+			 struct ip_vs_conn *cp, struct sk_buff *skb)
+{
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *data, *data_limit;
+	char *start, *end;
+	__u32 from;
+	__u16 port;
+	struct ip_vs_conn *n_cp;
+	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
+	unsigned buf_len;
+	int diff;
+
+	/* Only useful for established sessions */
+	if (cp->state != IP_VS_S_ESTABLISHED)
+		return 0;
+
+	if (cp->app_data == &ip_vs_ftp_pasv) {
+		iph = skb->nh.iph;
+		th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+		data = (char *)th + (th->doff << 2);
+		data_limit = skb->tail;
+
+		if (ip_vs_ftp_get_addrport(data, data_limit,
+					   SERVER_STRING,
+					   sizeof(SERVER_STRING)-1, ')',
+					   &from, &port,
+					   &start, &end) == 0)
+			return 0;
+
+		IP_VS_DBG(1-debug, "PASV response (%u.%u.%u.%u:%d) -> "
+			  "%u.%u.%u.%u:%d detected\n",
+			  NIPQUAD(from), ntohs(port), NIPQUAD(cp->caddr), 0);
+
+		/*
+		 * Now update or create an connection entry for it
+		 */
+		n_cp = ip_vs_conn_out_get(iph->protocol, from, port,
+					  cp->caddr, 0);
+		if (!n_cp) {
+			n_cp = ip_vs_conn_new(IPPROTO_TCP,
+					      cp->caddr, 0,
+					      cp->vaddr, port,
+					      from, port,
+					      IP_VS_CONN_F_NO_CPORT,
+					      cp->dest);
+			if (!n_cp)
+				return 0;
+
+			/* add its controller */
+			ip_vs_control_add(n_cp, cp);
+
+			/* increase dest's inactive connection counter */
+			if (cp->dest)
+				atomic_inc(&cp->dest->inactconns);
+		}
+
+		/*
+		 * Replace the old passive address with the new one
+		 */
+		from = n_cp->vaddr;
+		port = n_cp->vport;
+		sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from),
+			port&255, port>>8&255);
+		buf_len = strlen(buf);
+
+		/*
+		 * Calculate required delta-offset to keep TCP happy
+		 */
+		diff = buf_len - (end-start);
+
+		if (diff == 0) {
+			/* simply replace it with new passive address */
+			memcpy(start, buf, buf_len);
+		} else {
+			/* fixme: return value isn't checked here */
+			ip_vs_skb_replace(skb, GFP_ATOMIC, start,
+					  end-start, buf, buf_len);
+		}
+
+		cp->app_data = NULL;
+		ip_vs_conn_listen(n_cp);
+		ip_vs_conn_put(n_cp);
+		return diff;
+	}
+	return 0;
+}
+
+
+/*
+ * Look at incoming ftp packets to catch the PASV/PORT command
+ * (outside-to-inside).
+ *
+ * The incoming packet having the PORT command should be something like
+ *      "PORT xxx,xxx,xxx,xxx,ppp,ppp\n".
+ * xxx,xxx,xxx,xxx is the client address, ppp,ppp is the client port number.
+ * In this case, we create a connection entry using the client address and
+ * port, so that the active ftp data connection from the server can reach
+ * the client.
+ */
+static int ip_vs_ftp_in(struct ip_vs_app *vapp,
+			struct ip_vs_conn *cp, struct sk_buff *skb)
+{
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *data, *data_start, *data_limit;
+	char *start, *end;
+	__u32 to;
+	__u16 port;
+	struct ip_vs_conn *n_cp;
+
+	/* Only useful for established sessions */
+	if (cp->state != IP_VS_S_ESTABLISHED)
+		return 0;
+
+	/*
+	 * Detecting whether it is passive
+	 */
+	iph = skb->nh.iph;
+	th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+
+	/* Since there may be OPTIONS in the TCP packet and the HLEN is
+	   the length of the header in 32-bit multiples, it is accurate
+	   to calculate data address by th+HLEN*4 */
+	data = data_start = (char *)th + (th->doff << 2);
+	data_limit = skb->tail;
+
+	while (data < data_limit) {
+		if (strnicmp(data, "PASV\r\n", 6) == 0) {
+			IP_VS_DBG(1-debug, "got PASV at %d of %d\n",
+				  data - data_start,
+				  data_limit - data_start);
+			cp->app_data = &ip_vs_ftp_pasv;
+			return 0;
+		}
+		data++;
+	}
+
+	/*
+	 * To support virtual FTP server, the scenerio is as follows:
+	 *       FTP client ----> Load Balancer ----> FTP server
+	 * First detect the port number in the application data,
+	 * then create a new connection entry for the coming data
+	 * connection.
+	 */
+	data = data_start;
+	data_limit = skb->h.raw + skb->len - 18;
+
+	if (ip_vs_ftp_get_addrport(data, data_limit,
+				   CLIENT_STRING, sizeof(CLIENT_STRING)-1,
+				   '\r', &to, &port,
+				   &start, &end) == 0)
+		return 0;
+
+	IP_VS_DBG(1-debug, "PORT %u.%u.%u.%u:%d detected\n",
+		  NIPQUAD(to), ntohs(port));
+
+	/*
+	 * Now update or create a connection entry for it
+	 */
+	IP_VS_DBG(1-debug, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n",
+		  ip_vs_proto_name(iph->protocol),
+		  NIPQUAD(to), ntohs(port), NIPQUAD(iph->daddr), 0);
+
+	n_cp = ip_vs_conn_in_get(iph->protocol,
+				 to, port,
+				 iph->daddr, htons(ntohs(cp->vport)-1));
+	if (!n_cp) {
+		n_cp = ip_vs_conn_new(IPPROTO_TCP,
+				      to, port,
+				      cp->vaddr, htons(ntohs(cp->vport)-1),
+				      cp->daddr, htons(ntohs(cp->dport)-1),
+				      0,
+				      cp->dest);
+		if (!n_cp)
+			return 0;
+
+		/* add its controller */
+		ip_vs_control_add(n_cp, cp);
+
+		/* increase dest's inactive connection counter */
+		if (cp->dest)
+			atomic_inc(&cp->dest->inactconns);
+	}
+
+	/*
+	 *	Move tunnel to listen state
+	 */
+	ip_vs_conn_listen(n_cp);
+	ip_vs_conn_put(n_cp);
+
+	/* no diff required for incoming packets */
+	return 0;
+}
+
+
+static struct ip_vs_app ip_vs_ftp = {
+	{0},			/* n_list */
+	"ftp",			/* name */
+	0,                      /* type */
+	THIS_MODULE,            /* this module */
+	ip_vs_ftp_init_conn,    /* ip_vs_init_conn */
+	ip_vs_ftp_done_conn,    /* ip_vs_done_conn */
+	ip_vs_ftp_out,          /* pkt_out */
+	ip_vs_ftp_in,           /* pkt_in */
+};
+
+
+/*
+ *	ip_vs_ftp initialization
+ */
+static int __init ip_vs_ftp_init(void)
+{
+	int i, j;
+
+	for (i=0; i<IP_VS_APP_MAX_PORTS; i++) {
+		if (ports[i]) {
+			if (!(incarnations[i] =
+			     kmalloc(sizeof(struct ip_vs_app), GFP_KERNEL)))
+				return -ENOMEM;
+
+			memcpy(incarnations[i], &ip_vs_ftp,
+			       sizeof(struct ip_vs_app));
+			if ((j = register_ip_vs_app(incarnations[i],
+						    IPPROTO_TCP,
+						    ports[i]))) {
+				return j;
+			}
+			IP_VS_DBG(1-debug,
+				  "Ftp: loaded support on port[%d] = %d\n",
+				  i, ports[i]);
+		} else {
+			/* To be safe, force the incarnation table entry
+			   to be NULL */
+			incarnations[i] = NULL;
+		}
+	}
+	return 0;
+}
+
+
+/*
+ *	ip_vs_ftp finish.
+ */
+static void __exit ip_vs_ftp_exit(void)
+{
+	int i, j, k;
+
+	k=0;
+	for (i=0; i<IP_VS_APP_MAX_PORTS; i++) {
+		if (incarnations[i]) {
+			if ((j = unregister_ip_vs_app(incarnations[i]))) {
+				k = j;
+			} else {
+				kfree(incarnations[i]);
+				incarnations[i] = NULL;
+				IP_VS_DBG(1-debug, "Ftp: unloaded support on port[%d] = %d\n",
+					  i, ports[i]);
+			}
+		}
+	}
+}
+
+
+module_init(ip_vs_ftp_init);
+module_exit(ip_vs_ftp_exit);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_lblc.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,624 @@
+/*
+ * IPVS:        Locality-Based Least-Connection scheduling module
+ *
+ * Version:     $Id: ip_vs_lblc.c,v 1.9 2002/03/25 12:44:35 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@gnuchina.org>
+ *
+ *              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.
+ *
+ * Changes:
+ *     Martin Hamilton         :    fixed the terrible locking bugs
+ *                                   *lock(tbl->lock) ==> *lock(&tbl->lock)
+ *     Wensong Zhang           :    fixed the uninitilized tbl->lock bug
+ *     Wensong Zhang           :    added doing full expiration check to
+ *                                   collect stale entries of 24+ hours when
+ *                                   no partial expire check in a half hour
+ *     Julian Anastasov        :    replaced del_timer call with del_timer_sync
+ *                                   to avoid the possible race between timer
+ *                                   handler and del_timer thread in SMP
+ *
+ */
+
+/*
+ * The lblc algorithm is as follows (pseudo code):
+ *
+ *       if cachenode[dest_ip] is null then
+ *               n, cachenode[dest_ip] <- {weighted least-conn node};
+ *       else
+ *               n <- cachenode[dest_ip];
+ *               if (n is dead) OR
+ *                  (n.conns>n.weight AND
+ *                   there is a node m with m.conns<m.weight/2) then
+ *                 n, cachenode[dest_ip] <- {weighted least-conn node};
+ *
+ *       return n;
+ *
+ * Thanks must go to Wenzhuo Zhang for talking WCCP to me and pushing
+ * me to write this module.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+/* for systcl */
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *    It is for garbage collection of stale IPVS lblc entries,
+ *    when the table is full.
+ */
+#define CHECK_EXPIRE_INTERVAL   (60*HZ)
+#define ENTRY_TIMEOUT           (6*60*HZ)
+
+/*
+ *    It is for full expiration check.
+ *    When there is no partial expiration check (garbage collection)
+ *    in a half hour, do a full expiration check to collect stale
+ *    entries that haven't been touched for a day.
+ */
+#define COUNT_FOR_FULL_EXPIRATION   30
+int sysctl_ip_vs_lblc_expiration = 24*60*60*HZ;
+
+
+/*
+ *     for IPVS lblc entry hash table
+ */
+#ifndef CONFIG_IP_VS_LBLC_TAB_BITS
+#define CONFIG_IP_VS_LBLC_TAB_BITS      10
+#endif
+#define IP_VS_LBLC_TAB_BITS     CONFIG_IP_VS_LBLC_TAB_BITS
+#define IP_VS_LBLC_TAB_SIZE     (1 << IP_VS_LBLC_TAB_BITS)
+#define IP_VS_LBLC_TAB_MASK     (IP_VS_LBLC_TAB_SIZE - 1)
+
+
+/*
+ *      IPVS lblc entry represents an association between destination
+ *      IP address and its destination server
+ */
+struct ip_vs_lblc_entry {
+	struct list_head        list;
+	__u32                   addr;           /* destination IP address */
+	struct ip_vs_dest       *dest;          /* real server (cache) */
+	unsigned long           lastuse;        /* last used time */
+};
+
+
+/*
+ *      IPVS lblc hash table
+ */
+struct ip_vs_lblc_table {
+	rwlock_t	        lock;           /* lock for this table */
+	struct list_head        bucket[IP_VS_LBLC_TAB_SIZE];  /* hash bucket */
+	atomic_t                entries;        /* number of entries */
+	int                     max_size;       /* maximum size of entries */
+	struct timer_list       periodic_timer; /* collect stale entries */
+	int                     rover;          /* rover for expire check */
+	int                     counter;        /* counter for no expire */
+};
+
+
+/*
+ *      IPVS LBLC sysctl table
+ */
+struct ip_vs_lblc_sysctl_table {
+	struct ctl_table_header *sysctl_header;
+	ctl_table vs_vars[2];
+	ctl_table vs_dir[2];
+	ctl_table ipv4_dir[2];
+	ctl_table root_dir[2];
+};
+
+
+static struct ip_vs_lblc_sysctl_table lblc_sysctl_table = {
+	NULL,
+	{{NET_IPV4_VS_LBLC_EXPIRE, "lblc_expiration",
+	  &sysctl_ip_vs_lblc_expiration,
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {0}},
+	{{NET_IPV4_VS, "vs", NULL, 0, 0555, lblc_sysctl_table.vs_vars},
+	 {0}},
+	{{NET_IPV4, "ipv4", NULL, 0, 0555, lblc_sysctl_table.vs_dir},
+	 {0}},
+	{{CTL_NET, "net", NULL, 0, 0555, lblc_sysctl_table.ipv4_dir},
+	 {0}}
+};
+
+
+/*
+ *      new/free a ip_vs_lblc_entry, which is a mapping of a destionation
+ *      IP address to a server.
+ */
+static inline struct ip_vs_lblc_entry *
+ip_vs_lblc_new(__u32 daddr, struct ip_vs_dest *dest)
+{
+	struct ip_vs_lblc_entry *en;
+
+	en = kmalloc(sizeof(struct ip_vs_lblc_entry), GFP_ATOMIC);
+	if (en == NULL) {
+		IP_VS_ERR("ip_vs_lblc_new(): no memory\n");
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&en->list);
+	en->addr = daddr;
+
+	atomic_inc(&dest->refcnt);
+	en->dest = dest;
+
+	return en;
+}
+
+
+static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
+{
+	list_del(&en->list);
+	/*
+	 * We don't kfree dest because it is refered either by its service
+	 * or the trash dest list.
+	 */
+	atomic_dec(&en->dest->refcnt);
+	kfree(en);
+}
+
+
+/*
+ *	Returns hash value for IPVS LBLC entry
+ */
+static inline unsigned ip_vs_lblc_hashkey(__u32 addr)
+{
+	return (ntohl(addr)*2654435761UL) & IP_VS_LBLC_TAB_MASK;
+}
+
+
+/*
+ *	Hash an entry in the ip_vs_lblc_table.
+ *	returns bool success.
+ */
+static int
+ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en)
+{
+	unsigned hash;
+
+	if (!list_empty(&en->list)) {
+		IP_VS_ERR("ip_vs_lblc_hash(): request for already hashed, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	/*
+	 *	Hash by destination IP address
+	 */
+	hash = ip_vs_lblc_hashkey(en->addr);
+
+	write_lock(&tbl->lock);
+	list_add(&en->list, &tbl->bucket[hash]);
+	atomic_inc(&tbl->entries);
+	write_unlock(&tbl->lock);
+
+	return 1;
+}
+
+
+#if 0000
+/*
+ *	Unhash ip_vs_lblc_entry from ip_vs_lblc_table.
+ *	returns bool success.
+ */
+static int ip_vs_lblc_unhash(struct ip_vs_lblc_table *tbl,
+			     struct ip_vs_lblc_entry *en)
+{
+	if (list_empty(&en->list)) {
+		IP_VS_ERR("ip_vs_lblc_unhash(): request for not hashed entry, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	/*
+	 * Remove it from the table
+	 */
+	write_lock(&tbl->lock);
+	list_del(&en->list);
+	INIT_LIST_HEAD(&en->list);
+	write_unlock(&tbl->lock);
+
+	return 1;
+}
+#endif
+
+
+/*
+ *  Get ip_vs_lblc_entry associated with supplied parameters.
+ */
+static inline struct ip_vs_lblc_entry *
+ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __u32 addr)
+{
+	unsigned hash;
+	struct ip_vs_lblc_entry *en;
+	struct list_head *l,*e;
+
+	hash = ip_vs_lblc_hashkey(addr);
+	l = &tbl->bucket[hash];
+
+	read_lock(&tbl->lock);
+
+	for (e=l->next; e!=l; e=e->next) {
+		en = list_entry(e, struct ip_vs_lblc_entry, list);
+		if (en->addr == addr) {
+			/* HIT */
+			read_unlock(&tbl->lock);
+			return en;
+		}
+	}
+
+	read_unlock(&tbl->lock);
+
+	return NULL;
+}
+
+
+/*
+ *      Flush all the entries of the specified table.
+ */
+static void ip_vs_lblc_flush(struct ip_vs_lblc_table *tbl)
+{
+	int i;
+	struct list_head *l;
+	struct ip_vs_lblc_entry *en;
+
+	for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
+		write_lock(&tbl->lock);
+		for (l=&tbl->bucket[i]; l->next!=l; ) {
+			en = list_entry(l->next,
+					struct ip_vs_lblc_entry, list);
+			ip_vs_lblc_free(en);
+			atomic_dec(&tbl->entries);
+		}
+		write_unlock(&tbl->lock);
+	}
+}
+
+
+static inline void ip_vs_lblc_full_check(struct ip_vs_lblc_table *tbl)
+{
+	unsigned long now = jiffies;
+	int i, j;
+	struct list_head *l, *e;
+	struct ip_vs_lblc_entry *en;
+
+	for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
+		j = (j + 1) & IP_VS_LBLC_TAB_MASK;
+		e = l = &tbl->bucket[j];
+		write_lock(&tbl->lock);
+		while (e->next != l) {
+			en = list_entry(e->next,
+					struct ip_vs_lblc_entry, list);
+			if ((now - en->lastuse) <
+			    sysctl_ip_vs_lblc_expiration) {
+				e = e->next;
+				continue;
+			}
+			ip_vs_lblc_free(en);
+			atomic_dec(&tbl->entries);
+		}
+		write_unlock(&tbl->lock);
+	}
+	tbl->rover = j;
+}
+
+
+/*
+ *      Periodical timer handler for IPVS lblc table
+ *      It is used to collect stale entries when the number of entries
+ *      exceeds the maximum size of the table.
+ *
+ *      Fixme: we probably need more complicated algorithm to collect
+ *             entries that have not been used for a long time even
+ *             if the number of entries doesn't exceed the maximum size
+ *             of the table.
+ *      The full expiration check is for this purpose now.
+ */
+static void ip_vs_lblc_check_expire(unsigned long data)
+{
+	struct ip_vs_lblc_table *tbl;
+	unsigned long now = jiffies;
+	int goal;
+	int i, j;
+	struct list_head *l, *e;
+	struct ip_vs_lblc_entry *en;
+
+	tbl = (struct ip_vs_lblc_table *)data;
+
+	if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) {
+		/* do full expiration check */
+		ip_vs_lblc_full_check(tbl);
+		tbl->counter = 1;
+		goto out;
+	}
+
+	if (atomic_read(&tbl->entries) <= tbl->max_size) {
+		tbl->counter++;
+		goto out;
+	}
+
+	goal = (atomic_read(&tbl->entries) - tbl->max_size)*4/3;
+	if (goal > tbl->max_size/2)
+		goal = tbl->max_size/2;
+
+	for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
+		j = (j + 1) & IP_VS_LBLC_TAB_MASK;
+		e = l = &tbl->bucket[j];
+		write_lock(&tbl->lock);
+		while (e->next != l) {
+			en = list_entry(e->next,
+					struct ip_vs_lblc_entry, list);
+			if ((now - en->lastuse) < ENTRY_TIMEOUT) {
+				e = e->next;
+				continue;
+			}
+			ip_vs_lblc_free(en);
+			atomic_dec(&tbl->entries);
+			goal--;
+		}
+		write_unlock(&tbl->lock);
+		if (goal <= 0)
+			break;
+	}
+	tbl->rover = j;
+
+  out:
+	mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL);
+}
+
+
+static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
+{
+	int i;
+	struct ip_vs_lblc_table *tbl;
+
+	/*
+	 *    Allocate the ip_vs_lblc_table for this service
+	 */
+	tbl = kmalloc(sizeof(struct ip_vs_lblc_table), GFP_ATOMIC);
+	if (tbl == NULL) {
+		IP_VS_ERR("ip_vs_lblc_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	svc->sched_data = tbl;
+	IP_VS_DBG(6, "LBLC hash table (memory=%dbytes) allocated for "
+		  "current service\n",
+		  sizeof(struct ip_vs_lblc_table));
+
+	/*
+	 *    Initialize the hash buckets
+	 */
+	for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
+		INIT_LIST_HEAD(&tbl->bucket[i]);
+	}
+	tbl->lock = RW_LOCK_UNLOCKED;
+	tbl->max_size = IP_VS_LBLC_TAB_SIZE*16;
+	tbl->rover = 0;
+	tbl->counter = 1;
+
+	/*
+	 *    Hook periodic timer for garbage collection
+	 */
+	init_timer(&tbl->periodic_timer);
+	tbl->periodic_timer.data = (unsigned long)tbl;
+	tbl->periodic_timer.function = ip_vs_lblc_check_expire;
+	tbl->periodic_timer.expires = jiffies+CHECK_EXPIRE_INTERVAL;
+	add_timer(&tbl->periodic_timer);
+
+	return 0;
+}
+
+
+static int ip_vs_lblc_done_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_lblc_table *tbl = svc->sched_data;
+
+	/* remove periodic timer */
+	del_timer_sync(&tbl->periodic_timer);
+
+	/* got to clean up table entries here */
+	ip_vs_lblc_flush(tbl);
+
+	/* release the table itself */
+	kfree(svc->sched_data);
+	IP_VS_DBG(6, "LBLC hash table (memory=%dbytes) released\n",
+		  sizeof(struct ip_vs_lblc_table));
+
+	return 0;
+}
+
+
+static int ip_vs_lblc_update_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static inline struct ip_vs_dest *
+__ip_vs_wlc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	register struct list_head *l, *e;
+	struct ip_vs_dest *dest, *least;
+	int loh, doh;
+
+	/*
+	 * We think the overhead of processing active connections is fifty
+	 * times higher than that of inactive connections in average. (This
+	 * fifty times might not be accurate, we will change it later.) We
+	 * use the following formula to estimate the overhead:
+	 *                dest->activeconns*50 + dest->inactconns
+	 * and the load:
+	 *                (dest overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *                h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connection.
+	 */
+
+	l = &svc->destinations;
+	for (e=l->next; e!=l; e=e->next) {
+		least = list_entry(e, struct ip_vs_dest, n_list);
+		if (atomic_read(&least->weight) > 0) {
+			loh = atomic_read(&least->activeconns) * 50
+				+ atomic_read(&least->inactconns);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	for (e=e->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		doh = atomic_read(&dest->activeconns) * 50
+			+ atomic_read(&dest->inactconns);
+		if (loh * atomic_read(&dest->weight) >
+		    doh * atomic_read(&least->weight)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(least->addr), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->refcnt),
+		  atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+/*
+ *   If this destination server is overloaded and there is a less loaded
+ *   server, then return true.
+ */
+static inline int
+is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
+{
+	if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
+		register struct list_head *l, *e;
+		struct ip_vs_dest *d;
+
+		l = &svc->destinations;
+		for (e=l->next; e!=l; e=e->next) {
+			d = list_entry(e, struct ip_vs_dest, n_list);
+			if (atomic_read(&d->activeconns)*2
+			    < atomic_read(&d->weight)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+
+/*
+ *    Locality-Based (weighted) Least-Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_lblc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct ip_vs_dest *dest;
+	struct ip_vs_lblc_table *tbl;
+	struct ip_vs_lblc_entry *en;
+
+	IP_VS_DBG(6, "ip_vs_lblc_schedule(): Scheduling...\n");
+
+	tbl = (struct ip_vs_lblc_table *)svc->sched_data;
+	en = ip_vs_lblc_get(tbl, iph->daddr);
+	if (en == NULL) {
+		dest = __ip_vs_wlc_schedule(svc, iph);
+		if (dest == NULL) {
+			IP_VS_DBG(1, "no destination available\n");
+			return NULL;
+		}
+		en = ip_vs_lblc_new(iph->daddr, dest);
+		if (en == NULL) {
+			return NULL;
+		}
+		ip_vs_lblc_hash(tbl, en);
+	} else {
+		dest = en->dest;
+		if (!(dest->flags & IP_VS_DEST_F_AVAILABLE)
+		    || atomic_read(&dest->weight) <= 0
+		    || is_overloaded(dest, svc)) {
+			dest = __ip_vs_wlc_schedule(svc, iph);
+			if (dest == NULL) {
+				IP_VS_DBG(1, "no destination available\n");
+				return NULL;
+			}
+			atomic_dec(&en->dest->refcnt);
+			atomic_inc(&dest->refcnt);
+			en->dest = dest;
+		}
+	}
+	en->lastuse = jiffies;
+
+	IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u "
+		  "--> server %u.%u.%u.%u:%d\n",
+		  NIPQUAD(en->addr),
+		  NIPQUAD(dest->addr),
+		  ntohs(dest->port));
+
+	return dest;
+}
+
+
+/*
+ *      IPVS LBLC Scheduler structure
+ */
+static struct ip_vs_scheduler ip_vs_lblc_scheduler =
+{
+	{0},                    /* n_list */
+	"lblc",                 /* name */
+	ATOMIC_INIT(0),         /* refcnt */
+	THIS_MODULE,		/* this module */
+	ip_vs_lblc_init_svc,    /* service initializer */
+	ip_vs_lblc_done_svc,    /* service done */
+	ip_vs_lblc_update_svc,  /* service updater */
+	ip_vs_lblc_schedule,    /* select a server from the destination list */
+};
+
+
+static int __init ip_vs_lblc_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_lblc_scheduler.n_list);
+	lblc_sysctl_table.sysctl_header =
+		register_sysctl_table(lblc_sysctl_table.root_dir, 0);
+	return register_ip_vs_scheduler(&ip_vs_lblc_scheduler);
+}
+
+
+static void __exit ip_vs_lblc_cleanup(void)
+{
+	unregister_sysctl_table(lblc_sysctl_table.sysctl_header);
+	unregister_ip_vs_scheduler(&ip_vs_lblc_scheduler);
+}
+
+
+module_init(ip_vs_lblc_init);
+module_exit(ip_vs_lblc_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,884 @@
+/*
+ * IPVS:        Locality-Based Least-Connection with Replication scheduler
+ *
+ * Version:     $Id: ip_vs_lblcr.c,v 1.10 2002/03/25 12:44:35 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@gnuchina.org>
+ *
+ *              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.
+ *
+ * Changes:
+ *     Julian Anastasov        :    Added the missing (dest->weight>0)
+ *                                  condition in the ip_vs_dest_set_max.
+ *
+ */
+
+/*
+ * The lblc/r algorithm is as follows (pseudo code):
+ *
+ *       if serverSet[dest_ip] is null then
+ *               n, serverSet[dest_ip] <- {weighted least-conn node};
+ *       else
+ *               n <- {least-conn (alive) node in serverSet[dest_ip]};
+ *               if (n is null) OR
+ *                  (n.conns>n.weight AND
+ *                   there is a node m with m.conns<m.weight/2) then
+ *                   n <- {weighted least-conn node};
+ *                   add n to serverSet[dest_ip];
+ *               if |serverSet[dest_ip]| > 1 AND
+ *                   now - serverSet[dest_ip].lastMod > T then
+ *                   m <- {most conn node in serverSet[dest_ip]};
+ *                   remove m from serverSet[dest_ip];
+ *       if serverSet[dest_ip] changed then
+ *               serverSet[dest_ip].lastMod <- now;
+ *
+ *       return n;
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+/* for systcl */
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+/* for proc_net_create/proc_net_remove */
+#include <linux/proc_fs.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *    It is for garbage collection of stale IPVS lblcr entries,
+ *    when the table is full.
+ */
+#define CHECK_EXPIRE_INTERVAL   (60*HZ)
+#define ENTRY_TIMEOUT           (6*60*HZ)
+
+/*
+ *    It is for full expiration check.
+ *    When there is no partial expiration check (garbage collection)
+ *    in a half hour, do a full expiration check to collect stale
+ *    entries that haven't been touched for a day.
+ */
+#define COUNT_FOR_FULL_EXPIRATION   30
+int sysctl_ip_vs_lblcr_expiration = 24*60*60*HZ;
+
+
+/*
+ *     for IPVS lblcr entry hash table
+ */
+#ifndef CONFIG_IP_VS_LBLCR_TAB_BITS
+#define CONFIG_IP_VS_LBLCR_TAB_BITS      10
+#endif
+#define IP_VS_LBLCR_TAB_BITS     CONFIG_IP_VS_LBLCR_TAB_BITS
+#define IP_VS_LBLCR_TAB_SIZE     (1 << IP_VS_LBLCR_TAB_BITS)
+#define IP_VS_LBLCR_TAB_MASK     (IP_VS_LBLCR_TAB_SIZE - 1)
+
+
+/*
+ *      IPVS destination set structure and operations
+ */
+struct ip_vs_dest_list {
+	struct ip_vs_dest_list  *next;          /* list link */
+	struct ip_vs_dest       *dest;          /* destination server */
+};
+
+struct ip_vs_dest_set {
+	atomic_t                size;           /* set size */
+	unsigned long           lastmod;        /* last modified time */
+	struct ip_vs_dest_list  *list;          /* destination list */
+	rwlock_t	        lock;           /* lock for this list */
+};
+
+
+static struct ip_vs_dest_list *
+ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
+{
+	struct ip_vs_dest_list *e;
+
+	for (e=set->list; e!=NULL; e=e->next) {
+		if (e->dest == dest)
+			/* already existed */
+			return NULL;
+	}
+
+	e = kmalloc(sizeof(struct ip_vs_dest_list), GFP_ATOMIC);
+	if (e == NULL) {
+		IP_VS_ERR("ip_vs_dest_set_insert(): no memory\n");
+		return NULL;
+	}
+
+	atomic_inc(&dest->refcnt);
+	e->dest = dest;
+
+	/* link it to the list */
+	write_lock(&set->lock);
+	e->next = set->list;
+	set->list = e;
+	atomic_inc(&set->size);
+	write_unlock(&set->lock);
+
+	set->lastmod = jiffies;
+	return e;
+}
+
+static void
+ip_vs_dest_set_erase(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
+{
+	struct ip_vs_dest_list *e, **ep;
+
+	write_lock(&set->lock);
+	for (ep=&set->list, e=*ep; e!=NULL; e=*ep) {
+		if (e->dest == dest) {
+			/* HIT */
+			*ep = e->next;
+			atomic_dec(&set->size);
+			set->lastmod = jiffies;
+			atomic_dec(&e->dest->refcnt);
+			kfree(e);
+			break;
+		}
+		ep = &e->next;
+	}
+	write_unlock(&set->lock);
+}
+
+static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
+{
+	struct ip_vs_dest_list *e, **ep;
+
+	write_lock(&set->lock);
+	for (ep=&set->list, e=*ep; e!=NULL; e=*ep) {
+		*ep = e->next;
+		/*
+		 * We don't kfree dest because it is refered either
+		 * by its service or by the trash dest list.
+		 */
+		atomic_dec(&e->dest->refcnt);
+		kfree(e);
+	}
+	write_unlock(&set->lock);
+}
+
+/* get weighted least-connection node in the destination set */
+static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
+{
+	register struct ip_vs_dest_list *e;
+	struct ip_vs_dest *dest, *least;
+	int loh, doh;
+
+	if (set == NULL)
+		return NULL;
+
+	read_lock(&set->lock);
+	/* select the first destination server, whose weight > 0 */
+	for (e=set->list; e!=NULL; e=e->next) {
+		least = e->dest;
+		if ((atomic_read(&least->weight) > 0)
+		    && (least->flags & IP_VS_DEST_F_AVAILABLE)) {
+			loh = atomic_read(&least->activeconns) * 50
+				+ atomic_read(&least->inactconns);
+			goto nextstage;
+		}
+	}
+	read_unlock(&set->lock);
+	return NULL;
+
+	/* find the destination with the weighted least load */
+  nextstage:
+	for (e=e->next; e!=NULL; e=e->next) {
+		dest = e->dest;
+		doh = atomic_read(&dest->activeconns) * 50
+			+ atomic_read(&dest->inactconns);
+		if ((loh * atomic_read(&dest->weight) >
+		     doh * atomic_read(&least->weight))
+		    && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+	read_unlock(&set->lock);
+
+	IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(least->addr), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->refcnt),
+		  atomic_read(&least->weight), loh);
+	return least;
+}
+
+
+/* get weighted most-connection node in the destination set */
+static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
+{
+	register struct ip_vs_dest_list *e;
+	struct ip_vs_dest *dest, *most;
+	int moh, doh;
+
+	if (set == NULL)
+		return NULL;
+
+	read_lock(&set->lock);
+	/* select the first destination server, whose weight > 0 */
+	for (e=set->list; e!=NULL; e=e->next) {
+		most = e->dest;
+		if (atomic_read(&most->weight) > 0) {
+			moh = atomic_read(&most->activeconns) * 50
+				+ atomic_read(&most->inactconns);
+			goto nextstage;
+		}
+	}
+	read_unlock(&set->lock);
+	return NULL;
+
+	/* find the destination with the weighted most load */
+  nextstage:
+	for (e=e->next; e!=NULL; e=e->next) {
+		dest = e->dest;
+		doh = atomic_read(&dest->activeconns) * 50
+			+ atomic_read(&dest->inactconns);
+		/* moh/mw < doh/dw ==> moh*dw < doh*mw, where mw,dw>0 */
+		if ((moh * atomic_read(&dest->weight) <
+		     doh * atomic_read(&most->weight))
+		    && (atomic_read(&dest->weight) > 0)) {
+			most = dest;
+			moh = doh;
+		}
+	}
+	read_unlock(&set->lock);
+
+	IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(most->addr), ntohs(most->port),
+		  atomic_read(&most->activeconns),
+		  atomic_read(&most->refcnt),
+		  atomic_read(&most->weight), moh);
+	return most;
+}
+
+
+/*
+ *      IPVS lblcr entry represents an association between destination
+ *      IP address and its destination server set
+ */
+struct ip_vs_lblcr_entry {
+	struct list_head        list;
+	__u32                   addr;           /* destination IP address */
+	struct ip_vs_dest_set   set;            /* destination server set */
+	unsigned long           lastuse;        /* last used time */
+};
+
+
+/*
+ *      IPVS lblcr hash table
+ */
+struct ip_vs_lblcr_table {
+	rwlock_t	        lock;           /* lock for this table */
+	struct list_head        bucket[IP_VS_LBLCR_TAB_SIZE];  /* hash bucket */
+	atomic_t                entries;        /* number of entries */
+	int                     max_size;       /* maximum size of entries */
+	struct timer_list       periodic_timer; /* collect stale entries */
+	int                     rover;          /* rover for expire check */
+	int                     counter;        /* counter for no expire */
+};
+
+
+/*
+ *      IPVS LBLCR sysctl table
+ */
+struct ip_vs_lblcr_sysctl_table {
+	struct ctl_table_header *sysctl_header;
+	ctl_table vs_vars[2];
+	ctl_table vs_dir[2];
+	ctl_table ipv4_dir[2];
+	ctl_table root_dir[2];
+};
+
+
+static struct ip_vs_lblcr_sysctl_table lblcr_sysctl_table = {
+	NULL,
+	{{NET_IPV4_VS_LBLCR_EXPIRE, "lblcr_expiration",
+	  &sysctl_ip_vs_lblcr_expiration,
+	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	 {0}},
+	{{NET_IPV4_VS, "vs", NULL, 0, 0555, lblcr_sysctl_table.vs_vars},
+	 {0}},
+	{{NET_IPV4, "ipv4", NULL, 0, 0555, lblcr_sysctl_table.vs_dir},
+	 {0}},
+	{{CTL_NET, "net", NULL, 0, 0555, lblcr_sysctl_table.ipv4_dir},
+	 {0}}
+};
+
+
+/*
+ *      new/free a ip_vs_lblcr_entry, which is a mapping of a destination
+ *      IP address to a server.
+ */
+static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__u32 daddr)
+{
+	struct ip_vs_lblcr_entry *en;
+
+	en = kmalloc(sizeof(struct ip_vs_lblcr_entry), GFP_ATOMIC);
+	if (en == NULL) {
+		IP_VS_ERR("ip_vs_lblcr_new(): no memory\n");
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&en->list);
+	en->addr = daddr;
+
+	/* initilize its dest set */
+	atomic_set(&(en->set.size), 0);
+	en->set.list = NULL;
+	en->set.lock = RW_LOCK_UNLOCKED;
+
+	return en;
+}
+
+
+static inline void ip_vs_lblcr_free(struct ip_vs_lblcr_entry *en)
+{
+	list_del(&en->list);
+	ip_vs_dest_set_eraseall(&en->set);
+	kfree(en);
+}
+
+
+/*
+ *	Returns hash value for IPVS LBLCR entry
+ */
+static inline unsigned ip_vs_lblcr_hashkey(__u32 addr)
+{
+	return (ntohl(addr)*2654435761UL) & IP_VS_LBLCR_TAB_MASK;
+}
+
+
+/*
+ *	Hash an entry in the ip_vs_lblcr_table.
+ *	returns bool success.
+ */
+static int
+ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en)
+{
+	unsigned hash;
+
+	if (!list_empty(&en->list)) {
+		IP_VS_ERR("ip_vs_lblcr_hash(): request for already hashed, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	/*
+	 *	Hash by destination IP address
+	 */
+	hash = ip_vs_lblcr_hashkey(en->addr);
+
+	write_lock(&tbl->lock);
+	list_add(&en->list, &tbl->bucket[hash]);
+	atomic_inc(&tbl->entries);
+	write_unlock(&tbl->lock);
+
+	return 1;
+}
+
+
+#if 0000
+/*
+ *	Unhash ip_vs_lblcr_entry from ip_vs_lblcr_table.
+ *	returns bool success.
+ */
+static int ip_vs_lblcr_unhash(struct ip_vs_lblcr_table *tbl,
+			     struct ip_vs_lblcr_entry *en)
+{
+	if (list_empty(&en->list)) {
+		IP_VS_ERR("ip_vs_lblcr_unhash(): request for not hashed entry, "
+			  "called from %p\n", __builtin_return_address(0));
+		return 0;
+	}
+
+	/*
+	 * Remove it from the table
+	 */
+	write_lock(&tbl->lock);
+	list_del(&en->list);
+	INIT_LIST_HEAD(&en->list);
+	write_unlock(&tbl->lock);
+
+	return 1;
+}
+#endif
+
+
+/*
+ *  Get ip_vs_lblcr_entry associated with supplied parameters.
+ */
+static inline struct ip_vs_lblcr_entry *
+ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __u32 addr)
+{
+	unsigned hash;
+	struct ip_vs_lblcr_entry *en;
+	struct list_head *l,*e;
+
+	hash = ip_vs_lblcr_hashkey(addr);
+	l = &tbl->bucket[hash];
+
+	read_lock(&tbl->lock);
+
+	for (e=l->next; e!=l; e=e->next) {
+		en = list_entry(e, struct ip_vs_lblcr_entry, list);
+		if (en->addr == addr) {
+			/* HIT */
+			read_unlock(&tbl->lock);
+			return en;
+		}
+	}
+
+	read_unlock(&tbl->lock);
+
+	return NULL;
+}
+
+
+/*
+ *      Flush all the entries of the specified table.
+ */
+static void ip_vs_lblcr_flush(struct ip_vs_lblcr_table *tbl)
+{
+	int i;
+	struct list_head *l;
+	struct ip_vs_lblcr_entry *en;
+
+	for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
+		write_lock(&tbl->lock);
+		for (l=&tbl->bucket[i]; l->next!=l; ) {
+			en = list_entry(l->next,
+					struct ip_vs_lblcr_entry, list);
+			ip_vs_lblcr_free(en);
+			atomic_dec(&tbl->entries);
+		}
+		write_unlock(&tbl->lock);
+	}
+}
+
+
+static inline void ip_vs_lblcr_full_check(struct ip_vs_lblcr_table *tbl)
+{
+	unsigned long now = jiffies;
+	int i, j;
+	struct list_head *l, *e;
+	struct ip_vs_lblcr_entry *en;
+
+	for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) {
+		j = (j + 1) & IP_VS_LBLCR_TAB_MASK;
+		e = l = &tbl->bucket[j];
+		write_lock(&tbl->lock);
+		while (e->next != l) {
+			en = list_entry(e->next,
+					struct ip_vs_lblcr_entry, list);
+			if ((now - en->lastuse) <
+			    sysctl_ip_vs_lblcr_expiration) {
+				e = e->next;
+				continue;
+			}
+			ip_vs_lblcr_free(en);
+			atomic_dec(&tbl->entries);
+		}
+		write_unlock(&tbl->lock);
+	}
+	tbl->rover = j;
+}
+
+
+/*
+ *      Periodical timer handler for IPVS lblcr table
+ *      It is used to collect stale entries when the number of entries
+ *      exceeds the maximum size of the table.
+ *
+ *      Fixme: we probably need more complicated algorithm to collect
+ *             entries that have not been used for a long time even
+ *             if the number of entries doesn't exceed the maximum size
+ *             of the table.
+ *      The full expiration check is for this purpose now.
+ */
+static void ip_vs_lblcr_check_expire(unsigned long data)
+{
+	struct ip_vs_lblcr_table *tbl;
+	unsigned long now = jiffies;
+	int goal;
+	int i, j;
+	struct list_head *l, *e;
+	struct ip_vs_lblcr_entry *en;
+
+	tbl = (struct ip_vs_lblcr_table *)data;
+
+	if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) {
+		/* do full expiration check */
+		ip_vs_lblcr_full_check(tbl);
+		tbl->counter = 1;
+		goto out;
+	}
+
+	if (atomic_read(&tbl->entries) <= tbl->max_size) {
+		tbl->counter++;
+		goto out;
+	}
+
+	goal = (atomic_read(&tbl->entries) - tbl->max_size)*4/3;
+	if (goal > tbl->max_size/2)
+		goal = tbl->max_size/2;
+
+	for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) {
+		j = (j + 1) & IP_VS_LBLCR_TAB_MASK;
+		e = l = &tbl->bucket[j];
+		write_lock(&tbl->lock);
+		while (e->next != l) {
+			en = list_entry(e->next,
+					struct ip_vs_lblcr_entry, list);
+			if ((now - en->lastuse) < ENTRY_TIMEOUT) {
+				e = e->next;
+				continue;
+			}
+			ip_vs_lblcr_free(en);
+			atomic_dec(&tbl->entries);
+			goal--;
+		}
+		write_unlock(&tbl->lock);
+		if (goal <= 0)
+			break;
+	}
+	tbl->rover = j;
+
+  out:
+	mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL);
+}
+
+
+#ifdef CONFIG_IP_VS_LBLCR_DEBUG
+static struct ip_vs_lblcr_table *lblcr_table_list;
+
+/*
+ *	/proc/net/ip_vs_lblcr to display the mappings of
+ *                  destination IP address <==> its serverSet
+ */
+static int
+ip_vs_lblcr_getinfo(char *buffer, char **start, off_t offset, int length)
+{
+	off_t pos=0, begin;
+	int len=0, size;
+	struct ip_vs_lblcr_table *tbl;
+	unsigned long now = jiffies;
+	int i;
+	struct list_head *l, *e;
+	struct ip_vs_lblcr_entry *en;
+
+	tbl = lblcr_table_list;
+
+	size = sprintf(buffer, "LastTime Dest IP address  Server set\n");
+	pos += size;
+	len += size;
+
+	for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
+		l = &tbl->bucket[i];
+		read_lock_bh(&tbl->lock);
+		for (e=l->next; e!=l; e=e->next) {
+			char tbuf[16];
+			struct ip_vs_dest_list *d;
+
+			en = list_entry(e, struct ip_vs_lblcr_entry, list);
+			sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(en->addr));
+			size = sprintf(buffer+len, "%8lu %-16s ",
+				       now-en->lastuse, tbuf);
+
+			read_lock(&en->set.lock);
+			for (d=en->set.list; d!=NULL; d=d->next) {
+				size += sprintf(buffer+len+size,
+						"%u.%u.%u.%u ",
+						NIPQUAD(d->dest->addr));
+			}
+			read_unlock(&en->set.lock);
+			size += sprintf(buffer+len+size, "\n");
+			len += size;
+			pos += size;
+			if (pos <= offset)
+				len=0;
+			if (pos >= offset+length) {
+				read_unlock_bh(&tbl->lock);
+				goto done;
+			}
+		}
+		read_unlock_bh(&tbl->lock);
+	}
+
+  done:
+	begin = len - (pos - offset);
+	*start = buffer + begin;
+	len -= begin;
+	if(len>length)
+		len = length;
+	return len;
+}
+#endif
+
+
+static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc)
+{
+	int i;
+	struct ip_vs_lblcr_table *tbl;
+
+	/*
+	 *    Allocate the ip_vs_lblcr_table for this service
+	 */
+	tbl = kmalloc(sizeof(struct ip_vs_lblcr_table), GFP_ATOMIC);
+	if (tbl == NULL) {
+		IP_VS_ERR("ip_vs_lblcr_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	svc->sched_data = tbl;
+	IP_VS_DBG(6, "LBLCR hash table (memory=%dbytes) allocated for "
+		  "current service\n",
+		  sizeof(struct ip_vs_lblcr_table));
+
+	/*
+	 *    Initialize the hash buckets
+	 */
+	for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
+		INIT_LIST_HEAD(&tbl->bucket[i]);
+	}
+	tbl->lock = RW_LOCK_UNLOCKED;
+	tbl->max_size = IP_VS_LBLCR_TAB_SIZE*16;
+	tbl->rover = 0;
+	tbl->counter = 1;
+
+	/*
+	 *    Hook periodic timer for garbage collection
+	 */
+	init_timer(&tbl->periodic_timer);
+	tbl->periodic_timer.data = (unsigned long)tbl;
+	tbl->periodic_timer.function = ip_vs_lblcr_check_expire;
+	tbl->periodic_timer.expires = jiffies+CHECK_EXPIRE_INTERVAL;
+	add_timer(&tbl->periodic_timer);
+
+#ifdef CONFIG_IP_VS_LBLCR_DEBUG
+	lblcr_table_list = tbl;
+#endif
+	return 0;
+}
+
+
+static int ip_vs_lblcr_done_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_lblcr_table *tbl = svc->sched_data;
+
+	/* remove periodic timer */
+	del_timer_sync(&tbl->periodic_timer);
+
+	/* got to clean up table entries here */
+	ip_vs_lblcr_flush(tbl);
+
+	/* release the table itself */
+	kfree(svc->sched_data);
+	IP_VS_DBG(6, "LBLCR hash table (memory=%dbytes) released\n",
+		  sizeof(struct ip_vs_lblcr_table));
+
+	return 0;
+}
+
+
+static int ip_vs_lblcr_update_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static inline struct ip_vs_dest *
+__ip_vs_wlc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	register struct list_head *l, *e;
+	struct ip_vs_dest *dest, *least;
+	int loh, doh;
+
+	/*
+	 * We think the overhead of processing active connections is fifty
+	 * times higher than that of inactive connections in average. (This
+	 * fifty times might not be accurate, we will change it later.) We
+	 * use the following formula to estimate the overhead:
+	 *                dest->activeconns*50 + dest->inactconns
+	 * and the load:
+	 *                (dest overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *                h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connection.
+	 */
+
+	l = &svc->destinations;
+	for (e=l->next; e!=l; e=e->next) {
+		least = list_entry(e, struct ip_vs_dest, n_list);
+		if (atomic_read(&least->weight) > 0) {
+			loh = atomic_read(&least->activeconns) * 50
+				+ atomic_read(&least->inactconns);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	for (e=e->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		doh = atomic_read(&dest->activeconns) * 50
+			+ atomic_read(&dest->inactconns);
+		if (loh * atomic_read(&dest->weight) >
+		    doh * atomic_read(&least->weight)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(least->addr), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->refcnt),
+		  atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+/*
+ *   If this destination server is overloaded and there is a less loaded
+ *   server, then return true.
+ */
+static inline int
+is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
+{
+	if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
+		register struct list_head *l, *e;
+		struct ip_vs_dest *d;
+
+		l = &svc->destinations;
+		for (e=l->next; e!=l; e=e->next) {
+			d = list_entry(e, struct ip_vs_dest, n_list);
+			if (atomic_read(&d->activeconns)*2
+			    < atomic_read(&d->weight)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+
+/*
+ *    Locality-Based (weighted) Least-Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct ip_vs_dest *dest;
+	struct ip_vs_lblcr_table *tbl;
+	struct ip_vs_lblcr_entry *en;
+
+	IP_VS_DBG(6, "ip_vs_lblcr_schedule(): Scheduling...\n");
+
+	tbl = (struct ip_vs_lblcr_table *)svc->sched_data;
+	en = ip_vs_lblcr_get(tbl, iph->daddr);
+	if (en == NULL) {
+		dest = __ip_vs_wlc_schedule(svc, iph);
+		if (dest == NULL) {
+			IP_VS_DBG(1, "no destination available\n");
+			return NULL;
+		}
+		en = ip_vs_lblcr_new(iph->daddr);
+		if (en == NULL) {
+			return NULL;
+		}
+		ip_vs_dest_set_insert(&en->set, dest);
+		ip_vs_lblcr_hash(tbl, en);
+	} else {
+		dest = ip_vs_dest_set_min(&en->set);
+		if (!dest || is_overloaded(dest, svc)) {
+			dest = __ip_vs_wlc_schedule(svc, iph);
+			if (dest == NULL) {
+				IP_VS_DBG(1, "no destination available\n");
+				return NULL;
+			}
+			ip_vs_dest_set_insert(&en->set, dest);
+		}
+		if (atomic_read(&en->set.size) > 1 &&
+		    jiffies-en->set.lastmod > sysctl_ip_vs_lblcr_expiration) {
+			struct ip_vs_dest *m;
+			m = ip_vs_dest_set_max(&en->set);
+			if (m)
+				ip_vs_dest_set_erase(&en->set, m);
+		}
+	}
+	en->lastuse = jiffies;
+
+	IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u "
+		  "--> server %u.%u.%u.%u:%d\n",
+		  NIPQUAD(en->addr),
+		  NIPQUAD(dest->addr),
+		  ntohs(dest->port));
+
+	return dest;
+}
+
+
+/*
+ *      IPVS LBLCR Scheduler structure
+ */
+static struct ip_vs_scheduler ip_vs_lblcr_scheduler =
+{
+	{0},                     /* n_list */
+	"lblcr",                 /* name */
+	ATOMIC_INIT(0),          /* refcnt */
+	THIS_MODULE,             /* this module */
+	ip_vs_lblcr_init_svc,    /* service initializer */
+	ip_vs_lblcr_done_svc,    /* service done */
+	ip_vs_lblcr_update_svc,  /* service updater */
+	ip_vs_lblcr_schedule,    /* select a server from the destination list */
+};
+
+
+static int __init ip_vs_lblcr_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_lblcr_scheduler.n_list);
+	lblcr_sysctl_table.sysctl_header =
+		register_sysctl_table(lblcr_sysctl_table.root_dir, 0);
+#ifdef CONFIG_IP_VS_LBLCR_DEBUG
+	proc_net_create("ip_vs_lblcr", 0, ip_vs_lblcr_getinfo);
+#endif
+	return register_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
+}
+
+
+static void __exit ip_vs_lblcr_cleanup(void)
+{
+#ifdef CONFIG_IP_VS_LBLCR_DEBUG
+	proc_net_remove("ip_vs_lblcr");
+#endif
+	unregister_sysctl_table(lblcr_sysctl_table.sysctl_header);
+	unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
+}
+
+
+module_init(ip_vs_lblcr_init);
+module_exit(ip_vs_lblcr_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_lc.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,142 @@
+/*
+ * IPVS:        Least-Connection Scheduling module
+ *
+ * Version:     $Id: ip_vs_lc.c,v 1.8.2.1 2003/04/11 14:02:35 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              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.
+ *
+ * Changes:
+ *     Wensong Zhang            :     added the ip_vs_lc_update_svc
+ *     Wensong Zhang            :     added any dest with weight=0 is quiesced
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <net/ip_vs.h>
+
+
+static int ip_vs_lc_init_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static int ip_vs_lc_done_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static int ip_vs_lc_update_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static inline unsigned int
+ip_vs_lc_dest_overhead(struct ip_vs_dest *dest)
+{
+	/*
+	 * We think the overhead of processing active connections is 256
+	 * times higher than that of inactive connections in average. (This
+	 * 256 times might not be accurate, we will change it later) We
+	 * use the following formula to estimate the overhead now:
+	 *		  dest->activeconns*256 + dest->inactconns
+	 */
+	return (atomic_read(&dest->activeconns) << 8) +
+		atomic_read(&dest->inactconns);
+}
+
+
+/*
+ *	Least Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_lc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct list_head *l, *e;
+	struct ip_vs_dest *dest, *least;
+	unsigned int loh, doh;
+
+	IP_VS_DBG(6, "ip_vs_lc_schedule(): Scheduling...\n");
+
+	/*
+	 * Simply select the server with the least number of
+	 *        (activeconns<<5) + inactconns
+	 * Except whose weight is equal to zero.
+	 * If the weight is equal to zero, it means that the server is
+	 * quiesced, the existing connections to the server still get
+	 * served, but no new connection is assigned to the server.
+	 */
+
+	l = &svc->destinations;
+	for (e=l->next; e!=l; e=e->next) {
+		least = list_entry (e, struct ip_vs_dest, n_list);
+		if (atomic_read(&least->weight) > 0) {
+			loh = ip_vs_lc_dest_overhead(least);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	for (e=e->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		if (atomic_read(&dest->weight) == 0)
+			continue;
+		doh = ip_vs_lc_dest_overhead(dest);
+		if (doh < loh) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG(6, "LC: server %u.%u.%u.%u:%u activeconns %d inactconns %d\n",
+		  NIPQUAD(least->addr), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->inactconns));
+
+	return least;
+}
+
+
+static struct ip_vs_scheduler ip_vs_lc_scheduler = {
+	{0},			/* n_list */
+	"lc",			/* name */
+	ATOMIC_INIT(0),		/* refcnt */
+	THIS_MODULE,		/* this module */
+	ip_vs_lc_init_svc,	/* service initializer */
+	ip_vs_lc_done_svc,	/* service done */
+	ip_vs_lc_update_svc,	/* service updater */
+	ip_vs_lc_schedule,	/* select a server from the destination list */
+};
+
+
+static int __init ip_vs_lc_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_lc_scheduler.n_list);
+	return register_ip_vs_scheduler(&ip_vs_lc_scheduler) ;
+}
+
+static void __exit ip_vs_lc_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_lc_scheduler);
+}
+
+module_init(ip_vs_lc_init);
+module_exit(ip_vs_lc_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_nq.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,177 @@
+/*
+ * IPVS:        Never Queue scheduling module
+ *
+ * Version:     $Id: ip_vs_nq.c,v 1.1.2.1 2003/05/20 17:05:02 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+/*
+ * The NQ algorithm adopts a two-speed model. When there is an idle server
+ * available, the job will be sent to the idle server, instead of waiting
+ * for a fast one. When there is no idle server available, the job will be
+ * sent to the server that minimize its expected delay (The Shortest
+ * Expected Delay scheduling algorithm).
+ *
+ * See the following paper for more information:
+ * A. Weinrib and S. Shenker, Greed is not enough: Adaptive load sharing
+ * in large heterogeneous systems. In Proceedings IEEE INFOCOM'88,
+ * pages 986-994, 1988.
+ *
+ * Thanks must go to Marko Buuri <marko@buuri.name> for talking NQ to me.
+ *
+ * The difference between NQ and SED is that NQ can improve overall
+ * system utilization.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <net/ip_vs.h>
+
+
+static int
+ip_vs_nq_init_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static int
+ip_vs_nq_done_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static int
+ip_vs_nq_update_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static inline unsigned int
+ip_vs_nq_dest_overhead(struct ip_vs_dest *dest)
+{
+	/*
+	 * We only use the active connection number in the cost
+	 * calculation here.
+	 */
+	return atomic_read(&dest->activeconns) + 1;
+}
+
+
+/*
+ *	Weighted Least Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_nq_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	register struct list_head *l, *e;
+	struct ip_vs_dest *dest, *least;
+	unsigned int loh, doh;
+
+	IP_VS_DBG(6, "ip_vs_nq_schedule(): Scheduling...\n");
+
+	/*
+	 * We calculate the load of each dest server as follows:
+	 *	(server expected overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *		  h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connections.
+	 */
+
+	l = &svc->destinations;
+	for (e=l->next; e!=l; e=e->next) {
+		least = list_entry(e, struct ip_vs_dest, n_list);
+		if (atomic_read(&least->weight) > 0) {
+			loh = ip_vs_nq_dest_overhead(least);
+
+			/* return the server directly if it is idle */
+			if (atomic_read(&least->activeconns) == 0)
+				goto out;
+
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	for (e=e->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		doh = ip_vs_nq_dest_overhead(dest);
+
+		/* return the server directly if it is idle */
+		if (atomic_read(&dest->activeconns) == 0) {
+			least = dest;
+			loh = doh;
+			goto out;
+		}
+
+		if (loh * atomic_read(&dest->weight) >
+		    doh * atomic_read(&least->weight)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+  out:
+	IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(least->addr), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->refcnt),
+		  atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+static struct ip_vs_scheduler ip_vs_nq_scheduler =
+{
+	.name =			"nq",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.init_service =		ip_vs_nq_init_svc,
+	.done_service =		ip_vs_nq_done_svc,
+	.update_service =	ip_vs_nq_update_svc,
+	.schedule =		ip_vs_nq_schedule,
+};
+
+
+static int __init ip_vs_nq_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_nq_scheduler.n_list);
+	return register_ip_vs_scheduler(&ip_vs_nq_scheduler);
+}
+
+static void __exit ip_vs_nq_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_nq_scheduler);
+}
+
+module_init(ip_vs_nq_init);
+module_exit(ip_vs_nq_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_rr.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,120 @@
+/*
+ * IPVS:        Round-Robin Scheduling module
+ *
+ * Version:     $Id: ip_vs_rr.c,v 1.8 2001/10/19 15:05:17 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *
+ *              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.
+ *
+ * Fixes/Changes:
+ *     Wensong Zhang            :     changed the ip_vs_rr_schedule to return dest
+ *     Julian Anastasov         :     fixed the NULL pointer access bug in debugging
+ *     Wensong Zhang            :     changed some comestics things for debugging
+ *     Wensong Zhang            :     changed for the d-linked destination list
+ *     Wensong Zhang            :     added the ip_vs_rr_update_svc
+ *     Wensong Zhang            :     added any dest with weight=0 is quiesced
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <net/ip_vs.h>
+
+
+static int ip_vs_rr_init_svc(struct ip_vs_service *svc)
+{
+	svc->sched_data = &svc->destinations;
+	return 0;
+}
+
+
+static int ip_vs_rr_done_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static int ip_vs_rr_update_svc(struct ip_vs_service *svc)
+{
+	svc->sched_data = &svc->destinations;
+	return 0;
+}
+
+
+/*
+ * Round-Robin Scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_rr_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	register struct list_head *p, *q;
+	struct ip_vs_dest *dest;
+
+	IP_VS_DBG(6, "ip_vs_rr_schedule(): Scheduling...\n");
+
+	write_lock(&svc->sched_lock);
+	p = (struct list_head *)svc->sched_data;
+	p = p->next;
+	q = p;
+	do {
+		if (q == &svc->destinations) {
+			q = q->next;
+			continue;
+		}
+		dest = list_entry(q, struct ip_vs_dest, n_list);
+		if (atomic_read(&dest->weight) > 0)
+			/* HIT */
+			goto out;
+		q = q->next;
+	} while (q != p);
+	write_unlock(&svc->sched_lock);
+	return NULL;
+
+  out:
+	svc->sched_data = q;
+	write_unlock(&svc->sched_lock);
+	IP_VS_DBG(6, "RR: server %u.%u.%u.%u:%u "
+		  "activeconns %d refcnt %d weight %d\n",
+		  NIPQUAD(dest->addr), ntohs(dest->port),
+		  atomic_read(&dest->activeconns),
+		  atomic_read(&dest->refcnt), atomic_read(&dest->weight));
+
+	return dest;
+}
+
+
+static struct ip_vs_scheduler ip_vs_rr_scheduler = {
+	{0},			/* n_list */
+	"rr",			/* name */
+	ATOMIC_INIT(0),		/* refcnt */
+	THIS_MODULE,		/* this module */
+	ip_vs_rr_init_svc,	/* service initializer */
+	ip_vs_rr_done_svc,	/* service done */
+	ip_vs_rr_update_svc,	/* service updater */
+	ip_vs_rr_schedule,	/* select a server from the destination list */
+};
+
+static int __init ip_vs_rr_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_rr_scheduler.n_list);
+	return register_ip_vs_scheduler(&ip_vs_rr_scheduler);
+}
+
+static void __exit ip_vs_rr_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_rr_scheduler);
+}
+
+module_init(ip_vs_rr_init);
+module_exit(ip_vs_rr_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_sched.c b/net/ipv4/ipvs/ip_vs_sched.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_sched.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,260 @@
+/*
+ * IPVS         An implementation of the IP virtual server support for the
+ *              LINUX operating system.  IPVS is now implemented as a module
+ *              over the Netfilter framework. IPVS can be used to build a
+ *              high-performance and highly available server based on a
+ *              cluster of servers.
+ *
+ * Version:     $Id: ip_vs_sched.c,v 1.11 2001/11/04 08:58:43 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <asm/softirq.h>                /* for local_bh_* */
+#include <asm/string.h>
+#include <linux/kmod.h>
+
+#include <net/ip_vs.h>
+
+/*
+ *  IPVS scheduler list
+ */
+static LIST_HEAD(ip_vs_schedulers);
+
+/* lock for service table */
+static rwlock_t __ip_vs_sched_lock = RW_LOCK_UNLOCKED;
+
+
+/*
+ *  Bind a service with a scheduler
+ */
+int ip_vs_bind_scheduler(struct ip_vs_service *svc,
+			 struct ip_vs_scheduler *scheduler)
+{
+	int ret;
+
+	if (svc == NULL) {
+		IP_VS_ERR("ip_vs_bind_scheduler(): svc arg NULL\n");
+		return -EINVAL;
+	}
+	if (scheduler == NULL) {
+		IP_VS_ERR("ip_vs_bind_scheduler(): scheduler arg NULL\n");
+		return -EINVAL;
+	}
+
+	svc->scheduler = scheduler;
+
+	if (scheduler->init_service) {
+		ret = scheduler->init_service(svc);
+		if (ret) {
+			IP_VS_ERR("ip_vs_bind_scheduler(): init error\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ *  Unbind a service with its scheduler
+ */
+int ip_vs_unbind_scheduler(struct ip_vs_service *svc)
+{
+	struct ip_vs_scheduler *sched;
+
+	if (svc == NULL) {
+		IP_VS_ERR("ip_vs_unbind_scheduler(): svc arg NULL\n");
+		return -EINVAL;
+	}
+
+	sched = svc->scheduler;
+	if (sched == NULL) {
+		IP_VS_ERR("ip_vs_unbind_scheduler(): svc isn't bound\n");
+		return -EINVAL;
+	}
+
+	if (sched->done_service) {
+		if (sched->done_service(svc) != 0) {
+			IP_VS_ERR("ip_vs_unbind_scheduler(): done error\n");
+			return -EINVAL;
+		}
+	}
+
+	svc->scheduler = NULL;
+	return 0;
+}
+
+
+/*
+ *  Get scheduler in the scheduler list by name
+ */
+static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name)
+{
+	struct ip_vs_scheduler *sched;
+	struct list_head *l, *e;
+
+	IP_VS_DBG(2, "ip_vs_sched_getbyname(): sched_name \"%s\"\n",
+		  sched_name);
+
+	l = &ip_vs_schedulers;
+
+	read_lock_bh(&__ip_vs_sched_lock);
+
+	for (e=l->next; e!=l; e=e->next) {
+		sched = list_entry(e, struct ip_vs_scheduler, n_list);
+
+		/*
+		 * Test and MOD_INC_USE_COUNT atomically
+		 */
+		if (sched->module && !try_inc_mod_count(sched->module)) {
+			/*
+			 * This scheduler is just deleted
+			 */
+			continue;
+		}
+		if (strcmp(sched_name, sched->name)==0) {
+			/* HIT */
+			read_unlock_bh(&__ip_vs_sched_lock);
+			return sched;
+		}
+		if (sched->module)
+			__MOD_DEC_USE_COUNT(sched->module);
+	}
+
+	read_unlock_bh(&__ip_vs_sched_lock);
+	return NULL;
+}
+
+
+/*
+ *  Lookup scheduler and try to load it if it doesn't exist
+ */
+struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name)
+{
+	struct ip_vs_scheduler *sched;
+
+	/*
+	 *  Search for the scheduler by sched_name
+	 */
+	sched = ip_vs_sched_getbyname(sched_name);
+
+	/*
+	 *  If scheduler not found, load the module and search again
+	 */
+	if (sched == NULL) {
+		char module_name[IP_VS_SCHEDNAME_MAXLEN+8];
+		sprintf(module_name,"ip_vs_%s", sched_name);
+		request_module(module_name);
+		sched = ip_vs_sched_getbyname(sched_name);
+	}
+
+	return sched;
+}
+
+void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler)
+{
+	if (scheduler->module)
+		__MOD_DEC_USE_COUNT(scheduler->module);
+}
+
+
+/*
+ *  Register a scheduler in the scheduler list
+ */
+int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
+{
+	struct ip_vs_scheduler *sched;
+
+	if (!scheduler) {
+		IP_VS_ERR("register_ip_vs_scheduler(): NULL arg\n");
+		return -EINVAL;
+	}
+
+	if (!scheduler->name) {
+		IP_VS_ERR("register_ip_vs_scheduler(): NULL scheduler_name\n");
+		return -EINVAL;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	/*
+	 *  Make sure that the scheduler with this name doesn't exist
+	 *  in the scheduler list.
+	 */
+	sched = ip_vs_sched_getbyname(scheduler->name);
+	if (sched) {
+		ip_vs_scheduler_put(sched);
+		MOD_DEC_USE_COUNT;
+		IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler "
+			  "already existed in the system\n", scheduler->name);
+		return -EINVAL;
+	}
+
+	write_lock_bh(&__ip_vs_sched_lock);
+
+	if (scheduler->n_list.next != &scheduler->n_list) {
+		write_unlock_bh(&__ip_vs_sched_lock);
+		MOD_DEC_USE_COUNT;
+		IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler "
+			  "already linked\n", scheduler->name);
+		return -EINVAL;
+	}
+
+	/*
+	 *	Add it into the d-linked scheduler list
+	 */
+	list_add(&scheduler->n_list, &ip_vs_schedulers);
+	write_unlock_bh(&__ip_vs_sched_lock);
+
+	IP_VS_INFO("[%s] scheduler registered.\n", scheduler->name);
+
+	return 0;
+}
+
+
+/*
+ *  Unregister a scheduler from the scheduler list
+ */
+int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
+{
+	if (!scheduler) {
+		IP_VS_ERR( "unregister_ip_vs_scheduler(): NULL arg\n");
+		return -EINVAL;
+	}
+
+	write_lock_bh(&__ip_vs_sched_lock);
+	if (scheduler->n_list.next == &scheduler->n_list) {
+		write_unlock_bh(&__ip_vs_sched_lock);
+		IP_VS_ERR("unregister_ip_vs_scheduler(): [%s] scheduler "
+			  "is not in the list. failed\n", scheduler->name);
+		return -EINVAL;
+	}
+
+	/*
+	 *	Remove it from the d-linked scheduler list
+	 */
+	list_del(&scheduler->n_list);
+	write_unlock_bh(&__ip_vs_sched_lock);
+
+	MOD_DEC_USE_COUNT;
+
+	IP_VS_INFO("[%s] scheduler unregistered.\n", scheduler->name);
+
+	return 0;
+}
diff -Nru a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_sed.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,167 @@
+/*
+ * IPVS:        Shortest Expected Delay scheduling module
+ *
+ * Version:     $Id: ip_vs_sed.c,v 1.1.2.1 2003/05/20 17:05:02 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+/*
+ * The SED algorithm attempts to minimize each job's expected delay until
+ * completion. The expected delay that the job will experience is
+ * (Ci + 1) / Ui if sent to the ith server, in which Ci is the number of
+ * jobs on the the ith server and Ui is the fixed service rate (weight) of
+ * the ith server. The SED algorithm adopts a greedy policy that each does
+ * what is in its own best interest, i.e. to join the queue which would
+ * minimize its expected delay of completion.
+ *
+ * See the following paper for more information:
+ * A. Weinrib and S. Shenker, Greed is not enough: Adaptive load sharing
+ * in large heterogeneous systems. In Proceedings IEEE INFOCOM'88,
+ * pages 986-994, 1988.
+ *
+ * Thanks must go to Marko Buuri <marko@buuri.name> for talking SED to me.
+ *
+ * The difference between SED and WLC is that SED includes the incoming
+ * job in the cost function (the increment of 1). SED may outperform
+ * WLC, while scheduling big jobs under larger heterogeneous systems
+ * (the server weight varies a lot).
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <net/ip_vs.h>
+
+
+static int
+ip_vs_sed_init_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static int
+ip_vs_sed_done_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static int
+ip_vs_sed_update_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static inline unsigned int
+ip_vs_sed_dest_overhead(struct ip_vs_dest *dest)
+{
+	/*
+	 * We only use the active connection number in the cost
+	 * calculation here.
+	 */
+	return atomic_read(&dest->activeconns) + 1;
+}
+
+
+/*
+ *	Weighted Least Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_sed_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	register struct list_head *l, *e;
+	struct ip_vs_dest *dest, *least;
+	unsigned int loh, doh;
+
+	IP_VS_DBG(6, "ip_vs_sed_schedule(): Scheduling...\n");
+
+	/*
+	 * We calculate the load of each dest server as follows:
+	 *	(server expected overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *		  h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connections.
+	 */
+
+	l = &svc->destinations;
+	for (e=l->next; e!=l; e=e->next) {
+		least = list_entry(e, struct ip_vs_dest, n_list);
+		if (atomic_read(&least->weight) > 0) {
+			loh = ip_vs_sed_dest_overhead(least);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	for (e=e->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		doh = ip_vs_sed_dest_overhead(dest);
+		if (loh * atomic_read(&dest->weight) >
+		    doh * atomic_read(&least->weight)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(least->addr), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->refcnt),
+		  atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+static struct ip_vs_scheduler ip_vs_sed_scheduler =
+{
+	.name =			"sed",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.init_service =		ip_vs_sed_init_svc,
+	.done_service =		ip_vs_sed_done_svc,
+	.update_service =	ip_vs_sed_update_svc,
+	.schedule =		ip_vs_sed_schedule,
+};
+
+
+static int __init ip_vs_sed_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_sed_scheduler.n_list);
+	return register_ip_vs_scheduler(&ip_vs_sed_scheduler);
+}
+
+static void __exit ip_vs_sed_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_sed_scheduler);
+}
+
+module_init(ip_vs_sed_init);
+module_exit(ip_vs_sed_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_sh.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,262 @@
+/*
+ * IPVS:        Source Hashing scheduling module
+ *
+ * Version:     $Id: ip_vs_sh.c,v 1.4 2001/10/19 15:05:17 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@gnuchina.org>
+ *
+ *              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.
+ *
+ * Changes:
+ *
+ */
+
+/*
+ * The sh algorithm is to select server by the hash key of source IP
+ * address. The pseudo code is as follows:
+ *
+ *       n <- servernode[src_ip];
+ *       if (n is dead) OR
+ *          (n is overloaded, such as n.conns>2*n.weight) then
+ *                 return NULL;
+ *
+ *       return n;
+ *
+ * Notes that servernode is a 256-bucket hash table that maps the hash
+ * index derived from packet source IP address to the current server
+ * array. If the sh scheduler is used in cache cluster, it is good to
+ * combine it with cache_bypass feature. When the statically assigned
+ * server is dead or overloaded, the load balancer can bypass the cache
+ * server and send requests to the original server directly.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <net/ip_vs.h>
+
+
+/*
+ *      IPVS SH bucket
+ */
+struct ip_vs_sh_bucket {
+	struct ip_vs_dest       *dest;          /* real server (cache) */
+};
+
+/*
+ *     for IPVS SH entry hash table
+ */
+#ifndef CONFIG_IP_VS_SH_TAB_BITS
+#define CONFIG_IP_VS_SH_TAB_BITS        8
+#endif
+#define IP_VS_SH_TAB_BITS               CONFIG_IP_VS_SH_TAB_BITS
+#define IP_VS_SH_TAB_SIZE               (1 << IP_VS_SH_TAB_BITS)
+#define IP_VS_SH_TAB_MASK               (IP_VS_SH_TAB_SIZE - 1)
+
+
+/*
+ *	Returns hash value for IPVS SH entry
+ */
+static inline unsigned ip_vs_sh_hashkey(__u32 addr)
+{
+	return (ntohl(addr)*2654435761UL) & IP_VS_SH_TAB_MASK;
+}
+
+
+/*
+ *      Get ip_vs_dest associated with supplied parameters.
+ */
+static inline struct ip_vs_dest *
+ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __u32 addr)
+{
+	return (tbl[ip_vs_sh_hashkey(addr)]).dest;
+}
+
+
+/*
+ *      Assign all the hash buckets of the specified table with the service.
+ */
+static int
+ip_vs_sh_assign(struct ip_vs_sh_bucket *tbl, struct ip_vs_service *svc)
+{
+	int i;
+	struct ip_vs_sh_bucket *b;
+	struct list_head *p;
+	struct ip_vs_dest *dest;
+
+	b = tbl;
+	p = &svc->destinations;
+	for (i=0; i<IP_VS_SH_TAB_SIZE; i++) {
+		if (list_empty(p)) {
+			b->dest = NULL;
+		} else {
+			if (p == &svc->destinations)
+				p = p->next;
+
+			dest = list_entry(p, struct ip_vs_dest, n_list);
+			atomic_inc(&dest->refcnt);
+			b->dest = dest;
+
+			p = p->next;
+		}
+		b++;
+	}
+	return 0;
+}
+
+
+/*
+ *      Flush all the hash buckets of the specified table.
+ */
+static void ip_vs_sh_flush(struct ip_vs_sh_bucket *tbl)
+{
+	int i;
+	struct ip_vs_sh_bucket *b;
+
+	b = tbl;
+	for (i=0; i<IP_VS_SH_TAB_SIZE; i++) {
+		if (b->dest) {
+			atomic_dec(&b->dest->refcnt);
+			b->dest = NULL;
+		}
+		b++;
+	}
+}
+
+
+static int ip_vs_sh_init_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_sh_bucket *tbl;
+
+	/* allocate the SH table for this service */
+	tbl = kmalloc(sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE,
+		      GFP_ATOMIC);
+	if (tbl == NULL) {
+		IP_VS_ERR("ip_vs_sh_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	svc->sched_data = tbl;
+	IP_VS_DBG(6, "SH hash table (memory=%dbytes) allocated for "
+		  "current service\n",
+		  sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE);
+
+	/* assign the hash buckets with the updated service */
+	ip_vs_sh_assign(tbl, svc);
+
+	return 0;
+}
+
+
+static int ip_vs_sh_done_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_sh_bucket *tbl = svc->sched_data;
+
+	/* got to clean up hash buckets here */
+	ip_vs_sh_flush(tbl);
+
+	/* release the table itself */
+	kfree(svc->sched_data);
+	IP_VS_DBG(6, "SH hash table (memory=%dbytes) released\n",
+		  sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE);
+
+	return 0;
+}
+
+
+static int ip_vs_sh_update_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_sh_bucket *tbl = svc->sched_data;
+
+	/* got to clean up hash buckets here */
+	ip_vs_sh_flush(tbl);
+
+	/* assign the hash buckets with the updated service */
+	ip_vs_sh_assign(tbl, svc);
+
+	return 0;
+}
+
+
+/*
+ *      If the number of active connections is twice larger than its weight,
+ *      consider that the server is overloaded here.
+ */
+static inline int is_overloaded(struct ip_vs_dest *dest)
+{
+	if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)*2) {
+		return 1;
+	}
+	return 0;
+}
+
+
+/*
+ *      Source Hashing scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_sh_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct ip_vs_dest *dest;
+	struct ip_vs_sh_bucket *tbl;
+
+	IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n");
+
+	tbl = (struct ip_vs_sh_bucket *)svc->sched_data;
+	dest = ip_vs_sh_get(tbl, iph->saddr);
+	if (!dest
+	    || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
+	    || atomic_read(&dest->weight) <= 0
+	    || is_overloaded(dest)) {
+		return NULL;
+	}
+
+	IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u "
+		  "--> server %u.%u.%u.%u:%d\n",
+		  NIPQUAD(iph->saddr),
+		  NIPQUAD(dest->addr),
+		  ntohs(dest->port));
+
+	return dest;
+}
+
+
+/*
+ *      IPVS SH Scheduler structure
+ */
+static struct ip_vs_scheduler ip_vs_sh_scheduler =
+{
+	{0},                    /* n_list */
+	"sh",                   /* name */
+	ATOMIC_INIT(0),         /* refcnt */
+	THIS_MODULE,            /* this module */
+	ip_vs_sh_init_svc,      /* service initializer */
+	ip_vs_sh_done_svc,      /* service done */
+	ip_vs_sh_update_svc,    /* service updater */
+	ip_vs_sh_schedule,      /* select a server from the destination list */
+};
+
+
+static int __init ip_vs_sh_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_sh_scheduler.n_list);
+	return register_ip_vs_scheduler(&ip_vs_sh_scheduler);
+}
+
+
+static void __exit ip_vs_sh_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_sh_scheduler);
+}
+
+
+module_init(ip_vs_sh_init);
+module_exit(ip_vs_sh_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_sync.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,793 @@
+/*
+ * IPVS         An implementation of the IP virtual server support for the
+ *              LINUX operating system.  IPVS is now implemented as a module
+ *              over the NetFilter framework. IPVS can be used to build a
+ *              high-performance and highly available server based on a
+ *              cluster of servers.
+ *
+ * Version:     $Id: ip_vs_sync.c,v 1.8 2002/08/17 14:06:02 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ * ip_vs_sync:  sync connection info from master load balancer to backups
+ *              through multicast
+ */
+
+#define __KERNEL_SYSCALLS__             /*  for waitpid */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/net.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/unistd.h>
+
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/igmp.h>                 /* for ip_mc_join_group */
+
+#include <net/ip.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>                /* for get_fs and set_fs */
+
+#include <net/ip_vs.h>
+
+#define IP_VS_SYNC_GROUP 0xe0000051    /* multicast addr - 224.0.0.81 */
+#define IP_VS_SYNC_PORT  8848          /* multicast port */
+
+
+/*
+ *	IPVS sync connection entry
+ */
+struct ip_vs_sync_conn {
+	__u8			reserved;
+
+	/* Protocol, addresses and port numbers */
+	__u8			protocol;       /* Which protocol (TCP/UDP) */
+	__u16			cport;
+	__u16                   vport;
+	__u16                   dport;
+	__u32                   caddr;          /* client address */
+	__u32                   vaddr;          /* virtual address */
+	__u32                   daddr;          /* destination address */
+
+	/* Flags and state transition */
+	__u16                   flags;          /* status flags */
+	__u16                   state;          /* state info */
+
+	/* The sequence options start here */
+};
+
+struct ip_vs_sync_conn_options {
+	struct ip_vs_seq        in_seq;         /* incoming seq. struct */
+	struct ip_vs_seq        out_seq;        /* outgoing seq. struct */
+};
+
+#define IP_VS_SYNC_CONN_TIMEOUT (3*60*HZ)
+#define SIMPLE_CONN_SIZE  (sizeof(struct ip_vs_sync_conn))
+#define FULL_CONN_SIZE  \
+(sizeof(struct ip_vs_sync_conn) + sizeof(struct ip_vs_sync_conn_options))
+
+
+/*
+  The master mulitcasts messages to the backup load balancers in the
+  following format.
+
+       0                   1                   2                   3
+       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |  Count Conns  |   Reserved    |            Size               |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                                                               |
+      |                    IPVS Sync Connection (1)                   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                            .                                  |
+      |                            .                                  |
+      |                            .                                  |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                                                               |
+      |                    IPVS Sync Connection (n)                   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+#define SYNC_MESG_MAX_SIZE      (24*50+4)
+struct ip_vs_sync_mesg {
+	__u8                    nr_conns;
+	__u8                    reserved;
+	__u16                   size;
+
+	/* ip_vs_sync_conn entries start here */
+};
+
+
+struct ip_vs_sync_buff {
+	struct list_head        list;
+	unsigned long           firstuse;
+
+	/* pointers for the message data */
+	struct ip_vs_sync_mesg  *mesg;
+	unsigned char           *head;
+	unsigned char           *end;
+};
+
+
+/* the sync_buff list head and the lock */
+static LIST_HEAD(ip_vs_sync_queue);
+static spinlock_t ip_vs_sync_lock = SPIN_LOCK_UNLOCKED;
+
+/* current sync_buff for accepting new conn entries */
+static struct ip_vs_sync_buff   *curr_sb = NULL;
+static spinlock_t curr_sb_lock = SPIN_LOCK_UNLOCKED;
+
+static inline void sb_queue_tail(struct ip_vs_sync_buff *sb)
+{
+	spin_lock(&ip_vs_sync_lock);
+	list_add_tail(&sb->list, &ip_vs_sync_queue);
+	spin_unlock(&ip_vs_sync_lock);
+}
+
+static inline struct ip_vs_sync_buff * sb_dequeue(void)
+{
+	struct ip_vs_sync_buff *sb;
+
+	spin_lock_bh(&ip_vs_sync_lock);
+	if (list_empty(&ip_vs_sync_queue)) {
+		sb = NULL;
+	} else {
+		sb = list_entry(ip_vs_sync_queue.next,
+				struct ip_vs_sync_buff,
+				list);
+		list_del(&sb->list);
+	}
+	spin_unlock_bh(&ip_vs_sync_lock);
+
+	return sb;
+}
+
+static inline struct ip_vs_sync_buff * ip_vs_sync_buff_create(void)
+{
+	struct ip_vs_sync_buff *sb;
+
+	if (!(sb=kmalloc(sizeof(struct ip_vs_sync_buff), GFP_ATOMIC)))
+		return NULL;
+
+	if (!(sb->mesg=kmalloc(SYNC_MESG_MAX_SIZE, GFP_ATOMIC))) {
+		kfree(sb);
+		return NULL;
+	}
+	sb->mesg->nr_conns = 0;
+	sb->mesg->size = 4;
+	sb->head = (unsigned char *)sb->mesg + 4;
+	sb->end = (unsigned char *)sb->mesg + SYNC_MESG_MAX_SIZE;
+	sb->firstuse = jiffies;
+	return sb;
+}
+
+static inline void ip_vs_sync_buff_release(struct ip_vs_sync_buff *sb)
+{
+	kfree(sb->mesg);
+	kfree(sb);
+}
+
+/*
+ *	Get the current sync buffer if it has been created for more
+ *	than the specified time or the specified time is zero.
+ */
+static inline struct ip_vs_sync_buff *
+get_curr_sync_buff(unsigned long time)
+{
+	struct ip_vs_sync_buff *sb;
+
+	spin_lock_bh(&curr_sb_lock);
+	if (curr_sb &&
+	    (jiffies - curr_sb->firstuse > time || time == 0)) {
+		sb = curr_sb;
+		curr_sb = NULL;
+	} else
+		sb = NULL;
+	spin_unlock_bh(&curr_sb_lock);
+	return sb;
+}
+
+
+/*
+ *      Add an ip_vs_conn information into the current sync_buff.
+ *      Called by ip_vs_in.
+ */
+void ip_vs_sync_conn(struct ip_vs_conn *cp)
+{
+	struct ip_vs_sync_mesg *m;
+	struct ip_vs_sync_conn *s;
+	int len;
+
+	spin_lock(&curr_sb_lock);
+	if (!curr_sb) {
+		if (!(curr_sb=ip_vs_sync_buff_create())) {
+			spin_unlock(&curr_sb_lock);
+			IP_VS_ERR("ip_vs_sync_buff_create failed.\n");
+			return;
+		}
+	}
+
+	len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? FULL_CONN_SIZE :
+		SIMPLE_CONN_SIZE;
+	m = curr_sb->mesg;
+	s = (struct ip_vs_sync_conn *)curr_sb->head;
+
+	/* copy members */
+	s->protocol = cp->protocol;
+	s->cport = cp->cport;
+	s->vport = cp->vport;
+	s->dport = cp->dport;
+	s->caddr = cp->caddr;
+	s->vaddr = cp->vaddr;
+	s->daddr = cp->daddr;
+	s->flags = htons(cp->flags & ~IP_VS_CONN_F_HASHED);
+	s->state = htons(cp->state);
+	if (cp->flags & IP_VS_CONN_F_SEQ_MASK) {
+		struct ip_vs_sync_conn_options *opt =
+			(struct ip_vs_sync_conn_options *)&s[1];
+		memcpy(opt, &cp->in_seq, sizeof(*opt));
+	}
+
+	m->nr_conns++;
+	m->size += len;
+	curr_sb->head += len;
+
+	/* check if there is a space for next one */
+	if (curr_sb->head+FULL_CONN_SIZE > curr_sb->end) {
+		sb_queue_tail(curr_sb);
+		curr_sb = NULL;
+	}
+	spin_unlock(&curr_sb_lock);
+
+	/* synchronize its controller if it has */
+	if (cp->control)
+		ip_vs_sync_conn(cp->control);
+}
+
+
+/*
+ *      Process received multicast message and create the corresponding
+ *      ip_vs_conn entries.
+ */
+static void ip_vs_process_message(const char *buffer, const size_t buflen)
+{
+	struct ip_vs_sync_mesg *m = (struct ip_vs_sync_mesg *)buffer;
+	struct ip_vs_sync_conn *s;
+	struct ip_vs_sync_conn_options *opt;
+	struct ip_vs_conn *cp;
+	char *p;
+	int i;
+
+	if (buflen != m->size) {
+		IP_VS_ERR("bogus message\n");
+		return;
+	}
+
+	p = (char *)buffer + sizeof(struct ip_vs_sync_mesg);
+	for (i=0; i<m->nr_conns; i++) {
+		s = (struct ip_vs_sync_conn *)p;
+		cp = ip_vs_conn_in_get(s->protocol,
+				       s->caddr, s->cport,
+				       s->vaddr, s->vport);
+		if (!cp) {
+			cp = ip_vs_conn_new(s->protocol,
+					    s->caddr, s->cport,
+					    s->vaddr, s->vport,
+					    s->daddr, s->dport,
+					    ntohs(s->flags), NULL);
+			if (!cp) {
+				IP_VS_ERR("ip_vs_conn_new failed\n");
+				return;
+			}
+			cp->state = ntohs(s->state);
+		} else if (!cp->dest) {
+			/* it is an entry created by the synchronization */
+			cp->state = ntohs(s->state);
+			cp->flags = ntohs(s->flags) | IP_VS_CONN_F_HASHED;
+		}	/* Note that we don't touch its state and flags
+			   if it is a normal entry. */
+
+		if (ntohs(s->flags) & IP_VS_CONN_F_SEQ_MASK) {
+			opt = (struct ip_vs_sync_conn_options *)&s[1];
+			memcpy(&cp->in_seq, opt, sizeof(*opt));
+			p += FULL_CONN_SIZE;
+		} else
+			p += SIMPLE_CONN_SIZE;
+
+		atomic_set(&cp->in_pkts, sysctl_ip_vs_sync_threshold);
+		cp->timeout = IP_VS_SYNC_CONN_TIMEOUT;
+		ip_vs_conn_put(cp);
+
+		if (p > buffer+buflen) {
+			IP_VS_ERR("bogus message\n");
+			return;
+		}
+	}
+}
+
+
+/* ipvs sync daemon state */
+volatile int ip_vs_sync_state = IP_VS_STATE_NONE;
+
+/* multicast interface name */
+char ip_vs_mcast_ifn[IP_VS_IFNAME_MAXLEN];
+
+/* multicast addr */
+static struct sockaddr_in mcast_addr;
+
+
+/*
+ *      Setup loopback of outgoing multicasts on a sending socket
+ */
+static void set_mcast_loop(struct sock *sk, u_char loop)
+{
+	/* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */
+	lock_sock(sk);
+	sk->protinfo.af_inet.mc_loop = loop ? 1 : 0;
+	release_sock(sk);
+}
+
+/*
+ *      Specify TTL for outgoing multicasts on a sending socket
+ */
+static void set_mcast_ttl(struct sock *sk, u_char ttl)
+{
+	/* setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); */
+	lock_sock(sk);
+	sk->protinfo.af_inet.mc_ttl = ttl;
+	release_sock(sk);
+}
+
+/*
+ *      Specifiy default interface for outgoing multicasts
+ */
+static int set_mcast_if(struct sock *sk, char *ifname)
+{
+	struct net_device *dev;
+
+	if ((dev = __dev_get_by_name(ifname)) == NULL)
+		return -ENODEV;
+
+	if (sk->bound_dev_if && dev->ifindex != sk->bound_dev_if)
+		return -EINVAL;
+
+	lock_sock(sk);
+	sk->protinfo.af_inet.mc_index = dev->ifindex;
+	/*  sk->protinfo.af_inet.mc_addr  = 0; */
+	release_sock(sk);
+
+	return 0;
+}
+
+/*
+ *      Join a multicast group.
+ *      the group is specified by a class D multicast address 224.0.0.0/8
+ *      in the in_addr structure passed in as a parameter.
+ */
+static int
+join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname)
+{
+	struct ip_mreqn mreq;
+	struct net_device *dev;
+	int ret;
+
+	memset(&mreq, 0, sizeof(mreq));
+	memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr));
+
+	if ((dev = __dev_get_by_name(ifname)) == NULL)
+		return -ENODEV;
+	if (sk->bound_dev_if && dev->ifindex != sk->bound_dev_if)
+		return -EINVAL;
+
+	mreq.imr_ifindex = dev->ifindex;
+
+	lock_sock(sk);
+	ret = ip_mc_join_group(sk, &mreq);
+	release_sock(sk);
+
+	return ret;
+}
+
+
+static int bind_mcastif_addr(struct socket *sock, char *ifname)
+{
+	struct net_device *dev;
+	u32 addr;
+	struct sockaddr_in sin;
+
+	if ((dev = __dev_get_by_name(ifname)) == NULL)
+		return -ENODEV;
+
+	addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
+	if (!addr)
+		IP_VS_ERR("You probably need to specify IP address on "
+			  "multicast interface.\n");
+
+	IP_VS_DBG(7, "binding socket with (%s) %u.%u.%u.%u\n",
+		  ifname, NIPQUAD(addr));
+
+	/* Now bind the socket with the address of multicast interface */
+	sin.sin_family	     = AF_INET;
+	sin.sin_addr.s_addr  = addr;
+	sin.sin_port         = 0;
+
+	return sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin));
+}
+
+/*
+ *      Set up sending multicast socket over UDP
+ */
+static struct socket * make_send_sock(void)
+{
+	struct socket *sock;
+
+	/* First create a socket */
+	if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) {
+		IP_VS_ERR("Error during creation of socket; terminating\n");
+		return NULL;
+	}
+
+	if (set_mcast_if(sock->sk, ip_vs_mcast_ifn) < 0) {
+		IP_VS_ERR("Error setting outbound mcast interface\n");
+		goto error;
+	}
+
+	set_mcast_loop(sock->sk, 0);
+	set_mcast_ttl(sock->sk, 1);
+
+	if (bind_mcastif_addr(sock, ip_vs_mcast_ifn) < 0) {
+		IP_VS_ERR("Error binding address of the mcast interface\n");
+		goto error;
+	}
+
+	if (sock->ops->connect(sock,
+			       (struct sockaddr*)&mcast_addr,
+			       sizeof(struct sockaddr), 0) < 0) {
+		IP_VS_ERR("Error connecting to the multicast addr\n");
+		goto error;
+	}
+
+	return sock;
+
+  error:
+	sock_release(sock);
+	return NULL;
+}
+
+
+/*
+ *      Set up receiving multicast socket over UDP
+ */
+static struct socket * make_receive_sock(void)
+{
+	struct socket *sock;
+
+	/* First create a socket */
+	if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock) < 0) {
+		IP_VS_ERR("Error during creation of socket; terminating\n");
+		return NULL;
+	}
+
+	/* it is equivalent to the REUSEADDR option in user-space */
+	sock->sk->reuse = 1;
+
+	if (sock->ops->bind(sock,
+			    (struct sockaddr*)&mcast_addr,
+			    sizeof(struct sockaddr)) < 0) {
+		IP_VS_ERR("Error binding to the multicast addr\n");
+		goto error;
+	}
+
+	/* join the multicast group */
+	if (join_mcast_group(sock->sk,
+			     (struct in_addr*)&mcast_addr.sin_addr,
+			     ip_vs_mcast_ifn) < 0) {
+		IP_VS_ERR("Error joining to the multicast group\n");
+		goto error;
+	}
+
+	return sock;
+
+  error:
+	sock_release(sock);
+	return NULL;
+}
+
+
+static int
+ip_vs_send_async(struct socket *sock, const char *buffer, const size_t length)
+{
+	struct msghdr	msg;
+	mm_segment_t	oldfs;
+	struct iovec	iov;
+	int		len;
+
+	EnterFunction(7);
+	iov.iov_base     = (void *)buffer;
+	iov.iov_len      = length;
+	msg.msg_name     = 0;
+	msg.msg_namelen  = 0;
+	msg.msg_iov	 = &iov;
+	msg.msg_iovlen   = 1;
+	msg.msg_control  = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags    = MSG_DONTWAIT|MSG_NOSIGNAL;
+
+	oldfs = get_fs(); set_fs(KERNEL_DS);
+	len = sock_sendmsg(sock, &msg, (size_t)(length));
+	set_fs(oldfs);
+
+	LeaveFunction(7);
+	return len;
+}
+
+
+static int
+ip_vs_receive(struct socket *sock, char *buffer, const size_t buflen)
+{
+	struct msghdr		msg;
+	struct iovec		iov;
+	int			len;
+	mm_segment_t		oldfs;
+
+	EnterFunction(7);
+
+	/* Receive a packet */
+	iov.iov_base     = buffer;
+	iov.iov_len      = (size_t)buflen;
+	msg.msg_name     = 0;
+	msg.msg_namelen  = 0;
+	msg.msg_iov	 = &iov;
+	msg.msg_iovlen   = 1;
+	msg.msg_control  = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags    = 0;
+
+	oldfs = get_fs(); set_fs(KERNEL_DS);
+	len = sock_recvmsg(sock, &msg, buflen, 0);
+	set_fs(oldfs);
+
+	if (len < 0)
+		return -1;
+
+	LeaveFunction(7);
+	return len;
+}
+
+
+static int errno;
+
+static DECLARE_WAIT_QUEUE_HEAD(sync_wait);
+static pid_t sync_pid = 0;
+
+static DECLARE_WAIT_QUEUE_HEAD(stop_sync_wait);
+static int stop_sync = 0;
+
+static void sync_master_loop(void)
+{
+	struct socket *sock;
+	struct ip_vs_sync_buff *sb;
+	struct ip_vs_sync_mesg *m;
+
+	/* create the sending multicast socket */
+	sock = make_send_sock();
+	if (!sock)
+		return;
+
+	for (;;) {
+		while ((sb=sb_dequeue())) {
+			m = sb->mesg;
+			if (ip_vs_send_async(sock, (char *)m,
+					     m->size) != m->size)
+				IP_VS_ERR("ip_vs_send_async error\n");
+			ip_vs_sync_buff_release(sb);
+		}
+
+		/* check if entries stay in curr_sb for 2 seconds */
+		if ((sb = get_curr_sync_buff(2*HZ))) {
+			m = sb->mesg;
+			if (ip_vs_send_async(sock, (char *)m,
+					     m->size) != m->size)
+				IP_VS_ERR("ip_vs_send_async error\n");
+			ip_vs_sync_buff_release(sb);
+		}
+
+		if (stop_sync)
+			break;
+
+		__set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ);
+		__set_current_state(TASK_RUNNING);
+	}
+
+	/* clean up the sync_buff queue */
+	while ((sb=sb_dequeue())) {
+		ip_vs_sync_buff_release(sb);
+	}
+
+	/* clean up the current sync_buff */
+	if ((sb = get_curr_sync_buff(0))) {
+		ip_vs_sync_buff_release(sb);
+	}
+
+	/* release the sending multicast socket */
+	sock_release(sock);
+}
+
+
+static void sync_backup_loop(void)
+{
+	struct socket *sock;
+	char *buf;
+	int len;
+
+	if (!(buf=kmalloc(SYNC_MESG_MAX_SIZE, GFP_ATOMIC))) {
+		IP_VS_ERR("sync_backup_loop: kmalloc error\n");
+		return;
+	}
+
+	/* create the receiving multicast socket */
+	sock = make_receive_sock();
+	if (!sock)
+		goto out;
+
+	for (;;) {
+		/* do you have data now? */
+		while (!skb_queue_empty(&(sock->sk->receive_queue))) {
+			if ((len=ip_vs_receive(sock, buf,
+					       SYNC_MESG_MAX_SIZE))<=0) {
+				IP_VS_ERR("receiving message error\n");
+				break;
+			}
+			/* disable bottom half, because it accessed the data
+			   shared by softirq while getting/creating conns */
+			local_bh_disable();
+			ip_vs_process_message(buf, len);
+			local_bh_enable();
+		}
+
+		if (stop_sync)
+			break;
+
+		__set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ);
+		__set_current_state(TASK_RUNNING);
+	}
+
+	/* release the sending multicast socket */
+	sock_release(sock);
+
+  out:
+	kfree(buf);
+}
+
+
+static int sync_thread(void *startup)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	mm_segment_t oldmm;
+	int state;
+
+	MOD_INC_USE_COUNT;
+	daemonize();
+
+	oldmm = get_fs();
+	set_fs(KERNEL_DS);
+
+	if (ip_vs_sync_state == IP_VS_STATE_MASTER)
+		sprintf(current->comm, "ipvs syncmaster");
+	else if (ip_vs_sync_state == IP_VS_STATE_BACKUP)
+		sprintf(current->comm, "ipvs syncbackup");
+	else IP_VS_BUG();
+
+	spin_lock_irq(&current->sigmask_lock);
+	siginitsetinv(&current->blocked, 0);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	/* set up multicast address */
+	mcast_addr.sin_family = AF_INET;
+	mcast_addr.sin_port = htons(IP_VS_SYNC_PORT);
+	mcast_addr.sin_addr.s_addr = htonl(IP_VS_SYNC_GROUP);
+
+	add_wait_queue(&sync_wait, &wait);
+
+	state = ip_vs_sync_state;
+	sync_pid = current->pid;
+	IP_VS_INFO("sync thread started.\n");
+	complete((struct completion *)startup);
+
+	/* processing master/backup loop here */
+	if (state == IP_VS_STATE_MASTER)
+		sync_master_loop();
+	else if (state == IP_VS_STATE_BACKUP)
+		sync_backup_loop();
+	else IP_VS_BUG();
+
+	remove_wait_queue(&sync_wait, &wait);
+
+	/* thread exits */
+	sync_pid = 0;
+	IP_VS_INFO("sync thread stopped!\n");
+
+	set_fs(oldmm);
+	MOD_DEC_USE_COUNT;
+
+	stop_sync = 0;
+	wake_up(&stop_sync_wait);
+
+	return 0;
+}
+
+
+static int fork_sync_thread(void *startup)
+{
+	/* fork the sync thread here, then the parent process of the
+	   sync thread is the init process after this thread exits. */
+	if (kernel_thread(sync_thread, startup, 0) < 0)
+		IP_VS_BUG();
+	return 0;
+}
+
+
+int start_sync_thread(int state, char *mcast_ifn)
+{
+	DECLARE_COMPLETION(startup);
+	pid_t pid;
+	int waitpid_result;
+
+	if (sync_pid)
+		return -EEXIST;
+
+	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
+	IP_VS_DBG(7, "Each ip_vs_sync_conn entry need %d bytes\n",
+		  sizeof(struct ip_vs_sync_conn));
+
+	ip_vs_sync_state = state;
+	strcpy(ip_vs_mcast_ifn, mcast_ifn);
+
+	if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0)
+		IP_VS_BUG();
+
+	if ((waitpid_result = waitpid(pid, NULL, __WCLONE)) != pid) {
+		IP_VS_ERR("%s: waitpid(%d,...) failed, errno %d\n",
+			  __FUNCTION__, pid, -waitpid_result);
+	}
+
+	wait_for_completion(&startup);
+
+	return 0;
+}
+
+
+int stop_sync_thread(void)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (!sync_pid)
+		return -ESRCH;
+
+	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
+	IP_VS_INFO("stopping sync thread %d ...\n", sync_pid);
+
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&stop_sync_wait, &wait);
+	ip_vs_sync_state = IP_VS_STATE_NONE;
+	stop_sync = 1;
+	wake_up(&sync_wait);
+	schedule();
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&stop_sync_wait, &wait);
+
+	/* Note: no need to reap the sync thread, because its parent
+	   process is the init process */
+
+	if (stop_sync)
+		IP_VS_BUG();
+
+	return 0;
+}
diff -Nru a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_wlc.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,157 @@
+/*
+ * IPVS:        Weighted Least-Connection Scheduling module
+ *
+ * Version:     $Id: ip_vs_wlc.c,v 1.10.2.1 2003/04/11 14:02:35 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *              Peter Kese <peter.kese@ijs.si>
+ *
+ *              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.
+ *
+ * Changes:
+ *     Wensong Zhang            :     changed the ip_vs_wlc_schedule to return dest
+ *     Wensong Zhang            :     changed to use the inactconns in scheduling
+ *     Wensong Zhang            :     changed some comestics things for debugging
+ *     Wensong Zhang            :     changed for the d-linked destination list
+ *     Wensong Zhang            :     added the ip_vs_wlc_update_svc
+ *     Wensong Zhang            :     added any dest with weight=0 is quiesced
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <net/ip_vs.h>
+
+
+static int
+ip_vs_wlc_init_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static int
+ip_vs_wlc_done_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static int
+ip_vs_wlc_update_svc(struct ip_vs_service *svc)
+{
+	return 0;
+}
+
+
+static inline unsigned int
+ip_vs_wlc_dest_overhead(struct ip_vs_dest *dest)
+{
+	/*
+	 * We think the overhead of processing active connections is 256
+	 * times higher than that of inactive connections in average. (This
+	 * 256 times might not be accurate, we will change it later) We
+	 * use the following formula to estimate the overhead now:
+	 *		  dest->activeconns*256 + dest->inactconns
+	 */
+	return (atomic_read(&dest->activeconns) << 8) +
+		atomic_read(&dest->inactconns);
+}
+
+
+/*
+ *    Weighted Least Connection scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_wlc_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	register struct list_head *l, *e;
+	struct ip_vs_dest *dest, *least;
+	unsigned int loh, doh;
+
+	IP_VS_DBG(6, "ip_vs_wlc_schedule(): Scheduling...\n");
+
+	/*
+	 * We calculate the load of each dest server as follows:
+	 *		  (dest overhead) / dest->weight
+	 *
+	 * Remember -- no floats in kernel mode!!!
+	 * The comparison of h1*w2 > h2*w1 is equivalent to that of
+	 *		  h1/w1 > h2/w2
+	 * if every weight is larger than zero.
+	 *
+	 * The server with weight=0 is quiesced and will not receive any
+	 * new connections.
+	 */
+
+	l = &svc->destinations;
+	for (e=l->next; e!=l; e=e->next) {
+		least = list_entry(e, struct ip_vs_dest, n_list);
+		if (atomic_read(&least->weight) > 0) {
+			loh = ip_vs_wlc_dest_overhead(least);
+			goto nextstage;
+		}
+	}
+	return NULL;
+
+	/*
+	 *    Find the destination with the least load.
+	 */
+  nextstage:
+	for (e=e->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+
+		doh = ip_vs_wlc_dest_overhead(dest);
+		if (loh * atomic_read(&dest->weight) >
+		    doh * atomic_read(&least->weight)) {
+			least = dest;
+			loh = doh;
+		}
+	}
+
+	IP_VS_DBG(6, "WLC: server %u.%u.%u.%u:%u "
+		  "activeconns %d refcnt %d weight %d overhead %d\n",
+		  NIPQUAD(least->addr), ntohs(least->port),
+		  atomic_read(&least->activeconns),
+		  atomic_read(&least->refcnt),
+		  atomic_read(&least->weight), loh);
+
+	return least;
+}
+
+
+static struct ip_vs_scheduler ip_vs_wlc_scheduler =
+{
+	{0},			/* n_list */
+	"wlc",			/* name */
+	ATOMIC_INIT(0),         /* refcnt */
+	THIS_MODULE,		/* this module */
+	ip_vs_wlc_init_svc,	/* service initializer */
+	ip_vs_wlc_done_svc,	/* service done */
+	ip_vs_wlc_update_svc,	/* service updater */
+	ip_vs_wlc_schedule,	/* select a server from the destination list */
+};
+
+
+static int __init ip_vs_wlc_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_wlc_scheduler.n_list);
+	return register_ip_vs_scheduler(&ip_vs_wlc_scheduler);
+}
+
+static void __exit ip_vs_wlc_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_wlc_scheduler);
+}
+
+module_init(ip_vs_wlc_init);
+module_exit(ip_vs_wlc_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ipvs/ip_vs_wrr.c	Mon Aug 11 22:36:34 2003
@@ -0,0 +1,240 @@
+/*
+ * IPVS:        Weighted Round-Robin Scheduling module
+ *
+ * Version:     $Id: ip_vs_wrr.c,v 1.11 2002/03/25 12:44:35 wensong Exp $
+ *
+ * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
+ *
+ *              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.
+ *
+ * Changes:
+ *     Wensong Zhang            :     changed the ip_vs_wrr_schedule to return dest
+ *     Wensong Zhang            :     changed some comestics things for debugging
+ *     Wensong Zhang            :     changed for the d-linked destination list
+ *     Wensong Zhang            :     added the ip_vs_wrr_update_svc
+ *     Julian Anastasov         :     fixed the bug of returning destination
+ *                                    with weight 0 when all weights are zero
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <net/ip_vs.h>
+
+/*
+ * current destination pointer for weighted round-robin scheduling
+ */
+struct ip_vs_wrr_mark {
+	struct list_head *cl;	/* current list head */
+	int cw;			/* current weight */
+	int mw;			/* maximum weight */
+	int di;			/* decreasing interval */
+};
+
+
+/*
+ *    Get the gcd of server weights
+ */
+static int gcd(int a, int b)
+{
+	int c;
+
+	while ((c = a % b)) {
+		a = b;
+		b = c;
+	}
+	return b;
+}
+
+static int ip_vs_wrr_gcd_weight(struct ip_vs_service *svc)
+{
+	register struct list_head *l, *e;
+	struct ip_vs_dest *dest;
+	int weight;
+	int g = 1;
+
+	l = &svc->destinations;
+	for (e=l->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		weight = atomic_read(&dest->weight);
+		if (weight > 0) {
+			g = weight;
+			break;
+		}
+	}
+	if (e == l)
+		return g;
+
+	for (e=e->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		weight = atomic_read(&dest->weight);
+		if (weight > 0)
+			g = gcd(weight, g);
+	}
+
+	return g;
+}
+
+
+/*
+ *    Get the maximum weight of the service destinations.
+ */
+static int ip_vs_wrr_max_weight(struct ip_vs_service *svc)
+{
+	register struct list_head *l, *e;
+	struct ip_vs_dest *dest;
+	int weight = 0;
+
+	l = &svc->destinations;
+	for (e=l->next; e!=l; e=e->next) {
+		dest = list_entry(e, struct ip_vs_dest, n_list);
+		if (atomic_read(&dest->weight) > weight)
+			weight = atomic_read(&dest->weight);
+	}
+
+	return weight;
+}
+
+
+static int ip_vs_wrr_init_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_wrr_mark *mark;
+
+	/*
+	 *    Allocate the mark variable for WRR scheduling
+	 */
+	mark = kmalloc(sizeof(struct ip_vs_wrr_mark), GFP_ATOMIC);
+	if (mark == NULL) {
+		IP_VS_ERR("ip_vs_wrr_init_svc(): no memory\n");
+		return -ENOMEM;
+	}
+	mark->cl = &svc->destinations;
+	mark->cw = 0;
+	mark->mw = ip_vs_wrr_max_weight(svc);
+	mark->di = ip_vs_wrr_gcd_weight(svc);
+	svc->sched_data = mark;
+
+	return 0;
+}
+
+
+static int ip_vs_wrr_done_svc(struct ip_vs_service *svc)
+{
+	/*
+	 *    Release the mark variable
+	 */
+	kfree(svc->sched_data);
+
+	return 0;
+}
+
+
+static int ip_vs_wrr_update_svc(struct ip_vs_service *svc)
+{
+	struct ip_vs_wrr_mark *mark = svc->sched_data;
+
+	mark->cl = &svc->destinations;
+	mark->mw = ip_vs_wrr_max_weight(svc);
+	mark->di = ip_vs_wrr_gcd_weight(svc);
+	return 0;
+}
+
+
+/*
+ *    Weighted Round-Robin Scheduling
+ */
+static struct ip_vs_dest *
+ip_vs_wrr_schedule(struct ip_vs_service *svc, struct iphdr *iph)
+{
+	struct ip_vs_dest *dest;
+	struct ip_vs_wrr_mark *mark = svc->sched_data;
+
+	IP_VS_DBG(6, "ip_vs_wrr_schedule(): Scheduling...\n");
+
+	/*
+	 * This loop will always terminate, because 0<mark->cw<max_weight,
+	 * and at least one server has its weight equal to max_weight.
+	 */
+	write_lock(&svc->sched_lock);
+	while (1) {
+		if (mark->cl == &svc->destinations) {
+			/* it is at the head of the destination list */
+
+			if (mark->cl == mark->cl->next) {
+				/* no dest entry */
+				write_unlock(&svc->sched_lock);
+				return NULL;
+			}
+
+			mark->cl = svc->destinations.next;
+			mark->cw -= mark->di;
+			if (mark->cw <= 0) {
+				mark->cw = mark->mw;
+				/*
+				 * Still zero, which means no availabe servers.
+				 */
+				if (mark->cw == 0) {
+					mark->cl = &svc->destinations;
+					write_unlock(&svc->sched_lock);
+					IP_VS_INFO("ip_vs_wrr_schedule(): "
+						   "no available servers\n");
+					return NULL;
+				}
+			}
+		}
+		else mark->cl = mark->cl->next;
+
+		if (mark->cl != &svc->destinations) {
+			/* not at the head of the list */
+			dest = list_entry(mark->cl, struct ip_vs_dest, n_list);
+			if (atomic_read(&dest->weight) >= mark->cw) {
+				write_unlock(&svc->sched_lock);
+				break;
+			}
+		}
+	}
+
+	IP_VS_DBG(6, "WRR: server %u.%u.%u.%u:%u "
+		  "activeconns %d refcnt %d weight %d\n",
+		  NIPQUAD(dest->addr), ntohs(dest->port),
+		  atomic_read(&dest->activeconns),
+		  atomic_read(&dest->refcnt),
+		  atomic_read(&dest->weight));
+
+	return	dest;
+}
+
+
+static struct ip_vs_scheduler ip_vs_wrr_scheduler = {
+	{0},			/* n_list */
+	"wrr",			/* name */
+	ATOMIC_INIT(0),		/* refcnt */
+	THIS_MODULE,		/* this module */
+	ip_vs_wrr_init_svc,	/* service initializer */
+	ip_vs_wrr_done_svc,	/* service done */
+	ip_vs_wrr_update_svc,	/* service updater */
+	ip_vs_wrr_schedule,	/* select a server from the destination list */
+};
+
+static int __init ip_vs_wrr_init(void)
+{
+	INIT_LIST_HEAD(&ip_vs_wrr_scheduler.n_list);
+	return register_ip_vs_scheduler(&ip_vs_wrr_scheduler) ;
+}
+
+static void __exit ip_vs_wrr_cleanup(void)
+{
+	unregister_ip_vs_scheduler(&ip_vs_wrr_scheduler);
+}
+
+module_init(ip_vs_wrr_init);
+module_exit(ip_vs_wrr_cleanup);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c	Fri Jul 25 14:14:23 2003
+++ b/net/ipv4/netfilter/ip_conntrack_core.c	Mon Aug 25 13:38:24 2003
@@ -291,14 +291,15 @@
 static void
 clean_from_lists(struct ip_conntrack *ct)
 {
+	unsigned int ho, hr;
+	
 	DEBUGP("clean_from_lists(%p)\n", ct);
 	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
-	LIST_DELETE(&ip_conntrack_hash
-		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)],
-		    &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
-	LIST_DELETE(&ip_conntrack_hash
-		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
-		    &ct->tuplehash[IP_CT_DIR_REPLY]);
+
+	ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+	hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+	LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
+	LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
 
 	/* Destroy all un-established, pending expectations */
 	remove_expectations(ct, 1);
@@ -370,9 +371,10 @@
 		    const struct ip_conntrack *ignored_conntrack)
 {
 	struct ip_conntrack_tuple_hash *h;
+	unsigned int hash = hash_conntrack(tuple);
 
 	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-	h = LIST_FIND(&ip_conntrack_hash[hash_conntrack(tuple)],
+	h = LIST_FIND(&ip_conntrack_hash[hash],
 		      conntrack_tuple_cmp,
 		      struct ip_conntrack_tuple_hash *,
 		      tuple, ignored_conntrack);
diff -Nru a/net/ipv4/netfilter/ip_fw_compat.c b/net/ipv4/netfilter/ip_fw_compat.c
--- a/net/ipv4/netfilter/ip_fw_compat.c	Tue Feb  5 06:07:07 2002
+++ b/net/ipv4/netfilter/ip_fw_compat.c	Mon Aug 11 22:36:41 2003
@@ -47,6 +47,12 @@
 extern int __init masq_init(void);
 extern void masq_cleanup(void);
 
+#ifdef CONFIG_IP_VS
+/* From ip_vs_core.c */
+extern unsigned int
+check_for_ip_vs_out(struct sk_buff **skb_p, int (*okfn)(struct sk_buff *));
+#endif
+
 /* They call these; we do what they want. */
 int register_firewall(int pf, struct firewall_ops *fw)
 {
@@ -172,8 +178,14 @@
 		return NF_ACCEPT;
 
 	case FW_MASQUERADE:
-		if (hooknum == NF_IP_FORWARD)
+		if (hooknum == NF_IP_FORWARD) {
+#ifdef CONFIG_IP_VS
+                        /* check if it is for ip_vs */
+                        if (check_for_ip_vs_out(pskb, okfn) == NF_STOLEN)
+                                return NF_STOLEN;
+#endif
 			return do_masquerade(pskb, out);
+                }
 		else return NF_ACCEPT;
 
 	case FW_REDIRECT:
diff -Nru a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
--- a/net/ipv4/netfilter/ip_nat_core.c	Tue Jun 24 15:09:59 2003
+++ b/net/ipv4/netfilter/ip_nat_core.c	Sun Aug 24 05:03:00 2003
@@ -67,6 +67,7 @@
 static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
 {
 	struct ip_nat_info *info = &conn->nat.info;
+	unsigned int hs, hp;
 
 	if (!info->initialized)
 		return;
@@ -74,21 +75,18 @@
 	IP_NF_ASSERT(info->bysource.conntrack);
 	IP_NF_ASSERT(info->byipsproto.conntrack);
 
+	hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
+	                 conn->tuplehash[IP_CT_DIR_ORIGINAL]
+	                 .tuple.dst.protonum);
+
+	hp = hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
+	                      conn->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
+	                      conn->tuplehash[IP_CT_DIR_REPLY]
+	                      .tuple.dst.protonum);
+
 	WRITE_LOCK(&ip_nat_lock);
-	LIST_DELETE(&bysource[hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL]
-					  .tuple.src,
-					  conn->tuplehash[IP_CT_DIR_ORIGINAL]
-					  .tuple.dst.protonum)],
-		    &info->bysource);
-
-	LIST_DELETE(&byipsproto
-		    [hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY]
-				      .tuple.src.ip,
-				      conn->tuplehash[IP_CT_DIR_REPLY]
-				      .tuple.dst.ip,
-				      conn->tuplehash[IP_CT_DIR_REPLY]
-				      .tuple.dst.protonum)],
-		    &info->byipsproto);
+	LIST_DELETE(&bysource[hs], &info->bysource);
+	LIST_DELETE(&byipsproto[hp], &info->byipsproto);
 	WRITE_UNLOCK(&ip_nat_lock);
 }
 
@@ -244,11 +242,12 @@
 	   const struct ip_conntrack *conntrack)
 {
 	unsigned int score = 0;
+	unsigned int h;
 
 	MUST_BE_READ_LOCKED(&ip_nat_lock);
-	LIST_FIND(&byipsproto[hash_by_ipsproto(src, dst, protonum)],
-		  fake_cmp, struct ip_nat_hash *, src, dst, protonum, &score,
-		  conntrack);
+	h = hash_by_ipsproto(src, dst, protonum);
+	LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *,
+	          src, dst, protonum, &score, conntrack);
 
 	return score;
 }
diff -Nru a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c
--- a/net/ipv4/netfilter/ip_nat_tftp.c	Mon Mar 31 07:08:21 2003
+++ b/net/ipv4/netfilter/ip_nat_tftp.c	Sat Aug  2 22:55:33 2003
@@ -153,7 +153,7 @@
 
 static int __init init(void)
 {
-	int i, ret;
+	int i, ret = 0;
 	char *tmpname;
 
 	if (!ports[0])
diff -Nru a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
--- a/net/ipv4/netfilter/ipt_LOG.c	Tue Feb  5 06:10:25 2002
+++ b/net/ipv4/netfilter/ipt_LOG.c	Sat Aug  2 22:52:26 2003
@@ -3,15 +3,14 @@
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
-#include <linux/ip.h>
 #include <linux/spinlock.h>
+#include <linux/ip.h>
 #include <net/icmp.h>
 #include <net/udp.h>
 #include <net/tcp.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-struct in_device;
 #include <net/route.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_LOG.h>
 
 #if 0
@@ -20,10 +19,20 @@
 #define DEBUGP(format, args...)
 #endif
 
+/* FIXME: move to ip.h like in 2.5 */
+struct ahhdr {
+	__u8    nexthdr;
+	__u8    hdrlen;
+	__u16   reserved;
+	__u32   spi;
+	__u32   seq_no;
+};
+
 struct esphdr {
 	__u32   spi;
-}; /* FIXME evil kludge */
-        
+	__u32   seq_no;
+};
+
 /* Use lock to serialize, so printks don't overlap */
 static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
 
@@ -58,7 +67,8 @@
 		printk("FRAG:%u ", ntohs(iph->frag_off) & IP_OFFSET);
 
 	if ((info->logflags & IPT_LOG_IPOPT)
-	    && iph->ihl * 4 != sizeof(struct iphdr)) {
+	    && iph->ihl * 4 != sizeof(struct iphdr)
+	    && iph->ihl * 4 >= datalen) {
 		unsigned int i;
 
 		/* Max length: 127 "OPT (" 15*4*2chars ") " */
@@ -230,13 +240,30 @@
 		break;
 	}
 	/* Max Length */
-	case IPPROTO_AH:
+	case IPPROTO_AH: {
+		struct ahhdr *ah = protoh;
+
+		/* Max length: 9 "PROTO=AH " */
+		printk("PROTO=AH ");
+
+		if (ntohs(iph->frag_off) & IP_OFFSET)
+			break;
+
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		if (datalen < sizeof (*ah)) {
+			printk("INCOMPLETE [%u bytes] ", datalen);
+			break;
+		}
+
+		/* Length: 15 "SPI=0xF1234567 " */
+		printk("SPI=0x%x ", ntohl(ah->spi) );
+		break;
+	}
 	case IPPROTO_ESP: {
 		struct esphdr *esph = protoh;
-		int esp= (iph->protocol==IPPROTO_ESP);
 
 		/* Max length: 10 "PROTO=ESP " */
-		printk("PROTO=%s ",esp? "ESP" : "AH");
+		printk("PROTO=ESP ");
 
 		if (ntohs(iph->frag_off) & IP_OFFSET)
 			break;
diff -Nru a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c	Mon Feb  4 23:49:27 2002
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c	Sat Aug 30 20:45:05 2003
@@ -87,13 +87,21 @@
 	key.dst = (*pskb)->nh.iph->daddr;
 	key.src = 0; /* Unknown: that's what we're trying to establish */
 	key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN;
-	key.oif = out->ifindex;
+	key.oif = 0;
 #ifdef CONFIG_IP_ROUTE_FWMARK
 	key.fwmark = (*pskb)->nfmark;
 #endif
 	if (ip_route_output_key(&rt, &key) != 0) {
-		/* Shouldn't happen */
-		printk("MASQUERADE: No route: Rusty's brain broke!\n");
+                /* Funky routing can do this. */
+                if (net_ratelimit())
+                        printk("MASQUERADE:"
+                               " No route: Rusty's brain broke!\n");
+                return NF_DROP;
+        }
+        if (rt->u.dst.dev != out) {
+                if (net_ratelimit())
+                        printk("MASQUERADE:"
+                               " Route sent us somewhere else.\n");
 		return NF_DROP;
 	}
 
diff -Nru a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
--- a/net/ipv4/netfilter/ipt_ah.c	Thu Aug  8 07:52:52 2002
+++ b/net/ipv4/netfilter/ipt_ah.c	Sat Aug  2 22:52:26 2003
@@ -15,7 +15,11 @@
 #endif
 
 struct ahhdr {
+	__u8    nexthdr;
+	__u8    hdrlen;
+	__u16   reserved;
 	__u32   spi;
+	__u32   seq_no;
 };
 
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
diff -Nru a/net/ipv4/netfilter/ipt_esp.c b/net/ipv4/netfilter/ipt_esp.c
--- a/net/ipv4/netfilter/ipt_esp.c	Tue Feb  5 14:37:18 2002
+++ b/net/ipv4/netfilter/ipt_esp.c	Sat Aug  2 22:52:26 2003
@@ -16,6 +16,7 @@
 
 struct esphdr {
 	__u32   spi;
+	__u32   seq_no;
 };
 
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c
--- a/net/ipv4/route.c	Tue Jun 17 16:17:42 2003
+++ b/net/ipv4/route.c	Sat Aug 16 12:10:15 2003
@@ -375,7 +375,9 @@
  */
 static inline u32 rt_score(struct rtable *rt)
 {
-	u32 score = rt->u.dst.__use;
+	u32 score = jiffies - rt->u.dst.lastuse;
+
+	score = ~score & ~(3<<30);
 
 	if (rt_valuable(rt))
 		score |= (1<<31);
@@ -703,8 +705,7 @@
 		 * The second limit is less certain. At the moment it allows
 		 * only 2 entries per bucket. We will see.
 		 */
-		if (chain_length > ip_rt_gc_elasticity ||
-		    (chain_length > 1 && !(min_score & (1<<31)))) {
+		if (chain_length > ip_rt_gc_elasticity) {
 			*candp = cand->u.rt_next;
 			rt_free(cand);
 		}
diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c	Mon Jun 23 16:21:28 2003
+++ b/net/ipv6/addrconf.c	Sat Aug  9 20:49:50 2003
@@ -103,7 +103,7 @@
 
 static int addrconf_ifdown(struct net_device *dev, int how);
 
-static void addrconf_dad_start(struct inet6_ifaddr *ifp);
+static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
 static void addrconf_dad_timer(unsigned long data);
 static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
 static void addrconf_rs_timer(unsigned long data);
@@ -898,7 +898,7 @@
 	rtmsg.rtmsg_dst_len = 8;
 	rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
 	rtmsg.rtmsg_ifindex = dev->ifindex;
-	rtmsg.rtmsg_flags = RTF_UP|RTF_ADDRCONF;
+	rtmsg.rtmsg_flags = RTF_UP;
 	rtmsg.rtmsg_type = RTMSG_NEWROUTE;
 	ip6_route_add(&rtmsg, NULL);
 }
@@ -925,7 +925,7 @@
 	struct in6_addr addr;
 
 	ipv6_addr_set(&addr,  htonl(0xFE800000), 0, 0, 0);
-	addrconf_prefix_route(&addr, 64, dev, 0, RTF_ADDRCONF);
+	addrconf_prefix_route(&addr, 64, dev, 0, 0);
 }
 
 static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
@@ -1017,7 +1017,7 @@
 		}
 	} else if (pinfo->onlink && valid_lft) {
 		addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
-				      dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES);
+				      dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES|RTF_PREFIX_RT);
 	}
 	if (rt)
 		dst_release(&rt->u.dst);
@@ -1063,7 +1063,7 @@
 				return;
 			}
 
-			addrconf_dad_start(ifp);
+			addrconf_dad_start(ifp, RTF_ADDRCONF|RTF_PREFIX_RT);
 		}
 
 		if (ifp && valid_lft == 0) {
@@ -1175,7 +1175,7 @@
 
 	ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);
 	if (!IS_ERR(ifp)) {
-		addrconf_dad_start(ifp);
+		addrconf_dad_start(ifp, 0);
 		in6_ifa_put(ifp);
 		return 0;
 	}
@@ -1350,7 +1350,7 @@
 
 	ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
 	if (!IS_ERR(ifp)) {
-		addrconf_dad_start(ifp);
+		addrconf_dad_start(ifp, 0);
 		in6_ifa_put(ifp);
 	}
 }
@@ -1588,8 +1588,7 @@
 		memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
 		rtmsg.rtmsg_type = RTMSG_NEWROUTE;
 		rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
-		rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_ADDRCONF | 
-				     RTF_DEFAULT | RTF_UP);
+		rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_DEFAULT | RTF_UP);
 
 		rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;
 
@@ -1603,7 +1602,7 @@
 /*
  *	Duplicate Address Detection
  */
-static void addrconf_dad_start(struct inet6_ifaddr *ifp)
+static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
 {
 	struct net_device *dev;
 	unsigned long rand_num;
@@ -1613,7 +1612,7 @@
 	addrconf_join_solict(dev, &ifp->addr);
 
 	if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT))
-		addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0, RTF_ADDRCONF);
+		addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0, flags);
 
 	net_srandom(ifp->addr.s6_addr32[3]);
 	rand_num = net_random() % (ifp->idev->cnf.rtr_solicit_delay ? : 1);
@@ -1895,6 +1894,7 @@
 	unsigned char	 *b = skb->tail;
 
 	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));
+	if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;
 	ifm = NLMSG_DATA(nlh);
 	ifm->ifa_family = AF_INET6;
 	ifm->ifa_prefixlen = ifa->prefix_len;
diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
--- a/net/ipv6/ndisc.c	Mon Jun 23 16:21:28 2003
+++ b/net/ipv6/ndisc.c	Tue Aug 19 12:44:36 2003
@@ -1336,6 +1336,26 @@
 	return 0;
 }
 
+static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	switch (event) {
+	case NETDEV_CHANGEADDR:
+		neigh_changeaddr(&nd_tbl, dev);
+		fib6_run_gc(0);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+struct notifier_block ndisc_netdev_notifier = {
+	.notifier_call = ndisc_netdev_event,
+};
+
 int __init ndisc_init(struct net_proto_family *ops)
 {
 	struct sock *sk;
@@ -1377,6 +1397,7 @@
 	neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
 #endif
 
+	register_netdevice_notifier(&ndisc_netdev_notifier);
 	return 0;
 }
 
diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c	Thu Jul 10 17:38:59 2003
+++ b/net/ipv6/raw.c	Mon Aug 11 22:29:26 2003
@@ -771,6 +771,7 @@
 			val = -1;
 		else
 			val = opt->offset;
+		break;
 
 	default:
 		return -ENOPROTOOPT;
diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c
--- a/net/ipv6/route.c	Fri Jun 27 20:21:00 2003
+++ b/net/ipv6/route.c	Wed Jul 23 03:02:34 2003
@@ -1580,13 +1580,19 @@
 			 struct in6_addr *src,
 			 int iif,
 			 int type, u32 pid, u32 seq,
-			 struct nlmsghdr *in_nlh)
+			 struct nlmsghdr *in_nlh, int prefix)
 {
 	struct rtmsg *rtm;
 	struct nlmsghdr  *nlh;
 	unsigned char	 *b = skb->tail;
 	struct rta_cacheinfo ci;
 
+	if (prefix) {	/* user wants prefix routes only */
+		if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
+			/* success since this is not a prefix route */
+			return 1;
+		}
+	}
 	if (!pid && in_nlh) {
 		pid = in_nlh->nlmsg_pid;
 	}
@@ -1667,10 +1673,17 @@
 static int rt6_dump_route(struct rt6_info *rt, void *p_arg)
 {
 	struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
+	struct rtmsg *rtm;
+	int prefix;
+
+	rtm = NLMSG_DATA(arg->cb->nlh);
+	if (rtm)
+		prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
+	else prefix = 0;
 
 	return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
 		     NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
-		     NULL);
+		     NULL, prefix);
 }
 
 static int fib6_dump_node(struct fib6_walker_t *w)
@@ -1821,7 +1834,7 @@
 			    fl.nl_u.ip6_u.saddr,
 			    iif,
 			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
-			    nlh->nlmsg_seq, nlh);
+			    nlh->nlmsg_seq, nlh, 0);
 	if (err < 0) {
 		err = -EMSGSIZE;
 		goto out_free;
@@ -1847,7 +1860,7 @@
 		netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
 		return;
 	}
-	if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh) < 0) {
+	if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh, 0) < 0) {
 		kfree_skb(skb);
 		netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
 		return;
diff -Nru a/net/netsyms.c b/net/netsyms.c
--- a/net/netsyms.c	Fri Jul 11 23:06:42 2003
+++ b/net/netsyms.c	Mon Aug 25 14:24:22 2003
@@ -18,6 +18,7 @@
 #include <linux/fcdevice.h>
 #include <linux/ioport.h>
 #include <linux/tty.h>
+#include <linux/ethtool.h>
 #include <net/neighbour.h>
 #include <net/snmp.h>
 #include <net/dst.h>
@@ -193,6 +194,7 @@
 EXPORT_SYMBOL(neigh_parms_release);
 EXPORT_SYMBOL(neigh_rand_reach_time);
 EXPORT_SYMBOL(neigh_compat_output); 
+EXPORT_SYMBOL(neigh_changeaddr);
 
 /*	dst_entry	*/
 EXPORT_SYMBOL(dst_alloc);
@@ -265,6 +267,7 @@
 EXPORT_SYMBOL(in_aton);
 EXPORT_SYMBOL(ip_mc_inc_group);
 EXPORT_SYMBOL(ip_mc_dec_group);
+EXPORT_SYMBOL(ip_mc_join_group);
 EXPORT_SYMBOL(ip_finish_output);
 EXPORT_SYMBOL(inet_stream_ops);
 EXPORT_SYMBOL(inet_dgram_ops);
@@ -610,5 +613,11 @@
 #include <net/iw_handler.h>
 EXPORT_SYMBOL(wireless_send_event);
 #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+
+/* ethtool.c */
+EXPORT_SYMBOL(ethtool_op_get_link);
+EXPORT_SYMBOL(ethtool_op_get_tx_csum);
+EXPORT_SYMBOL(ethtool_op_get_sg);
+EXPORT_SYMBOL(ethtool_op_set_sg);
 
 #endif  /* CONFIG_NET */
diff -Nru a/net/sched/sch_htb.c b/net/sched/sch_htb.c
--- a/net/sched/sch_htb.c	Tue Jul  8 18:53:06 2003
+++ b/net/sched/sch_htb.c	Mon Jul 28 16:41:52 2003
@@ -19,9 +19,11 @@
  *			code review and helpful comments on shaping
  *		Tomasz Wrona, <tw@eter.tym.pl>
  *			created test case so that I was able to fix nasty bug
+ *		Wilfried Weissmann
+ *			spotted bug in dequeue code and helped with fix
  *		and many others. thanks.
  *
- * $Id: sch_htb.c,v 1.20 2003/06/18 19:55:49 devik Exp devik $
+ * $Id: sch_htb.c,v 1.24 2003/07/28 15:25:23 devik Exp devik $
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -73,7 +75,7 @@
 #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */
 #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock)
 #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock)
-#define HTB_VER 0x3000c	/* major must be matched with number suplied by TC as version */
+#define HTB_VER 0x3000d	/* major must be matched with number suplied by TC as version */
 
 #if HTB_VER >> 16 != TC_HTB_PROTOVER
 #error "Mismatched sch_htb.c and pkt_sch.h"
@@ -98,7 +100,8 @@
  from LSB
  */
 #ifdef HTB_DEBUG
-#define HTB_DBG(S,L,FMT,ARG...) if (((q->debug>>(2*S))&3) >= L) \
+#define HTB_DBG_COND(S,L) (((q->debug>>(2*S))&3) >= L)
+#define HTB_DBG(S,L,FMT,ARG...) if (HTB_DBG_COND(S,L)) \
 	printk(KERN_DEBUG FMT,##ARG)
 #define HTB_CHCL(cl) BUG_TRAP((cl)->magic == HTB_CMAGIC)
 #define HTB_PASSQ q,
@@ -114,6 +117,7 @@
 		rb_erase(N,R); \
 		(N)->rb_color = -1; } while (0)
 #else
+#define HTB_DBG_COND(S,L) (0)
 #define HTB_DBG(S,L,FMT,ARG...)
 #define HTB_PASSQ
 #define HTB_ARGQ
@@ -454,12 +458,14 @@
 {
 	rb_node_t *p;
 	if ((*n)->rb_right) {
+		/* child at right. use it or its leftmost ancestor */
 		*n = (*n)->rb_right;
 		while ((*n)->rb_left) 
 			*n = (*n)->rb_left;
 		return;
 	}
 	while ((p = (*n)->rb_parent) != NULL) {
+		/* if we've arrived from left child then we have next node */
 		if (p->rb_left == *n) break;
 		*n = p;
 	}
@@ -912,6 +918,7 @@
 		rb_node_t **pptr;
 	} stk[TC_HTB_MAXDEPTH],*sp = stk;
 	
+	BUG_TRAP(tree->rb_node);
 	sp->root = tree->rb_node;
 	sp->pptr = pptr;
 
@@ -945,15 +952,36 @@
 htb_dequeue_tree(struct htb_sched *q,int prio,int level)
 {
 	struct sk_buff *skb = NULL;
-	//struct htb_sched *q = (struct htb_sched *)sch->data;
 	struct htb_class *cl,*start;
 	/* look initial class up in the row */
 	start = cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio);
 	
 	do {
-		BUG_TRAP(cl && cl->un.leaf.q->q.qlen); if (!cl) return NULL;
+next:
+		BUG_TRAP(cl); 
+		if (!cl) return NULL;
 		HTB_DBG(4,1,"htb_deq_tr prio=%d lev=%d cl=%X defic=%d\n",
 				prio,level,cl->classid,cl->un.leaf.deficit[level]);
+
+		/* class can be empty - it is unlikely but can be true if leaf
+		   qdisc drops packets in enqueue routine or if someone used
+		   graft operation on the leaf since last dequeue; 
+		   simply deactivate and skip such class */
+		if (unlikely(cl->un.leaf.q->q.qlen == 0)) {
+			struct htb_class *next;
+			htb_deactivate(q,cl);
+
+			/* row/level might become empty */
+			if ((q->row_mask[level] & (1 << prio)) == 0)
+				return NULL; 
+			
+			next = htb_lookup_leaf (q->row[level]+prio,
+					prio,q->ptr[level]+prio);
+			if (cl == start) /* fix start if we just deleted it */
+				start = next;
+			cl = next;
+			goto next;
+		}
 	
 		if (likely((skb = cl->un.leaf.q->dequeue(cl->un.leaf.q)) != NULL)) 
 			break;
@@ -1201,7 +1229,8 @@
 	gopt.direct_pkts = q->direct_pkts;
 
 #ifdef HTB_DEBUG
-	htb_debug_dump(q);
+	if (HTB_DBG_COND(0,2))
+		htb_debug_dump(q);
 #endif
 	gopt.version = HTB_VER;
 	gopt.rate2quantum = q->rate2quantum;
@@ -1282,6 +1311,9 @@
 					return -ENOBUFS;
 		sch_tree_lock(sch);
 		if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) {
+			if (cl->prio_activity)
+				htb_deactivate ((struct htb_sched*)sch->data,cl);
+
 			/* TODO: is it correct ? Why CBQ doesn't do it ? */
 			sch->q.qlen -= (*old)->q.qlen;	
 			qdisc_reset(*old);
