diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/CodingStyle linux-2.4.27-pre3/Documentation/CodingStyle
--- linux-2.4.26/Documentation/CodingStyle	2001-09-09 23:40:43.000000000 +0000
+++ linux-2.4.27-pre3/Documentation/CodingStyle	2004-05-18 16:52:26.000000000 +0000
@@ -1,42 +1,75 @@
 
-		Linux kernel coding style 
+		Linux kernel coding style
 
 This is a short document describing the preferred coding style for the
 linux kernel.  Coding style is very personal, and I won't _force_ my
 views on anybody, but this is what goes for anything that I have to be
 able to maintain, and I'd prefer it for most other things too.  Please
-at least consider the points made here. 
+at least consider the points made here.
 
 First off, I'd suggest printing out a copy of the GNU coding standards,
-and NOT read it.  Burn them, it's a great symbolic gesture. 
+and NOT reading it.  Burn them, it's a great symbolic gesture.
 
 Anyway, here goes:
 
 
 	 	Chapter 1: Indentation
 
-Tabs are 8 characters, and thus indentations are also 8 characters. 
+Tabs are 8 characters, and thus indentations are also 8 characters.
 There are heretic movements that try to make indentations 4 (or even 2!)
 characters deep, and that is akin to trying to define the value of PI to
-be 3. 
+be 3.
 
 Rationale: The whole idea behind indentation is to clearly define where
 a block of control starts and ends.  Especially when you've been looking
 at your screen for 20 straight hours, you'll find it a lot easier to see
-how the indentation works if you have large indentations. 
+how the indentation works if you have large indentations.
 
 Now, some people will claim that having 8-character indentations makes
 the code move too far to the right, and makes it hard to read on a
 80-character terminal screen.  The answer to that is that if you need
 more than 3 levels of indentation, you're screwed anyway, and should fix
-your program. 
+your program.
 
 In short, 8-char indents make things easier to read, and have the added
-benefit of warning you when you're nesting your functions too deep. 
-Heed that warning. 
+benefit of warning you when you're nesting your functions too deep.
+Heed that warning.
 
+Don't put multiple statements on a single line unless you have
+something to hide:
 
-		Chapter 2: Placing Braces
+	if (condition) do_this;
+	  do_something_everytime;
+
+Outside of comments, documentation and except in [cC]onfig.in, spaces are never
+used for indentation, and the above example is deliberately broken.
+
+Get a decent editor and don't leave whitespace at the end of lines.
+
+
+		Chapter 2: Breaking long lines and strings
+
+Coding style is all about readability and maintainability using commonly
+available tools.
+
+The limit on the length of lines is 80 columns and this is a hard limit.
+
+Statements longer than 80 columns will be broken into sensible chunks.
+Descendants are always substantially shorter than the parent and are placed
+substantially to the right. The same applies to function headers with a long
+argument list. Long strings are as well broken into shorter strings.
+
+void fun(int a, int b, int c)
+{
+	if (condition)
+		printk(KERN_WARNING "Warning this is a long printk with "
+						"3 parameters a: %u b: %u "
+						"c: %u \n", a, b, c);
+	else
+		next_statement;
+}
+
+		Chapter 3: Placing Braces
 
 The other issue that always comes up in C styling is the placement of
 braces.  Unlike the indent size, there are few technical reasons to
@@ -59,7 +92,7 @@ opening brace at the beginning of the ne
 Heretic people all over the world have claimed that this inconsistency
 is ...  well ...  inconsistent, but all right-thinking people know that
 (a) K&R are _right_ and (b) K&R are right.  Besides, functions are
-special anyway (you can't nest them in C). 
+special anyway (you can't nest them in C).
 
 Note that the closing brace is empty on a line of its own, _except_ in
 the cases where it is followed by a continuation of the same statement,
@@ -79,60 +112,60 @@ and
 	} else {
 		....
 	}
-			
-Rationale: K&R. 
+
+Rationale: K&R.
 
 Also, note that this brace-placement also minimizes the number of empty
 (or almost empty) lines, without any loss of readability.  Thus, as the
 supply of new-lines on your screen is not a renewable resource (think
 25-line terminal screens here), you have more empty lines to put
-comments on. 
+comments on.
 
 
-		Chapter 3: Naming
+		Chapter 4: Naming
 
 C is a Spartan language, and so should your naming be.  Unlike Modula-2
 and Pascal programmers, C programmers do not use cute names like
 ThisVariableIsATemporaryCounter.  A C programmer would call that
 variable "tmp", which is much easier to write, and not the least more
-difficult to understand. 
+difficult to understand.
 
 HOWEVER, while mixed-case names are frowned upon, descriptive names for
 global variables are a must.  To call a global function "foo" is a
-shooting offense. 
+shooting offense.
 
 GLOBAL variables (to be used only if you _really_ need them) need to
 have descriptive names, as do global functions.  If you have a function
 that counts the number of active users, you should call that
-"count_active_users()" or similar, you should _not_ call it "cntusr()". 
+"count_active_users()" or similar, you should _not_ call it "cntusr()".
 
 Encoding the type of a function into the name (so-called Hungarian
 notation) is brain damaged - the compiler knows the types anyway and can
 check those, and it only confuses the programmer.  No wonder MicroSoft
-makes buggy programs. 
+makes buggy programs.
 
 LOCAL variable names should be short, and to the point.  If you have
-some random integer loop counter, it should probably be called "i". 
+some random integer loop counter, it should probably be called "i".
 Calling it "loop_counter" is non-productive, if there is no chance of it
 being mis-understood.  Similarly, "tmp" can be just about any type of
-variable that is used to hold a temporary value. 
+variable that is used to hold a temporary value.
 
 If you are afraid to mix up your local variable names, you have another
-problem, which is called the function-growth-hormone-imbalance syndrome. 
-See next chapter. 
+problem, which is called the function-growth-hormone-imbalance syndrome.
+See next chapter.
 
-		
-		Chapter 4: Functions
+
+		Chapter 5: Functions
 
 Functions should be short and sweet, and do just one thing.  They should
 fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
-as we all know), and do one thing and do that well. 
+as we all know), and do one thing and do that well.
 
 The maximum length of a function is inversely proportional to the
 complexity and indentation level of that function.  So, if you have a
 conceptually simple function that is just one long (but simple)
 case-statement, where you have to do lots of small things for a lot of
-different cases, it's OK to have a longer function. 
+different cases, it's OK to have a longer function.
 
 However, if you have a complex function, and you suspect that a
 less-than-gifted first-year high-school student might not even
@@ -140,41 +173,78 @@ understand what the function is all abou
 maximum limits all the more closely.  Use helper functions with
 descriptive names (you can ask the compiler to in-line them if you think
 it's performance-critical, and it will probably do a better job of it
-that you would have done). 
+than you would have done).
 
 Another measure of the function is the number of local variables.  They
 shouldn't exceed 5-10, or you're doing something wrong.  Re-think the
 function, and split it into smaller pieces.  A human brain can
 generally easily keep track of about 7 different things, anything more
 and it gets confused.  You know you're brilliant, but maybe you'd like
-to understand what you did 2 weeks from now. 
+to understand what you did 2 weeks from now.
+
+
+		Chapter 6: Centralized exiting of functions
 
+Albeit deprecated by some people, the equivalent of the goto statement is
+used frequently by compilers in form of the unconditional jump instruction.
 
-		Chapter 5: Commenting
+The goto statement comes in handy when a function exits from multiple
+locations and some common work such as cleanup has to be done.
+
+The rationale is:
+
+- unconditional statements are easier to understand and follow
+- nesting is reduced
+- errors by not updating individual exit points when making
+    modifications are prevented
+- saves the compiler work to optimize redundant code away ;)
+
+int fun(int )
+{
+	int result = 0;
+	char *buffer = kmalloc(SIZE);
+
+	if (buffer == NULL)
+		return -ENOMEM;
+
+	if (condition1) {
+		while (loop1) {
+			...
+		}
+		result = 1;
+		goto out;
+	}
+	...
+out:
+	kfree(buffer);
+	return result;
+}
+
+		Chapter 7: Commenting
 
 Comments are good, but there is also a danger of over-commenting.  NEVER
 try to explain HOW your code works in a comment: it's much better to
 write the code so that the _working_ is obvious, and it's a waste of
-time to explain badly written code. 
+time to explain badly written code.
 
-Generally, you want your comments to tell WHAT your code does, not HOW. 
+Generally, you want your comments to tell WHAT your code does, not HOW.
 Also, try to avoid putting comments inside a function body: if the
 function is so complex that you need to separately comment parts of it,
-you should probably go back to chapter 4 for a while.  You can make
+you should probably go back to chapter 5 for a while.  You can make
 small comments to note or warn about something particularly clever (or
 ugly), but try to avoid excess.  Instead, put the comments at the head
 of the function, telling people what it does, and possibly WHY it does
-it. 
+it.
 
 
-		Chapter 6: You've made a mess of it
+		Chapter 8: You've made a mess of it
 
 That's OK, we all do.  You've probably been told by your long-time Unix
 user helper that "GNU emacs" automatically formats the C sources for
 you, and you've noticed that yes, it does do that, but the defaults it
 uses are less than desirable (in fact, they are worse than random
-typing - a infinite number of monkeys typing into GNU emacs would never
-make a good program). 
+typing - an infinite number of monkeys typing into GNU emacs would never
+make a good program).
 
 So, you can either get rid of GNU emacs, or change it to use saner
 values.  To do the latter, you can stick the following in your .emacs file:
@@ -192,7 +262,7 @@ two lines, this mode will be automatical
 to add
 
 (setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
-                       auto-mode-alist))
+			auto-mode-alist))
 
 to your .emacs file if you want to have linux-c-mode switched on
 automagically when you edit source files under /usr/src/linux.
@@ -200,19 +270,20 @@ automagically when you edit source files
 But even if you fail in getting emacs to do sane formatting, not
 everything is lost: use "indent".
 
-Now, again, GNU indent has the same brain dead settings that GNU emacs
-has, which is why you need to give it a few command line options. 
+Now, again, GNU indent has the same brain-dead settings that GNU emacs
+has, which is why you need to give it a few command line options.
 However, that's not too bad, because even the makers of GNU indent
 recognize the authority of K&R (the GNU people aren't evil, they are
 just severely misguided in this matter), so you just give indent the
-options "-kr -i8" (stands for "K&R, 8 character indents"). 
+options "-kr -i8" (stands for "K&R, 8 character indents"), or use
+"scripts/Lindent", which indents in the latest style.
 
 "indent" has a lot of options, and especially when it comes to comment
-re-formatting you may want to take a look at the manual page.  But
-remember: "indent" is not a fix for bad programming. 
+re-formatting you may want to take a look at the man page.  But
+remember: "indent" is not a fix for bad programming.
 
 
-		Chapter 7: Configuration-files
+		Chapter 9: Configuration-files
 
 For configuration options (arch/xxx/config.in, and all the Config.in files),
 somewhat different indentation is used.
@@ -235,20 +306,20 @@ support for file-systems, for instance) 
 Experimental options should be denoted (EXPERIMENTAL).
 
 
-		Chapter 8: Data structures
+		Chapter 10: Data structures
 
 Data structures that have visibility outside the single-threaded
 environment they are created and destroyed in should always have
 reference counts.  In the kernel, garbage collection doesn't exist (and
 outside the kernel garbage collection is slow and inefficient), which
-means that you absolutely _have_ to reference count all your uses. 
+means that you absolutely _have_ to reference count all your uses.
 
 Reference counting means that you can avoid locking, and allows multiple
 users to have access to the data structure in parallel - and not having
 to worry about the structure suddenly going away from under them just
-because they slept or did something else for a while. 
+because they slept or did something else for a while.
 
-Note that locking is _not_ a replacement for reference counting. 
+Note that locking is _not_ a replacement for reference counting.
 Locking is used to keep data structures coherent, while reference
 counting is a memory management technique.  Usually both are needed, and
 they are not to be confused with each other.
@@ -258,9 +329,99 @@ when there are users of different "class
 the number of subclass users, and decrements the global count just once
 when the subclass count goes to zero.
 
-Examples of this kind of "multi-reference-counting" can be found in
+Examples of this kind of "multi-level-reference-counting" can be found in
 memory management ("struct mm_struct": mm_users and mm_count), and in
 filesystem code ("struct super_block": s_count and s_active).
 
 Remember: if another thread can find your data structure, and you don't
 have a reference count on it, you almost certainly have a bug.
+
+
+		Chapter 11: Macros, Enums, Inline functions and RTL
+
+Names of macros defining constants and labels in enums are capitalized.
+
+#define CONSTANT 0x12345
+
+Enums are preferred when defining several related constants.
+
+CAPITALIZED macro names are appreciated but macros resembling functions
+may be named in lower case.
+
+Generally, inline functions are preferable to macros resembling functions.
+
+Macros with multiple statements should be enclosed in a do - while block:
+
+#define macrofun(a,b,c) 			\
+	do {					\
+		if (a == 5)			\
+			do_this(b,c);		\
+	} while (0)
+
+Things to avoid when using macros:
+
+1) macros that affect control flow:
+
+#define FOO(x)					\
+	do {					\
+		if (blah(x) < 0)		\
+			return -EBUGGERED;	\
+	} while(0)
+
+is a _very_ bad idea.  It looks like a function call but exits the "calling"
+function; don't break the internal parsers of those who will read the code.
+
+2) macros that depend on having a local variable with a magic name:
+
+#define FOO(val) bar(index, val)
+
+might look like a good thing, but it's confusing as hell when one reads the
+code and it's prone to breakage from seemingly innocent changes.
+
+3) macros with arguments that are used as l-values: FOO(x) = y; will
+bite you if somebody e.g. turns FOO into an inline function.
+
+4) forgetting about precedence: macros defining constants using expressions
+must enclose the expression in parentheses. Beware of similar issues with
+macros using parameters.
+
+#define CONSTANT 0x4000
+#define CONSTEXP (CONSTANT | 3)
+
+The cpp manual deals with macros exhaustively. The gcc internals manual also
+covers RTL which is used frequently with assembly language in the kernel.
+
+
+		Chapter 12: Printing kernel messages
+
+Kernel developers like to be seen as literate. Do mind the spelling
+of kernel messages to make a good impression. Do not use crippled
+words like "dont" and use "do not" or "don't" instead.
+
+Kernel messages do not have to be terminated with a period.
+
+Printing numbers in parentheses (%d) adds no value and should be avoided.
+
+
+		Chapter 13: References
+
+The C Programming Language, Second Edition
+by Brian W. Kernighan and Dennis M. Ritchie.
+Prentice Hall, Inc., 1988.
+ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback).
+URL: http://cm.bell-labs.com/cm/cs/cbook/
+
+The Practice of Programming
+by Brian W. Kernighan and Rob Pike.
+Addison-Wesley, Inc., 1999.
+ISBN 0-201-61586-X.
+URL: http://cm.bell-labs.com/cm/cs/tpop/
+
+GNU manuals - where in compliance with K&R and this text - for cpp, gcc,
+gcc internals and indent, all available from http://www.gnu.org
+
+WG14 is the international standardization working group for the programming
+language C, URL: http://std.dkuug.dk/JTC1/SC22/WG14/
+
+--
+Last updated on 16 March 2004 by a community effort on LKML.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/Configure.help linux-2.4.27-pre3/Documentation/Configure.help
--- linux-2.4.26/Documentation/Configure.help	2004-04-14 13:05:24.000000000 +0000
+++ linux-2.4.27-pre3/Documentation/Configure.help	2004-05-18 16:55:06.000000000 +0000
@@ -569,6 +569,19 @@ CONFIG_BLK_DEV_UMEM
   The umem driver has been allocated block major number 116.
   See Documentation/devices.txt for recommended device naming.
 
+Promise SATA SX8 (carmel) support
+CONFIG_BLK_DEV_CARMEL
+   Saying Y or M here will enable support for the 
+   Promise SATA SX8 (carmel) controllers.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called carmel.o.
+
+  The carmel driver has been allocated block major numbers 160, 161.
+  See Documentation/devices.txt for recommended device naming.
+
 Network block device support
 CONFIG_BLK_DEV_NBD
   Saying Y here will allow your computer to be a client for network
@@ -13407,6 +13420,16 @@ CONFIG_HIPPI
   under Linux, say Y here (you must also remember to enable the driver
   for your HIPPI card below). Most people will say N here.
 
+IBM PowerPC Virtual Ethernet driver support
+CONFIG_IBMVETH
+  This driver supports virtual ethernet adapters on newer IBM iSeries
+  and pSeries systems.
+
+  If you want to compile the 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 ibmveth.o.
+
 Essential RoadRunner HIPPI PCI adapter support
 CONFIG_ROADRUNNER
   Say Y here if this is your PCI HIPPI network card.
@@ -17427,13 +17450,10 @@ Tracing support (EXPERIMENTAL)
 CONFIG_XFS_TRACE
   Say Y here to get an XFS build with activity tracing enabled.
   Enabling this option will attach historical information to XFS
-  inodes, pagebufs, certain locks, the log, the IO path, and a
+  inodes, buffers, certain locks, the log, the IO path, and a
   few other key areas within XFS.  These traces can be examined
   using a kernel debugger.
 
-  Note that for the pagebuf traces, you will also have to enable
-  the sysctl in /proc/sys/vm/pagebuf/debug for this to work.
-
   Say N unless you are an XFS developer.
 
 Debugging support (EXPERIMENTAL)
@@ -23167,9 +23187,6 @@ CONFIG_BLUEZ_HCIBT3C
      3Com Bluetooth Card (3CRWB6096)
      HP Bluetooth Card
 
-  The HCI BT3C driver uses external firmware loader program provided in
-  the BlueFW package. For more information, see <http://bluez.sf.net>.
-
   Say Y here to compile support for HCI BT3C devices into the
   kernel or say M to compile it as module (bt3c_cs.o).
 
@@ -28784,9 +28801,10 @@ CONFIG_CRYPTO_CAST6
 CONFIG_CRYPTO_ARC4
   ARC4 cipher algorithm.
   
-  This is a stream cipher using keys ranging from 8 bits to 2048
-  bits in length.  ARC4 is commonly used in protocols such as WEP 
-  and SSL.
+  ARC4 is a stream cipher using keys ranging from 8 bits to 2048
+  bits in length.  This algorithm is required for driver-based 
+  WEP, but it should not be for other purposes because of the
+  weakness of the algorithm.
 
 CONFIG_CRYPTO_DEFLATE
   This is the Deflate algorithm (RFC1951), specified for use in
@@ -28794,6 +28812,12 @@ CONFIG_CRYPTO_DEFLATE
 
   You will most probably want this if using IPSec.
 
+CONFIG_CRYPTO_MICHAEL_MIC
+  Michael MIC is used for message integrity protection in TKIP
+  (IEEE 802.11i). This algorithm is required for TKIP, but it
+  should not be used for other purposes because of the weakness
+  of the algorithm.
+
 CONFIG_CRYPTO_TEST
   Quick & dirty crypto test module.
   
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/DocBook/Makefile linux-2.4.27-pre3/Documentation/DocBook/Makefile
--- linux-2.4.26/Documentation/DocBook/Makefile	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.27-pre3/Documentation/DocBook/Makefile	2004-05-18 16:53:11.000000000 +0000
@@ -2,7 +2,7 @@ BOOKS	:= wanbook.sgml z8530book.sgml mca
 	   kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
 	   kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
 	   deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
-	   journal-api.sgml
+	   journal-api.sgml libata.sgml
 
 PS	:=	$(patsubst %.sgml, %.ps, $(BOOKS))
 PDF	:=	$(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -79,6 +79,16 @@ mcabook.sgml: mcabook.tmpl $(TOPDIR)/arc
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \
 		<mcabook.tmpl >mcabook.sgml
 
+libata.sgml: libata.tmpl $(TOPDIR)/drivers/scsi/libata-core.c \
+		$(TOPDIR)/drivers/scsi/libata-scsi.c	\
+		$(TOPDIR)/drivers/scsi/sata_sil.c	\
+		$(TOPDIR)/drivers/scsi/sata_via.c
+	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/scsi/libata-core.c \
+		$(TOPDIR)/drivers/scsi/libata-scsi.c	\
+		$(TOPDIR)/drivers/scsi/sata_sil.c	\
+		$(TOPDIR)/drivers/scsi/sata_via.c	\
+		< libata.tmpl > libata.sgml
+
 videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/media/video/videodev.c
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/media/video/videodev.c \
 		<videobook.tmpl >videobook.sgml
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/DocBook/libata.tmpl linux-2.4.27-pre3/Documentation/DocBook/libata.tmpl
--- linux-2.4.26/Documentation/DocBook/libata.tmpl	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/Documentation/DocBook/libata.tmpl	2004-05-18 16:52:35.000000000 +0000
@@ -0,0 +1,86 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="libataDevGuide">
+ <bookinfo>
+  <title>libATA Developer's Guide</title>
+  
+  <authorgroup>
+   <author>
+    <firstname>Jeff</firstname>
+    <surname>Garzik</surname>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2003</year>
+   <holder>Jeff Garzik</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   <ulink url="http://www.opensource.org/licenses/osl-1.1.txt">http://www.opensource.org/licenses/osl-1.1.txt</ulink> and is included herein
+   by reference.
+   </para>
+
+   <para>
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+   </para>
+
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="libataThanks">
+     <title>Thanks</title>
+  <para>
+  The bulk of the ATA knowledge comes thanks to long conversations with
+  Andre Hedrick (www.linux-ide.org).
+  </para>
+  <para>
+  Thanks to Alan Cox for pointing out similarities 
+  between SATA and SCSI, and in general for motivation to hack on
+  libata.
+  </para>
+  <para>
+  libata's device detection
+  method, ata_pio_devchk, and in general all the early probing was
+  based on extensive study of Hale Landis's probe/reset code in his
+  ATADRVR driver (www.ata-atapi.com).
+  </para>
+  </chapter>
+
+  <chapter id="libataExt">
+     <title>libata Library</title>
+!Edrivers/scsi/libata-core.c
+!Edrivers/scsi/libata-scsi.c
+  </chapter>
+
+  <chapter id="libataInt">
+     <title>libata Internals</title>
+!Idrivers/scsi/libata-core.c
+!Idrivers/scsi/libata-scsi.c
+  </chapter>
+
+  <chapter id="SILInt">
+     <title>ata_sil Internals</title>
+!Idrivers/scsi/sata_sil.c
+  </chapter>
+
+  <chapter id="VIAInt">
+     <title>ata_via Internals</title>
+!Idrivers/scsi/sata_via.c
+  </chapter>
+
+</book>
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/cciss.txt linux-2.4.27-pre3/Documentation/cciss.txt
--- linux-2.4.26/Documentation/cciss.txt	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-pre3/Documentation/cciss.txt	2004-05-18 16:51:27.000000000 +0000
@@ -14,6 +14,8 @@ This driver is known to work with the fo
 	* SA 6400
 	* SA 6400 U320 Expansion Module
 	* SA 6i
+	* SA 6422
+	* SA V100
 
 If nodes are not already created in the /dev/cciss directory
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/crypto/api-intro.txt linux-2.4.27-pre3/Documentation/crypto/api-intro.txt
--- linux-2.4.26/Documentation/crypto/api-intro.txt	2004-04-14 13:05:24.000000000 +0000
+++ linux-2.4.27-pre3/Documentation/crypto/api-intro.txt	2004-05-18 16:55:33.000000000 +0000
@@ -187,6 +187,7 @@ Original developers of the crypto algori
   Brian Gladman (AES)
   Kartikey Mahendra Bhatt (CAST6)
   Jon Oberheide (ARC4)
+  Jouni Malinen (Michael MIC)
 
 SHA1 algorithm contributors:
   Jean-Francois Dive
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/filesystems/xfs.txt linux-2.4.27-pre3/Documentation/filesystems/xfs.txt
--- linux-2.4.26/Documentation/filesystems/xfs.txt	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/Documentation/filesystems/xfs.txt	2004-05-18 16:51:51.000000000 +0000
@@ -123,9 +123,15 @@ The following sysctls are available for 
 	in /proc/fs/xfs/stat.  It then immediately reset to "0".
   	
   fs.xfs.sync_interval		(Min: HZ  Default: 30*HZ  Max: 60*HZ)
-	The interval at which the xfssyncd thread for xfs filesystems
-	flushes metadata out to disk. This thread will flush log
-	activity out, and do some processing on unlinked inodes
+	The interval at which the xfssyncd thread flushes metadata
+	out to disk.  This thread will flush log activity out, and
+	do some processing on unlinked inodes.
+
+  fs.xfs.age_buffer             (Min: 1*HZ  Default: 15*HZ  Max: 300*HZ)
+	The age at which xfsbufd flushes dirty metadata buffers to disk.
+
+  fs.xfs.flush_interval         (Min: HZ/2  Default: HZ  Max: 30*HZ)
+	The interval at which xfsbufd scans the dirty metadata buffers list.
 
   fs.xfs.error_level		(Min: 0  Default: 3  Max: 11)
 	A volume knob for error reporting when internal errors occur.
@@ -190,14 +196,3 @@ The following sysctls are available for 
 	Setting this to "1" will cause the "noatime" flag set 
 	by the chattr(1) command on a directory to be
 	inherited by files in that directory.
-
-  vm.pagebuf.stats_clear	(Min: 0  Default: 0  Max: 1)
-	Setting this to "1" clears accumulated pagebuf statistics 
-	in /proc/fs/pagebuf/stat.  It then immediately reset to "0".
-  	
-  vm.pagebuf.flush_age		(Min: 1*HZ  Default: 15*HZ  Max: 300*HZ)
-	The age at which dirty metadata buffers are flushed to disk
-
-  vm.pagebuf.flush_int		(Min: HZ/2  Default: HZ  Max: 30*HZ)
-	The interval at which the list of dirty metadata buffers is
-	scanned.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/kernel-parameters.txt linux-2.4.27-pre3/Documentation/kernel-parameters.txt
--- linux-2.4.26/Documentation/kernel-parameters.txt	2004-04-14 13:05:24.000000000 +0000
+++ linux-2.4.27-pre3/Documentation/kernel-parameters.txt	2004-05-18 16:55:38.850004184 +0000
@@ -69,8 +69,9 @@ running once the system is up.
 	53c7xx=		[HW,SCSI] Amiga SCSI controllers.
 
 	acpi=		[HW,ACPI] Advanced Configuration and Power Interface 
-		force	Force ACPI on, even if blacklisted platform
-		off	Disable ACPI
+		force	Enable ACPI if default was off
+		off	Disable ACPI if default was on
+		noirq	Do not use ACPI for IRQ routing (see pci=noacpi)
 		ht	Limit ACPI to boot-time LAPIC enumeration for HT,
 			disabling the run-time AML interpreter.
 		strict	Be less tolerant of platforms that are not
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/usb/silverlink.txt linux-2.4.27-pre3/Documentation/usb/silverlink.txt
--- linux-2.4.26/Documentation/usb/silverlink.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.27-pre3/Documentation/usb/silverlink.txt	2004-05-18 16:51:27.000000000 +0000
@@ -8,7 +8,7 @@ Homepage: http://lpg.ticalc.org/prj_usb
 INTRODUCTION:
 
 This is a driver for the TI-GRAPH LINK USB (aka SilverLink) cable, a cable 
-designed by TI for connecting their TI8x/9x calculators to a computer 
+designed by TI for connecting their TI8x/9x graphing handhelds to a computer 
 (PC or Mac usually).
 
 If you need more information, please visit the 'SilverLink drivers' homepage 
@@ -16,10 +16,8 @@ at the above URL.
 
 WHAT YOU NEED:
 
-A TI calculator of course and a program capable to communicate with your 
-calculator.
-TiLP will work for sure (since I am his developer !). yal92 may be able to use
-it by changing tidev for tiglusb (may require some hacking...).
+A TI calculator/handheld of course and a program capable to communicate with 
+your calculator. A good choice is TiLP (http://www.tilp.info).
 
 HOW TO USE IT:
 
@@ -58,14 +56,19 @@ MODULE PARAMETERS:
 QUIRKS:
 
 The following problem seems to be specific to the link cable since it appears 
-on all platforms (Linux, Windows, Mac OS-X). 
+on all platforms (Linux, Windows, Mac OS-X). A guy told me it was a common but
+weird behaviour with Cypress microcontrollers (it uses an CY7C64013).
 
-In some very particular cases, the driver returns with success but
+In some very particular cases, the driver returns with success (no error) but
 without any data. The application should retry a read operation at least once.
 
+This problem and the need to issue IOCTL_TIUSB_RESET_PIPES before doing any
+packet transfer (like TI's software do) make this driver difficult to use in 
+pure raw access.
+
 HOW TO CONTACT US:
 
-You can email me at roms@lpg.ticalc.org. Please prefix the subject line
+You can email me at roms@tilp.info. Please prefix the subject line
 with "TIGLUSB: " so that I am certain to notice your message.
 You can also mail JB at jb@jblache.org: he has written the first release of 
 this driver but he better knows the Mac OS-X driver.
@@ -73,4 +76,4 @@ this driver but he better knows the Mac 
 CREDITS:
 
 The code is based on dabusb.c, printer.c and scanner.c !
-The driver has been developed independantly of Texas Instruments.
+The driver has been developed without any support from Texas Instruments Inc.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/MAINTAINERS linux-2.4.27-pre3/MAINTAINERS
--- linux-2.4.26/MAINTAINERS	2004-04-14 13:05:25.000000000 +0000
+++ linux-2.4.27-pre3/MAINTAINERS	2004-05-18 16:53:47.000000000 +0000
@@ -954,11 +954,21 @@ P:	Tigran Aivazian
 M:	tigran@veritas.com
 S:	Maintained
 
+INTEL PRO/100 ETHERNET SUPPORT
+P:	John Ronciak
+M:	john.ronciak@intel.com
+P:	Ganesh Venkatesan
+M:	Ganesh.Venkatesan@intel.com
+W:	http://sourceforge.net/projects/e1000/
+S:	Supported
+
 INTEL PRO/1000 GIGABIT ETHERNET SUPPORT
 P:	Jeb Cramer
 M:	cramerj@intel.com
-P:	Scott Feldman
-M:	scott.feldman@intel.com
+P:	John Ronciak
+M:	john.ronciak@intel.com
+P:	Ganesh Venkatesan
+M:	Ganesh.Venkatesan@intel.com
 W:	http://sourceforge.net/projects/e1000/
 S:	Supported
 
@@ -1638,6 +1648,12 @@ M:	christer@weinigel.se
 W:	http://www.weinigel.se
 S:	Supported
 
+SERIAL ATA (SATA) SUBSYSTEM:
+P:	Jeff Garzik
+M:	jgarzik@pobox.com
+L:	linux-ide@vger.kernel.org
+S:	Supported
+
 SGI VISUAL WORKSTATION 320 AND 540
 P:	Bent Hagemark
 M:	bh@sgi.com
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Makefile linux-2.4.27-pre3/Makefile
--- linux-2.4.26/Makefile	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/Makefile	2004-05-18 16:54:04.000000000 +0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 26
-EXTRAVERSION =
+SUBLEVEL = 27
+EXTRAVERSION = -pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/acpi.c linux-2.4.27-pre3/arch/i386/kernel/acpi.c
--- linux-2.4.26/arch/i386/kernel/acpi.c	2004-04-14 13:05:25.000000000 +0000
+++ linux-2.4.27-pre3/arch/i386/kernel/acpi.c	2004-05-18 16:54:40.000000000 +0000
@@ -59,7 +59,10 @@ int acpi_sci_override_gsi __initdata;
                               Boot-time Configuration
    -------------------------------------------------------------------------- */
 
-int acpi_noirq __initdata = 0;  /* skip ACPI IRQ initialization */
+#ifdef CONFIG_ACPI_PCI
+int acpi_noirq __initdata;	/* skip ACPI IRQ initialization */
+int acpi_pci_disabled __initdata; /* skip ACPI PCI scan and IRQ initialization */
+#endif
 int acpi_ht __initdata = 1;     /* enable HT */
 
 enum acpi_irq_model_id		acpi_irq_model;
@@ -105,6 +108,35 @@ char *__acpi_map_table(unsigned long phy
 	return ((unsigned char *) base + offset);
 }
 
+#ifdef CONFIG_ACPI_MMCONFIG
+
+u32 pci_mmcfg_base_addr;
+
+static int __init 
+acpi_parse_mcfg(unsigned long phys_addr,
+		unsigned long size)
+{
+	struct acpi_table_mcfg *mcfg = NULL;
+
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size);
+	if (!mcfg) {
+		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
+		return -ENODEV;
+	}
+
+	if (mcfg->base_reserved) {
+		printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n");
+		return -ENODEV;
+	}
+
+	pci_mmcfg_base_addr = mcfg->base_address;
+
+	return 0;
+}
+#endif /* CONFIG_ACPI_MMCONFIG */
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
@@ -406,6 +438,15 @@ acpi_boot_init (void)
 		return result;
 	}
 
+#ifdef CONFIG_ACPI_MMCONFIG
+	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (result < 0) {
+		printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", result);
+	} else if (result > 1) {
+		printk(KERN_WARNING PREFIX "Multiple MCFG tables exist\n");
+	}
+#endif
+
 #ifdef CONFIG_X86_LOCAL_APIC
 
 	/* 
@@ -502,9 +543,6 @@ acpi_boot_init (void)
 		return result;
 	}
 
-	/* Build a default routing table for legacy (ISA) interrupts. */
-	mp_config_acpi_legacy_irqs();
-
 	/* Record sci_int for use when looking for MADT sci_int override */
 	acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
 
@@ -522,6 +560,9 @@ acpi_boot_init (void)
 	if (!acpi_sci_override_gsi)
 		acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
 
+	/* Fill in identity legacy mapings where no override */
+	mp_config_acpi_legacy_irqs();
+
 	result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src);
 	if (result < 0) {
 		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/i8259.c linux-2.4.27-pre3/arch/i386/kernel/i8259.c
--- linux-2.4.26/arch/i386/kernel/i8259.c	2001-09-18 06:03:09.000000000 +0000
+++ linux-2.4.27-pre3/arch/i386/kernel/i8259.c	2004-05-18 16:55:06.000000000 +0000
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 
+#include <asm/acpi.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -498,7 +499,8 @@ void __init init_IRQ(void)
 	outb(LATCH >> 8 , 0x40);	/* MSB */
 
 #ifndef CONFIG_VISWS
-	setup_irq(2, &irq2);
+	if (!acpi_ioapic)
+		setup_irq(2, &irq2);
 #endif
 
 	/*
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/io_apic.c linux-2.4.27-pre3/arch/i386/kernel/io_apic.c
--- linux-2.4.26/arch/i386/kernel/io_apic.c	2004-04-14 13:05:25.000000000 +0000
+++ linux-2.4.27-pre3/arch/i386/kernel/io_apic.c	2004-05-18 16:52:28.000000000 +0000
@@ -1691,18 +1691,10 @@ static inline void check_timer(void)
 
 /*
  *
- * IRQ's that are handled by the old PIC in all cases:
+ * IRQ's that are handled by the PIC in the MPS IOAPIC case.
  * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ.
  *   Linux doesn't really care, as it's not actually used
  *   for any interrupt handling anyway.
- * - There used to be IRQ13 here as well, but all
- *   MPS-compliant must not use it for FPU coupling and we
- *   want to use exception 16 anyway.  And there are
- *   systems who connect it to an I/O APIC for other uses.
- *   Thus we don't mark it special any longer.
- *
- * Additionally, something is definitely wrong with irq9
- * on PIIX4 boards.
  */
 #define PIC_IRQS	(1<<2)
 
@@ -1710,7 +1702,11 @@ void __init setup_IO_APIC(void)
 {
 	enable_IO_APIC();
 
-	io_apic_irqs = ~PIC_IRQS;
+	if (acpi_ioapic)
+		io_apic_irqs = ~0;	/* all IRQs go through IOAPIC */
+	else
+		io_apic_irqs = ~PIC_IRQS;
+
 	printk("ENABLING IO-APIC IRQs\n");
 
 	/*
@@ -1872,7 +1868,7 @@ int io_apic_set_pci_routing (int ioapic,
 
 	entry.vector = assign_irq_vector(irq);
 
-	printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
+	Dprintk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
 		"IRQ %d Mode:%i Active:%i)\n", ioapic,
 		mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/mpparse.c linux-2.4.27-pre3/arch/i386/kernel/mpparse.c
--- linux-2.4.26/arch/i386/kernel/mpparse.c	2004-04-14 13:05:25.000000000 +0000
+++ linux-2.4.27-pre3/arch/i386/kernel/mpparse.c	2004-05-18 16:52:23.000000000 +0000
@@ -1111,8 +1111,6 @@ void __init mp_override_legacy_irq (
 	u32			global_irq)
 {
 	struct mpc_config_intsrc intsrc;
-	int			i = 0;
-	int			found = 0;
 	int			ioapic = -1;
 	int			pin = -1;
 
@@ -1145,23 +1143,9 @@ void __init mp_override_legacy_irq (
 		(intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, 
 		intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);
 
-	/* 
-	 * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it.
-	 * Otherwise create a new entry (e.g. global_irq == 2).
-	 */
-	for (i = 0; i < mp_irq_entries; i++) {
-		if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) 
-			&& (mp_irqs[i].mpc_srcbusirq == intsrc.mpc_srcbusirq)) {
-			mp_irqs[i] = intsrc;
-			found = 1;
-			break;
-		}
-	}
-	if (!found) {
-		mp_irqs[mp_irq_entries] = intsrc;
-		if (++mp_irq_entries == MAX_IRQ_SOURCES)
-			panic("Max # of irq sources exceeded!\n");
-	}
+	mp_irqs[mp_irq_entries] = intsrc;
+	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+		panic("Max # of irq sources exceeded!\n");
 
 	return;
 }
@@ -1206,13 +1190,19 @@ void __init mp_config_acpi_legacy_irqs (
 		return;
 
 	/* 
-	 * Use the default configuration for the IRQs 0-15.  These may be
+	 * Use the default configuration for the IRQs 0-15.  Unless
 	 * overriden by (MADT) interrupt source override entries.
 	 */
 	for (i = 0; i < 16; i++) {
+		int idx;
 
-		if (i == 2)
-			continue;			/* Don't connect IRQ2 */
+		for (idx = 0; idx < mp_irq_entries; idx++)
+			if (mp_irqs[idx].mpc_srcbus == MP_ISA_BUS &&
+				(mp_irqs[idx].mpc_srcbusirq == i ||
+				mp_irqs[idx].mpc_dstirq == i))
+					break;
+		if (idx != mp_irq_entries)
+			continue;			  /* IRQ already used */
 
 		mp_irqs[mp_irq_entries].mpc_type = MP_INTSRC;
 		mp_irqs[mp_irq_entries].mpc_irqflag = 0;	/* Conforming */
@@ -1308,11 +1298,13 @@ void __init mp_parse_prt (void)
 		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low))
 			entry->irq = irq;
 
-		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
-			entry->id.segment, entry->id.bus, 
-			entry->id.device, ('A' + entry->pin), 
-			mp_ioapic_routing[ioapic].apic_id, ioapic_pin, 
-			entry->irq);
+                printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d"
+                        " -> IRQ %d %s %s\n", entry->id.segment, entry->id.bus,
+                        entry->id.device, ('A' + entry->pin),
+                        mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
+                        entry->irq, edge_level ? "level" : "edge",
+                        active_high_low ? "low" : "high");
+
 	}
 	
 	print_IO_APIC();
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/pci-irq.c linux-2.4.27-pre3/arch/i386/kernel/pci-irq.c
--- linux-2.4.26/arch/i386/kernel/pci-irq.c	2004-04-14 13:05:25.000000000 +0000
+++ linux-2.4.27-pre3/arch/i386/kernel/pci-irq.c	2004-05-18 16:55:25.000000000 +0000
@@ -1067,6 +1067,7 @@ void pcibios_enable_irq(struct pci_dev *
 {
 	u8 pin;
 	extern int interrupt_line_quirk;
+ 	struct pci_dev *temp_dev;
 	
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
@@ -1076,9 +1077,44 @@ void pcibios_enable_irq(struct pci_dev *
 		if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5))
 			return;
 
-		if (io_apic_assign_pci_irqs)
-			msg = " Probably buggy MP table.";
-		else if (pci_probe & PCI_BIOS_IRQ_SCAN)
+		if (io_apic_assign_pci_irqs) {
+			int irq;
+
+			if (pin) {
+				pin--;		/* interrupt pins are numbered starting from 1 */
+				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
+				/*
+				 * Busses behind bridges are typically not listed in the MP-table.
+				 * In this case we have to look up the IRQ based on the parent bus,
+				 * parent slot, and pin number. The SMP code detects such bridged
+				 * busses itself so we should get into this branch reliably.
+				 */
+				temp_dev = dev;
+				while (irq < 0 && dev->bus->parent) { /* go back to the bridge */
+					struct pci_dev * bridge = dev->bus->self;
+
+					pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+					irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
+							PCI_SLOT(bridge->devfn), pin);
+					if (irq >= 0)
+						printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
+							bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
+					dev = bridge;
+				}
+				dev = temp_dev;
+				if (irq >= 0) {
+#ifdef CONFIG_PCI_USE_VECTOR
+					if (!platform_legacy_irq(irq))
+						irq = IO_APIC_VECTOR(irq);
+#endif
+					printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
+						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
+					dev->irq = irq;
+					return;
+				} else
+					msg = " Probably buggy MP table.";
+			}
+		} else if (pci_probe & PCI_BIOS_IRQ_SCAN)
 			msg = "";
 		else
 			msg = " Please try using pci=biosirq.";
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/pci-pc.c linux-2.4.27-pre3/arch/i386/kernel/pci-pc.c
--- linux-2.4.26/arch/i386/kernel/pci-pc.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-pre3/arch/i386/kernel/pci-pc.c	2004-05-18 16:52:47.000000000 +0000
@@ -1321,13 +1321,46 @@ static void __init pci_fixup_via_northbr
  * system to PCI bus no matter what are their window settings, so they are
  * "transparent" (or subtractive decoding) from programmers point of view.
  */
-static void __init pci_fixup_transparent_bridge(struct pci_dev *dev)
+static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev)
 {
 	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
 	    (dev->device & 0xff00) == 0x2400)
 		dev->transparent = 1;
 }
 
+/*
+ * Fixup for C1 Halt Disconnect problem on nForce2 systems.
+ *
+ * From information provided by "Allen Martin" <AMartin@nvidia.com>:
+ *
+ * A hang is caused when the CPU generates a very fast CONNECT/HALT cycle
+ * sequence.  Workaround is to set the SYSTEM_IDLE_TIMEOUT to 80 ns.
+ * This allows the state-machine and timer to return to a proper state within
+ * 80 ns of the CONNECT and probe appearing together.  Since the CPU will not
+ * issue another HALT within 80 ns of the initial HALT, the failure condition
+ * is avoided.
+ */
+static void __devinit pci_fixup_nforce2(struct pci_dev *dev)
+{
+	u32 val, fixed_val;
+	u8 rev;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+	/*
+	* Chip 	Old value   	New value
+	* C17  	0x1F01FF01  	0x1F0FFF01
+	* C18D 	0x9F01FF01  	0x9F0FFF01
+	*/
+	fixed_val = rev < 0xC1 ? 0x1F01FF01 : 0x9F01FF01;
+
+	pci_read_config_dword(dev, 0x6c, &val);
+	if (val != fixed_val) {
+		printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n");
+		pci_write_config_dword(dev, 0x6c, fixed_val);
+	}
+}
+
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454GX,	pci_fixup_i450gx },
@@ -1343,6 +1376,7 @@ struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8367_0,	pci_fixup_via_northbridge_bug },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	pci_fixup_ncr53c810 },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_ANY_ID,			pci_fixup_transparent_bridge },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE2,	pci_fixup_nforce2},
 	{ 0 }
 };
 
@@ -1433,7 +1467,6 @@ void __init pcibios_init(void)
 	if (!acpi_noirq && !acpi_pci_irq_init()) {
 		pci_using_acpi_prt = 1;
 		printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
-		printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi' or even 'acpi=off'\n");
 	}
 #endif
 	if (!pci_using_acpi_prt) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/mm/fault.c linux-2.4.27-pre3/arch/i386/mm/fault.c
--- linux-2.4.26/arch/i386/mm/fault.c	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/i386/mm/fault.c	2004-05-18 16:50:49.000000000 +0000
@@ -71,7 +71,7 @@ good_area:
 		if (!vma || vma->vm_start != start)
 			goto bad_area;
 		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;;
+			goto bad_area;
 	}
 	return 1;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/dig linux-2.4.27-pre3/arch/ia64/configs/dig
--- linux-2.4.26/arch/ia64/configs/dig	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/configs/dig	2004-05-18 16:53:53.000000000 +0000
@@ -28,9 +28,9 @@ CONFIG_ITANIUM=y
 # CONFIG_MCKINLEY is not set
 # CONFIG_IA64_GENERIC is not set
 CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_HP_ZX1 is not set
 # CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
@@ -116,7 +116,6 @@ CONFIG_INET=y
 #
 #    SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -265,6 +264,7 @@ CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
 # CONFIG_BLK_DEV_CMD64X is not set
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -293,6 +293,7 @@ CONFIG_BLK_DEV_PIIX=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
 # CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
@@ -430,6 +431,7 @@ CONFIG_EEPRO100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_8139CP is not set
@@ -511,6 +513,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Character devices
@@ -586,6 +589,7 @@ CONFIG_INPUT_SERPORT=y
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200 is not set
 # CONFIG_SCx200_GPIO is not set
 # CONFIG_INTEL_RNG is not set
 # CONFIG_HW_RANDOM is not set
@@ -727,6 +731,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
 
 #
 # Network File Systems
@@ -940,7 +949,6 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
-# CONFIG_USB_AX8817X is not set
 # CONFIG_USB_CDCETHER is not set
 # CONFIG_USB_USBNET is not set
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/generic linux-2.4.27-pre3/arch/ia64/configs/generic
--- linux-2.4.26/arch/ia64/configs/generic	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/configs/generic	2004-05-18 16:51:10.000000000 +0000
@@ -28,9 +28,9 @@ CONFIG_ITANIUM=y
 # CONFIG_MCKINLEY is not set
 CONFIG_IA64_GENERIC=y
 # CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_HP_ZX1 is not set
 # CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
@@ -116,7 +116,6 @@ CONFIG_INET=y
 #
 #    SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -265,6 +264,7 @@ CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
 CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -294,6 +294,7 @@ CONFIG_BLK_DEV_PIIX=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
 # CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
@@ -436,6 +437,7 @@ CONFIG_EEPRO100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_8139CP is not set
@@ -517,6 +519,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Character devices
@@ -592,6 +595,7 @@ CONFIG_INPUT_SERPORT=y
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200 is not set
 # CONFIG_SCx200_GPIO is not set
 # CONFIG_FETCHOP is not set
 # CONFIG_INTEL_RNG is not set
@@ -734,6 +738,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
 
 #
 # Network File Systems
@@ -947,7 +956,6 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
-# CONFIG_USB_AX8817X is not set
 # CONFIG_USB_CDCETHER is not set
 # CONFIG_USB_USBNET is not set
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/numa linux-2.4.27-pre3/arch/ia64/configs/numa
--- linux-2.4.26/arch/ia64/configs/numa	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/configs/numa	2004-05-18 16:53:42.000000000 +0000
@@ -28,9 +28,9 @@ CONFIG_ITANIUM=y
 # CONFIG_MCKINLEY is not set
 CONFIG_IA64_GENERIC=y
 # CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_HP_ZX1 is not set
 # CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
@@ -118,7 +118,6 @@ CONFIG_INET=y
 #
 #    SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -267,6 +266,7 @@ CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
 CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -296,6 +296,7 @@ CONFIG_BLK_DEV_PIIX=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
 # CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
@@ -438,6 +439,7 @@ CONFIG_EEPRO100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_8139CP is not set
@@ -519,6 +521,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Character devices
@@ -594,6 +597,7 @@ CONFIG_INPUT_SERPORT=y
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200 is not set
 # CONFIG_SCx200_GPIO is not set
 # CONFIG_FETCHOP is not set
 # CONFIG_INTEL_RNG is not set
@@ -736,6 +740,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
 
 #
 # Network File Systems
@@ -949,7 +958,6 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
-# CONFIG_USB_AX8817X is not set
 # CONFIG_USB_CDCETHER is not set
 # CONFIG_USB_USBNET is not set
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/ski linux-2.4.27-pre3/arch/ia64/configs/ski
--- linux-2.4.26/arch/ia64/configs/ski	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/configs/ski	2004-05-18 16:52:00.000000000 +0000
@@ -28,9 +28,9 @@ CONFIG_ITANIUM=y
 # CONFIG_MCKINLEY is not set
 # CONFIG_IA64_GENERIC is not set
 # CONFIG_IA64_DIG is not set
-CONFIG_IA64_HP_SIM=y
 # CONFIG_IA64_HP_ZX1 is not set
 # CONFIG_IA64_SGI_SN2 is not set
+CONFIG_IA64_HP_SIM=y
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
@@ -83,7 +83,6 @@ CONFIG_INET=y
 #
 #    SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -202,6 +201,7 @@ CONFIG_SCSI_LOGGING=y
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Character devices
@@ -256,6 +256,7 @@ CONFIG_PSMOUSE=y
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200 is not set
 # CONFIG_SCx200_GPIO is not set
 # CONFIG_INTEL_RNG is not set
 # CONFIG_HW_RANDOM is not set
@@ -374,6 +375,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
 
 #
 # Network File Systems
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/zx1 linux-2.4.27-pre3/arch/ia64/configs/zx1
--- linux-2.4.26/arch/ia64/configs/zx1	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/configs/zx1	2004-05-18 16:54:48.000000000 +0000
@@ -28,9 +28,9 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_MCKINLEY=y
 # CONFIG_IA64_GENERIC is not set
 # CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
 CONFIG_IA64_HP_ZX1=y
 # CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
@@ -117,7 +117,6 @@ CONFIG_INET=y
 #
 #    SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -266,6 +265,7 @@ CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
 # CONFIG_BLK_DEV_CMD64X is not set
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -294,6 +294,7 @@ CONFIG_BLK_DEV_PIIX=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
 # CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
@@ -431,6 +432,7 @@ CONFIG_EEPRO100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_8139CP is not set
@@ -512,6 +514,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Character devices
@@ -587,6 +590,7 @@ CONFIG_INPUT_SERPORT=y
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200 is not set
 # CONFIG_SCx200_GPIO is not set
 # CONFIG_INTEL_RNG is not set
 # CONFIG_HW_RANDOM is not set
@@ -728,6 +732,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
 
 #
 # Network File Systems
@@ -941,7 +950,6 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
-# CONFIG_USB_AX8817X is not set
 # CONFIG_USB_CDCETHER is not set
 # CONFIG_USB_USBNET is not set
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/defconfig linux-2.4.27-pre3/arch/ia64/defconfig
--- linux-2.4.26/arch/ia64/defconfig	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/defconfig	2004-05-18 16:51:17.000000000 +0000
@@ -28,9 +28,9 @@ CONFIG_ITANIUM=y
 # CONFIG_MCKINLEY is not set
 CONFIG_IA64_GENERIC=y
 # CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_HP_ZX1 is not set
 # CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
@@ -116,7 +116,6 @@ CONFIG_INET=y
 #
 #    SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -265,6 +264,7 @@ CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
 CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -294,6 +294,7 @@ CONFIG_BLK_DEV_PIIX=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
 # CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
@@ -436,6 +437,7 @@ CONFIG_EEPRO100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_8139CP is not set
@@ -517,6 +519,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Character devices
@@ -592,6 +595,7 @@ CONFIG_INPUT_SERPORT=y
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200 is not set
 # CONFIG_SCx200_GPIO is not set
 # CONFIG_FETCHOP is not set
 # CONFIG_INTEL_RNG is not set
@@ -734,6 +738,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
 
 #
 # Network File Systems
@@ -947,7 +956,6 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
-# CONFIG_USB_AX8817X is not set
 # CONFIG_USB_CDCETHER is not set
 # CONFIG_USB_USBNET is not set
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/ia32/binfmt_elf32.c linux-2.4.27-pre3/arch/ia64/ia32/binfmt_elf32.c
--- linux-2.4.26/arch/ia64/ia32/binfmt_elf32.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/ia32/binfmt_elf32.c	2004-05-18 16:55:06.000000000 +0000
@@ -17,6 +17,8 @@
 #include <asm/signal.h>
 #include <asm/ia32.h>
 
+#include "elfcore32.h"
+
 #define CONFIG_BINFMT_ELF32
 
 /* Override some function names */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/ia32/elfcore32.h linux-2.4.27-pre3/arch/ia64/ia32/elfcore32.h
--- linux-2.4.26/arch/ia64/ia32/elfcore32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/ia32/elfcore32.h	2004-05-18 16:54:57.000000000 +0000
@@ -0,0 +1,133 @@
+/*
+ * IA-32 ELF core dump support.
+ *
+ * Copyright (C) 2003 Arun Sharma <arun.sharma@intel.com>
+ *
+ * Derived from the x86_64 version
+ */
+#ifndef _ELFCORE32_H_
+#define _ELFCORE32_H_
+
+#define USE_ELF_CORE_DUMP 1
+
+/* Override elfcore.h */ 
+#define _LINUX_ELFCORE_H 1
+typedef unsigned int elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct user_regs_struct32) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct ia32_user_i387_struct elf_fpregset_t;
+typedef struct ia32_user_fxsr_struct elf_fpxregset_t;
+
+struct elf_siginfo
+{
+	int	si_signo;			/* signal number */
+	int	si_code;			/* extra code */
+	int	si_errno;			/* errno */
+};
+
+#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0)
+
+struct compat_timeval
+{
+    int tv_sec, tv_usec;
+};
+
+struct elf_prstatus
+{
+	struct elf_siginfo pr_info;	/* Info associated with signal */
+	short	pr_cursig;		/* Current signal */
+	unsigned int pr_sigpend;	/* Set of pending signals */
+	unsigned int pr_sighold;	/* Set of held signals */
+	pid_t	pr_pid;
+	pid_t	pr_ppid;
+	pid_t	pr_pgrp;
+	pid_t	pr_sid;
+	struct compat_timeval pr_utime;	/* User time */
+	struct compat_timeval pr_stime;	/* System time */
+	struct compat_timeval pr_cutime;	/* Cumulative user time */
+	struct compat_timeval pr_cstime;	/* Cumulative system time */
+	elf_gregset_t pr_reg;	/* GP registers */
+	int pr_fpvalid;		/* True if math co-processor being used.  */
+};
+
+#define ELF_PRARGSZ	(80)	/* Number of chars for args */
+
+struct elf_prpsinfo
+{
+	char	pr_state;	/* numeric process state */
+	char	pr_sname;	/* char for pr_state */
+	char	pr_zomb;	/* zombie */
+	char	pr_nice;	/* nice val */
+	unsigned int pr_flag;	/* flags */
+	__u16	pr_uid;
+	__u16	pr_gid;
+	pid_t	pr_pid, pr_ppid, pr_pgrp, pr_sid;
+	/* Lots missing */
+	char	pr_fname[16];	/* filename of executable */
+	char	pr_psargs[ELF_PRARGSZ];	/* initial part of arg list */
+};
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs)       		\
+	pr_reg[0] = regs->r11;				\
+	pr_reg[1] = regs->r9;				\
+	pr_reg[2] = regs->r10;				\
+	pr_reg[3] = regs->r14;				\
+	pr_reg[4] = regs->r15;				\
+	pr_reg[5] = regs->r13;				\
+	pr_reg[6] = regs->r8;				\
+	pr_reg[7] = regs->r16 & 0xffff;			\
+	pr_reg[8] = (regs->r16 >> 16) & 0xffff;		\
+	pr_reg[9] = (regs->r16 >> 32) & 0xffff;		\
+	pr_reg[10] = (regs->r16 >> 48) & 0xffff;	\
+	pr_reg[11] = regs->r1; 				\
+	pr_reg[12] = regs->cr_iip;			\
+	pr_reg[13] = regs->r17 & 0xffff;		\
+	asm volatile ("mov %0=ar.eflag ;;"		\
+		      : "=r"(pr_reg[14]));		\
+	pr_reg[15] = regs->r12;				\
+	pr_reg[16] = (regs->r17 >> 16) & 0xffff;
+
+static inline void elf_core_copy_regs(elf_gregset_t *elfregs,
+				      struct pt_regs *regs)
+{
+	ELF_CORE_COPY_REGS((*elfregs), regs)
+}
+
+static inline int elf_core_copy_task_regs(struct task_struct *t,
+					  elf_gregset_t* elfregs)
+{	
+	struct pt_regs *pp = ia64_task_regs(t);
+	ELF_CORE_COPY_REGS((*elfregs), pp);
+	return 1; 
+}
+
+static inline int 
+elf_core_copy_task_fpregs(struct task_struct *tsk, elf_fpregset_t *fpu)
+{
+	struct ia32_user_i387_struct *fpstate = (void*)fpu;
+
+	if (!tsk->used_math) 
+		return 0;
+
+	save_ia32_fpstate(tsk, fpstate);
+
+	return 1; 
+}
+
+#define ELF_CORE_COPY_XFPREGS 1
+static inline int 
+elf_core_copy_task_xfpregs(struct task_struct *tsk, elf_fpxregset_t *xfpu)
+{
+	struct ia32_user_fxsr_struct *fpxstate = (void*) xfpu; 
+
+	if (!tsk->used_math) 
+		return 0;
+
+	save_ia32_fpxstate(tsk, fpxstate);
+	
+	return 1;
+}
+
+#endif /* _ELFCORE32_H_ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/ia32/sys_ia32.c linux-2.4.27-pre3/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.26/arch/ia64/ia32/sys_ia32.c	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/ia32/sys_ia32.c	2004-05-18 16:53:49.000000000 +0000
@@ -2949,7 +2949,7 @@ get_fpreg (int regno, struct _fpreg_ia32
 	return;
 }
 
-static int
+int
 save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save)
 {
 	struct switch_stack *swp;
@@ -3011,7 +3011,7 @@ restore_ia32_fpstate (struct task_struct
 	return 0;
 }
 
-static int
+int
 save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save)
 {
 	struct switch_stack *swp;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/kernel/efi.c linux-2.4.27-pre3/arch/ia64/kernel/efi.c
--- linux-2.4.26/arch/ia64/kernel/efi.c	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/kernel/efi.c	2004-05-18 16:51:02.000000000 +0000
@@ -673,8 +673,7 @@ efi_get_iobase (void)
 	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
 		md = p;
 		if (md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) {
-			/* paranoia attribute checking */
-			if (md->attribute == (EFI_MEMORY_UC | EFI_MEMORY_RUNTIME))
+			if (md->attribute & EFI_MEMORY_UC)
 				return md->phys_addr;
 		}
 	}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/kernel/perfmon.c linux-2.4.27-pre3/arch/ia64/kernel/perfmon.c
--- linux-2.4.26/arch/ia64/kernel/perfmon.c	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/kernel/perfmon.c	2004-05-18 16:55:07.000000000 +0000
@@ -25,6 +25,7 @@
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <linux/smp.h>
+#include <linux/seq_file.h>
 
 #include <asm/bitops.h>
 #include <asm/errno.h>
@@ -3166,62 +3167,111 @@ pfm_interrupt_handler(int irq, void *arg
 	}
 }
 
-/* for debug only */
-static int
-pfm_proc_info(char *page)
+#define PFM_PROC_SHOW_HEADER	((void *)NR_CPUS+1)
+  
+static void *
+pfm_proc_start(struct seq_file *m, loff_t *pos)
 {
-	char *p = page;
-	int i;
-
-	p += sprintf(p, "fastctxsw              : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
-	p += sprintf(p, "ovfl_mask              : 0x%lx\n", pmu_conf.ovfl_val);
-
-	for(i=0; i < NR_CPUS; i++) {
-		if (cpu_online(i) == 0) continue;
-		p += sprintf(p, "CPU%-2d overflow intrs   : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count);
-		p += sprintf(p, "CPU%-2d spurious intrs   : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count);
-		p += sprintf(p, "CPU%-2d recorded samples : %lu\n", i, pfm_stats[i].pfm_recorded_samples_count);
-		p += sprintf(p, "CPU%-2d smpl buffer full : %lu\n", i, pfm_stats[i].pfm_full_smpl_buffer_count);
-		p += sprintf(p, "CPU%-2d syst_wide        : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_SYST_WIDE ? 1 : 0);
-		p += sprintf(p, "CPU%-2d dcr_pp           : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_DCR_PP ? 1 : 0);
-		p += sprintf(p, "CPU%-2d exclude idle     : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_EXCL_IDLE ? 1 : 0);
-		p += sprintf(p, "CPU%-2d owner            : %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
-		p += sprintf(p, "CPU%-2d activations      : %lu\n", i, pmu_owners[i].activation_number);
+	if (*pos == 0) {
+		return PFM_PROC_SHOW_HEADER;
 	}
 
-	LOCK_PFS();
-
-	p += sprintf(p, "proc_sessions          : %u\n"
-			"sys_sessions           : %u\n"
-			"sys_use_dbregs         : %u\n"
-			"ptrace_use_dbregs      : %u\n", 
-			pfm_sessions.pfs_task_sessions, 
-			pfm_sessions.pfs_sys_sessions,
-			pfm_sessions.pfs_sys_use_dbregs,
-			pfm_sessions.pfs_ptrace_use_dbregs);
-
-	UNLOCK_PFS();
-
-	return p - page;
+	while (*pos <= NR_CPUS) {
+		if (cpu_online(*pos - 1)) {
+			return (void *)*pos;
+		}
+		++*pos;
+	}
+	return NULL;
+}
+ 
+static void *
+pfm_proc_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return pfm_proc_start(m, pos);
+}
+ 
+static void
+pfm_proc_stop(struct seq_file *m, void *v)
+{
 }
 
-/* /proc interface, for debug only */
+static void
+pfm_proc_show_header(struct seq_file *m)
+{
+ 	seq_printf(m,
+		"perfmon version           : %u.%u\n"
+		"fastctxsw                 : %s\n"
+		"ovfl_mask                 : 0x%lx\n",
+		PFM_VERSION_MAJ, PFM_VERSION_MIN,
+		pfm_sysctl.fastctxsw > 0 ? "Yes": "No",
+		pmu_conf.ovfl_val);
+  
+  	LOCK_PFS();
+  
+ 	seq_printf(m,
+ 		"proc_sessions             : %u\n"
+ 		"sys_sessions              : %u\n"
+ 		"sys_use_dbregs            : %u\n"
+ 		"ptrace_use_dbregs         : %u\n",
+ 		pfm_sessions.pfs_task_sessions, 
+ 		pfm_sessions.pfs_sys_sessions,
+ 		pfm_sessions.pfs_sys_use_dbregs,
+ 		pfm_sessions.pfs_ptrace_use_dbregs);
+  
+  	UNLOCK_PFS();
+}
+  
 static int
-perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
+pfm_proc_show(struct seq_file *m, void *v)
 {
-	int len = pfm_proc_info(page);
+	int cpu;
 
-	if (len <= off+count) *eof = 1;
+	if (v == PFM_PROC_SHOW_HEADER) {
+		pfm_proc_show_header(m);
+		return 0;
+	}
 
-	*start = page + off;
-	len   -= off;
+	/* show info for CPU (v - 1) */
 
-	if (len>count) len = count;
-	if (len<0) len = 0;
+	cpu = (long)v - 1;
+	seq_printf(m,
+		"CPU%-2d overflow intrs      : %lu\n"
+		"CPU%-2d spurious intrs      : %lu\n"
+		"CPU%-2d recorded samples    : %lu\n"
+		"CPU%-2d smpl buffer full    : %lu\n"
+		"CPU%-2d syst_wide           : %d\n"
+		"CPU%-2d dcr_pp              : %d\n"
+		"CPU%-2d exclude idle        : %d\n"
+		"CPU%-2d owner               : %d\n"
+		"CPU%-2d activations         : %lu\n",
+		cpu, pfm_stats[cpu].pfm_ovfl_intr_count,
+		cpu, pfm_stats[cpu].pfm_spurious_ovfl_intr_count,
+		cpu, pfm_stats[cpu].pfm_recorded_samples_count,
+		cpu, pfm_stats[cpu].pfm_full_smpl_buffer_count,
+		cpu, cpu_data(cpu)->pfm_syst_info & PFM_CPUINFO_SYST_WIDE ? 1 : 0,
+		cpu, cpu_data(cpu)->pfm_syst_info & PFM_CPUINFO_DCR_PP ? 1 : 0,
+		cpu, cpu_data(cpu)->pfm_syst_info & PFM_CPUINFO_EXCL_IDLE ? 1 : 0,
+		cpu, pmu_owners[cpu].owner ? pmu_owners[cpu].owner->pid: -1,
+		cpu, pmu_owners[cpu].activation_number);
 
-	return len;
+	return 0;
 }
-
+ 
+struct seq_operations pfm_seq_ops = {
+	.start =	pfm_proc_start,
+ 	.next =		pfm_proc_next,
+ 	.stop =		pfm_proc_stop,
+ 	.show =		pfm_proc_show
+};
+ 
+static int
+pfm_proc_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &pfm_seq_ops);
+}
+ 
 /*
  * we come here as soon as local_cpu_data->pfm_syst_wide is set. this happens
  * during pfm_enable() hence before pfm_start(). We cannot assume monitoring
@@ -4448,6 +4498,13 @@ pfm_remove_alternate_syswide_subsystem(p
 	return 0;
 }
 
+static struct file_operations pfm_proc_fops = {
+	.open		= pfm_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
 /*
  * perfmon initialization routine, called from the initcall() table
  */
@@ -4498,11 +4555,15 @@ pfm_init(void)
 	/*
 	 * for now here for debug purposes
 	 */
-	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
+ 	perfmon_dir = create_proc_entry("perfmon", S_IRUGO, NULL);
 	if (perfmon_dir == NULL) {
 		printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n");
 		return -1;
 	}
+  	/*
+ 	 * install customized file operations for /proc/perfmon entry
+ 	 */
+ 	perfmon_dir->proc_fops = &pfm_proc_fops;
 
 	/*
 	 * create /proc/sys/kernel/perfmon
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/kernel/unwind.c linux-2.4.27-pre3/arch/ia64/kernel/unwind.c
--- linux-2.4.26/arch/ia64/kernel/unwind.c	2004-04-14 13:05:26.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/kernel/unwind.c	2004-05-18 16:55:38.000000000 +0000
@@ -1750,7 +1750,7 @@ run_script (struct unw_script *script, s
 			if (!state->pri_unat_loc)
 				state->pri_unat_loc = &state->sw->ar_unat;
 			/* register off. is a multiple of 8, so the least 3 bits (type) are 0 */
-			s[dst+1] = (*state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;
+			s[dst+1] = ((unsigned long) state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;
 			break;
 
 		      case UNW_INSN_SETNAT_TYPE:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/mm/hugetlbpage.c linux-2.4.27-pre3/arch/ia64/mm/hugetlbpage.c
--- linux-2.4.26/arch/ia64/mm/hugetlbpage.c	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/ia64/mm/hugetlbpage.c	2004-05-18 16:52:37.000000000 +0000
@@ -73,8 +73,12 @@ huge_pte_offset (struct mm_struct *mm, u
 	pte_t *pte = NULL;
 
 	pgd = pgd_offset(mm, taddr);
-	pmd = pmd_offset(pgd, taddr);
-	pte = pte_offset(pmd, taddr);
+	if (pgd_present(*pgd)) {
+		pmd = pmd_offset(pgd, taddr);
+		if (pmd_present(*pmd))
+			pte = pte_offset(pmd, taddr);
+	}
+
 	return pte;
 }
 
@@ -269,7 +273,7 @@ void unmap_hugepage_range(struct vm_area
 
 	for (address = start; address < end; address += HPAGE_SIZE) {
 		pte = huge_pte_offset(mm, address);
-		if (pte_none(*pte))
+		if (!pte || pte_none(*pte))
 			continue;
 		page = pte_page(*pte);
 		huge_page_release(page);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ppc/kernel/head_44x.S linux-2.4.27-pre3/arch/ppc/kernel/head_44x.S
--- linux-2.4.26/arch/ppc/kernel/head_44x.S	2004-04-14 13:05:27.000000000 +0000
+++ linux-2.4.27-pre3/arch/ppc/kernel/head_44x.S	2004-05-18 16:50:50.000000000 +0000
@@ -3,9 +3,26 @@
  *
  * Kernel execution entry point code.
  *
- * Matt Porter <mporter@mvista.com>
- *
- * Copyright 2002-2003 MontaVista Software, Inc.
+ *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
+ *      Initial PowerPC version.
+ *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *      Rewritten for PReP
+ *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
+ *      Low-level exception handers, MMU support, and rewrite.
+ *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
+ *      PowerPC 8xx modifications.
+ *    Copyright (c) 1998-1999 TiVo, Inc.
+ *      PowerPC 403GCX modifications.
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *      PowerPC 403GCX/405GP modifications.
+ *    Copyright 2000 MontaVista Software Inc.
+ *	PPC405 modifications
+ *      PowerPC 403GCX/405GP modifications.
+ * 	Author: MontaVista Software, Inc.
+ *         	frank_rowand@mvista.com or source@mvista.com
+ * 	   	debbie_chu@mvista.com
+ *    Copyright 2002-2004 MontaVista Software, Inc.
+ *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.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
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/config.in linux-2.4.27-pre3/arch/sh64/config.in
--- linux-2.4.26/arch/sh64/config.in	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/config.in	2004-05-18 16:55:35.000000000 +0000
@@ -58,8 +58,7 @@ bool 'Fixup misaligned loads/stores occu
 
 # Use 32-bit addressing for now.
 # EMI based.
-# P2 (UNCACHED) required to use identity mapping
-# P1 (CACHED) assumes non-identity.
+# (CACHED) assumes non-identity.
 
 #
 # Memory options
@@ -68,7 +67,6 @@ comment 'Memory options'
 
 int 'Memory size (in MB)' CONFIG_MEMORY_SIZE_IN_MB 64
 hex 'Cached Area Offset' CONFIG_CACHED_MEMORY_OFFSET 20000000
-hex 'Uncached Area Offset' CONFIG_UNCACHED_MEMORY_OFFSET 00000000
 hex 'Physical memory start address' CONFIG_MEMORY_START 80000000
 
 #
@@ -304,6 +302,7 @@ bool 'GDB Stub kernel debug' CONFIG_DEBU
 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
 dep_bool "Debug: report ASIDS through /proc/asids" CONFIG_SH64_PROC_ASIDS $CONFIG_PROC_FS
+bool "Debug: set SR.WATCH to enable hardware watchpoints and trace" CONFIG_SH64_SR_WATCH
 
 int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/defconfig linux-2.4.27-pre3/arch/sh64/defconfig
--- linux-2.4.26/arch/sh64/defconfig	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/defconfig	2004-05-18 16:55:10.000000000 +0000
@@ -490,6 +490,7 @@ CONFIG_FONT_8x16=y
 # CONFIG_SH64_PAGE_TABLE_AUDIT is not set
 # CONFIG_SH64_PROC_TLB is not set
 # CONFIG_SH64_PROC_ASIDS is not set
+# CONFIG_SH64_SR_WATCH is not set
 
 #
 # Library routines
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/kernel/entry.S linux-2.4.27-pre3/arch/sh64/kernel/entry.S
--- linux-2.4.26/arch/sh64/kernel/entry.S	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/kernel/entry.S	2004-05-18 16:53:53.000000000 +0000
@@ -1607,12 +1607,6 @@ poke_real_address_q:
 	shlli	r36, 31, r36
 	andc	r1, r36, r1	/* turn sr.mmu off in real mode section */
 
-	/* Bodge : force sr.watch high on return.  Can't understand why else this
-	   isn't happening. */
-	movi	1, r38
-	shlli	r38, 26, r38
-	or	r38, r0, r0
-
 	putcon	r1, ssr
 	_loada	.poke0-CONFIG_CACHED_MEMORY_OFFSET, r36 /* real mode target address */
 	_loada	1f, r37		/* virtual mode return addr */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/kernel/head.S linux-2.4.27-pre3/arch/sh64/kernel/head.S
--- linux-2.4.26/arch/sh64/kernel/head.S	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/kernel/head.S	2004-05-18 16:52:37.000000000 +0000
@@ -37,18 +37,29 @@
 #define MMUDR_END	DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP
 #define MMUDR_STEP	TLB_STEP
 
+/* Safety check : CONFIG_CACHED_MEMORY_OFFSET has to be a multiple of 512Mb */
+#if (CONFIG_CACHED_MEMORY_OFFSET & ((1UL<<29)-1))
+#error "CONFIG_CACHED_MEMORY_OFFSET must be a multiple of 512Mb"
+#endif
+
 /*
  * MMU defines: Fixed TLBs.
  */
-#define MMUIR_TEXT_H	0x0000000000000003 | (CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START)
+/* Deal safely with the case where the base of RAM is not 512Mb aligned */
+
+#define ALIGN_512M_MASK (0xffffffffe0000000)
+#define ALIGNED_EFFECTIVE ((CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START) & ALIGN_512M_MASK)
+#define ALIGNED_PHYSICAL (CONFIG_MEMORY_START & ALIGN_512M_MASK)
+
+#define MMUIR_TEXT_H	(0x0000000000000003 | ALIGNED_EFFECTIVE)
 			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
 
-#define MMUIR_TEXT_L	0x000000000000009a | (CONFIG_MEMORY_START)
+#define MMUIR_TEXT_L	(0x000000000000009a | ALIGNED_PHYSICAL)
 			/* 512 Mb, Cacheable, Write-back, execute, Not User, Ph. Add. */
 
-#define MMUDR_CACHED_H	0x0000000000000003 | (CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START)
+#define MMUDR_CACHED_H	0x0000000000000003 | ALIGNED_EFFECTIVE
 			/* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */
-#define MMUDR_CACHED_L	0x000000000000015a | (CONFIG_MEMORY_START)
+#define MMUDR_CACHED_L	0x000000000000015a | ALIGNED_PHYSICAL
 			/* 512 Mb, Cacheable, Write-back, read/write, Not User, Ph. Add. */
 
 #ifdef CONFIG_ICACHE_DISABLED
@@ -209,15 +220,19 @@ clear_DTLB:
 	/* Map one big (512Mb) page for ITLB */
 	movi	MMUIR_FIRST, r21
 	movi	MMUIR_TEXT_L, r22	/* PTEL first */
+	add.l	r22, r63, r22		/* Sign extend */
 	putcfg	r21, 1, r22		/* Set MMUIR[0].PTEL */
 	movi	MMUIR_TEXT_H, r22	/* PTEH last */
+	add.l	r22, r63, r22		/* Sign extend */
 	putcfg	r21, 0, r22		/* Set MMUIR[0].PTEH */
 	
 	/* Map one big CACHED (512Mb) page for DTLB */
 	movi	MMUDR_FIRST, r21
 	movi	MMUDR_CACHED_L, r22	/* PTEL first */
+	add.l	r22, r63, r22		/* Sign extend */
 	putcfg	r21, 1, r22		/* Set MMUDR[0].PTEL */
 	movi	MMUDR_CACHED_H, r22	/* PTEH last */
+	add.l	r22, r63, r22		/* Sign extend */
 	putcfg	r21, 0, r22		/* Set MMUDR[0].PTEH */
 	
 	/*
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/kernel/pci_sh5.c linux-2.4.27-pre3/arch/sh64/kernel/pci_sh5.c
--- linux-2.4.26/arch/sh64/kernel/pci_sh5.c	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/kernel/pci_sh5.c	2004-05-18 16:50:45.000000000 +0000
@@ -320,43 +320,70 @@ static int __init map_cayman_irq(struct 
 {
 	int result = -1;
 
-	if (dev->bus->number == 0) {
-	        switch ((slot + (pin-1)) & 3) {
-	        case 0:
-	          result = IRQ_INTA;
-		  break;
-                case 1:
-	          result = IRQ_INTB;
-		  break;
-                case 2:
-	          result = IRQ_INTC;
-		  break;
-		case 3:
-		  result = IRQ_INTD;
-		  break;
-                }
-        }
-
-	if (dev->bus->number == 2) {
-	        switch((slot + (pin-1)) & 3) {
-	        case 0:
-	          result = IRQ_P2INTA;
-		  break;
-                case 1:
-	          result = IRQ_P2INTB;
-		  break;
-                case 2:
-	          result = IRQ_P2INTC;
-		  break;
-                case 3:
-	          result = IRQ_P2INTD;
-		  break;
-                }
-        }
-
-	dprintk("map_cayman_irq for dev %d on bus %d slot %d, pin is %d : irq=%d\n",
-	       dev->devfn,dev->bus->number,slot,pin,result);
+	/* The complication here is that the PCI IRQ lines from the Cayman's 2
+	   5V slots get into the CPU via a different path from the IRQ lines
+	   from the 3 3.3V slots.  Thus, we have to detect whether the card's
+	   interrupts go via the 5V or 3.3V path, i.e. the 'bridge swizzling'
+	   at the point where we cross from 5V to 3.3V is not the normal case.
+
+	   The added complication is that we don't know that the 5V slots are
+	   always bus 2, because a card containing a PCI-PCI bridge may be
+	   plugged into a 3.3V slot, and this changes the bus numbering.
+
+	   Also, the Cayman has an intermediate PCI bus that goes a custom
+	   expansion board header (and to the secondary bridge).  This bus has
+	   never been used in practice.
+
+	   The 1ary onboard PCI-PCI bridge is device 3 on bus 0
+	   The 2ary onboard PCI-PCI bridge is device 0 on the 2ary bus of the 1ary bridge.
+	   */
+
+	struct slot_pin {
+		int slot;
+		int pin;
+	} path[4];
+	int i=0;
+	int base;
+
+	while (dev->bus->number > 0) {
+
+		slot = path[i].slot = PCI_SLOT(dev->devfn);
+		pin = path[i].pin = bridge_swizzle(pin, slot);
+		dev = dev->bus->self;
+		i++;
+		if (i > 3) panic("PCI path to root bus too long!\n");
+	}
 
+	slot = PCI_SLOT(dev->devfn);
+	/* This is the slot on bus 0 through which the device is eventually
+	   reachable. */
+
+	/* Now work back up. */
+	if ((slot < 3) || (i == 0)) {
+		/* Bus 0 (incl. PCI-PCI bridge itself) : perform the final
+		   swizzle now. */
+		result = IRQ_INTA + bridge_swizzle(pin, slot) - 1;
+	} else {
+		i--;
+		slot = path[i].slot;
+		pin  = path[i].pin;
+		if (slot > 0) {
+			panic("PCI expansion bus device found - not handled!\n");
+		} else {
+			if (i > 0) {
+				/* 5V slots */
+				i--;
+				slot = path[i].slot;
+				pin  = path[i].pin;
+				/* 'pin' was swizzled earlier wrt slot, don't do it again. */
+				result = IRQ_P2INTA + (pin - 1);
+			} else {
+				/* IRQ for 2ary PCI-PCI bridge : unused */
+				result = -1;
+			}
+		}
+	}
+	
 	return result;
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/kernel/time.c linux-2.4.27-pre3/arch/sh64/kernel/time.c
--- linux-2.4.26/arch/sh64/kernel/time.c	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/kernel/time.c	2004-05-18 16:54:12.000000000 +0000
@@ -404,13 +404,14 @@ static __init unsigned int get_cpu_mhz(v
 {
 	unsigned int count;
 	unsigned long __dummy;
-	
+	unsigned long ctc_val_init, ctc_val;
+
 	/*
 	** Regardless the toolchain, force the compiler to use the
 	** arbitrary register r3 as a clock tick counter.
 	** NOTE: r3 must be in accordance with rtc_interrupt()
 	*/
-	register unsigned long long  __clock_tick_count __asm__ ("r3");
+	register unsigned long long  __rtc_irq_flag __asm__ ("r3");
 
 	sti();
 	do {} while (ctrl_inb(R64CNT) != 0);
@@ -419,13 +420,17 @@ static __init unsigned int get_cpu_mhz(v
 	/*
 	 * r3 is arbitrary. CDC does not support "=z".
 	 */
+	ctc_val_init = 0xffffffff;
+	ctc_val = ctc_val_init;
+
 	asm volatile("gettr	" __t0 ", %1\n\t"
+		     "putcon	%0, cr62\n\t"
 		     "and	%2, r63, %2\n\t"
 		     "_pta	4, " __t0 "\n\t"
-		     "addi	%0, 1, %0\n\t"
 		     "beq/l	%2, r63, " __t0 "\n\t"
 		     "ptabs	%1, " __t0 "\n\t"
-		: "=r"(count), "=r" (__dummy), "=r" (__clock_tick_count)
+		     "getcon	cr62, %0\n\t"
+		: "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag)
 		: "0" (0));
 	cli();
 	/*
@@ -445,11 +450,13 @@ static __init unsigned int get_cpu_mhz(v
          * ....
 	 *
 	 * SH-5:
-	 * CPU clock = 2 stages * loop
-         * ....
+	 * Use CTC register to count.  This approach returns the right value
+	 * even if the I-cache is disabled (e.g. whilst debugging.)
 	 *
 	 */
 
+	count = ctc_val_init - ctc_val; /* CTC counts down */
+
 #if defined (CONFIG_SH_SIMULATOR)
 	/*
 	 * Let's pretend we are a 5MHz SH-5 to avoid a too
@@ -457,18 +464,13 @@ static __init unsigned int get_cpu_mhz(v
 	 * calibration within a reasonable time.
 	 */
 	return 5000000;
-#elif defined (CONFIG_ICACHE_DISABLED)
-	/*
-	 * Let's pretend we are a 300MHz SH-5.
-	 */
-	return 300000000;
 #else
 	/*
 	 * This really is count by the number of clock cycles
-         * per loop (2) by the ratio between a complete R64CNT
+         * by the ratio between a complete R64CNT
          * wrap-around (128) and CUI interrupt being raised (64).
 	 */
-	return count*2*2;
+	return count*2;
 #endif
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/lib/io.c linux-2.4.27-pre3/arch/sh64/lib/io.c
--- linux-2.4.26/arch/sh64/lib/io.c	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/lib/io.c	2004-05-18 16:51:13.000000000 +0000
@@ -27,17 +27,23 @@
 
 #define dprintk(x...)
 
-//#define io_addr(x)  (((unsigned)(x) & 0x000fffff)| PCI_ST50_IO_ADDR )
-
+static int io_addr(int x) {
+	if (x < 0x400) {
 #ifdef CONFIG_SH_CAYMAN
-extern unsigned long smsc_virt;
-extern unsigned long pciio_virt;
-#define io_addr(x)  ( ((x)<0x400) ? \
-			(((x) << 2)|smsc_virt) : \
-			((unsigned long)(x)+pciio_virt) )
+		return (x << 2) | smsc_superio_virt;
+#else
+		panic ("Illegal access to I/O port 0x%04x\n", x);
+		return 0;
+#endif
+	} else {
+#ifdef CONFIG_PCI
+		return (x + pciio_virt);
 #else
-#define io_addr(x)  ((unsigned long)(x)+pciio_virt)
+		panic ("Illegal access to I/O port 0x%04x\n", x);
+		return 0;
 #endif
+	}
+}
 
 unsigned long inb(unsigned long port)
 {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/mach-cayman/irq.c linux-2.4.27-pre3/arch/sh64/mach-cayman/irq.c
--- linux-2.4.26/arch/sh64/mach-cayman/irq.c	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/mach-cayman/irq.c	2004-05-18 16:54:32.000000000 +0000
@@ -27,9 +27,12 @@ unsigned long epld_virt;
 #define EPLD_STATUS_BASE (epld_virt + 0x10)
 #define EPLD_MASK_BASE   (epld_virt + 0x20)
 
+/* Note the SMSC SuperIO chip and SMSC LAN chip interrupts are all muxed onto
+   the same SH-5 interrupt */
+
 static void cayman_interrupt_smsc(int irq, void *dev_id, struct pt_regs *regs)
 {
-        printk(KERN_INFO "CAYMAN: spurious interrupt\n");
+        printk(KERN_INFO "CAYMAN: spurious SMSC interrupt\n");
 }
 
 static void cayman_interrupt_pci2(int irq, void *dev_id, struct pt_regs *regs)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/mach-cayman/setup.c linux-2.4.27-pre3/arch/sh64/mach-cayman/setup.c
--- linux-2.4.26/arch/sh64/mach-cayman/setup.c	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/mach-cayman/setup.c	2004-05-18 16:51:09.000000000 +0000
@@ -74,7 +74,7 @@
 #define ITI TOP_PRIORITY	/* WDT Ints */
 
 /* Setup for the SMSC FDC37C935 */
-#define SMSC_BASE               0x04000000
+#define SMSC_SUPERIO_BASE	0x04000000
 #define SMSC_CONFIG_PORT_ADDR	0x3f0
 #define SMSC_INDEX_PORT_ADDR	SMSC_CONFIG_PORT_ADDR
 #define SMSC_DATA_PORT_ADDR	0x3f1
@@ -91,14 +91,14 @@
 
 #define SMSC_KEYBOARD_DEVICE 7
 
-#define SMSC_READ_INDEXED(index) ({ \
+#define SMSC_SUPERIO_READ_INDEXED(index) ({ \
 	outb((index), SMSC_INDEX_PORT_ADDR); \
 	inb(SMSC_DATA_PORT_ADDR); })
-#define SMSC_WRITE_INDEXED(val, index) ({ \
+#define SMSC_SUPERIO_WRITE_INDEXED(val, index) ({ \
 	outb((index), SMSC_INDEX_PORT_ADDR); \
 	outb((val),   SMSC_DATA_PORT_ADDR); })
 
-unsigned long smsc_virt;
+unsigned long smsc_superio_virt;
 
 /*
  * Platform dependent structures: maps and parms block.
@@ -145,13 +145,13 @@ int platform_int_priority[NR_INTC_IRQS] 
 	RES, RES, RES, RES, RES, RES, RES, ITI,	/* IRQ 56-63 */
 };
 
-static int __init smsc_setup(void)
+static int __init smsc_superio_setup(void)
 {
 	unsigned char devid, devrev;
 
-	smsc_virt = onchip_remap(SMSC_BASE, 1024, "SMSC");
-	if (!smsc_virt) {
-		panic("Unable to remap SMSC\n");
+	smsc_superio_virt = onchip_remap(SMSC_SUPERIO_BASE, 1024, "SMSC SuperIO");
+	if (!smsc_superio_virt) {
+		panic("Unable to remap SMSC SuperIO\n");
 	}
 
 	/* Initially the chip is in run state */
@@ -160,20 +160,20 @@ static int __init smsc_setup(void)
 	outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
 
 	/* Read device ID info */
-	devid = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
-	devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
-	printk("SMSC devid %02x rev %02x\n", devid, devrev);
+	devid = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
+	devrev = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
+	printk("SMSC SuperIO devid %02x rev %02x\n", devid, devrev);
 
 	/* Select the keyboard device */
-	SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+	SMSC_SUPERIO_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
 
 	/* enable it */
-	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);	
+	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);	
 
 	/* Select the interrupts */
 	/* On a PC keyboard is IRQ1, mouse is IRQ12 */
-	SMSC_WRITE_INDEXED(1, SMSC_PRIMARY_INT_INDEX);
-	SMSC_WRITE_INDEXED(12, SMSC_SECONDARY_INT_INDEX);
+	SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_PRIMARY_INT_INDEX);
+	SMSC_SUPERIO_WRITE_INDEXED(12, SMSC_SECONDARY_INT_INDEX);
 
 	/* Exit the configuraton state */
 	outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
@@ -184,7 +184,7 @@ static int __init smsc_setup(void)
 /* This is grotty, but, because kernel is always referenced on the link line
  * before any devices, this is safe.
  */
-__initcall(smsc_setup);
+__initcall(smsc_superio_setup);
 
 void __init platform_setup(void)
 {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/mm/cache.c linux-2.4.27-pre3/arch/sh64/mm/cache.c
--- linux-2.4.26/arch/sh64/mm/cache.c	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/mm/cache.c	2004-05-18 16:53:17.000000000 +0000
@@ -474,7 +474,7 @@ static void sh64_dcache_purge_kernel_ran
 
 /* Assumes this address (+ (2**n_synbits) pages up from it) aren't used for
    anything else in the kernel */
-#define MAGIC_PAGE0_START 0xffffffffe0000000ULL
+#define MAGIC_PAGE0_START 0xffffffffec000000ULL
 
 static void sh64_dcache_purge_coloured_phy_page(unsigned long paddr, unsigned long eaddr)
 {
@@ -740,8 +740,8 @@ static void sh64_dcache_wback_current_us
 /****************************************************************************/
 
 /* These *MUST* lie in an area of virtual address space that's otherwise unused. */
-#define UNIQUE_EADDR_START 0xc0000000UL
-#define UNIQUE_EADDR_END   0xd0000000UL
+#define UNIQUE_EADDR_START 0xe0000000UL
+#define UNIQUE_EADDR_END   0xe8000000UL
 
 static unsigned long sh64_make_unique_eaddr(unsigned long user_eaddr, unsigned long paddr)
 {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/vmlinux.lds.S linux-2.4.27-pre3/arch/sh64/vmlinux.lds.S
--- linux-2.4.26/arch/sh64/vmlinux.lds.S	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/arch/sh64/vmlinux.lds.S	2004-05-18 16:52:30.000000000 +0000
@@ -38,7 +38,6 @@ OUTPUT_FORMAT("elf32-sh64", "elf32-sh64"
 OUTPUT_ARCH(sh:sh5)
 
 #define C_PHYS(x) AT (ADDR(x) - CONFIG_CACHED_MEMORY_OFFSET)
-#define U_PHYS(x) AT (ADDR(x) - CONFIG_UNCACHED_MEMORY_OFFSET)
 
 ENTRY(__start)
 SECTIONS
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc/kernel/process.c linux-2.4.27-pre3/arch/sparc/kernel/process.c
--- linux-2.4.26/arch/sparc/kernel/process.c	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc/kernel/process.c	2004-05-18 16:51:31.000000000 +0000
@@ -54,6 +54,12 @@ void (*pm_idle)(void);
  */
 void (*pm_power_off)(void);
 
+/*
+ * sysctl - toggle power-off restriction for serial console 
+ * systems in machine_power_off()
+ */
+int scons_pwroff = 1;
+
 extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
 
 struct task_struct *last_task_used_math = NULL;
@@ -189,7 +195,7 @@ void machine_restart(char * cmd)
 void machine_power_off(void)
 {
 #ifdef CONFIG_SUN_AUXIO
-	if (auxio_power_register && !serial_console)
+	if (auxio_power_register && (!serial_console || scons_pwroff))
 		*auxio_power_register |= AUXIO_POWER_OFF;
 #endif
 	machine_halt();
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/defconfig linux-2.4.27-pre3/arch/sparc64/defconfig
--- linux-2.4.26/arch/sparc64/defconfig	2004-04-14 13:05:27.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc64/defconfig	2004-05-18 16:52:30.000000000 +0000
@@ -428,6 +428,7 @@ CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_ALI15X3 is not set
 CONFIG_BLK_DEV_AMD74XX=m
 # CONFIG_AMD74XX_OVERRIDE is not set
+CONFIG_BLK_DEV_ATIIXP=m
 CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_TRIFLEX is not set
 CONFIG_BLK_DEV_CY82C693=m
@@ -1121,6 +1122,7 @@ CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
 # CONFIG_CRYPTO_TEST is not set
 
 #
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/ioctl32.c linux-2.4.27-pre3/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.26/arch/sparc64/kernel/ioctl32.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc64/kernel/ioctl32.c	2004-05-18 16:54:59.000000000 +0000
@@ -1271,6 +1271,7 @@ static int fd_ioctl_trans(unsigned int f
 		case FDGETPRM32:
 		{
 			struct floppy_struct *f;
+			u32 u_name;
 
 			f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
 			if (!karg)
@@ -1286,7 +1287,8 @@ static int fd_ioctl_trans(unsigned int f
 			err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
 			err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
 			err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
-			err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
+			err |= __get_user(u_name, &((struct floppy_struct32 *)arg)->name);
+			f->name = (void *) (long) u_name;
 			if (err) {
 				err = -EFAULT;
 				goto out;
@@ -3810,13 +3812,15 @@ static int blkpg_ioctl_trans(unsigned in
 {
 	struct blkpg_ioctl_arg a;
 	struct blkpg_partition p;
+	u32 u_data;
 	int err;
 	mm_segment_t old_fs = get_fs();
 	
 	err = get_user(a.op, &arg->op);
 	err |= __get_user(a.flags, &arg->flags);
 	err |= __get_user(a.datalen, &arg->datalen);
-	err |= __get_user((long)a.data, &arg->data);
+	err |= __get_user(u_data, &arg->data);
+	a.data = (void *) (long) u_data;
 	if (err) return err;
 	switch (a.op) {
 	case BLKPG_ADD_PARTITION:
@@ -4416,6 +4420,7 @@ COMPATIBLE_IOCTL(HDIO_SET_NOWERR)
 COMPATIBLE_IOCTL(HDIO_SET_32BIT)
 COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT)
 COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
+COMPATIBLE_IOCTL(HDIO_DRIVE_TASK)
 COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
 COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
 COMPATIBLE_IOCTL(HDIO_SET_NICE)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/power.c linux-2.4.27-pre3/arch/sparc64/kernel/power.c
--- linux-2.4.26/arch/sparc64/kernel/power.c	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc64/kernel/power.c	2004-05-18 16:54:57.000000000 +0000
@@ -17,6 +17,12 @@
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
 
+/*
+ * sysctl - toggle power-off restriction for serial console 
+ * systems in machine_power_off()
+ */
+int scons_pwroff = 1; 
+
 #ifdef CONFIG_PCI
 static unsigned long power_reg = 0UL;
 
@@ -40,7 +46,7 @@ extern int serial_console;
 
 void machine_power_off(void)
 {
-	if (!serial_console) {
+	if (!serial_console || scons_pwroff) {
 #ifdef CONFIG_PCI
 		if (power_reg != 0UL) {
 			/* Both register bits seem to have the
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/process.c linux-2.4.27-pre3/arch/sparc64/kernel/process.c
--- linux-2.4.26/arch/sparc64/kernel/process.c	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc64/kernel/process.c	2004-05-18 16:52:52.000000000 +0000
@@ -453,7 +453,7 @@ void flush_thread(void)
 					page = pmd_alloc_one(NULL, 0);
 				pgd_set(pgd0, page);
 			}
-			pgd_cache = pgd_val(*pgd0) << 11UL;
+			pgd_cache = ((unsigned long) pgd_val(*pgd0)) << 11UL;
 		}
 		__asm__ __volatile__("stxa %0, [%1] %2\n\t"
 				     "membar #Sync"
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/signal32.c linux-2.4.27-pre3/arch/sparc64/kernel/signal32.c
--- linux-2.4.26/arch/sparc64/kernel/signal32.c	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc64/kernel/signal32.c	2004-05-18 16:50:48.000000000 +0000
@@ -393,7 +393,7 @@ asmlinkage void do_rt_sigreturn32(struct
 {
 	struct rt_signal_frame32 *sf;
 	unsigned int psr;
-	unsigned pc, npc, fpu_save;
+	unsigned pc, npc, fpu_save, u_ss_sp;
 	mm_segment_t old_fs;
 	sigset_t set;
 	sigset_t32 seta;
@@ -444,7 +444,8 @@ asmlinkage void do_rt_sigreturn32(struct
 	if (fpu_save)
 		err |= restore_fpu_state32(regs, &sf->fpu_state);
 	err |= copy_from_user(&seta, &sf->mask, sizeof(sigset_t32));
-	err |= __get_user((long)st.ss_sp, &sf->stack.ss_sp);
+	err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
+	st.ss_sp = (void *) (long) u_ss_sp;
 	err |= __get_user(st.ss_flags, &sf->stack.ss_flags);
 	err |= __get_user(st.ss_size, &sf->stack.ss_size);
 	if (err)
@@ -1030,7 +1031,7 @@ asmlinkage int svr4_setcontext(svr4_ucon
 	struct thread_struct *tp = &current->thread;
 	svr4_gregset_t  *gr;
 	mm_segment_t old_fs;
-	u32 pc, npc, psr;
+	u32 pc, npc, psr, u_ss_sp;
 	sigset_t set;
 	svr4_sigset_t setv;
 	int i, err;
@@ -1075,7 +1076,8 @@ asmlinkage int svr4_setcontext(svr4_ucon
 	if (_NSIG_WORDS >= 2)
 		set.sig[1] = setv.sigbits[2] | (((long)setv.sigbits[3]) << 32);
 	
-	err |= __get_user((long)st.ss_sp, &c->stack.sp);
+	err |= __get_user(u_ss_sp, &c->stack.sp);
+	st.ss_sp = (void *) (long) u_ss_sp;
 	err |= __get_user(st.ss_flags, &c->stack.flags);
 	err |= __get_user(st.ss_size, &c->stack.size);
 	if (err)
@@ -1545,9 +1547,9 @@ asmlinkage int do_sys32_sigstack(u32 u_s
 	
 	/* Now see if we want to update the new state. */
 	if (ssptr) {
-		void *ss_sp;
+		u32 ss_sp;
 
-		if (get_user((long)ss_sp, &ssptr->the_stack))
+		if (get_user(ss_sp, &ssptr->the_stack))
 			goto out;
 		/* If the current stack was set with sigaltstack, don't
 		   swap stacks while we are on it.  */
@@ -1570,13 +1572,15 @@ out:
 asmlinkage int do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp)
 {
 	stack_t uss, uoss;
+	u32 u_ss_sp = 0;
 	int ret;
 	mm_segment_t old_fs;
 	
-	if (ussa && (get_user((long)uss.ss_sp, &((stack_t32 *)(long)ussa)->ss_sp) ||
+	if (ussa && (get_user(u_ss_sp, &((stack_t32 *)(long)ussa)->ss_sp) ||
 		    __get_user(uss.ss_flags, &((stack_t32 *)(long)ussa)->ss_flags) ||
 		    __get_user(uss.ss_size, &((stack_t32 *)(long)ussa)->ss_size)))
 		return -EFAULT;
+	uss.ss_sp = (void *) (long) u_ss_sp;
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
 	ret = do_sigaltstack(ussa ? &uss : NULL, uossa ? &uoss : NULL, sp);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.27-pre3/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.4.26/arch/sparc64/kernel/sparc64_ksyms.c	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc64/kernel/sparc64_ksyms.c	2004-05-18 16:54:43.000000000 +0000
@@ -89,6 +89,7 @@ extern long sparc32_open(const char * fi
 extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
 extern int unregister_ioctl32_conversion(unsigned int cmd);
 extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
+extern void (*prom_palette)(int);
                 
 extern int __ashrdi3(int, int);
 
@@ -371,3 +372,5 @@ EXPORT_SYMBOL(do_BUG);
 #endif
 
 EXPORT_SYMBOL(tick_ops);
+
+EXPORT_SYMBOL(prom_palette);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/sys_sparc32.c linux-2.4.27-pre3/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.26/arch/sparc64/kernel/sys_sparc32.c	2004-04-14 13:05:27.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc64/kernel/sys_sparc32.c	2004-05-18 16:53:54.000000000 +0000
@@ -1316,7 +1316,7 @@ static int filldir(void * __buf, const c
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *) dirent + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
@@ -3056,9 +3056,12 @@ asmlinkage int sys32_sigaction (int sig,
 
         if (act) {
 		old_sigset_t32 mask;
+		u32 u_handler, u_restorer;
 		
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
-		ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer);
+		ret = get_user(u_handler, &act->sa_handler);
+		new_ka.sa.sa_handler = (void *) (long) u_handler;
+		ret |= __get_user(u_restorer, &act->sa_restorer);
+		new_ka.sa.sa_restorer = (void *) (long) u_restorer;
 		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 		ret |= __get_user(mask, &act->sa_mask);
 		if (ret)
@@ -3097,8 +3100,11 @@ sys32_rt_sigaction(int sig, struct sigac
 	current->thread.flags |= SPARC_FLAG_NEWSIGNALS;
 
         if (act) {
+		u32 u_handler, u_restorer;
+
 		new_ka.ka_restorer = restorer;
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
+		ret = get_user(u_handler, &act->sa_handler);
+		new_ka.sa.sa_handler = (void *) (long) u_handler;
 		ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(sigset_t32));
 		switch (_NSIG_WORDS) {
 		case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
@@ -3107,7 +3113,8 @@ sys32_rt_sigaction(int sig, struct sigac
 		case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
 		}
 		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-		ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer);
+		ret |= __get_user(u_restorer, &act->sa_restorer);
+		new_ka.sa.sa_restorer = (void *) (long) u_restorer;
                 if (ret)
                 	return -EFAULT;
 	}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/sys_sunos32.c linux-2.4.27-pre3/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.4.26/arch/sparc64/kernel/sys_sunos32.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc64/kernel/sys_sunos32.c	2004-05-18 16:53:49.000000000 +0000
@@ -296,7 +296,7 @@ static int sunos_filldir(void * __buf, c
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *) dirent + reclen;
 	buf->curr = dirent;
 	buf->count -= reclen;
 	return 0;
@@ -376,7 +376,7 @@ static int sunos_filldirentry(void * __b
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *) dirent + reclen;
 	buf->curr = dirent;
 	buf->count -= reclen;
 	return 0;
@@ -1309,10 +1309,12 @@ asmlinkage int sunos_sigaction (int sig,
 
 	if (act) {
 		old_sigset_t32 mask;
+		u32 u_handler;
 
-		if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) ||
+		if (get_user(u_handler, &((struct old_sigaction32 *)A(act))->sa_handler) ||
 		    __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags))
 			return -EFAULT;
+		new_ka.sa.sa_handler = (void *) (long) u_handler;
 		__get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask);
 		new_ka.sa.sa_restorer = NULL;
 		new_ka.ka_restorer = NULL;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/mm/init.c linux-2.4.27-pre3/arch/sparc64/mm/init.c
--- linux-2.4.26/arch/sparc64/mm/init.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/arch/sparc64/mm/init.c	2004-05-18 16:52:37.000000000 +0000
@@ -1433,8 +1433,10 @@ void __init paging_init(void)
 	/* Now can init the kernel/bad page tables. */
 	pgd_set(&swapper_pg_dir[0], swapper_pmd_dir + (shift / sizeof(pgd_t)));
 	
-	sparc64_vpte_patchme1[0] |= (pgd_val(init_mm.pgd[0]) >> 10);
-	sparc64_vpte_patchme2[0] |= (pgd_val(init_mm.pgd[0]) & 0x3ff);
+	sparc64_vpte_patchme1[0] |=
+		(((unsigned long)pgd_val(init_mm.pgd[0])) >> 10);
+	sparc64_vpte_patchme2[0] |=
+		(((unsigned long)pgd_val(init_mm.pgd[0])) & 0x3ff);
 	flushi((long)&sparc64_vpte_patchme1[0]);
 	
 	/* Setup bootmem... */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/acpi.c linux-2.4.27-pre3/arch/x86_64/kernel/acpi.c
--- linux-2.4.26/arch/x86_64/kernel/acpi.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/arch/x86_64/kernel/acpi.c	2004-05-18 16:55:14.000000000 +0000
@@ -56,7 +56,10 @@ int acpi_sci_override_gsi __initdata;
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
    -------------------------------------------------------------------------- */
-
+#ifdef CONFIG_ACPI_PCI
+int acpi_noirq __initdata;	/* skip ACPI IRQ initialization */
+int acpi_pci_disabled __initdata; /* skip ACPI PCI scan and IRQ initialization */
+#endif
 int acpi_ht __initdata = 1;	/* enable HT */
 
 enum acpi_irq_model_id		acpi_irq_model;
@@ -119,11 +122,40 @@ __acpi_map_table (
 #endif
 }
 
+#ifdef CONFIG_ACPI_MMCONFIG
+
+u32 pci_mmcfg_base_addr;
+
+static int __init 
+acpi_parse_mcfg(unsigned long phys_addr,
+		unsigned long size)
+{
+	struct acpi_table_mcfg *mcfg = NULL;
+
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size);
+	if (!mcfg) {
+		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
+		return -ENODEV;
+	}
+
+	if (mcfg->base_reserved) {
+		printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n");
+		return -ENODEV;
+	}
+
+	pci_mmcfg_base_addr = mcfg->base_address;
+
+	return 0;
+}
+#endif /* CONFIG_ACPI_MMCONFIG */
+
 #ifdef CONFIG_X86_LOCAL_APIC
 
 static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
 
-
 static int __init
 acpi_parse_madt (
 	unsigned long		phys_addr,
@@ -330,7 +362,7 @@ acpi_parse_nmi_src (
 
 #endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/
 
-
+#ifdef CONFIG_HPET_TIMER
 static int __init
 acpi_parse_hpet (
 	unsigned long		phys_addr,
@@ -351,6 +383,7 @@ acpi_parse_hpet (
 
 	return 0;
 } 
+#endif	/* CONFIG_HPET_TIMER */
 
 #ifdef CONFIG_ACPI_BUS
 /*
@@ -457,17 +490,16 @@ acpi_boot_init (void)
 		return result;
 	}
 
-#ifdef CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_ACPI_MMCONFIG
+	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (result < 0) {
+		printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", result);
+	} else if (result > 1) {
+		printk(KERN_WARNING PREFIX "Multiple MCFG tables exist\n");
+	}
+#endif
 
-	/* this check should not need to be here -lenb */
-	/* If "nolocalapic" is specified don't look further */
-	extern int apic_disabled;
-	if (apic_disabled) {
-		printk(KERN_INFO PREFIX "Skipping Local/IO-APIC probe due to \"nolocalapic\"\n");
-		return 0;	
-	}	
-	printk(KERN_INFO PREFIX "Parsing Local APIC info in MADT\n"); 
-	
+#ifdef CONFIG_X86_LOCAL_APIC
 
 	/* 
 	 * MADT
@@ -573,9 +605,6 @@ acpi_boot_init (void)
 		return result;
 	}
 
-	/* Build a default routing table for legacy (ISA) interrupts. */
-	mp_config_acpi_legacy_irqs();
-
 	/* Record sci_int for use when looking for MADT sci_int override */
 	acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
 
@@ -593,6 +622,9 @@ acpi_boot_init (void)
 	if (!acpi_sci_override_gsi)
 		acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
 
+	/* Fill in identity legacy mapings where no override */
+	mp_config_acpi_legacy_irqs();
+
 	result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src);
 	if (result < 0) {
 		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
@@ -609,9 +641,11 @@ acpi_boot_init (void)
 	if (acpi_lapic && acpi_ioapic)
 		smp_found_config = 1;
 
+#ifdef CONFIG_HPET_TIMER
 	result = acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
 	if (result < 0) 
 		printk("ACPI: no HPET table found (%d).\n", result); 
+#endif
 
 #endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/e820.c linux-2.4.27-pre3/arch/x86_64/kernel/e820.c
--- linux-2.4.26/arch/x86_64/kernel/e820.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/arch/x86_64/kernel/e820.c	2004-05-18 16:52:32.000000000 +0000
@@ -567,10 +567,10 @@ void __init parse_mem_cmdline (char ** c
 			acpi_strict = 1;
 		}
 
-		else if (!memcmp(from, "pci=noacpi", 10)) {
+		else if (!memcmp(from, "pci=noacpi", 10))
+			acpi_disable_pci();
+		else if (!memcmp(from, "acpi=noirq", 10))
 			acpi_noirq_set();
-		}
-
 		else if (!memcmp(from, "acpi_sci=edge", 13))
 			acpi_sci_flags.trigger =  1;
 		else if (!memcmp(from, "acpi_sci=level", 14))
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/i8259.c linux-2.4.27-pre3/arch/x86_64/kernel/i8259.c
--- linux-2.4.26/arch/x86_64/kernel/i8259.c	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.27-pre3/arch/x86_64/kernel/i8259.c	2004-05-18 16:53:35.000000000 +0000
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 
+#include <asm/acpi.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -439,6 +440,7 @@ void __init init_IRQ(void)
 #endif
 
 #ifndef CONFIG_VISWS
-	setup_irq(2, &irq2);
+	if (!acpi_ioapic)
+		setup_irq(2, &irq2);
 #endif
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/io_apic.c linux-2.4.27-pre3/arch/x86_64/kernel/io_apic.c
--- linux-2.4.26/arch/x86_64/kernel/io_apic.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/arch/x86_64/kernel/io_apic.c	2004-05-18 16:54:57.000000000 +0000
@@ -1684,18 +1684,10 @@ static inline void check_timer(void)
 
 /*
  *
- * IRQ's that are handled by the old PIC in all cases:
+ * IRQ's that are handled by the PIC in the MPS IOAPIC case.
  * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ.
  *   Linux doesn't really care, as it's not actually used
  *   for any interrupt handling anyway.
- * - There used to be IRQ13 here as well, but all
- *   MPS-compliant must not use it for FPU coupling and we
- *   want to use exception 16 anyway.  And there are
- *   systems who connect it to an I/O APIC for other uses.
- *   Thus we don't mark it special any longer.
- *
- * Additionally, something is definitely wrong with irq9
- * on PIIX4 boards.
  */
 #define PIC_IRQS	(1<<2)
 
@@ -1703,7 +1695,11 @@ void __init setup_IO_APIC(void)
 {
 	enable_IO_APIC();
 
-	io_apic_irqs = ~PIC_IRQS;
+	if (acpi_ioapic)
+		io_apic_irqs = ~0;	/* all IRQs go through IOAPIC */
+	else
+		io_apic_irqs = ~PIC_IRQS;
+
 	printk("ENABLING IO-APIC IRQs\n");
 
 	/*
@@ -1858,7 +1854,7 @@ int io_apic_set_pci_routing (int ioapic,
 
 	entry.vector = assign_irq_vector(irq);
 
-	printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
+	Dprintk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
 		"IRQ %d Mode:%i Active:%i)\n", ioapic,
 		mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/mpparse.c linux-2.4.27-pre3/arch/x86_64/kernel/mpparse.c
--- linux-2.4.26/arch/x86_64/kernel/mpparse.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/arch/x86_64/kernel/mpparse.c	2004-05-18 16:52:23.000000000 +0000
@@ -793,8 +793,6 @@ void __init mp_override_legacy_irq (
 	u32			global_irq)
 {
 	struct mpc_config_intsrc intsrc;
-	int			i = 0;
-	int			found = 0;
 	int			ioapic = -1;
 	int			pin = -1;
 
@@ -827,23 +825,9 @@ void __init mp_override_legacy_irq (
 		(intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, 
 		intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);
 
-	/* 
-	 * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it.
-	 * Otherwise create a new entry (e.g. global_irq == 2).
-	 */
-	for (i = 0; i < mp_irq_entries; i++) {
-		if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) 
-			&& (mp_irqs[i].mpc_dstirq == intsrc.mpc_dstirq)) {
-			mp_irqs[i] = intsrc;
-			found = 1;
-			break;
-		}
-	}
-	if (!found) {
-		mp_irqs[mp_irq_entries] = intsrc;
-		if (++mp_irq_entries == MAX_IRQ_SOURCES)
-			panic("Max # of irq sources exceeded!\n");
-	}
+	mp_irqs[mp_irq_entries] = intsrc;
+	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+		panic("Max # of irq sources exceeded!\n");
 
 	return;
 }
@@ -874,13 +858,22 @@ void __init mp_config_acpi_legacy_irqs (
 	intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;
 
 	/* 
-	 * Use the default configuration for the IRQs 0-15.  These may be
+	 * Use the default configuration for the IRQs 0-15.  Unless
 	 * overriden by (MADT) interrupt source override entries.
 	 */
 	for (i = 0; i < 16; i++) {
+		int idx;
 
-		if (i == 2)
-			continue;			/* Don't connect IRQ2 */
+		for (idx = 0; idx < mp_irq_entries; idx++)
+			if (mp_irqs[idx].mpc_srcbus == MP_ISA_BUS &&
+				(mp_irqs[idx].mpc_srcbusirq == i ||
+				mp_irqs[idx].mpc_dstirq == i))
+					break;
+
+		if (idx != mp_irq_entries) {
+			printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
+			continue;			  /* IRQ already used */
+		}
 
 		intsrc.mpc_irqtype = mp_INT;
 		intsrc.mpc_srcbusirq = i;		   /* Identity mapped */
@@ -982,10 +975,11 @@ void __init mp_parse_prt (void)
 			entry->irq = irq;
 
 		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> vector 0x%02x"
-			" -> IRQ %d\n", entry->id.segment, entry->id.bus, 
-			entry->id.device, ('A' + entry->pin), 
-			mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector, 
-			entry->irq);
+			" -> IRQ %d %s %s\n", entry->id.segment, entry->id.bus,
+			entry->id.device, ('A' + entry->pin),
+			mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector,
+			entry->irq, edge_level ? "level" : "edge",
+			active_high_low ? "low" : "high");
 	}
 
 	print_IO_APIC();
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/pci-pc.c linux-2.4.27-pre3/arch/x86_64/kernel/pci-pc.c
--- linux-2.4.26/arch/x86_64/kernel/pci-pc.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/arch/x86_64/kernel/pci-pc.c	2004-05-18 16:54:03.000000000 +0000
@@ -646,7 +646,7 @@ char * __devinit pcibios_setup(char *str
 		pcibios_last_bus = simple_strtol(str+8, NULL, 0);
 		return NULL;
 	} else if (!strncmp(str, "noacpi", 6)) {
-		acpi_noirq_set();
+		acpi_disable_pci();
 		return NULL;
 	}
 	return str;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/setup.c linux-2.4.27-pre3/arch/x86_64/kernel/setup.c
--- linux-2.4.26/arch/x86_64/kernel/setup.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/arch/x86_64/kernel/setup.c	2004-05-18 16:51:51.000000000 +0000
@@ -48,11 +48,8 @@
 #include <asm/bootsetup.h>
 #include <asm/proto.h>
 
-int acpi_disabled = 0;
-#ifdef	CONFIG_ACPI_BOOT
-int acpi_noirq __initdata = 0;	/* skip ACPI IRQ initialization */
-#endif
-
+int acpi_disabled;
+EXPORT_SYMBOL(acpi_disabled);
 
 int swiotlb;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/Config.in linux-2.4.27-pre3/crypto/Config.in
--- linux-2.4.26/crypto/Config.in	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/crypto/Config.in	2004-05-18 16:54:59.000000000 +0000
@@ -81,6 +81,7 @@ if [ "$CONFIG_CRYPTO" = "y" ]; then
   else
     tristate       '  Deflate compression algorithm' CONFIG_CRYPTO_DEFLATE
   fi
+  tristate       '  Michael MIC keyed digest algorithm' CONFIG_CRYPTO_MICHAEL_MIC
   tristate       '  Testing module' CONFIG_CRYPTO_TEST
 fi
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/Makefile linux-2.4.27-pre3/crypto/Makefile
--- linux-2.4.26/crypto/Makefile	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/crypto/Makefile	2004-05-18 16:52:04.000000000 +0000
@@ -28,6 +28,7 @@ obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
 obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
 obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
+obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/digest.c linux-2.4.27-pre3/crypto/digest.c
--- linux-2.4.26/crypto/digest.c	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/crypto/digest.c	2004-05-18 16:51:26.000000000 +0000
@@ -42,6 +42,15 @@ static void final(struct crypto_tfm *tfm
 	tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out);
 }
 
+static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+	u32 flags;
+	if (tfm->__crt_alg->cra_digest.dia_setkey == NULL)
+		return -ENOSYS;
+	return tfm->__crt_alg->cra_digest.dia_setkey(crypto_tfm_ctx(tfm),
+						     key, keylen, &flags);
+}
+
 static void digest(struct crypto_tfm *tfm,
                    struct scatterlist *sg, unsigned int nsg, u8 *out)
 {
@@ -72,6 +81,7 @@ int crypto_init_digest_ops(struct crypto
 	ops->dit_update	= update;
 	ops->dit_final	= final;
 	ops->dit_digest	= digest;
+	ops->dit_setkey	= setkey;
 	
 	return crypto_alloc_hmac_block(tfm);
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/michael_mic.c linux-2.4.27-pre3/crypto/michael_mic.c
--- linux-2.4.26/crypto/michael_mic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/crypto/michael_mic.c	2004-05-18 16:52:57.000000000 +0000
@@ -0,0 +1,193 @@
+/*
+ * Cryptographic API
+ *
+ * Michael MIC (IEEE 802.11i/TKIP) keyed digest
+ *
+ * Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+
+
+struct michael_mic_ctx {
+	u8 pending[4];
+	size_t pending_len;
+
+	u32 l, r;
+};
+
+
+static inline u32 rotl(u32 val, int bits)
+{
+	return (val << bits) | (val >> (32 - bits));
+}
+
+
+static inline u32 rotr(u32 val, int bits)
+{
+	return (val >> bits) | (val << (32 - bits));
+}
+
+
+static inline u32 xswap(u32 val)
+{
+	return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
+}
+
+
+#define michael_block(l, r)	\
+do {				\
+	r ^= rotl(l, 17);	\
+	l += r;			\
+	r ^= xswap(l);		\
+	l += r;			\
+	r ^= rotl(l, 3);	\
+	l += r;			\
+	r ^= rotr(l, 2);	\
+	l += r;			\
+} while (0)
+
+
+static inline u32 get_le32(const u8 *p)
+{
+	return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+
+static inline void put_le32(u8 *p, u32 v)
+{
+	p[0] = v;
+	p[1] = v >> 8;
+	p[2] = v >> 16;
+	p[3] = v >> 24;
+}
+
+
+static void michael_init(void *ctx)
+{
+	struct michael_mic_ctx *mctx = ctx;
+	mctx->pending_len = 0;
+}
+
+
+static void michael_update(void *ctx, const u8 *data, unsigned int len)
+{
+	struct michael_mic_ctx *mctx = ctx;
+
+	if (mctx->pending_len) {
+		int flen = 4 - mctx->pending_len;
+		if (flen > len)
+			flen = len;
+		memcpy(&mctx->pending[mctx->pending_len], data, flen);
+		mctx->pending_len += flen;
+		data += flen;
+		len -= flen;
+
+		if (mctx->pending_len < 4)
+			return;
+
+		mctx->l ^= get_le32(mctx->pending);
+		michael_block(mctx->l, mctx->r);
+		mctx->pending_len = 0;
+	}
+
+	while (len >= 4) {
+		mctx->l ^= get_le32(data);
+		michael_block(mctx->l, mctx->r);
+		data += 4;
+		len -= 4;
+	}
+
+	if (len > 0) {
+		mctx->pending_len = len;
+		memcpy(mctx->pending, data, len);
+	}
+}
+
+
+static void michael_final(void *ctx, u8 *out)
+{
+	struct michael_mic_ctx *mctx = ctx;
+	u8 *data = mctx->pending;
+
+	/* Last block and padding (0x5a, 4..7 x 0) */
+	switch (mctx->pending_len) {
+	case 0:
+		mctx->l ^= 0x5a;
+		break;
+	case 1:
+		mctx->l ^= data[0] | 0x5a00;
+		break;
+	case 2:
+		mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000;
+		break;
+	case 3:
+		mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) |
+			0x5a000000;
+		break;
+	}
+	michael_block(mctx->l, mctx->r);
+	/* l ^= 0; */
+	michael_block(mctx->l, mctx->r);
+
+	put_le32(out, mctx->l);
+	put_le32(out + 4, mctx->r);
+}
+
+
+static int michael_setkey(void *ctx, const u8 *key, unsigned int keylen,
+			  u32 *flags)
+{
+	struct michael_mic_ctx *mctx = ctx;
+	if (keylen != 8) {
+		if (flags)
+			*flags = CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+	mctx->l = get_le32(key);
+	mctx->r = get_le32(key + 4);
+	return 0;
+}
+
+
+static struct crypto_alg michael_mic_alg = {
+	.cra_name	= "michael_mic",
+	.cra_flags	= CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize	= 8,
+	.cra_ctxsize	= sizeof(struct michael_mic_ctx),
+	.cra_module	= THIS_MODULE,
+	.cra_list	= LIST_HEAD_INIT(michael_mic_alg.cra_list),
+	.cra_u		= { .digest = {
+	.dia_digestsize	= 8,
+	.dia_init	= michael_init,
+	.dia_update	= michael_update,
+	.dia_final	= michael_final,
+	.dia_setkey	= michael_setkey } }
+};
+
+
+static int __init michael_mic_init(void)
+{
+	return crypto_register_alg(&michael_mic_alg);
+}
+
+
+static void __exit michael_mic_exit(void)
+{
+	crypto_unregister_alg(&michael_mic_alg);
+}
+
+
+module_init(michael_mic_init);
+module_exit(michael_mic_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Michael MIC");
+MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/tcrypt.c linux-2.4.27-pre3/crypto/tcrypt.c
--- linux-2.4.26/crypto/tcrypt.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/crypto/tcrypt.c	2004-05-18 16:53:57.000000000 +0000
@@ -63,7 +63,7 @@ static char *tvmem;
 static char *check[] = {
 	"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
 	"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", 
-	"arc4", "deflate", NULL
+	"arc4", "michael_mic", "deflate", NULL
 };
 
 static void
@@ -114,6 +114,10 @@ test_hash (char * algo, struct hash_test
 		sg[0].length = hash_tv[i].psize;
 
 		crypto_digest_init (tfm);
+		if (tfm->crt_u.digest.dit_setkey) {
+			crypto_digest_setkey (tfm, hash_tv[i].key,
+					      hash_tv[i].ksize);
+		}
 		crypto_digest_update (tfm, sg, 1);
 		crypto_digest_final (tfm, result);
 
@@ -570,6 +574,8 @@ do_test(void)
 		test_hmac("sha1", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS);		
 		test_hmac("sha256", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS);
 #endif		
+
+		test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS);
 		break;
 
 	case 1:
@@ -649,6 +655,10 @@ do_test(void)
 		test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS);
 		break;
 
+	case 17:
+		test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS);
+		break;
+
 #ifdef CONFIG_CRYPTO_HMAC
 	case 100:
 		test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/tcrypt.h linux-2.4.27-pre3/crypto/tcrypt.h
--- linux-2.4.26/crypto/tcrypt.h	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/crypto/tcrypt.h	2004-05-18 16:55:15.000000000 +0000
@@ -30,6 +30,8 @@ struct hash_testvec {
 	char digest[MAX_DIGEST_SIZE];
 	unsigned char np;
 	unsigned char tap[MAX_TAP];		
+	char key[128]; /* only used with keyed hash algorithms */
+	unsigned char ksize;
 };
 
 struct hmac_testvec {	
@@ -1719,4 +1721,54 @@ struct comp_testvec deflate_decomp_tv_te
 	},
 };
 
+/*
+ * Michael MIC test vectors from IEEE 802.11i
+ */
+#define MICHAEL_MIC_TEST_VECTORS 6
+
+struct hash_testvec michael_mic_tv_template[] =
+{
+	{
+		.key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.ksize = 8,
+		.plaintext = { },
+		.psize = 0,
+		.digest = { 0x82, 0x92, 0x5c, 0x1c, 0xa1, 0xd1, 0x30, 0xb8 }
+	},
+	{
+		.key = { 0x82, 0x92, 0x5c, 0x1c, 0xa1, 0xd1, 0x30, 0xb8 },
+		.ksize = 8,
+		.plaintext = { 'M' },
+		.psize = 1,
+		.digest = { 0x43, 0x47, 0x21, 0xca, 0x40, 0x63, 0x9b, 0x3f }
+	},
+	{
+		.key = { 0x43, 0x47, 0x21, 0xca, 0x40, 0x63, 0x9b, 0x3f },
+		.ksize = 8,
+		.plaintext = { 'M', 'i' },
+		.psize = 2,
+		.digest = { 0xe8, 0xf9, 0xbe, 0xca, 0xe9, 0x7e, 0x5d, 0x29 }
+	},
+	{
+		.key = { 0xe8, 0xf9, 0xbe, 0xca, 0xe9, 0x7e, 0x5d, 0x29 },
+		.ksize = 8,
+		.plaintext = { 'M', 'i', 'c' },
+		.psize = 3,
+		.digest = { 0x90, 0x03, 0x8f, 0xc6, 0xcf, 0x13, 0xc1, 0xdb }
+	},
+	{
+		.key = { 0x90, 0x03, 0x8f, 0xc6, 0xcf, 0x13, 0xc1, 0xdb },
+		.ksize = 8,
+		.plaintext = { 'M', 'i', 'c', 'h' },
+		.psize = 4,
+		.digest = { 0xd5, 0x5e, 0x10, 0x05, 0x10, 0x12, 0x89, 0x86 }
+	},
+	{
+		.key = { 0xd5, 0x5e, 0x10, 0x05, 0x10, 0x12, 0x89, 0x86 },
+		.ksize = 8,
+		.plaintext = { 'M', 'i', 'c', 'h', 'a', 'e', 'l' },
+		.psize = 7,
+		.digest = { 0x0a, 0x94, 0x2b, 0x12, 0x4e, 0xca, 0xa5, 0x46 },
+	}
+};
 #endif	/* _CRYPTO_TCRYPT_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/Config.in linux-2.4.27-pre3/drivers/acpi/Config.in
--- linux-2.4.26/drivers/acpi/Config.in	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/Config.in	2004-05-18 16:54:51.000000000 +0000
@@ -16,6 +16,7 @@ if [ "$CONFIG_X86" = "y" ]; then
     define_bool CONFIG_ACPI_POWER		y
     if [ "$CONFIG_PCI" = "y" ]; then
       define_bool CONFIG_ACPI_PCI		y
+      define_bool CONFIG_ACPI_MMCONFIG		y
     fi
     define_bool CONFIG_ACPI_SLEEP		y
     define_bool CONFIG_ACPI_SYSTEM		y
@@ -28,7 +29,6 @@ if [ "$CONFIG_X86" = "y" ]; then
     tristate     '  ASUS Laptop Extras'  CONFIG_ACPI_ASUS
     tristate     '  Toshiba Laptop Extras'	CONFIG_ACPI_TOSHIBA
     bool         '  Debug Statements'	CONFIG_ACPI_DEBUG
-    bool         '  Relaxed AML Checking'	CONFIG_ACPI_RELAXED_AML
   else
     if [ "$CONFIG_SMP" = "y" ]; then
       define_bool CONFIG_ACPI_BOOT		y
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/Makefile linux-2.4.27-pre3/drivers/acpi/Makefile
--- linux-2.4.26/drivers/acpi/Makefile	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/Makefile	2004-05-18 16:55:10.000000000 +0000
@@ -14,7 +14,7 @@ endif
 
 EXTRA_CFLAGS	+= $(ACPI_CFLAGS)
 
-export-objs 	:= acpi_ksyms.o processor.o
+export-objs 	:= acpi_ksyms.o processor.o bus.o
 
 obj-$(CONFIG_ACPI)	:= acpi_ksyms.o 
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/ac.c linux-2.4.27-pre3/drivers/acpi/ac.c
--- linux-2.4.26/drivers/acpi/ac.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/ac.c	2004-05-18 16:54:37.000000000 +0000
@@ -156,6 +156,7 @@ acpi_ac_add_fs (
 			acpi_ac_dir);
 		if (!acpi_device_dir(device))
 			return_VALUE(-ENODEV);
+		acpi_device_dir(device)->owner = THIS_MODULE;
 	}
 
 	/* 'state' [R] */
@@ -168,6 +169,7 @@ acpi_ac_add_fs (
 	else {
 		entry->read_proc = acpi_ac_read_state;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	return_VALUE(0);
@@ -318,6 +320,7 @@ acpi_ac_init (void)
 	acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
 	if (!acpi_ac_dir)
 		return_VALUE(-ENODEV);
+	acpi_ac_dir->owner = THIS_MODULE;
 
 	result = acpi_bus_register_driver(&acpi_ac_driver);
 	if (result < 0) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/asus_acpi.c linux-2.4.27-pre3/drivers/acpi/asus_acpi.c
--- linux-2.4.26/drivers/acpi/asus_acpi.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/asus_acpi.c	2004-05-18 16:53:50.000000000 +0000
@@ -41,7 +41,7 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 
-#define ASUS_ACPI_VERSION "0.27"
+#define ASUS_ACPI_VERSION "0.28"
 
 #define PROC_ASUS       "asus"	//the directory
 #define PROC_MLED       "mled"
@@ -125,12 +125,11 @@ struct asus_hotk {
 		L5x,      //L5800C 
 		L8L,      //L8400L
 		M1A,      //M1300A
-		M2E,      //M2400E
+		M2E,      //M2400E, L4400L
+		P30,	  //Samsung P30
 		S1x,      //S1300A, but also L1400B and M2400A (L84F)
 		S2x,      //S200 (J1 reported), Victor MP-XP7210
-		          //TODO  A1370D does not seem to have an ATK device 
-		          // L8400 model doesn't have ATK
-		xxN,      //M2400N, M3700N, S1300N (Centrino)
+		xxN,      //M2400N, M3700N, M6800N, S1300N, S5200N (Centrino)
 		END_MODEL
 	} model;              //Models currently supported
 	u16 event_count[128]; //count for each event TODO make this better
@@ -140,6 +139,7 @@ struct asus_hotk {
 #define A1x_PREFIX "\\_SB.PCI0.ISA.EC0."
 #define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0."
 #define M1A_PREFIX "\\_SB.PCI0.PX40.EC0."
+#define P30_PREFIX "\\_SB.PCI0.LPCB.EC0."
 #define S1x_PREFIX "\\_SB.PCI0.PX40."
 #define S2x_PREFIX A1x_PREFIX
 #define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0."
@@ -166,7 +166,7 @@ static struct model_data model_conf[END_
 		.mt_lcd_switch     = A1x_PREFIX "_Q10",
 		.lcd_status        = "\\BKLI",
 		.brightness_up     = A1x_PREFIX "_Q0E",
-		.brightness_down   = A1x_PREFIX "_Q0F",
+		.brightness_down   = A1x_PREFIX "_Q0F"
 	},
 
 	{
@@ -176,11 +176,8 @@ static struct model_data model_conf[END_
 		.wled_status       = "\\SG66",
 		.mt_lcd_switch     = "\\Q10",
 		.lcd_status        = "\\BAOF",
-		.brightness_up     = "\\Q0E",
-		.brightness_down   = "\\Q0F",
 		.brightness_set    = "SPLV",
 		.brightness_get    = "GPLV",
-		.brightness_status = "\\CMOD",
 		.display_set       = "SDSP",
 		.display_get       = "\\INFB"
 	},
@@ -217,11 +214,8 @@ static struct model_data model_conf[END_
 		.mt_wled           = "WLED",
 		.mt_lcd_switch     = L3C_PREFIX "_Q10",
 		.lcd_status        = "\\GL32",
-		.brightness_up     = L3C_PREFIX "_Q0F",
-		.brightness_down   = L3C_PREFIX "_Q0E",
 		.brightness_set    = "SPLV",
 		.brightness_get    = "GPLV",
-		.brightness_status = "\\BLVL",
 		.display_set       = "SDSP",
 		.display_get       = "\\_SB.PCI0.PCI1.VGAC.NMAP"
 	},
@@ -233,11 +227,8 @@ static struct model_data model_conf[END_
 		.mt_wled           = "WLED",
 		.mt_lcd_switch     = "\\Q10",
 		.lcd_status        = "\\BKLG",
-		.brightness_up     = "\\Q0E",
-		.brightness_down   = "\\Q0F",
 		.brightness_set    = "SPLV",
 		.brightness_get    = "GPLV",
-		.brightness_status = "\\BLVL",
 		.display_set       = "SDSP",
 		.display_get       = "\\INFB"
 	},
@@ -257,14 +248,10 @@ static struct model_data model_conf[END_
 	{
 		.name              = "L5x",
 		.mt_mled           = "MLED",
-//		.mt_wled           = "WLED",
-//		.wled_status       = "\\WRED",
-/* Present, but not controlled by ACPI */
+/* WLED present, but not controlled by ACPI */
 		.mt_tled           = "TLED",
 		.mt_lcd_switch     = "\\Q0D",
 		.lcd_status        = "\\BAOF",
-		.brightness_up     = "\\Q0C",
-		.brightness_down   = "\\Q0B",
 		.brightness_set    = "SPLV",
 		.brightness_get    = "GPLV",
 		.display_set       = "SDSP",
@@ -294,8 +281,6 @@ static struct model_data model_conf[END_
 		.mt_wled           = "WLED",
 		.mt_lcd_switch     = "\\Q10",
 		.lcd_status        = "\\GP06",
-		.brightness_up     = "\\Q0E",
-		.brightness_down   = "\\Q0F",
 		.brightness_set    = "SPLV",
 		.brightness_get    = "GPLV",
 		.display_set       = "SDSP",
@@ -303,17 +288,26 @@ static struct model_data model_conf[END_
 	},
 
 	{
+		.name              = "P30",
+		.mt_wled           = "WLED",
+		.mt_lcd_switch     = P30_PREFIX "_Q0E",
+		.lcd_status        = "\\BKLT",
+		.brightness_up     = P30_PREFIX "_Q68",
+		.brightness_down   = P30_PREFIX "_Q69",
+		.brightness_get    = "GPLV",
+		.display_set       = "SDSP",
+		.display_get       = "\\DNXT"
+	},
+
+	{
 		.name              = "S1x",
 		.mt_mled           = "MLED",
 		.mled_status       = "\\EMLE",
 		.mt_wled           = "WLED",
 		.mt_lcd_switch     = S1x_PREFIX "Q10" ,
 		.lcd_status        = "\\PNOF",
-		.brightness_up     = S1x_PREFIX "Q0F",
-		.brightness_down   = S1x_PREFIX "Q0E",
 		.brightness_set    = "SPLV",
-		.brightness_get    = "GPLV",
-		.brightness_status = "\\BRIT",
+		.brightness_get    = "GPLV"
 	},
 
 	{
@@ -323,22 +317,17 @@ static struct model_data model_conf[END_
 		.mt_lcd_switch     = S2x_PREFIX "_Q10",
 		.lcd_status        = "\\BKLI",
 		.brightness_up     = S2x_PREFIX "_Q0B",
-		.brightness_down   = S2x_PREFIX "_Q0A",
+		.brightness_down   = S2x_PREFIX "_Q0A"
 	},
 
 	{
 		.name              = "xxN",
 		.mt_mled           = "MLED",
-//		.mt_wled           = "WLED",
-//		.wled_status       = "\\PO33",
-/* Present, but not controlled by ACPI */
+/* WLED present, but not controlled by ACPI */
 		.mt_lcd_switch     = xxN_PREFIX "_Q10",
 		.lcd_status        = "\\BKLT",
-		.brightness_up     = xxN_PREFIX "_Q0F",
-		.brightness_down   = xxN_PREFIX "_Q0E",
 		.brightness_set    = "SPLV",
 		.brightness_get    = "GPLV",
-		.brightness_status = "\\LBTN",
 		.display_set       = "SDSP",
 		.display_get       = "\\ADVG"
 	}
@@ -663,6 +652,23 @@ proc_write_lcd(struct file *file, const 
 }
 
 
+static int read_brightness(struct asus_hotk *hotk)
+{
+	int value;
+	
+	if(hotk->methods->brightness_get) { /* SPLV/GPLV laptop */
+		if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get, 
+				   &value))
+			printk(KERN_WARNING "Asus ACPI: Error reading brightness\n");
+	} else if (hotk->methods->brightness_status) { /* For D1 for example */
+		if (!read_acpi_int(NULL, hotk->methods->brightness_status, 
+				   &value))
+			printk(KERN_WARNING "Asus ACPI: Error reading brightness\n");
+	} else /* No GPLV method */
+		value = hotk->brightness;
+	return value;
+}
+
 /*
  * Change the brightness level
  */
@@ -679,7 +685,7 @@ static void set_brightness(int value, st
 	}
 
 	/* No SPLV method if we are here, act as appropriate */
-	value -= hotk->brightness;
+	value -= read_brightness(hotk);
 	while (value != 0) {
 		status = acpi_evaluate_object(NULL, (value > 0) ? 
 					      hotk->methods->brightness_up : 
@@ -692,23 +698,6 @@ static void set_brightness(int value, st
 	return;
 }
 
-static int read_brightness(struct asus_hotk *hotk)
-{
-	int value;
-	
-	if(hotk->methods->brightness_get) { /* SPLV/GPLV laptop */
-		if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get, 
-				   &value))
-			printk(KERN_WARNING "Asus ACPI: Error reading brightness\n");
-	} else if (hotk->methods->brightness_status) { /* For D1 for example */
-		if (!read_acpi_int(NULL, hotk->methods->brightness_status, 
-				   &value))
-			printk(KERN_WARNING "Asus ACPI: Error reading brightness\n");
-	} else /* No GPLV method */
-		value = hotk->brightness;
-	return value;
-}
-
 static int
 proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
 	      void *data)
@@ -929,12 +918,29 @@ static int __init asus_hotk_get_info(str
 		return -ENODEV;
 	}
 
-	/* For testing purposes */
+	/* This needs to be called for some laptops to init properly */
 	if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
 		printk(KERN_WARNING "  Error calling BSTS\n");
 	else if (bsts_result)
 		printk(KERN_NOTICE "  BSTS called, 0x%02x returned\n", bsts_result);
 
+	/* Samsung P30 has a device with a valid _HID whose INIT does not 
+	 * return anything. Catch this one and any similar here */
+	if (buffer.pointer == NULL) {
+		if (asus_info && /* Samsung P30 */
+		    strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
+			hotk->model = P30;
+			printk(KERN_NOTICE "  Samsung P30 detected, supported\n");
+		} else {
+			hotk->model = M2E;
+			printk(KERN_WARNING "  no string returned by INIT\n");
+			printk(KERN_WARNING "  trying default values, supply "
+			       "the developers with your DSDT\n");
+		}
+		hotk->methods = &model_conf[hotk->model];
+		return AE_OK;
+	}
+	
 	model = (union acpi_object *) buffer.pointer;
 	if (model->type == ACPI_TYPE_STRING) {
 		printk(KERN_NOTICE "  %s model detected, ", model->string.pointer);
@@ -953,12 +959,14 @@ static int __init asus_hotk_get_info(str
 		hotk->model = L8L;
 	else if (strncmp(model->string.pointer, "M2N", 3) == 0 ||
 		 strncmp(model->string.pointer, "M3N", 3) == 0 ||
+		 strncmp(model->string.pointer, "M6N", 3) == 0 ||
 		 strncmp(model->string.pointer, "S1N", 3) == 0 ||
 		 strncmp(model->string.pointer, "S5N", 3) == 0)
 		hotk->model = xxN;
 	else if (strncmp(model->string.pointer, "M1", 2) == 0)
 		hotk->model = M1A;
-	else if (strncmp(model->string.pointer, "M2", 2) == 0)
+	else if (strncmp(model->string.pointer, "M2", 2) == 0 ||
+		 strncmp(model->string.pointer, "L4E", 3) == 0)
 		hotk->model = M2E;
 	else if (strncmp(model->string.pointer, "L2", 2) == 0)
 		hotk->model = L2D;
@@ -994,6 +1002,13 @@ static int __init asus_hotk_get_info(str
 	else if (strncmp(model->string.pointer, "S5N", 3) == 0)
 		hotk->methods->mt_mled = NULL; 
 	/* S5N has no MLED */
+	else if (strncmp(model->string.pointer, "M6N", 3) == 0) {
+		hotk->methods->display_get = NULL; //TODO
+		hotk->methods->lcd_status = "\\_SB.BKLT";
+		hotk->methods->mt_wled = "WLED";
+		hotk->methods->wled_status = "\\_SB.PCI0.SBRG.SG13";
+	/* M6N differs slightly and has a usable WLED */
+	}
 	else if (asus_info) {
 		if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
 			hotk->methods->mled_status = NULL;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/battery.c linux-2.4.27-pre3/drivers/acpi/battery.c
--- linux-2.4.26/drivers/acpi/battery.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/battery.c	2004-05-18 16:54:35.000000000 +0000
@@ -474,14 +474,18 @@ acpi_battery_read_state (
 	else
 		p += sprintf(p, "capacity state:          critical\n");
 
-	if ((bst->state & 0x01) && (bst->state & 0x02))
+	if ((bst->state & 0x01) && (bst->state & 0x02)){
 		p += sprintf(p, "charging state:          charging/discharging\n");
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+					"Battery Charging and Discharging?\n"));
+	}
 	else if (bst->state & 0x01)
 		p += sprintf(p, "charging state:          discharging\n");
 	else if (bst->state & 0x02)
 		p += sprintf(p, "charging state:          charging\n");
-	else
-		p += sprintf(p, "charging state:          unknown\n");
+	else {
+		p += sprintf(p, "charging state:          charged\n");
+	}
 
 	if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN)
 		p += sprintf(p, "present rate:            unknown\n");
@@ -609,6 +613,7 @@ acpi_battery_add_fs (
 			acpi_battery_dir);
 		if (!acpi_device_dir(device))
 			return_VALUE(-ENODEV);
+		acpi_device_dir(device)->owner = THIS_MODULE;
 	}
 
 	/* 'info' [R] */
@@ -621,6 +626,7 @@ acpi_battery_add_fs (
 	else {
 		entry->read_proc = acpi_battery_read_info;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'status' [R] */
@@ -633,6 +639,7 @@ acpi_battery_add_fs (
 	else {
 		entry->read_proc = acpi_battery_read_state;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'alarm' [R/W] */
@@ -646,6 +653,7 @@ acpi_battery_add_fs (
 		entry->read_proc = acpi_battery_read_alarm;
 		entry->write_proc = acpi_battery_write_alarm;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	return_VALUE(0);
@@ -797,6 +805,7 @@ acpi_battery_init (void)
 	acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
 	if (!acpi_battery_dir)
 		return_VALUE(-ENODEV);
+	acpi_battery_dir->owner = THIS_MODULE;
 
 	result = acpi_bus_register_driver(&acpi_battery_driver);
 	if (result < 0) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/bus.c linux-2.4.27-pre3/drivers/acpi/bus.c
--- linux-2.4.26/drivers/acpi/bus.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/bus.c	2004-05-18 16:53:38.000000000 +0000
@@ -1769,15 +1769,23 @@ acpi_bus_scan (
 }
 
 
+struct acpi_device *acpi_fixed_pwr_button;
+struct acpi_device *acpi_fixed_sleep_button;
+
+EXPORT_SYMBOL(acpi_fixed_pwr_button);
+EXPORT_SYMBOL(acpi_fixed_sleep_button);
+
 static int
 acpi_bus_scan_fixed (
 	struct acpi_device	*root)
 {
 	int			result = 0;
-	struct acpi_device	*device = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_bus_scan_fixed");
 
+	acpi_fixed_pwr_button = NULL;
+	acpi_fixed_sleep_button = NULL;
+
 	if (!root)
 		return_VALUE(-ENODEV);
 
@@ -1785,11 +1793,11 @@ acpi_bus_scan_fixed (
 	 * Enumerate all fixed-feature devices.
 	 */
 	if (acpi_fadt.pwr_button == 0)
-		result = acpi_bus_add(&device, acpi_root, 
+		result = acpi_bus_add(&acpi_fixed_pwr_button, acpi_root, 
 			NULL, ACPI_BUS_TYPE_POWER_BUTTON);
 
 	if (acpi_fadt.sleep_button == 0)
-		result = acpi_bus_add(&device, acpi_root, 
+		result = acpi_bus_add(&acpi_fixed_sleep_button, acpi_root, 
 			NULL, ACPI_BUS_TYPE_SLEEP_BUTTON);
 
 	return_VALUE(result);
@@ -1964,8 +1972,10 @@ acpi_bus_init (void)
 	acpi_ec_init();		/* ACPI Embedded Controller */
 #endif
 #ifdef CONFIG_ACPI_PCI
-	acpi_pci_link_init();	/* ACPI PCI Interrupt Link */
-	acpi_pci_root_init();	/* ACPI PCI Root Bridge */
+	if (!acpi_pci_disabled) {
+		acpi_pci_link_init();	/* ACPI PCI Interrupt Link */
+		acpi_pci_root_init();	/* ACPI PCI Root Bridge */
+	}
 #endif
 	/*
 	 * Enumerate devices in the ACPI namespace.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/button.c linux-2.4.27-pre3/drivers/acpi/button.c
--- linux-2.4.26/drivers/acpi/button.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/button.c	2004-05-18 16:54:35.000000000 +0000
@@ -69,6 +69,8 @@ struct acpi_button {
    -------------------------------------------------------------------------- */
 
 static struct proc_dir_entry	*acpi_button_dir;
+extern struct acpi_device 	*acpi_fixed_pwr_button;
+extern struct acpi_device	*acpi_fixed_sleep_button;
 
 static int
 acpi_button_read_info (
@@ -171,10 +173,15 @@ acpi_button_add_fs (
 				acpi_button_dir);
 		break;
 	}
+	
+	if (!entry)
+		return_VALUE(-ENODEV);
+	entry->owner = THIS_MODULE;
 
 	acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
 	if (!acpi_device_dir(device))
 		return_VALUE(-ENODEV);
+	acpi_device_dir(device)->owner = THIS_MODULE;
 
 	/* 'info' [R] */
 	entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
@@ -186,6 +193,7 @@ acpi_button_add_fs (
 	else {
 		entry->read_proc = acpi_button_read_info;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 	
 	if (button->type==ACPI_BUTTON_TYPE_LID){
@@ -199,6 +207,7 @@ acpi_button_add_fs (
 	    else {
 		entry->read_proc = acpi_button_lid_read_state;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	    }
 	}
 
@@ -210,10 +219,28 @@ static int
 acpi_button_remove_fs (
 	struct acpi_device	*device)
 {
+	struct acpi_button	*button = NULL;
+
 	ACPI_FUNCTION_TRACE("acpi_button_remove_fs");
 
+	button = acpi_driver_data(device);
 	if (acpi_device_dir(device)) {
-		remove_proc_entry(acpi_device_bid(device), acpi_button_dir);
+		switch (button->type) {
+			case ACPI_BUTTON_TYPE_POWER:
+			case ACPI_BUTTON_TYPE_POWERF:
+				remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, 
+					acpi_button_dir);
+				break;
+			case ACPI_BUTTON_TYPE_SLEEP:
+			case ACPI_BUTTON_TYPE_SLEEPF:
+				remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, 
+					acpi_button_dir);
+				break;
+			case ACPI_BUTTON_TYPE_LID:
+				remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, 
+					acpi_button_dir);
+				break;
+		}
 		acpi_device_dir(device) = NULL;
 	}
 
@@ -470,6 +497,7 @@ acpi_button_init (void)
 	acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
 	if (!acpi_button_dir)
 		return_VALUE(-ENODEV);
+	acpi_button_dir->owner = THIS_MODULE;
 
 	result = acpi_bus_register_driver(&acpi_button_driver);
 	if (result < 0) {
@@ -486,6 +514,12 @@ acpi_button_exit (void)
 {
 	ACPI_FUNCTION_TRACE("acpi_button_exit");
 
+	if(acpi_fixed_pwr_button) 
+		acpi_button_remove(acpi_fixed_pwr_button, ACPI_BUS_TYPE_POWER_BUTTON);
+
+	if(acpi_fixed_sleep_button)
+		acpi_button_remove(acpi_fixed_sleep_button, ACPI_BUS_TYPE_SLEEP_BUTTON);
+
 	acpi_bus_unregister_driver(&acpi_button_driver);
 
 	remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/fan.c linux-2.4.27-pre3/drivers/acpi/fan.c
--- linux-2.4.26/drivers/acpi/fan.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/fan.c	2004-05-18 16:51:35.000000000 +0000
@@ -151,6 +151,7 @@ acpi_fan_add_fs (
 			acpi_fan_dir);
 		if (!acpi_device_dir(device))
 			return_VALUE(-ENODEV);
+		acpi_device_dir(device)->owner = THIS_MODULE;
 	}
 
 	/* 'status' [R/W] */
@@ -164,6 +165,7 @@ acpi_fan_add_fs (
 		entry->read_proc = acpi_fan_read_state;
 		entry->write_proc = acpi_fan_write_state;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	return_VALUE(0);
@@ -267,6 +269,7 @@ acpi_fan_init (void)
 	acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
 	if (!acpi_fan_dir)
 		return_VALUE(-ENODEV);
+	acpi_fan_dir->owner = THIS_MODULE;
 
 	result = acpi_bus_register_driver(&acpi_fan_driver);
 	if (result < 0) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/pci_irq.c linux-2.4.27-pre3/drivers/acpi/pci_irq.c
--- linux-2.4.26/drivers/acpi/pci_irq.c	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/pci_irq.c	2004-05-18 16:55:20.000000000 +0000
@@ -373,7 +373,7 @@ acpi_pci_irq_enable (
 	if (!irq) {
 		printk(KERN_WARNING PREFIX "No IRQ known for interrupt pin %c of device %s", ('A' + pin), dev->slot_name);
 		/* Interrupt Line values above 0xF are forbidden */
-		if (dev->irq && dev->irq >= 0xF) {
+		if (dev->irq && (dev->irq <= 0xF)) {
 			printk(" - using IRQ %d\n", dev->irq);
 			return_VALUE(dev->irq);
 		}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/pci_link.c linux-2.4.27-pre3/drivers/acpi/pci_link.c
--- linux-2.4.26/drivers/acpi/pci_link.c	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/pci_link.c	2004-05-18 16:55:38.000000000 +0000
@@ -90,6 +90,9 @@ static struct {
                             PCI Link Device Management
    -------------------------------------------------------------------------- */
 
+/*
+ * set context (link) possible list from resource list
+ */
 static acpi_status
 acpi_pci_link_check_possible (
 	struct acpi_resource	*resource,
@@ -128,7 +131,7 @@ acpi_pci_link_check_possible (
 		struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
 		if (!p || !p->number_of_interrupts) {
 			ACPI_DEBUG_PRINT((ACPI_DB_WARN, 
-				"Blank IRQ resource\n"));
+				"Blank EXT IRQ resource\n"));
 			return AE_OK;
 		}
 		for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
@@ -193,8 +196,12 @@ acpi_pci_link_check_current (
 	{
 		struct acpi_resource_irq *p = &resource->data.irq;
 		if (!p || !p->number_of_interrupts) {
-			ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				"Blank IRQ resource\n"));
+			/*
+			 * IRQ descriptors may have no IRQ# bits set,
+			 * particularly those those w/ _STA disabled
+			 */
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				"Blank IRQ resource\n")); 
 			return AE_OK;
 		}
 		*irq = p->interrupts[0];
@@ -204,8 +211,12 @@ acpi_pci_link_check_current (
 	{
 		struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
 		if (!p || !p->number_of_interrupts) {
+			/*
+			 * extended IRQ descriptors must
+			 * return at least 1 IRQ
+			 */
 			ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				"Blank IRQ resource\n"));
+				"Blank EXT IRQ resource\n"));
 			return AE_OK;
 		}
 		*irq = p->interrupts[0];
@@ -219,6 +230,13 @@ acpi_pci_link_check_current (
 	return AE_CTRL_TERMINATE;
 }
 
+/*
+ * Run _CRS and set link->irq.active
+ *
+ * return value:
+ * 0 - success
+ * !0 - failure
+ */
 static int
 acpi_pci_link_get_current (
 	struct acpi_pci_link	*link)
@@ -234,15 +252,19 @@ acpi_pci_link_get_current (
 
 	link->irq.active = 0;
 
-	/* Make sure the link is enabled (no use querying if it isn't). */
-	result = acpi_bus_get_status(link->device);
-	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
-		goto end;
-	}
-	if (!link->device->status.enabled) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
-		return_VALUE(0);
+	/* in practice, status disabled is meaningless, ignore it */
+	if (acpi_strict) {
+		/* Query _STA, set link->device->status */
+		result = acpi_bus_get_status(link->device);
+		if (result) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
+			goto end;
+		}
+
+		if (!link->device->status.enabled) {
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
+			return_VALUE(0);
+		}
 	}
 
 	/* 
@@ -257,18 +279,11 @@ acpi_pci_link_get_current (
 		goto end;
 	}
 
-	if (!irq) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No IRQ resource found\n"));
+	if (acpi_strict && !irq) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_CRS returned 0\n"));
 		result = -ENODEV;
-		goto end;
 	}
 
-	/*
-	 * Note that we don't validate that the current IRQ (_CRS) exists
-	 * within the possible IRQs (_PRS): we blindly assume that whatever
-	 * IRQ a boot-enabled Link device is set to is the correct one.
-	 * (Required to support systems such as the Toshiba 5005-S504.)
-	 */
 	link->irq.active = irq;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
@@ -278,32 +293,6 @@ end:
 }
 
 static int
-acpi_pci_link_try_get_current (
-	struct acpi_pci_link *link,
-	int irq)
-{
-	int result;
-
-	ACPI_FUNCTION_TRACE("acpi_pci_link_try_get_current");
-
-	result = acpi_pci_link_get_current(link);
-	if (result && link->irq.active) {
- 		return_VALUE(result);
- 	}
-
-	if (!link->irq.active) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No active IRQ resource found\n"));
-		printk(KERN_WARNING "_CRS returns NULL! Using IRQ %d for"
-			"device (%s [%s]).\n", irq,
-			acpi_device_name(link->device),
-			acpi_device_bid(link->device));
-		link->irq.active = irq;
-	}
-	
-	return 0;
-}
-
-static int
 acpi_pci_link_set (
 	struct acpi_pci_link	*link,
 	int			irq)
@@ -317,8 +306,7 @@ acpi_pci_link_set (
 	struct acpi_buffer	buffer = {sizeof(resource)+1, &resource};
 	int			i = 0;
 	int			valid = 0;
-	int			resource_type = 0;
-   
+
 	ACPI_FUNCTION_TRACE("acpi_pci_link_set");
 
 	if (!link || !irq)
@@ -341,33 +329,18 @@ acpi_pci_link_set (
 		}
 	}
 
-	resource_type = link->irq.resource_type;
-
-	if (resource_type != ACPI_RSTYPE_IRQ &&
-			resource_type != ACPI_RSTYPE_EXT_IRQ){
-	/* If IRQ<=15, first try with a "normal" IRQ descriptor. If that fails, try with
-	 * an extended one */
-		if (irq <= 15) {
-			resource_type = ACPI_RSTYPE_IRQ;
-		} else {
-			resource_type = ACPI_RSTYPE_EXT_IRQ;
-		}
-	} 
-
-retry_programming:
-   
 	memset(&resource, 0, sizeof(resource));
 
-	/* NOTE: PCI interrupts are always level / active_low / shared. But not all
-	   interrupts > 15 are PCI interrupts. Rely on the ACPI IRQ definition for 
-	   parameters */
-	switch(resource_type) {
+	switch(link->irq.resource_type) {
 	case ACPI_RSTYPE_IRQ:
 		resource.res.id = ACPI_RSTYPE_IRQ;
 		resource.res.length = sizeof(struct acpi_resource);
 		resource.res.data.irq.edge_level = link->irq.edge_level;
 		resource.res.data.irq.active_high_low = link->irq.active_high_low;
-		resource.res.data.irq.shared_exclusive = ACPI_SHARED;
+		if (link->irq.edge_level == ACPI_EDGE_SENSITIVE)
+			resource.res.data.irq.shared_exclusive = ACPI_EXCLUSIVE;
+		else
+			resource.res.data.irq.shared_exclusive = ACPI_SHARED;
 		resource.res.data.irq.number_of_interrupts = 1;
 		resource.res.data.irq.interrupts[0] = irq;
 		break;
@@ -378,55 +351,63 @@ retry_programming:
 		resource.res.data.extended_irq.producer_consumer = ACPI_CONSUMER;
 		resource.res.data.extended_irq.edge_level = link->irq.edge_level;
 		resource.res.data.extended_irq.active_high_low = link->irq.active_high_low;
-		resource.res.data.extended_irq.shared_exclusive = ACPI_SHARED;
+		if (link->irq.edge_level == ACPI_EDGE_SENSITIVE)
+			resource.res.data.irq.shared_exclusive = ACPI_EXCLUSIVE;
+		else
+			resource.res.data.irq.shared_exclusive = ACPI_SHARED;
 		resource.res.data.extended_irq.number_of_interrupts = 1;
 		resource.res.data.extended_irq.interrupts[0] = irq;
 		/* ignore resource_source, it's optional */
 		break;
+	default:
+		printk("ACPI BUG: resource_type %d\n", link->irq.resource_type);
+		return_VALUE(-EINVAL);
 	}
 	resource.end.id = ACPI_RSTYPE_END_TAG;
 
 	/* Attempt to set the resource */
 	status = acpi_set_current_resources(link->handle, &buffer);
-   
 
-	/* if we failed and IRQ <= 15, try again with an extended descriptor */
-	if (ACPI_FAILURE(status) && (resource_type == ACPI_RSTYPE_IRQ)) {
-                resource_type = ACPI_RSTYPE_EXT_IRQ;
-                printk(PREFIX "Retrying with extended IRQ descriptor\n");
-                goto retry_programming;
-	}
-  
 	/* check for total failure */
 	if (ACPI_FAILURE(status)) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n"));
 		return_VALUE(-ENODEV);
 	}
 
-	/* Make sure the device is enabled. */
+	/* Query _STA, set device->status */
 	result = acpi_bus_get_status(link->device);
 	if (result) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
 		return_VALUE(result);
 	}
 	if (!link->device->status.enabled) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n"));
-		return_VALUE(-ENODEV);
+		printk(KERN_WARNING PREFIX
+			"%s [%s] disabled and referenced, BIOS bug.\n",
+			acpi_device_name(link->device),
+			acpi_device_bid(link->device));
 	}
 
-	/* Make sure the active IRQ is the one we requested. */
-	result = acpi_pci_link_try_get_current(link, irq);
+	/* Query _CRS, set link->irq.active */
+	result = acpi_pci_link_get_current(link);
 	if (result) {
 		return_VALUE(result);
 	}
-   
+
+	/*
+	 * Is current setting not what we set?
+	 * set link->irq.active
+	 */
 	if (link->irq.active != irq) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
-			"Attempt to enable at IRQ %d resulted in IRQ %d\n", 
-			irq, link->irq.active));
-		link->irq.active = 0;
-		acpi_ut_evaluate_object (link->handle, "_DIS", 0, NULL);	   
-		return_VALUE(-ENODEV);
+		/*
+		 * policy: when _CRS doesn't return what we just _SRS
+		 * assume _SRS worked and override _CRS value.
+		 */
+		printk(KERN_WARNING PREFIX
+			"%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
+			acpi_device_name(link->device),
+			acpi_device_bid(link->device),
+			link->irq.active, irq);
+		link->irq.active = irq;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active));
@@ -480,7 +461,7 @@ retry_programming:
 #define PIRQ_PENALTY_ISA_USED		(16*16*16*16*16)
 #define PIRQ_PENALTY_ISA_ALWAYS		(16*16*16*16*16*16)
 
-static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
+static int __initdata acpi_irq_penalty[ACPI_MAX_IRQS] = {
 	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ0 timer */
 	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ1 keyboard */
 	PIRQ_PENALTY_ISA_ALWAYS,	/* IRQ2 cascade */
@@ -493,7 +474,7 @@ static int acpi_irq_penalty[ACPI_MAX_IRQ
 	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ9  PCI, often acpi */
 	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ10 PCI */
 	PIRQ_PENALTY_PCI_AVAILABLE,	/* IRQ11 PCI */
-	PIRQ_PENALTY_ISA_TYPICAL,	/* IRQ12 mouse */
+	PIRQ_PENALTY_ISA_USED,	/* IRQ12 mouse */
 	PIRQ_PENALTY_ISA_USED,	/* IRQ13 fpe, sometimes */
 	PIRQ_PENALTY_ISA_USED,	/* IRQ14 ide0 */
 	PIRQ_PENALTY_ISA_USED,	/* IRQ15 ide1 */
@@ -553,10 +534,30 @@ static int acpi_pci_link_allocate(struct
 	if (link->irq.setonboot)
 		return_VALUE(0);
 
+	/*
+	 * search for active IRQ in list of possible IRQs.
+	 */
+	for (i = 0; i < link->irq.possible_count; ++i) {
+		if (link->irq.active == link->irq.possible[i])
+			break;
+	}
+	/*
+	 * forget active IRQ that is not in possible list
+	 */
+	if (i == link->irq.possible_count) {
+		if (acpi_strict)
+			printk(KERN_WARNING PREFIX "_CRS %d not found"
+				" in _PRS\n", link->irq.active);
+		link->irq.active = 0;
+	}
+
+	/*
+	 * if active found, use it; else pick entry from end of possible list.
+	 */
 	if (link->irq.active) {
 		irq = link->irq.active;
 	} else {
-		irq = link->irq.possible[0];
+		irq = link->irq.possible[link->irq.possible_count - 1];
 	}
 
 	if (acpi_irq_balance || !link->irq.active) {
@@ -572,7 +573,8 @@ static int acpi_pci_link_allocate(struct
 
 	/* Attempt to enable the link device at this IRQ. */
 	if (acpi_pci_link_set(link, irq)) {
-		printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS). Aborting ACPI-based IRQ routing. Try pci=noacpi or acpi=off\n",
+		printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS).\n"
+				"Try pci=noacpi or acpi=off\n",
 			acpi_device_name(link->device),
 			acpi_device_bid(link->device));
 		return_VALUE(-ENODEV);
@@ -624,7 +626,7 @@ acpi_pci_link_get_irq (
 		return_VALUE(0);
 
 	if (!link->irq.active) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n"));
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n"));
 		return_VALUE(0);
 	}
 
@@ -670,7 +672,6 @@ acpi_pci_link_add (
 	/* query and set link->irq.active */
 	acpi_pci_link_get_current(link);
 
-//#ifdef CONFIG_ACPI_DEBUG
 	printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
 		acpi_device_bid(device));
 	for (i = 0; i < link->irq.possible_count; i++) {
@@ -681,8 +682,16 @@ acpi_pci_link_add (
 		else
 			printk(" %d", link->irq.possible[i]);
 	}
-	printk(")\n");
-//#endif /* CONFIG_ACPI_DEBUG */
+
+	printk(")");
+
+	if (!found)
+		printk(" *%d", link->irq.active);
+
+	if(!link->device->status.enabled)
+		printk(", disabled.");
+
+	printk("\n");
 
 	/* TBD: Acquire/release lock */
 	list_add_tail(&link->node, &acpi_link.entries);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/pci_root.c linux-2.4.27-pre3/drivers/acpi/pci_root.c
--- linux-2.4.26/drivers/acpi/pci_root.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/pci_root.c	2004-05-18 16:50:59.000000000 +0000
@@ -118,6 +118,7 @@ acpi_pci_root_add (
 {
 	int			result = 0;
 	struct acpi_pci_root	*root = NULL;
+	struct acpi_pci_root	*tmp;
 	acpi_status		status = AE_OK;
 	unsigned long		value = 0;
 	acpi_handle		handle = NULL;
@@ -152,8 +153,6 @@ acpi_pci_root_add (
 	switch (status) {
 	case AE_OK:
 		root->id.segment = (u16) value;
-		printk("_SEG exists! Unsupported. Abort.\n");
-		BUG();
 		break;
 	case AE_NOT_FOUND:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
@@ -187,6 +186,14 @@ acpi_pci_root_add (
 		goto end;
 	}
 
+	/* Some systems have wrong _BBN */
+	list_for_each_entry(tmp, &acpi_pci_roots, node) {
+		if ((tmp->id.segment == root->id.segment)
+				&& (tmp->id.bus == root->id.bus))
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+				"Wrong _BBN value, please reboot and using option 'pci=noacpi'\n"));
+	}
+
 	/*
 	 * Device & Function
 	 * -----------------
@@ -213,7 +220,12 @@ acpi_pci_root_add (
 	 * PCI namespace does not get created until this call is made (and 
 	 * thus the root bridge's pci_dev does not exist).
 	 */
+#ifdef CONFIG_X86
 	root->bus = pcibios_scan_root(root->id.bus);
+#else
+	root->bus = pcibios_scan_root(root->handle,
+				      root->id.segment, root->id.bus);
+#endif
 	if (!root->bus) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
 			"Bus %02x:%02x not present in PCI namespace\n", 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/processor.c linux-2.4.27-pre3/drivers/acpi/processor.c
--- linux-2.4.26/drivers/acpi/processor.c	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/processor.c	2004-05-18 16:53:21.000000000 +0000
@@ -2011,6 +2011,7 @@ acpi_processor_add_fs (
 		if (!acpi_device_dir(device))
 			return_VALUE(-ENODEV);
 	}
+	acpi_device_dir(device)->owner = THIS_MODULE;
 
 	/* 'info' [R] */
 	entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO,
@@ -2022,6 +2023,7 @@ acpi_processor_add_fs (
 	else {
 		entry->read_proc = acpi_processor_read_info;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'power' [R] */
@@ -2034,6 +2036,7 @@ acpi_processor_add_fs (
 	else {
 		entry->read_proc = acpi_processor_read_power;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'performance' [R/W] */
@@ -2047,6 +2050,7 @@ acpi_processor_add_fs (
 		entry->read_proc = acpi_processor_read_performance;
 		entry->write_proc = acpi_processor_write_performance;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'throttling' [R/W] */
@@ -2060,6 +2064,7 @@ acpi_processor_add_fs (
 		entry->read_proc = acpi_processor_read_throttling;
 		entry->write_proc = acpi_processor_write_throttling;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'limit' [R/W] */
@@ -2073,6 +2078,7 @@ acpi_processor_add_fs (
 		entry->read_proc = acpi_processor_read_limit;
 		entry->write_proc = acpi_processor_write_limit;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	return_VALUE(0);
@@ -2349,6 +2355,7 @@ acpi_processor_init (void)
 	acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
 	if (!acpi_processor_dir)
 		return_VALUE(-ENODEV);
+	acpi_processor_dir->owner = THIS_MODULE;
 
 	result = acpi_bus_register_driver(&acpi_processor_driver);
 	if (result < 0) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/tables.c linux-2.4.27-pre3/drivers/acpi/tables.c
--- linux-2.4.26/drivers/acpi/tables.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/tables.c	2004-05-18 16:51:39.000000000 +0000
@@ -58,6 +58,7 @@ static char *acpi_table_signatures[ACPI_
 	[ACPI_SSDT]		= "SSDT",
 	[ACPI_SPMI]		= "SPMI",
 	[ACPI_HPET]		= "HPET",
+	[ACPI_MCFG]		= "MCFG",
 };
 
 static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/thermal.c linux-2.4.27-pre3/drivers/acpi/thermal.c
--- linux-2.4.26/drivers/acpi/thermal.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/thermal.c	2004-05-18 16:53:47.000000000 +0000
@@ -1051,6 +1051,7 @@ acpi_thermal_add_fs (
 			acpi_thermal_dir);
 		if (!acpi_device_dir(device))
 			return_VALUE(-ENODEV);
+		acpi_device_dir(device)->owner = THIS_MODULE;
 	}
 
 	/* 'state' [R] */
@@ -1063,6 +1064,7 @@ acpi_thermal_add_fs (
 	else {
 		entry->read_proc = acpi_thermal_read_state;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'temperature' [R] */
@@ -1075,6 +1077,7 @@ acpi_thermal_add_fs (
 	else {
 		entry->read_proc = acpi_thermal_read_temperature;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'trip_points' [R/W] */
@@ -1088,6 +1091,7 @@ acpi_thermal_add_fs (
 		entry->read_proc = acpi_thermal_read_trip_points;
 		entry->write_proc = acpi_thermal_write_trip_points;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'cooling_mode' [R/W] */
@@ -1101,6 +1105,7 @@ acpi_thermal_add_fs (
 		entry->read_proc = acpi_thermal_read_cooling_mode;
 		entry->write_proc = acpi_thermal_write_cooling_mode;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	/* 'polling_frequency' [R/W] */
@@ -1114,6 +1119,7 @@ acpi_thermal_add_fs (
 		entry->read_proc = acpi_thermal_read_polling;
 		entry->write_proc = acpi_thermal_write_polling;
 		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
 	}
 
 	return_VALUE(0);
@@ -1332,6 +1338,7 @@ acpi_thermal_init (void)
 	acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
 	if (!acpi_thermal_dir)
 		return_VALUE(-ENODEV);
+	acpi_thermal_dir->owner = THIS_MODULE;
 
 	result = acpi_bus_register_driver(&acpi_thermal_driver);
 	if (result < 0) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/toshiba_acpi.c linux-2.4.27-pre3/drivers/acpi/toshiba_acpi.c
--- linux-2.4.26/drivers/acpi/toshiba_acpi.c	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/acpi/toshiba_acpi.c	2004-05-18 16:51:22.000000000 +0000
@@ -503,6 +503,8 @@ add_device(void)
 		proc = create_proc_read_entry(item->name,
 			S_IFREG | S_IRUGO | S_IWUSR,
 			toshiba_proc_dir, (read_proc_t*)dispatch_read, item);
+		if (proc)
+			proc->owner = THIS_MODULE;
 		if (proc && item->write_func)
 			proc->write_proc = (write_proc_t*)dispatch_write;
 	}
@@ -526,6 +528,8 @@ toshiba_acpi_init(void)
 	acpi_status status = AE_OK;
 	u32 hci_result;
 
+	if (acpi_disabled)
+		return -ENODEV;
 	/* simple device detection: look for HCI method */
 	if (is_valid_acpi_path(METHOD_HCI_1))
 		method_hci = METHOD_HCI_1;
@@ -548,6 +552,7 @@ toshiba_acpi_init(void)
 	if (!toshiba_proc_dir) {
 		status = AE_ERROR;
 	} else {
+		toshiba_proc_dir->owner = THIS_MODULE;
 		status = add_device();
 		if (ACPI_FAILURE(status))
 			remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/atm/Config.in linux-2.4.27-pre3/drivers/atm/Config.in
--- linux-2.4.26/drivers/atm/Config.in	2003-08-25 11:44:41.000000000 +0000
+++ linux-2.4.27-pre3/drivers/atm/Config.in	2004-05-18 16:54:48.000000000 +0000
@@ -83,6 +83,7 @@ if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBU
   fi
   if [ "$CONFIG_ATM_FORE200E_PCA" = "y" -o "$CONFIG_ATM_FORE200E_SBA" = "y" ]; \
     then
+    bool '  Defer interrupt work to a tasklet' CONFIG_ATM_FORE200E_USE_TASKLET
     int  '  Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16
     int  '  Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0
     if [ "$CONFIG_ATM_FORE200E_MAYBE" = "y" ]; then
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/atm/fore200e.c linux-2.4.27-pre3/drivers/atm/fore200e.c
--- linux-2.4.26/drivers/atm/fore200e.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-pre3/drivers/atm/fore200e.c	2004-05-18 16:55:24.000000000 +0000
@@ -2,7 +2,7 @@
   $Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $
 
   A FORE Systems 200E-series driver for ATM on Linux.
-  Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2000.
+  Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2003.
 
   Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de).
 
@@ -34,6 +34,8 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
+#include <linux/pci.h>
+#include <linux/module.h>
 #include <linux/atmdev.h>
 #include <linux/sonet.h>
 #include <linux/atm_suni.h>
@@ -46,7 +48,6 @@
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
-#include <linux/pci.h>
 
 #ifdef CONFIG_ATM_FORE200E_SBA
 #include <asm/idprom.h>
@@ -56,25 +57,33 @@
 #include <asm/pgtable.h>
 #endif
 
-#include <linux/module.h>
+#if defined(CONFIG_ATM_FORE200E_USE_TASKLET) /* defer interrupt work to a tasklet */
+#define FORE200E_USE_TASKLET
+#endif
 
-#include "fore200e.h"
-#include "suni.h"
+#if 0 /* enable the debugging code of the buffer supply queues */
+#define FORE200E_BSQ_DEBUG
+#endif
 
-#if 1   /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */
+#if 1 /* ensure correct handling of 52-byte AAL0 SDUs expected by atmdump-like apps */
 #define FORE200E_52BYTE_AAL0_SDU
 #endif
 
-#define FORE200E_VERSION "0.2d"
+#include "fore200e.h"
+#include "suni.h"
 
+#define FORE200E_VERSION "0.3e"
 
 #define FORE200E         "fore200e: "
 
+#if 0 /* override .config */
+#define CONFIG_ATM_FORE200E_DEBUG 1
+#endif
 #if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0)
 #define DPRINTK(level, format, args...)  do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \
-                                                  printk(FORE200E format, ##args); } while(0)
+                                                  printk(FORE200E format, ##args); } while (0)
 #else
-#define DPRINTK(level, format, args...)  while(0)
+#define DPRINTK(level, format, args...)  do {} while (0)
 #endif
 
 
@@ -85,18 +94,28 @@
 
 #define FORE200E_INDEX(virt_addr, type, index)     (&((type *)(virt_addr))[ index ])
 
-#define FORE200E_NEXT_ENTRY(index, modulo)    (index = ++(index) % (modulo))
+#define FORE200E_NEXT_ENTRY(index, modulo)         (index = ++(index) % (modulo))
 
 
 #define MSECS(ms)  (((ms)*HZ/1000)+1)
 
 
+#if 1
+#define ASSERT(expr)     if (!(expr)) { \
+                             printk(FORE200E "assertion failed! %s[%d]: %s\n", \
+			            __FUNCTION__, __LINE__, #expr); \
+                             panic(FORE200E "%s", __FUNCTION__); \
+                         }
+#else
+#define ASSERT(expr)     do {} while (0)
+#endif
+
+
 extern const struct atmdev_ops   fore200e_ops;
 extern const struct fore200e_bus fore200e_bus[];
 
 static struct fore200e* fore200e_boards = NULL;
 
-
 #ifdef MODULE
 MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen");
 MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION);
@@ -225,29 +244,6 @@ fore200e_chunk_free(struct fore200e* for
 }
 
 
-
-#if 0 /* currently unused */
-static int
-fore200e_checkup(struct fore200e* fore200e)
-{
-    u32 hb1, hb2;
-
-    hb1 = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
-    fore200e_spin(10);
-    hb2 = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
-    
-    if (hb2 <= hb1) {
-	printk(FORE200E "device %s heartbeat is not counting upwards, hb1 = %x; hb2 = %x\n",
-	       fore200e->name, hb1, hb2);
-	return -EIO;
-    }
-    printk(FORE200E "device %s heartbeat is ok\n", fore200e->name);
-    
-    return 0;
-}
-#endif 
-
-
 static void
 fore200e_spin(int msecs)
 {
@@ -444,7 +440,6 @@ fore200e_shutdown(struct fore200e* fore2
 }
 
 
-
 #ifdef CONFIG_ATM_FORE200E_PCA
 
 static u32 fore200e_pca_read(volatile u32* addr)
@@ -501,20 +496,16 @@ static int
 fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
 			     int size, int nbr, int alignment)
 {
-#if defined(__sparc_v9__)
     /* returned chunks are page-aligned */
+    chunk->alloc_size = size * nbr;
     chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev,
 					     chunk->alloc_size,
 					     &chunk->dma_addr);
     
-    if (chunk->alloc_addr == NULL || chunk->dma_addr == 0)
+    if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
 	return -ENOMEM;
 
     chunk->align_addr = chunk->alloc_addr;
-#else
-    if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment, FORE200E_DMA_BIDIRECTIONAL) < 0)
-	return -ENOMEM;
-#endif
     
     return 0;
 }
@@ -525,14 +516,10 @@ fore200e_pca_dma_chunk_alloc(struct fore
 static void
 fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
 {
-#if defined(__sparc_v9__)
     pci_free_consistent((struct pci_dev*)fore200e->bus_dev,
 			chunk->alloc_size,
 			chunk->alloc_addr,
 			chunk->dma_addr);
-#else
-    fore200e_chunk_free(fore200e, chunk);
-#endif
 }
 
 
@@ -540,7 +527,15 @@ static int
 fore200e_pca_irq_check(struct fore200e* fore200e)
 {
     /* this is a 1 bit register */
-    return readl(fore200e->regs.pca.psr);
+    int irq_posted = readl(fore200e->regs.pca.psr);
+
+#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG == 2)
+    if (irq_posted && (readl(fore200e->regs.pca.hcr) & PCA200E_HCR_OUTFULL)) {
+	DPRINTK(2,"FIFO OUT full, device %d\n", fore200e->atm_dev->number);
+    }
+#endif
+
+    return irq_posted;
 }
 
 
@@ -574,7 +569,7 @@ fore200e_pca_map(struct fore200e* fore20
 
     DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
 
-    /* gain access to the PCA-200E specific registers  */
+    /* gain access to the PCA specific registers  */
     fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET);
     fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET);
     fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET);
@@ -589,8 +584,6 @@ fore200e_pca_unmap(struct fore200e* fore
 {
     DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name);
 
-    /* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41),
-       this leads to a kernel panic if the module is loaded and unloaded several times */
     if (fore200e->virt_base != NULL)
 	iounmap(fore200e->virt_base);
 }
@@ -600,7 +593,7 @@ static int __init
 fore200e_pca_configure(struct fore200e* fore200e)
 {
     struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev;
-    u8              master_ctrl;
+    u8              master_ctrl, latency;
 
     DPRINTK(2, "device %s being configured\n", fore200e->name);
 
@@ -609,21 +602,29 @@ fore200e_pca_configure(struct fore200e* 
 	return -EIO;
     }
 
-	pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl);
+    pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl);
 
     master_ctrl = master_ctrl
-#if 0
-	| PCA200E_CTRL_DIS_CACHE_RD
-        | PCA200E_CTRL_DIS_WRT_INVAL
-#endif
 #if defined(__BIG_ENDIAN)
 	/* request the PCA board to convert the endianess of slave RAM accesses */
 	| PCA200E_CTRL_CONVERT_ENDIAN
 #endif
+#if 0
+        | PCA200E_CTRL_DIS_CACHE_RD
+        | PCA200E_CTRL_DIS_WRT_INVAL
+        | PCA200E_CTRL_ENA_CONT_REQ_MODE
+        | PCA200E_CTRL_2_CACHE_WRT_INVAL
+#endif
 	| PCA200E_CTRL_LARGE_PCI_BURSTS;
     
     pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl);
 
+    /* raise latency from 32 (default) to 192, as this seems to prevent NIC
+       lockups (under heavy rx loads) due to continuous 'FIFO OUT full' condition.
+       this may impact the performances of other PCI devices on the same bus, though */
+    latency = 192;
+    pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+
     fore200e->state = FORE200E_STATE_CONFIGURE;
     return 0;
 }
@@ -657,11 +658,7 @@ fore200e_pca_detect(const struct fore200
     fore200e->bus       = bus;
     fore200e->bus_dev   = pci_dev;    
     fore200e->irq       = pci_dev->irq;
-    fore200e->phys_base = pci_resource_start (pci_dev, 0);
-
-#if defined(__powerpc__)
-    fore200e->phys_base += KERNELBASE;
-#endif
+    fore200e->phys_base = pci_resource_start(pci_dev, 0);
 
     sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
 
@@ -729,8 +726,6 @@ fore200e_pca_proc_read(struct fore200e* 
 #endif /* CONFIG_ATM_FORE200E_PCA */
 
 
-
-
 #ifdef CONFIG_ATM_FORE200E_SBA
 
 static u32
@@ -792,7 +787,7 @@ fore200e_sba_dma_chunk_alloc(struct fore
 					      chunk->alloc_size,
 					      &chunk->dma_addr);
 
-    if (chunk->alloc_addr == NULL || chunk->dma_addr == 0)
+    if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
 	return -ENOMEM;
 
     chunk->align_addr = chunk->alloc_addr;
@@ -851,8 +846,7 @@ fore200e_sba_map(struct fore200e* fore20
     struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
     unsigned int bursts;
 
-    /* gain access to the SBA-200E specific registers  */
-    
+    /* gain access to the SBA specific registers  */
     fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
     fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
     fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
@@ -873,17 +867,6 @@ fore200e_sba_map(struct fore200e* fore20
     if (sbus_can_dma_64bit(sbus_dev))
 	sbus_set_sbus64(sbus_dev, bursts);
 
-#if 0
-    if (bursts & DMA_BURST16)
-	fore200e->bus->write(SBA200E_BSR_BURST16, fore200e->regs.sba.bsr);
-    else
-    if (bursts & DMA_BURST8)
-       fore200e->bus->write(SBA200E_BSR_BURST8, fore200e->regs.sba.bsr);
-    else
-    if (bursts & DMA_BURST4)
-        fore200e->bus->write(SBA200E_BSR_BURST4, fore200e->regs.sba.bsr);
-#endif
-
     fore200e->state = FORE200E_STATE_MAP;
     return 0;
 }
@@ -928,13 +911,11 @@ fore200e_sba_detect(const struct fore200
     return NULL;
     
   found:
-#if 1
     if (sbus_dev->num_registers != 4) {
 	printk(FORE200E "this %s device has %d instead of 4 registers\n",
 	       bus->model_name, sbus_dev->num_registers);
 	return NULL;
     }
-#endif
 
     fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
     if (fore200e == NULL)
@@ -987,46 +968,143 @@ fore200e_sba_proc_read(struct fore200e* 
 
 
 static void
-fore200e_irq_tx(struct fore200e* fore200e)
+fore200e_tx_irq(struct fore200e* fore200e)
 {
-    struct host_txq_entry* entry;
-    int i;
-    
-    entry = fore200e->host_txq.host_entry;
+    struct host_txq*        txq = &fore200e->host_txq;
+    struct host_txq_entry*  entry;
+    struct atm_vcc*         vcc;
+    struct fore200e_vc_map* vc_map;
 
-    for (i = 0; i < QUEUE_SIZE_TX; i++) {
+    if (fore200e->host_txq.txing == 0)
+	return;
+
+    for (;;) {
+	
+	entry = &txq->host_entry[ txq->tail ];
 
-	if (*entry->status & STATUS_COMPLETE) {
+        if ((*entry->status & STATUS_COMPLETE) == 0) {
+	    break;
+	}
 
-	    DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb);
+	DPRINTK(3, "TX COMPLETED: entry = %p [tail = %d], vc_map = %p, skb = %p\n", 
+		entry, txq->tail, entry->vc_map, entry->skb);
 
-	    /* free copy of misaligned data */
-	    if (entry->data)
-		kfree(entry->data);
+	/* free copy of misaligned data */
+	if (entry->data)
+	    kfree(entry->data);
+	
+	/* remove DMA mapping */
+	fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
+				 FORE200E_DMA_TODEVICE);
 
-	    /* remove DMA mapping */
-	    fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
-				     FORE200E_DMA_TODEVICE);
+	vc_map = entry->vc_map;
 
-	    /* notify tx completion */
-	    if (entry->vcc->pop)
-		entry->vcc->pop(entry->vcc, entry->skb);
-	    else
-		dev_kfree_skb_irq(entry->skb);
+	/* vcc closed since the time the entry was submitted for tx? */
+	if ((vc_map->vcc == NULL) ||
+	    (test_bit(ATM_VF_READY, &vc_map->vcc->flags) == 0)) {
 
-	    /* check error condition */
-	    if (*entry->status & STATUS_ERROR)
-		atomic_inc(&entry->vcc->stats->tx_err);
-	    else
-		atomic_inc(&entry->vcc->stats->tx);
+	    DPRINTK(1, "no ready vcc found for PDU sent on device %d\n",
+		    fore200e->atm_dev->number);
 
-	    *entry->status = STATUS_FREE;
-	    
-	    fore200e->host_txq.txing--;
+	    dev_kfree_skb_any(entry->skb);
+	}
+	else {
+	    ASSERT(vc_map->vcc);
+
+	    /* vcc closed then immediately re-opened? */
+	    if (vc_map->incarn != entry->incarn) {
+
+		/* when a vcc is closed, some PDUs may be still pending in the tx queue.
+		   if the same vcc is immediately re-opened, those pending PDUs must
+		   not be popped after the completion of their emission, as they refer
+		   to the prior incarnation of that vcc. otherwise, vcc->sk->wmem_alloc
+		   would be decremented by the size of the (unrelated) skb, possibly
+		   leading to a negative sk->wmem_alloc count, ultimately freezing the vcc.
+		   we thus bind the tx entry to the current incarnation of the vcc
+		   when the entry is submitted for tx. When the tx later completes,
+		   if the incarnation number of the tx entry does not match the one
+		   of the vcc, then this implies that the vcc has been closed then re-opened.
+		   we thus just drop the skb here. */
+
+		DPRINTK(1, "vcc closed-then-re-opened; dropping PDU sent on device %d\n",
+			fore200e->atm_dev->number);
+
+		dev_kfree_skb_any(entry->skb);
+	    }
+	    else {
+		vcc = vc_map->vcc;
+		ASSERT(vcc);
+
+		/* notify tx completion */
+		if (vcc->pop) {
+		    vcc->pop(vcc, entry->skb);
+		}
+		else {
+		    dev_kfree_skb_any(entry->skb);
+		}
+#if 1
+		/* race fixed by the above incarnation mechanism, but... */
+		if (atomic_read(&vcc->sk->wmem_alloc) < 0) {
+		    atomic_set(&vcc->sk->wmem_alloc, 0);
+		}
+#endif
+		/* check error condition */
+		if (*entry->status & STATUS_ERROR)
+		    atomic_inc(&vcc->stats->tx_err);
+		else
+		    atomic_inc(&vcc->stats->tx);
+	    }
+	}
+
+	*entry->status = STATUS_FREE;
+
+	fore200e->host_txq.txing--;
+
+	FORE200E_NEXT_ENTRY(txq->tail, QUEUE_SIZE_TX);
+    }
+}
+
+
+#ifdef FORE200E_BSQ_DEBUG
+int bsq_audit(int where, struct host_bsq* bsq, int scheme, int magn)
+{
+    struct buffer* buffer;
+    int count = 0;
+
+    buffer = bsq->freebuf;
+    while (buffer) {
+
+	if (buffer->supplied) {
+	    printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld supplied but in free list!\n",
+		   where, scheme, magn, buffer->index);
+	}
+
+	if (buffer->magn != magn) {
+	    printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected magn = %d\n",
+		   where, scheme, magn, buffer->index, buffer->magn);
+	}
+
+	if (buffer->scheme != scheme) {
+	    printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected scheme = %d\n",
+		   where, scheme, magn, buffer->index, buffer->scheme);
+	}
+
+	if ((buffer->index < 0) || (buffer->index >= fore200e_rx_buf_nbr[ scheme ][ magn ])) {
+	    printk(FORE200E "bsq_audit(%d): queue %d.%d, out of range buffer index = %ld !\n",
+		   where, scheme, magn, buffer->index);
 	}
-	entry++;
+
+	count++;
+	buffer = buffer->next;
+    }
+
+    if (count != bsq->freebuf_count) {
+	printk(FORE200E "bsq_audit(%d): queue %d.%d, %d bufs in free list, but freebuf_count = %d\n",
+	       where, scheme, magn, count, bsq->freebuf_count);
     }
+    return 0;
 }
+#endif
 
 
 static void
@@ -1043,28 +1121,42 @@ fore200e_supply(struct fore200e* fore200
 
 	    bsq = &fore200e->host_bsq[ scheme ][ magn ];
 
-	    if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) {
+#ifdef FORE200E_BSQ_DEBUG
+	    bsq_audit(1, bsq, scheme, magn);
+#endif
+	    while (bsq->freebuf_count >= RBD_BLK_SIZE) {
 
-		DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n",
-			scheme, magn, bsq->count);
+		DPRINTK(2, "supplying %d rx buffers to queue %d / %d, freebuf_count = %d\n",
+			RBD_BLK_SIZE, scheme, magn, bsq->freebuf_count);
 
 		entry = &bsq->host_entry[ bsq->head ];
-		
-		FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS);
 
 		for (i = 0; i < RBD_BLK_SIZE; i++) {
 
-		    buffer = &bsq->buffer[ bsq->free ];
-		    
-		    FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]);
+		    /* take the first buffer in the free buffer list */
+		    buffer = bsq->freebuf;
+		    if (!buffer) {
+			printk(FORE200E "no more free bufs in queue %d.%d, but freebuf_count = %d\n",
+			       scheme, magn, bsq->freebuf_count);
+			return;
+		    }
+		    bsq->freebuf = buffer->next;
 		    
+#ifdef FORE200E_BSQ_DEBUG
+		    if (buffer->supplied)
+			printk(FORE200E "queue %d.%d, buffer %lu already supplied\n",
+			       scheme, magn, buffer->index);
+		    buffer->supplied = 1;
+#endif
 		    entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr;
 		    entry->rbd_block->rbd[ i ].handle       = FORE200E_BUF2HDL(buffer);
 		}
 
-		/* increase the number of supplied rx buffers */
-		bsq->count += RBD_BLK_SIZE;
-		
+		FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS);
+
+ 		/* decrease accordingly the number of free rx buffers */
+		bsq->freebuf_count -= RBD_BLK_SIZE;
+
 		*entry->status = STATUS_PENDING;
 		fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr);
 	    }
@@ -1073,33 +1165,9 @@ fore200e_supply(struct fore200e* fore200
 }
 
 
-
-static struct atm_vcc* 
-fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
-{
-    struct sock *s;
-    struct atm_vcc* vcc;
-
-    read_lock(&vcc_sklist_lock);
-    for(s = vcc_sklist; s; s = s->next) {
-	vcc = s->protinfo.af_atm;
-	if (vcc->dev != fore200e->atm_dev)
-		continue;
-	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) {
-            read_unlock(&vcc_sklist_lock);
-	    return vcc;
-	}
-    }
-    read_unlock(&vcc_sklist_lock);
-
-    return NULL;
-}
-
-
-static void
-fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
+static int
+fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rpd)
 {
-    struct atm_vcc*      vcc;
     struct sk_buff*      skb;
     struct buffer*       buffer;
     struct fore200e_vcc* fore200e_vcc;
@@ -1108,15 +1176,10 @@ fore200e_push_rpd(struct fore200e* fore2
     u32                  cell_header = 0;
 #endif
 
-    vcc = fore200e_find_vcc(fore200e, rpd);
-    if (vcc == NULL) {
-	
-	printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n",
-	       fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci);
-	return;
-    }
-
+    ASSERT(vcc);
+    
     fore200e_vcc = FORE200E_VCC(vcc);
+    ASSERT(fore200e_vcc);
 
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) {
@@ -1136,10 +1199,10 @@ fore200e_push_rpd(struct fore200e* fore2
     
     skb = alloc_skb(pdu_len, GFP_ATOMIC);
     if (skb == NULL) {
-	
-	printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
+	DPRINTK(2, "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
+
 	atomic_inc(&vcc->stats->rx_drop);
-	return;
+	return -ENOMEM;
     } 
 
     skb->stamp = xtime;
@@ -1161,13 +1224,14 @@ fore200e_push_rpd(struct fore200e* fore2
 	
 	memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length);
     }
-    
+
     DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize);
     
     if (pdu_len < fore200e_vcc->rx_min_pdu)
 	fore200e_vcc->rx_min_pdu = pdu_len;
     if (pdu_len > fore200e_vcc->rx_max_pdu)
 	fore200e_vcc->rx_max_pdu = pdu_len;
+    fore200e_vcc->rx_pdu++;
 
     /* push PDU */
     if (atm_charge(vcc, skb->truesize) == 0) {
@@ -1175,37 +1239,63 @@ fore200e_push_rpd(struct fore200e* fore2
 	DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n",
 		vcc->itf, vcc->vpi, vcc->vci);
 
-	dev_kfree_skb_irq(skb);
-	return;
+	dev_kfree_skb_any(skb);
+
+	atomic_inc(&vcc->stats->rx_drop);
+	return -ENOMEM;
     }
 
+    ASSERT(atomic_read(&vcc->sk->wmem_alloc) >= 0);
+
     vcc->push(vcc, skb);
     atomic_inc(&vcc->stats->rx);
+
+    ASSERT(atomic_read(&vcc->sk->wmem_alloc) >= 0);
+
+    return 0;
 }
 
 
 static void
 fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd)
 {
-    struct buffer* buffer;
-    int            i;
+    struct host_bsq* bsq;
+    struct buffer*   buffer;
+    int              i;
     
     for (i = 0; i < rpd->nseg; i++) {
 
 	/* rebuild rx buffer address from rsd handle */
 	buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
 
-	/* decrease the number of supplied rx buffers */
-	fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--;
+	bsq = &fore200e->host_bsq[ buffer->scheme ][ buffer->magn ];
+
+#ifdef FORE200E_BSQ_DEBUG
+	bsq_audit(2, bsq, buffer->scheme, buffer->magn);
+
+	if (buffer->supplied == 0)
+	    printk(FORE200E "queue %d.%d, buffer %ld was not supplied\n",
+		   buffer->scheme, buffer->magn, buffer->index);
+	buffer->supplied = 0;
+#endif
+
+	/* re-insert the buffer into the free buffer list */
+	buffer->next = bsq->freebuf;
+	bsq->freebuf = buffer;
+
+	/* then increment the number of free rx buffers */
+	bsq->freebuf_count++;
     }
 }
 
 
 static void
-fore200e_irq_rx(struct fore200e* fore200e)
+fore200e_rx_irq(struct fore200e* fore200e)
 {
-    struct host_rxq*       rxq = &fore200e->host_rxq;
-    struct host_rxq_entry* entry;
+    struct host_rxq*        rxq = &fore200e->host_rxq;
+    struct host_rxq_entry*  entry;
+    struct atm_vcc*         vcc;
+    struct fore200e_vc_map* vc_map;
 
     for (;;) {
 	
@@ -1215,28 +1305,61 @@ fore200e_irq_rx(struct fore200e* fore200
 	if ((*entry->status & STATUS_COMPLETE) == 0)
 	    break;
 
-	FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX);
+	vc_map = FORE200E_VC_MAP(fore200e, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
 
-	if ((*entry->status & STATUS_ERROR) == 0) {
+	if ((vc_map->vcc == NULL) || 
+	    (test_bit(ATM_VF_READY, &vc_map->vcc->flags) == 0)) {
 
-	    fore200e_push_rpd(fore200e, entry->rpd);
+	    DPRINTK(1, "no ready VC found for PDU received on %d.%d.%d\n",
+		    fore200e->atm_dev->number,
+		    entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
 	}
 	else {
-	    printk(FORE200E "damaged PDU on %d.%d.%d\n", 
-		   fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
+	    vcc = vc_map->vcc;
+	    ASSERT(vcc);
+
+	    if ((*entry->status & STATUS_ERROR) == 0) {
+
+		fore200e_push_rpd(fore200e, vcc, entry->rpd);
+	    }
+	    else {
+		DPRINTK(2, "damaged PDU on %d.%d.%d\n", 
+			fore200e->atm_dev->number,
+			entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
+		atomic_inc(&vcc->stats->rx_err);
+	    }
 	}
 
-	fore200e_collect_rpd(fore200e, entry->rpd);
+	FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX);
 
-	fore200e_supply(fore200e);
+	fore200e_collect_rpd(fore200e, entry->rpd);
 
 	/* rewrite the rpd address to ack the received PDU */
 	fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr);
 	*entry->status = STATUS_FREE;
+
+	fore200e_supply(fore200e);
     }
 }
 
 
+#ifndef FORE200E_USE_TASKLET
+static void 
+fore200e_irq(struct fore200e* fore200e)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&fore200e->q_lock, flags);
+    fore200e_rx_irq(fore200e);
+    spin_unlock_irqrestore(&fore200e->q_lock, flags);
+    
+    spin_lock_irqsave(&fore200e->q_lock, flags);
+    fore200e_tx_irq(fore200e);
+    spin_unlock_irqrestore(&fore200e->q_lock, flags);
+}
+#endif
+
+
 static void
 fore200e_interrupt(int irq, void* dev, struct pt_regs* regs)
 {
@@ -1244,57 +1367,65 @@ fore200e_interrupt(int irq, void* dev, s
 
     if (fore200e->bus->irq_check(fore200e) == 0) {
 	
-	DPRINTK(3, "unexpected interrupt on device %c\n", fore200e->name[9]);
+	DPRINTK(3, "interrupt NOT triggered by device %d\n", fore200e->atm_dev->number);
 	return;
     }
-    DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]);
+    DPRINTK(3, "interrupt triggered by device %d\n", fore200e->atm_dev->number);
 
-    tasklet_schedule(&fore200e->tasklet);
+#ifdef FORE200E_USE_TASKLET
+    tasklet_schedule(&fore200e->tx_tasklet);
+    tasklet_schedule(&fore200e->rx_tasklet);
+#else
+    fore200e_irq(fore200e);
+#endif
     
     fore200e->bus->irq_ack(fore200e);
 }
 
 
+#ifdef FORE200E_USE_TASKLET
 static void
-fore200e_tasklet(unsigned long data)
+fore200e_tx_tasklet(unsigned long data)
 {
     struct fore200e* fore200e = (struct fore200e*) data;
+    unsigned long    flags;
 
-    fore200e_irq_rx(fore200e);
-    
-    if (fore200e->host_txq.txing)
-	fore200e_irq_tx(fore200e);
+    DPRINTK(3, "tx tasklet scheduled for device %d\n", fore200e->atm_dev->number);
+
+    spin_lock_irqsave(&fore200e->q_lock, flags);
+    fore200e_tx_irq(fore200e);
+    spin_unlock_irqrestore(&fore200e->q_lock, flags);
 }
 
 
+static void
+fore200e_rx_tasklet(unsigned long data)
+{
+    struct fore200e* fore200e = (struct fore200e*) data;
+    unsigned long    flags;
+
+    DPRINTK(3, "rx tasklet scheduled for device %d\n", fore200e->atm_dev->number);
+
+    spin_lock_irqsave(&fore200e->q_lock, flags);
+    fore200e_rx_irq((struct fore200e*) data);
+    spin_unlock_irqrestore(&fore200e->q_lock, flags);
+}
+#endif
+
 
 static int
 fore200e_select_scheme(struct atm_vcc* vcc)
 {
-    int scheme;
-
-#if 1
-    /* fairly balance VCs over (identical) buffer schemes */
-    scheme =  vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO;
-#else
-    /* bit 7 of VPI magically selects the second buffer scheme */
-    if (vcc->vpi & (1<<7)) {
-	vcc->vpi &= ((1<<7) - 1);    /* reset the magic bit */
-	scheme = BUFFER_SCHEME_TWO;
-    }
-    else {
-	scheme = BUFFER_SCHEME_ONE;
-    }
-#endif
+    /* fairly balance the VCs over (identical) buffer schemes */
+    int scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO;
     
-    DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n",
-	    vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second");
+    DPRINTK(1, "VC %d.%d.%d uses buffer scheme %d\n",
+	    vcc->itf, vcc->vpi, vcc->vci, scheme);
 
     return scheme;
 }
 
 
-
 static int 
 fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu)
 {
@@ -1331,7 +1462,7 @@ fore200e_activate_vcin(struct fore200e* 
 #ifdef FORE200E_52BYTE_AAL0_SDU
 	mtu = 48;
 #endif
-	/* the MTU is unused by the cp, except in the case of AAL0 */
+	/* the MTU is not used by the cp, except in the case of AAL0 */
 	fore200e->bus->write(mtu,                        &entry->cp_entry->cmd.activate_block.mtu);
 	fore200e->bus->write(*(u32*)&vpvc,         (u32*)&entry->cp_entry->cmd.activate_block.vpvc);
 	fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode);
@@ -1346,13 +1477,13 @@ fore200e_activate_vcin(struct fore200e* 
     *entry->status = STATUS_FREE;
 
     if (ok == 0) {
-	printk(FORE200E "unable to %s vpvc %d.%d on device %s\n",
-	       activate ? "open" : "close", vcc->vpi, vcc->vci, fore200e->name);
+	printk(FORE200E "unable to %s VC %d.%d.%d\n",
+	       activate ? "open" : "close", vcc->itf, vcc->vpi, vcc->vci);
 	return -EIO;
     }
 
-    DPRINTK(1, "vpvc %d.%d %sed on device %s\n", vcc->vpi, vcc->vci, 
-	    activate ? "open" : "clos", fore200e->name);
+    DPRINTK(1, "VC %d.%d.%d %sed\n", vcc->itf, vcc->vpi, vcc->vci, 
+	    activate ? "open" : "clos");
 
     return 0;
 }
@@ -1410,7 +1541,7 @@ fore200e_rate_ctrl(struct atm_qos* qos, 
 {
     if (qos->txtp.max_pcr < ATM_OC3_PCR) {
     
-	/* compute the data cells to idle cells ratio from the PCR */
+	/* compute the data cells to idle cells ratio from the tx PCR */
 	rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR;
 	rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells;
     }
@@ -1424,21 +1555,38 @@ fore200e_rate_ctrl(struct atm_qos* qos, 
 static int
 fore200e_open(struct atm_vcc *vcc, short vpi, int vci)
 {
-    struct fore200e*     fore200e = FORE200E_DEV(vcc->dev);
-    struct fore200e_vcc* fore200e_vcc;
-    
-    /* find a free VPI/VCI */
+    struct fore200e*        fore200e = FORE200E_DEV(vcc->dev);
+    struct fore200e_vcc*    fore200e_vcc;
+    struct fore200e_vc_map* vc_map;
+    unsigned long           flags;
+
     fore200e_walk_vccs(vcc, &vpi, &vci);
+	
+    ASSERT((vpi >= 0) && (vpi < 1<<FORE200E_VPI_BITS));
+    ASSERT((vci >= 0) && (vci < 1<<FORE200E_VCI_BITS));
 
-    vcc->vpi = vpi;
-    vcc->vci = vci;
+    spin_lock_irqsave(&fore200e->q_lock, flags);
 
-    /* ressource checking only? */
-    if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
-	return 0;
+    vc_map = FORE200E_VC_MAP(fore200e, vpi, vci);
+    if (vc_map->vcc) {
 
-    set_bit(ATM_VF_ADDR, &vcc->flags);
-    vcc->itf    = vcc->dev->number;
+	spin_unlock_irqrestore(&fore200e->q_lock, flags);
+
+	printk(FORE200E "VC %d.%d.%d already in use\n",
+	       fore200e->atm_dev->number, vpi, vci);
+
+	return -EINVAL;
+    }
+
+    vc_map->vcc = vcc;
+
+    spin_unlock_irqrestore(&fore200e->q_lock, flags);
+
+    fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_ATOMIC);
+    if (fore200e_vcc == NULL) {
+	vc_map->vcc = NULL;
+	return -ENOMEM;
+    }
 
     DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
 	    "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n",
@@ -1448,44 +1596,52 @@ fore200e_open(struct atm_vcc *vcc, short
 	    fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ],
 	    vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu);
     
+    /* pseudo-CBR bandwidth requested? */
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
 	
 	down(&fore200e->rate_sf);
 	if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
 	    up(&fore200e->rate_sf);
+
+	    fore200e_kfree(fore200e_vcc);
+	    vc_map->vcc = NULL;
 	    return -EAGAIN;
 	}
-	/* reserving the pseudo-CBR bandwidth at this point grants us
-	   to reduce the length of the critical section protected
-	   by 'rate_sf'. in counterpart, we have to reset the available
-	   bandwidth if we later encounter an error */
 
+	/* reserve bandwidth */
 	fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
     }
-    
-    fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_KERNEL);
-    if (fore200e_vcc == NULL) {
-	down(&fore200e->rate_sf);
-	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
-	up(&fore200e->rate_sf);
-	return -ENOMEM;
-    }
+
+    vcc->itf = vcc->dev->number;
+    vcc->vpi = vpi;
+    vcc->vci = vci;
+
+    set_bit(ATM_VF_PARTIAL,&vcc->flags);
+    set_bit(ATM_VF_ADDR, &vcc->flags);
 
     FORE200E_VCC(vcc) = fore200e_vcc;
-    
+
     if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) {
-	kfree(fore200e_vcc);
-	down(&fore200e->rate_sf);
+
+	vc_map->vcc = NULL;
+
+	clear_bit(ATM_VF_ADDR, &vcc->flags);
+	clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+
+	FORE200E_VCC(vcc) = NULL;
+
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
-	up(&fore200e->rate_sf);
-	return -EBUSY;
+
+	fore200e_kfree(fore200e_vcc);
+	return -EINVAL;
     }
     
     /* compute rate control parameters */
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
 	
 	fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate);
+	set_bit(ATM_VF_HASQOS, &vcc->flags);
 
 	DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n",
 		vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
@@ -1493,57 +1649,99 @@ fore200e_open(struct atm_vcc *vcc, short
 		fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells);
     }
     
-    fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536;
+    fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = MAX_PDU_SIZE + 1;
     fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0;
-    
+    fore200e_vcc->tx_pdu     = fore200e_vcc->rx_pdu     = 0;
+
+    /* new incarnation of the vcc */
+    vc_map->incarn = ++fore200e->incarn_count;
+
+    /* VC unusable before this flag is set */
     set_bit(ATM_VF_READY, &vcc->flags);
+
     return 0;
 }
 
 
-
 static void
 fore200e_close(struct atm_vcc* vcc)
 {
-    struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
-    
+    struct fore200e*        fore200e = FORE200E_DEV(vcc->dev);
+    struct fore200e_vcc*    fore200e_vcc;
+    struct fore200e_vc_map* vc_map;
+    unsigned long           flags;
+
+    ASSERT(vcc);
+    ASSERT((vcc->vpi >= 0) && (vcc->vpi < 1<<FORE200E_VPI_BITS));
+    ASSERT((vcc->vci >= 0) && (vcc->vci < 1<<FORE200E_VCI_BITS));
+
     DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal));
-    
+
+    clear_bit(ATM_VF_READY, &vcc->flags);
+
     fore200e_activate_vcin(fore200e, 0, vcc, 0);
-    
-    kfree(FORE200E_VCC(vcc));
-	
+
+    spin_lock_irqsave(&fore200e->q_lock, flags);
+
+    vc_map = FORE200E_VC_MAP(fore200e, vcc->vpi, vcc->vci);
+
+    /* the vc is no longer considered as "in use" by fore200e_open() */
+    vc_map->vcc = NULL;
+
+    vcc->itf = vcc->vci = vcc->vpi = 0;
+
+    fore200e_vcc = FORE200E_VCC(vcc);
+    FORE200E_VCC(vcc) = NULL;
+
+    spin_unlock_irqrestore(&fore200e->q_lock, flags);
+
+    /* release reserved bandwidth, if any */
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
+
 	down(&fore200e->rate_sf);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	up(&fore200e->rate_sf);
-    }
 
-    clear_bit(ATM_VF_READY, &vcc->flags);
-}
+	clear_bit(ATM_VF_HASQOS, &vcc->flags);
+    }
 
+    clear_bit(ATM_VF_ADDR, &vcc->flags);
+    clear_bit(ATM_VF_PARTIAL,&vcc->flags);
 
-#if 0
-#define FORE200E_SYNC_SEND    /* wait tx completion before returning */
-#endif
+    ASSERT(fore200e_vcc);
+    fore200e_kfree(fore200e_vcc);
+}
 
 
 static int
 fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
 {
-    struct fore200e*       fore200e     = FORE200E_DEV(vcc->dev);
-    struct fore200e_vcc*   fore200e_vcc = FORE200E_VCC(vcc);
-    struct host_txq*       txq          = &fore200e->host_txq;
-    struct host_txq_entry* entry;
-    struct tpd*            tpd;
-    struct tpd_haddr       tpd_haddr;
-    //unsigned long          flags;
-    int                    retry        = CONFIG_ATM_FORE200E_TX_RETRY;
-    int                    tx_copy      = 0;
-    int                    tx_len       = skb->len;
-    u32*                   cell_header  = NULL;
-    unsigned char*         skb_data;
-    int                    skb_len;
+    struct fore200e*        fore200e     = FORE200E_DEV(vcc->dev);
+    struct fore200e_vcc*    fore200e_vcc = FORE200E_VCC(vcc);
+    struct fore200e_vc_map* vc_map;
+    struct host_txq*        txq          = &fore200e->host_txq;
+    struct host_txq_entry*  entry;
+    struct tpd*             tpd;
+    struct tpd_haddr        tpd_haddr;
+    int                     retry        = CONFIG_ATM_FORE200E_TX_RETRY;
+    int                     tx_copy      = 0;
+    int                     tx_len       = skb->len;
+    u32*                    cell_header  = NULL;
+    unsigned char*          skb_data;
+    int                     skb_len;
+    unsigned char*          data;
+    unsigned long           flags;
+
+    ASSERT(vcc);
+    ASSERT(atomic_read(&vcc->sk->wmem_alloc) >= 0);
+    ASSERT(fore200e);
+    ASSERT(fore200e_vcc);
+
+    if (!test_bit(ATM_VF_READY, &vcc->flags)) {
+	DPRINTK(1, "VC %d.%d.%d not ready for tx\n", vcc->itf, vcc->vpi, vcc->vpi);
+	dev_kfree_skb_any(skb);
+	return -EINVAL;
+    }
 
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) {
@@ -1551,7 +1749,7 @@ fore200e_send(struct atm_vcc *vcc, struc
 	skb_data    = skb->data + 4;    /* skip 4-byte cell header */
 	skb_len     = tx_len = skb->len  - 4;
 
-	DPRINTK(3, "skipping user-supplied cell header 0x%08x", *cell_header);
+	DPRINTK(3, "user-supplied cell header = 0x%08x\n", *cell_header);
     }
     else 
 #endif
@@ -1560,39 +1758,6 @@ fore200e_send(struct atm_vcc *vcc, struc
 	skb_len  = skb->len;
     }
     
-  retry_here:
-    
-    tasklet_disable(&fore200e->tasklet);
-
-    entry = &txq->host_entry[ txq->head ];
-    
-    if (*entry->status != STATUS_FREE) {
-	
-	/* try to free completed tx queue entries */
-	fore200e_irq_tx(fore200e);
-	
-	if (*entry->status != STATUS_FREE) {
-	    
-	    tasklet_enable(&fore200e->tasklet);
-
-	    /* retry once again? */
-	    if(--retry > 0)
-		goto retry_here;
-	    
-	    atomic_inc(&vcc->stats->tx_err);
-	    
-	    printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n",
-		   fore200e->name, fore200e->cp_queues->heartbeat);
-	    if (vcc->pop)
-		vcc->pop(vcc, skb);
-	    else
-		dev_kfree_skb(skb);
-	    return -EIO;
-	}
-    }
-
-    tpd = entry->tpd;
-
     if (((unsigned long)skb_data) & 0x3) {
 
 	DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name);
@@ -1602,43 +1767,87 @@ fore200e_send(struct atm_vcc *vcc, struc
 
     if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) {
 
-	/* this simply NUKES the PCA-200E board */
+	/* this simply NUKES the PCA board */
 	DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name);
 	tx_copy = 1;
 	tx_len  = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD;
     }
     
     if (tx_copy) {
-	
-	entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA);
-	if (entry->data == NULL) {
-	    
-	    tasklet_enable(&fore200e->tasklet);
-	    if (vcc->pop)
+	data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA);
+	if (data == NULL) {
+	    if (vcc->pop) {
 		vcc->pop(vcc, skb);
-	    else
-		dev_kfree_skb(skb);
+	    }
+	    else {
+		dev_kfree_skb_any(skb);
+	    }
 	    return -ENOMEM;
 	}
 
-	memcpy(entry->data, skb_data, skb_len);
+	memcpy(data, skb_data, skb_len);
 	if (skb_len < tx_len)
-	    memset(entry->data + skb_len, 0x00, tx_len - skb_len);
-	
-	tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len, FORE200E_DMA_TODEVICE);
+	    memset(data + skb_len, 0x00, tx_len - skb_len);
     }
     else {
-	entry->data = NULL;
-	tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len, FORE200E_DMA_TODEVICE);
+	data = skb_data;
     }
 
+    vc_map = FORE200E_VC_MAP(fore200e, vcc->vpi, vcc->vci);
+    ASSERT(vc_map->vcc == vcc);
+
+  retry_here:
+    
+    spin_lock_irqsave(&fore200e->q_lock, flags);
+
+    entry = &txq->host_entry[ txq->head ];
+    
+    if ((*entry->status != STATUS_FREE) || (txq->txing >= QUEUE_SIZE_TX - 2)) {
+	
+	/* try to free completed tx queue entries */
+	fore200e_tx_irq(fore200e);
+	
+	if (*entry->status != STATUS_FREE) {
+	    
+	    spin_unlock_irqrestore(&fore200e->q_lock, flags);
+
+	    /* retry once again? */
+	    if(--retry > 0) {
+		schedule();
+		goto retry_here;
+	    }
+	    
+	    atomic_inc(&vcc->stats->tx_err);
+	    
+	    fore200e->tx_sat++;
+	    DPRINTK(2, "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n",
+		   fore200e->name, fore200e->cp_queues->heartbeat);
+	    if (vcc->pop) {
+		vcc->pop(vcc, skb);
+	    }
+	    else {
+		dev_kfree_skb_any(skb);
+	    }
+
+	    if (tx_copy)
+		kfree(data);
+
+	    return -ENOBUFS;
+	}
+    }
+
+    entry->incarn = vc_map->incarn;
+    entry->vc_map = vc_map;
+    entry->skb    = skb;
+    entry->data   = tx_copy ? data : NULL;
+
+    tpd = entry->tpd;
+    tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, data, tx_len, FORE200E_DMA_TODEVICE);
     tpd->tsd[ 0 ].length = tx_len;
 
     FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX);
     txq->txing++;
 
-    tasklet_enable(&fore200e->tasklet);
-
     /* ensure DMA synchronisation */
     fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE);
     
@@ -1650,9 +1859,7 @@ fore200e_send(struct atm_vcc *vcc, struc
 	fore200e_vcc->tx_min_pdu = skb_len;
     if (skb_len > fore200e_vcc->tx_max_pdu)
 	fore200e_vcc->tx_max_pdu = skb_len;
-    
-    entry->vcc = vcc;
-    entry->skb = skb;
+    fore200e_vcc->tx_pdu++;
 
     /* set tx rate control information */
     tpd->rate.data_cells = fore200e_vcc->rate.data_cells;
@@ -1677,49 +1884,16 @@ fore200e_send(struct atm_vcc *vcc, struc
     tpd->spec.length = tx_len;
     tpd->spec.nseg   = 1;
     tpd->spec.aal    = fore200e_atm2fore_aal(vcc->qos.aal);
-#ifdef FORE200E_SYNC_SEND
-    tpd->spec.intr   = 0;
-#else
     tpd->spec.intr   = 1;
-#endif
 
-    tpd_haddr.size  = sizeof(struct tpd) / 32;    /* size is expressed in 32 byte blocks */
+    tpd_haddr.size  = sizeof(struct tpd) / (1<<TPD_HADDR_SHIFT);  /* size is expressed in 32 byte blocks */
     tpd_haddr.pad   = 0;
-    tpd_haddr.haddr = entry->tpd_dma >> 5;        /* shift the address, as we are in a bitfield */
+    tpd_haddr.haddr = entry->tpd_dma >> TPD_HADDR_SHIFT;          /* shift the address, as we are in a bitfield */
 
     *entry->status = STATUS_PENDING;
     fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr);
 
-
-#ifdef FORE200E_SYNC_SEND
-    {
-	int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10);
-
-	fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
-				 FORE200E_DMA_TODEVICE);
-	
-	/* free tmp copy of misaligned data */
-	if (entry->data)
-	    kfree(entry->data);
-
-	/* notify tx completion */
-	if (vcc->pop)
-	    vcc->pop(vcc, skb);
-	else
-	    dev_kfree_skb(skb);
-
-	if (ok == 0) {
-	    printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
-
-	    atomic_inc(&entry->vcc->stats->tx_err);
-	    return -EIO;
-	}
-	atomic_inc(&entry->vcc->stats->tx);
-
-	DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
-
-    }
-#endif
+    spin_unlock_irqrestore(&fore200e->q_lock, flags);
 
     return 0;
 }
@@ -1740,7 +1914,8 @@ fore200e_getstats(struct fore200e* fore2
 	    return -ENOMEM;
     }
     
-    stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats), FORE200E_DMA_FROMDEVICE);
+    stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats,
+					    sizeof(struct stats), FORE200E_DMA_FROMDEVICE);
     
     FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
 
@@ -1769,9 +1944,9 @@ fore200e_getstats(struct fore200e* fore2
 
 
 static int
-fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, int optlen)
+fore200e_getsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen)
 {
-    // struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
+    /* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */
 
     DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n",
 	    vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen);
@@ -1783,7 +1958,7 @@ fore200e_getsockopt (struct atm_vcc* vcc
 static int
 fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen)
 {
-    // struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
+    /* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */
     
     DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n",
 	    vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen);
@@ -1841,6 +2016,8 @@ fore200e_set_oc3(struct fore200e* fore20
     struct oc3_opcode       opcode;
     int                     ok;
 
+    DPRINTK(2, "set OC-3 reg = 0x%02x, value = 0x%02x, mask = 0x%02x\n", reg, value, mask);
+
     FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
 
     opcode.opcode = OPCODE_SET_OC3;
@@ -1896,7 +2073,7 @@ fore200e_setloop(struct fore200e* fore20
     }
 
     error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask);
-    if ( error == 0)
+    if (error == 0)
 	fore200e->loop_mode = loop_mode;
 
     return error;
@@ -1978,6 +2155,11 @@ fore200e_change_qos(struct atm_vcc* vcc,
     struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc);
     struct fore200e*     fore200e     = FORE200E_DEV(vcc->dev);
 
+    if (!test_bit(ATM_VF_READY, &vcc->flags)) {
+	DPRINTK(1, "VC %d.%d.%d not ready for QoS change\n", vcc->itf, vcc->vpi, vcc->vpi);
+	return -EINVAL;
+    }
+
     DPRINTK(2, "change_qos %d.%d.%d, "
 	    "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
 	    "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n"
@@ -1999,6 +2181,7 @@ fore200e_change_qos(struct atm_vcc* vcc,
 
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	fore200e->available_cell_rate -= qos->txtp.max_pcr;
+
 	up(&fore200e->rate_sf);
 	
 	memcpy(&vcc->qos, qos, sizeof(struct atm_qos));
@@ -2007,6 +2190,7 @@ fore200e_change_qos(struct atm_vcc* vcc,
 	fore200e_rate_ctrl(qos, &fore200e_vcc->rate);
 
 	set_bit(ATM_VF_HASQOS, &vcc->flags);
+
 	return 0;
     }
     
@@ -2027,7 +2211,10 @@ fore200e_irq_request(struct fore200e* fo
     printk(FORE200E "IRQ %s reserved for device %s\n",
 	   fore200e_irq_itoa(fore200e->irq), fore200e->name);
 
-    tasklet_init(&fore200e->tasklet, fore200e_tasklet, (unsigned long)fore200e);
+#ifdef FORE200E_USE_TASKLET
+    tasklet_init(&fore200e->tx_tasklet, fore200e_tx_tasklet, (unsigned long)fore200e);
+    tasklet_init(&fore200e->rx_tasklet, fore200e_rx_tasklet, (unsigned long)fore200e);
+#endif
 
     fore200e->state = FORE200E_STATE_IRQ;
     return 0;
@@ -2042,6 +2229,7 @@ fore200e_get_esi(struct fore200e* fore20
 
     if (!prom)
 	return -ENOMEM;
+
     ok = fore200e->bus->prom_read(fore200e, prom);
     if (ok < 0) {
 	fore200e_kfree(prom);
@@ -2089,10 +2277,16 @@ fore200e_alloc_rx_buf(struct fore200e* f
 	    if (buffer == NULL)
 		return -ENOMEM;
 
+	    bsq->freebuf = NULL;
+
 	    for (i = 0; i < nbr; i++) {
 
 		buffer[ i ].scheme = scheme;
 		buffer[ i ].magn   = magn;
+#ifdef FORE200E_BSQ_DEBUG
+		buffer[ i ].index  = i;
+		buffer[ i ].supplied = 0;
+#endif
 
 		/* allocate the receive buffer body */
 		if (fore200e_chunk_alloc(fore200e,
@@ -2105,9 +2299,17 @@ fore200e_alloc_rx_buf(struct fore200e* f
 		    
 		    return -ENOMEM;
 		}
+
+		/* insert the buffer into the free buffer list */
+		buffer[ i ].next = bsq->freebuf;
+		bsq->freebuf = &buffer[ i ];
 	    }
-	    /* set next free buffer index */
-	    bsq->free = 0;
+	    /* all the buffers are free, initially */
+	    bsq->freebuf_count = nbr;
+
+#ifdef FORE200E_BSQ_DEBUG
+	    bsq_audit(3, bsq, scheme, magn);
+#endif
 	}
     }
 
@@ -2164,9 +2366,9 @@ fore200e_init_bs_queue(struct fore200e* 
 		                     FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i);
 		bsq->host_entry[ i ].rbd_block_dma =
 		                     FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i);
-		bsq->host_entry[ i ].cp_entry      = &cp_entry[ i ];
+		bsq->host_entry[ i ].cp_entry = &cp_entry[ i ];
 		
-		*bsq->host_entry[ i ].status   = STATUS_FREE;
+		*bsq->host_entry[ i ].status = STATUS_FREE;
 		
 		fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i), 
 				     &cp_entry[ i ].status_haddr);
@@ -2293,10 +2495,11 @@ fore200e_init_tx_queue(struct fore200e* 
 	   we do not write here the DMA (physical) base address of each tpd into
 	   the related cp resident entry, because the cp relies on this write
 	   operation to detect that a new pdu has been submitted for tx */
-}
+    }
 
-    /* set the head entry of the queue */
+    /* set the head and tail entries of the queue */
     txq->head = 0;
+    txq->tail = 0;
 
     fore200e->state = FORE200E_STATE_INIT_TXQ;
     return 0;
@@ -2315,9 +2518,9 @@ fore200e_init_cmd_queue(struct fore200e*
     /* allocate and align the array of status words */
     if (fore200e->bus->dma_chunk_alloc(fore200e,
 				       &cmdq->status,
-				 sizeof(enum status), 
-				 QUEUE_SIZE_CMD,
-				 fore200e->bus->status_alignment) < 0) {
+				       sizeof(enum status), 
+				       QUEUE_SIZE_CMD,
+				       fore200e->bus->status_alignment) < 0) {
 	return -ENOMEM;
     }
     
@@ -2353,12 +2556,6 @@ fore200e_param_bs_queue(struct fore200e*
 {
     struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ];
 
-    /* dumb value; the firmware doesn't allow us to activate a VC while
-       selecting a buffer scheme with zero-sized rbd pools */
-
-    if (pool_size == 0)
-	pool_size = 64;
-
     fore200e->bus->write(queue_length,                           &bs_spec->queue_length);
     fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size);
     fore200e->bus->write(pool_size,                              &bs_spec->pool_size);
@@ -2375,7 +2572,8 @@ fore200e_initialize(struct fore200e* for
     DPRINTK(2, "device %s being initialized\n", fore200e->name);
 
     init_MUTEX(&fore200e->rate_sf);
-    
+    spin_lock_init(&fore200e->q_lock);
+
     cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET);
 
     /* enable cp to host interrupts */
@@ -2457,7 +2655,7 @@ fore200e_monitor_getc(struct fore200e* f
 static void __init
 fore200e_monitor_puts(struct fore200e* fore200e, char* str)
 {
-    while(*str) {
+    while (*str) {
 
 	/* the i960 monitor doesn't accept any new character if it has something to say */
 	while (fore200e_monitor_getc(fore200e) >= 0);
@@ -2478,6 +2676,11 @@ fore200e_start_fw(struct fore200e* fore2
 
     DPRINTK(2, "device %s firmware being started\n", fore200e->name);
 
+#if defined(__sparc_v9__)
+    /* reported to be required by SBA cards on some sparc64 hosts */
+    fore200e_spin(100);
+#endif
+
     sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset));
 
     fore200e_monitor_puts(fore200e, cmd);
@@ -2508,12 +2711,10 @@ fore200e_load_fw(struct fore200e* fore20
     DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", 
 	    fore200e->name, load_addr, fw_size);
 
-#if 1
     if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) {
 	printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name);
 	return -ENODEV;
     }
-#endif
 
     for (; fw_size--; fw_data++, load_addr++)
 	fore200e->bus->write(le32_to_cpu(*fw_data), load_addr);
@@ -2540,8 +2741,8 @@ fore200e_register(struct fore200e* fore2
     FORE200E_DEV(atm_dev) = fore200e;
     fore200e->atm_dev = atm_dev;
 
-    atm_dev->ci_range.vpi_bits = 8;
-    atm_dev->ci_range.vci_bits = 10;
+    atm_dev->ci_range.vpi_bits = FORE200E_VPI_BITS;
+    atm_dev->ci_range.vci_bits = FORE200E_VCI_BITS;
 
     fore200e->available_cell_rate = ATM_OC3_PCR;
 
@@ -2610,7 +2811,7 @@ fore200e_detect(void)
     struct       fore200e*     fore200e;
     int                        index, link;
 
-    printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n");
+    printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
 
     /* for each configured bus interface */
     for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
@@ -2657,11 +2858,13 @@ fore200e_cleanup(struct fore200e** head)
 
 
 static int
-fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
+fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
 {
-    struct sock *s;
-    struct fore200e* fore200e  = FORE200E_DEV(dev);
-    int              len, left = *pos;
+    struct fore200e*     fore200e  = FORE200E_DEV(dev);
+    struct fore200e_vcc* fore200e_vcc;
+    struct atm_vcc*      vcc;
+    int                  i, len, left = *pos;
+    unsigned long        flags;
 
     if (!left--) {
 
@@ -2694,14 +2897,15 @@ fore200e_proc_read(struct atm_dev *dev,l
 
     if (!left--)
 	return sprintf(page,
-		       "   supplied small bufs (1):\t%d\n"
-		       "   supplied large bufs (1):\t%d\n"
-		       "   supplied small bufs (2):\t%d\n"
-		       "   supplied large bufs (2):\t%d\n",
-		       fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count,
-		       fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count,
-		       fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count,
-		       fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count);
+		       "   free small bufs, scheme 1:\t%d\n"
+		       "   free large bufs, scheme 1:\t%d\n"
+		       "   free small bufs, scheme 2:\t%d\n"
+		       "   free large bufs, scheme 2:\t%d\n",
+		       fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].freebuf_count,
+		       fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].freebuf_count,
+		       fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].freebuf_count,
+		       fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].freebuf_count);
+
     if (!left--) {
 	u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
 
@@ -2740,7 +2944,7 @@ fore200e_proc_read(struct atm_dev *dev,l
 	u32 media_index    = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type));
 	u32 oc3_index;
 
-	if (media_index < 0 || media_index > 4)
+	if ((media_index < 0) || (media_index > 4))
 	    media_index = 5;
 	
 	switch (fore200e->loop_mode) {
@@ -2887,49 +3091,60 @@ fore200e_proc_read(struct atm_dev *dev,l
 		       "     large b1:\t\t\t%10u\n"
 		       "     small b2:\t\t\t%10u\n"
 		       "     large b2:\t\t\t%10u\n"
-		       "     RX PDUs:\t\t\t%10u\n",
+		       "     RX PDUs:\t\t\t%10u\n"
+		       "     TX PDUs:\t\t\t%10lu\n",
 		       fore200e_swap(fore200e->stats->aux.small_b1_failed),
 		       fore200e_swap(fore200e->stats->aux.large_b1_failed),
 		       fore200e_swap(fore200e->stats->aux.small_b2_failed),
 		       fore200e_swap(fore200e->stats->aux.large_b2_failed),
-		       fore200e_swap(fore200e->stats->aux.rpd_alloc_failed));
-    
+		       fore200e_swap(fore200e->stats->aux.rpd_alloc_failed),
+                       fore200e->tx_sat);
+
     if (!left--)
 	return sprintf(page,"\n"
 		       " receive carrier:\t\t\t%s\n",
 		       fore200e->stats->aux.receive_carrier ? "ON" : "OFF!");
     
     if (!left--) {
-	struct atm_vcc *vcc;
-	struct fore200e_vcc* fore200e_vcc;
-	
-	len = sprintf(page,"\n"    
-		      " VCCs:\n  address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
-	
-	read_lock(&vcc_sklist_lock);
-	for (s = vcc_sklist; s; s = s->next) {
-	    vcc = s->protinfo.af_atm;
+	return sprintf(page,"\n"    
+		       " VCCs:\n  address   VPI VCI   AAL "
+		       "TX PDUs   TX min/max size  RX PDUs   RX min/max size\n");
+    }
 
-	    if (vcc->dev != fore200e->atm_dev)
-		    continue;
+
+    for (i = 0; i < NBR_CONNECT; i++) {
+
+	vcc = fore200e->vc_map[i].vcc;
+
+	if (vcc == NULL) 
+	    continue;
+
+	spin_lock_irqsave(&fore200e->q_lock, flags);
+
+	if (vcc && test_bit(ATM_VF_READY, &vcc->flags) && !left--) {
 
 	    fore200e_vcc = FORE200E_VCC(vcc);
-	    
-	    len += sprintf(page + len,
-			   "  %x\t%d.%d:%d\t\t(%d/%d)\t(%d/%d)\n",
+	    ASSERT(fore200e_vcc);
+	
+	    len = sprintf(page,
+			   "  %08x  %03d %05d %1d   %09lu %05d/%05d      %09lu %05d/%05d\n",
 			   (u32)(unsigned long)vcc,
 			   vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
+			   fore200e_vcc->tx_pdu,
 			   fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu,
 			   fore200e_vcc->tx_max_pdu,
+			   fore200e_vcc->rx_pdu,
 			   fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu,
 			   fore200e_vcc->rx_max_pdu
 		);
+
+	    spin_unlock_irqrestore(&fore200e->q_lock, flags);
+	    return len;
 	}
-	read_unlock(&vcc_sklist_lock);
 
-	return len;
+	spin_unlock_irqrestore(&fore200e->q_lock, flags);
     }
-    
+
     return 0;
 }
 
@@ -2966,7 +3181,7 @@ static const struct atmdev_ops fore200e_
 	send:         fore200e_send,
 	change_qos:   fore200e_change_qos,
 	proc_read:    fore200e_proc_read,
-	owner:        THIS_MODULE,
+	owner:        THIS_MODULE
 };
 
 
@@ -3027,4 +3242,6 @@ static const struct fore200e_bus fore200
     {}
 };
 
+#ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
+#endif
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/atm/fore200e.h linux-2.4.27-pre3/drivers/atm/fore200e.h
--- linux-2.4.26/drivers/atm/fore200e.h	2000-12-11 21:22:12.000000000 +0000
+++ linux-2.4.27-pre3/drivers/atm/fore200e.h	2004-05-18 16:50:48.000000000 +0000
@@ -23,19 +23,21 @@
 #define BUFFER_S2_SIZE       SMALL_BUFFER_SIZE    /* size of small buffers, scheme 2 */
 #define BUFFER_L2_SIZE       LARGE_BUFFER_SIZE    /* size of large buffers, scheme 2 */
 
-#define BUFFER_S1_NBR        (RBD_BLK_SIZE * 2)
-#define BUFFER_L1_NBR        (RBD_BLK_SIZE * 2)
+#define BUFFER_S1_NBR        (RBD_BLK_SIZE * 6)
+#define BUFFER_L1_NBR        (RBD_BLK_SIZE * 4)
 
-#define BUFFER_S2_NBR        (RBD_BLK_SIZE * 2)
-#define BUFFER_L2_NBR        (RBD_BLK_SIZE * 2)
+#define BUFFER_S2_NBR        (RBD_BLK_SIZE * 6)
+#define BUFFER_L2_NBR        (RBD_BLK_SIZE * 4)
 
 
 #define QUEUE_SIZE_CMD       16	     /* command queue capacity       */
 #define QUEUE_SIZE_RX	     64	     /* receive queue capacity       */
 #define QUEUE_SIZE_TX	     256     /* transmit queue capacity      */
-#define QUEUE_SIZE_BS        16	     /* buffer supply queue capacity */
+#define QUEUE_SIZE_BS        32	     /* buffer supply queue capacity */
 
-#define NBR_CONNECT          1024    /* number of ATM connections     */
+#define FORE200E_VPI_BITS     0
+#define FORE200E_VCI_BITS    10
+#define NBR_CONNECT          (1 << (FORE200E_VPI_BITS + FORE200E_VCI_BITS)) /* number of connections */
 
 
 #define TSD_FIXED            2
@@ -207,6 +209,7 @@ typedef struct tpd_haddr {
     )
 } tpd_haddr_t;
 
+#define TPD_HADDR_SHIFT 5  /* addr aligned on 32 byte boundary */
 
 /* cp resident transmit queue entry */
 
@@ -517,13 +520,15 @@ typedef struct cp_cmdq_entry {
 /* host resident transmit queue entry */
 
 typedef struct host_txq_entry {
-    struct cp_txq_entry*   cp_entry;    /* addr of cp resident tx queue entry */
-    enum   status*         status;      /* addr of host resident status       */
-    struct tpd*            tpd;         /* addr of transmit PDU descriptor    */
-    u32                    tpd_dma;     /* DMA address of tpd                 */
-    struct sk_buff*        skb;         /* related skb                        */
-    struct atm_vcc*        vcc;         /* related vcc                        */
-    void*                  data;        /* copy of misaligned data            */
+    struct cp_txq_entry*    cp_entry;    /* addr of cp resident tx queue entry       */
+    enum   status*          status;      /* addr of host resident status             */
+    struct tpd*             tpd;         /* addr of transmit PDU descriptor          */
+    u32                     tpd_dma;     /* DMA address of tpd                       */
+    struct sk_buff*         skb;         /* related skb                              */
+    void*                   data;        /* copy of misaligned data                  */
+    unsigned long           incarn;      /* vc_map incarnation when submitted for tx */
+    struct fore200e_vc_map* vc_map;
+
 } host_txq_entry_t;
 
 
@@ -576,6 +581,10 @@ typedef struct buffer {
     enum   buffer_scheme scheme;      /* buffer scheme           */
     enum   buffer_magn   magn;        /* buffer magnitude        */
     struct chunk         data;        /* data buffer             */
+#ifdef FORE200E_BSQ_DEBUG
+    unsigned long        index;       /* buffer # in queue       */
+    int                  supplied;    /* 'buffer supplied' flag  */
+#endif
 } buffer_t;
 
 
@@ -602,6 +611,7 @@ typedef struct host_cmdq {
 typedef struct host_txq {
     struct host_txq_entry host_entry[ QUEUE_SIZE_TX ];    /* host resident tx queue entries         */
     int                   head;                           /* head of tx queue                       */
+    int                   tail;                           /* tail of tx queue                       */
     struct chunk          tpd;                            /* array of tpds                          */
     struct chunk          status;                         /* arry of completion status              */
     int                   txing;                          /* number of pending PDUs in tx queue     */
@@ -626,8 +636,8 @@ typedef struct host_bsq {
     struct chunk          rbd_block;                      /* array of rbds                             */
     struct chunk          status;                         /* array of completion status                */
     struct buffer*        buffer;                         /* array of rx buffers                       */
-    int                   free;                           /* index of first free rx buffer             */
-    volatile int          count;                          /* count of supplied rx buffers              */
+    struct buffer*        freebuf;                        /* list of free rx buffers                   */
+    volatile int          freebuf_count;                  /* count of free rx buffers                  */
 } host_bsq_t;
 
 
@@ -846,6 +856,17 @@ typedef struct fore200e_bus {
 #endif
 
 
+/* vc mapping */
+
+typedef struct fore200e_vc_map {
+    struct atm_vcc* vcc;       /* vcc entry              */
+    unsigned long   incarn;    /* vcc incarnation number */
+} fore200e_vc_map_t;
+
+#define FORE200E_VC_MAP(fore200e, vpi, vci)  \
+        (& (fore200e)->vc_map[ ((vpi) << FORE200E_VCI_BITS) | (vci) ])
+
+
 /* per-device data */
 
 typedef struct fore200e {
@@ -879,20 +900,29 @@ typedef struct fore200e {
     struct stats*              stats;                  /* last snapshot of the stats         */
     
     struct semaphore           rate_sf;                /* protects rate reservation ops      */
-    struct tasklet_struct      tasklet;                /* performs interrupt work            */
+    spinlock_t                 q_lock;                 /* protects queue ops                 */
+#ifdef FORE200E_USE_TASKLET
+    struct tasklet_struct      tx_tasklet;             /* performs tx interrupt work         */
+    struct tasklet_struct      rx_tasklet;             /* performs rx interrupt work         */
+#endif
+    unsigned long              tx_sat;                 /* tx queue saturation count          */
 
+    unsigned long              incarn_count;
+    struct fore200e_vc_map     vc_map[ NBR_CONNECT ];  /* vc mapping                         */
 } fore200e_t;
 
 
 /* per-vcc data */
 
 typedef struct fore200e_vcc {
-    enum buffer_scheme scheme;        /* rx buffer scheme                   */
-    struct tpd_rate    rate;          /* tx rate control data               */
-    int                rx_min_pdu;    /* size of smallest PDU received      */
-    int                rx_max_pdu;    /* size of largest PDU received       */
-    int                tx_min_pdu;    /* size of smallest PDU transmitted   */
-    int                tx_max_pdu;    /* size of largest PDU transmitted    */
+    enum buffer_scheme     scheme;             /* rx buffer scheme                   */
+    struct tpd_rate        rate;               /* tx rate control data               */
+    int                    rx_min_pdu;         /* size of smallest PDU received      */
+    int                    rx_max_pdu;         /* size of largest PDU received       */
+    int                    tx_min_pdu;         /* size of smallest PDU transmitted   */
+    int                    tx_max_pdu;         /* size of largest PDU transmitted    */
+    unsigned long          tx_pdu;             /* nbr of tx pdus                     */
+    unsigned long          rx_pdu;             /* nbr of rx pdus                     */
 } fore200e_vcc_t;
 
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/atm/nicstar.c linux-2.4.27-pre3/drivers/atm/nicstar.c
--- linux-2.4.26/drivers/atm/nicstar.c	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/atm/nicstar.c	2004-05-18 16:51:54.000000000 +0000
@@ -760,7 +760,7 @@ static int __devinit ns_init_card(int i,
    for (j = 0; j < NUM_HB; j++)
    {
       struct sk_buff *hb;
-      hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+      hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
       if (hb == NULL)
       {
          printk("nicstar%d: can't allocate %dth of %d huge buffers.\n",
@@ -780,7 +780,7 @@ static int __devinit ns_init_card(int i,
    for (j = 0; j < NUM_LB; j++)
    {
       struct sk_buff *lb;
-      lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+      lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
       if (lb == NULL)
       {
          printk("nicstar%d: can't allocate %dth of %d large buffers.\n",
@@ -816,7 +816,7 @@ static int __devinit ns_init_card(int i,
    for (j = 0; j < NUM_SB; j++)
    {
       struct sk_buff *sb;
-      sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+      sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
       if (sb == NULL)
       {
          printk("nicstar%d: can't allocate %dth of %d small buffers.\n",
@@ -1318,7 +1318,7 @@ static void ns_irq_handler(int irq, void
              card->index);
       for (i = 0; i < card->sbnr.min; i++)
       {
-         sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC);
+         sb = dev_alloc_skb(NS_SMSKBSIZE);
          if (sb == NULL)
          {
             writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
@@ -1344,7 +1344,7 @@ static void ns_irq_handler(int irq, void
              card->index);
       for (i = 0; i < card->lbnr.min; i++)
       {
-         lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC);
+         lb = dev_alloc_skb(NS_LGSKBSIZE);
          if (lb == NULL)
          {
             writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
@@ -2167,7 +2167,7 @@ static void dequeue_rx(ns_dev *card, ns_
       cell = skb->data;
       for (i = ns_rsqe_cellcount(rsqe); i; i--)
       {
-         if ((sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) == NULL)
+         if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL)
          {
             printk("nicstar%d: Can't allocate buffers for aal0.\n",
                    card->index);
@@ -2399,7 +2399,7 @@ static void dequeue_rx(ns_dev *card, ns_
          if (hb == NULL)		/* No buffers in the queue */
          {
 
-            hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC);
+            hb = dev_alloc_skb(NS_HBUFSIZE);
             if (hb == NULL)
             {
                printk("nicstar%d: Out of huge buffers.\n", card->index);
@@ -2413,7 +2413,7 @@ static void dequeue_rx(ns_dev *card, ns_
             else if (card->hbpool.count < card->hbnr.min)
 	    {
                struct sk_buff *new_hb;
-               if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL)
+               if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
                {
                   skb_queue_tail(&card->hbpool.queue, new_hb);
                   card->hbpool.count++;
@@ -2424,14 +2424,14 @@ static void dequeue_rx(ns_dev *card, ns_
          if (--card->hbpool.count < card->hbnr.min)
          {
             struct sk_buff *new_hb;
-            if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL)
+            if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
             {
                skb_queue_tail(&card->hbpool.queue, new_hb);
                card->hbpool.count++;
             }
             if (card->hbpool.count < card->hbnr.min)
 	    {
-               if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL)
+               if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
                {
                   skb_queue_tail(&card->hbpool.queue, new_hb);
                   card->hbpool.count++;
@@ -2513,7 +2513,7 @@ static void ns_sb_destructor(struct sk_b
 
    do
    {
-      sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+      sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
       if (sb == NULL)
          break;
       skb_queue_tail(&card->sbpool.queue, sb);
@@ -2536,7 +2536,7 @@ static void ns_lb_destructor(struct sk_b
 
    do
    {
-      lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+      lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
       if (lb == NULL)
          break;
       skb_queue_tail(&card->lbpool.queue, lb);
@@ -2555,7 +2555,7 @@ static void ns_hb_destructor(struct sk_b
 
    while (card->hbpool.count < card->hbnr.init)
    {
-      hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+      hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
       if (hb == NULL)
          break;
       skb_queue_tail(&card->hbpool.queue, hb);
@@ -2627,7 +2627,7 @@ static void dequeue_sm_buf(ns_dev *card,
    if (card->sbfqc < card->sbnr.init)
    {
       struct sk_buff *new_sb;
-      if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL)
+      if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
       {
          skb_queue_tail(&card->sbpool.queue, new_sb);
          skb_reserve(new_sb, NS_AAL0_HEADER);
@@ -2639,7 +2639,7 @@ static void dequeue_sm_buf(ns_dev *card,
 #endif /* NS_USE_DESTRUCTORS */
    {
       struct sk_buff *new_sb;
-      if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL)
+      if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
       {
          skb_queue_tail(&card->sbpool.queue, new_sb);
          skb_reserve(new_sb, NS_AAL0_HEADER);
@@ -2660,7 +2660,7 @@ static void dequeue_lg_buf(ns_dev *card,
    if (card->lbfqc < card->lbnr.init)
    {
       struct sk_buff *new_lb;
-      if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL)
+      if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
       {
          skb_queue_tail(&card->lbpool.queue, new_lb);
          skb_reserve(new_lb, NS_SMBUFSIZE);
@@ -2672,7 +2672,7 @@ static void dequeue_lg_buf(ns_dev *card,
 #endif /* NS_USE_DESTRUCTORS */
    {
       struct sk_buff *new_lb;
-      if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL)
+      if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
       {
          skb_queue_tail(&card->lbpool.queue, new_lb);
          skb_reserve(new_lb, NS_SMBUFSIZE);
@@ -2866,7 +2866,7 @@ static int ns_ioctl(struct atm_dev *dev,
 	       {
                   struct sk_buff *sb;
 
-                  sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+                  sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
                   if (sb == NULL)
                      return -ENOMEM;
                   skb_queue_tail(&card->sbpool.queue, sb);
@@ -2880,7 +2880,7 @@ static int ns_ioctl(struct atm_dev *dev,
 	       {
                   struct sk_buff *lb;
 
-                  lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+                  lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
                   if (lb == NULL)
                      return -ENOMEM;
                   skb_queue_tail(&card->lbpool.queue, lb);
@@ -2909,7 +2909,7 @@ static int ns_ioctl(struct atm_dev *dev,
                {
                   struct sk_buff *hb;
 
-                  hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+                  hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
                   if (hb == NULL)
                      return -ENOMEM;
                   ns_grab_int_lock(card, flags);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/Config.in linux-2.4.27-pre3/drivers/block/Config.in
--- linux-2.4.26/drivers/block/Config.in	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-pre3/drivers/block/Config.in	2004-05-18 16:52:04.000000000 +0000
@@ -39,6 +39,7 @@ dep_mbool '       SCSI tape drive suppor
 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
+dep_tristate 'Promise SATA SX8 (carmel) support' CONFIG_BLK_DEV_CARMEL $CONFIG_PCI
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/Makefile linux-2.4.27-pre3/drivers/block/Makefile
--- linux-2.4.26/drivers/block/Makefile	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.27-pre3/drivers/block/Makefile	2004-05-18 16:54:37.000000000 +0000
@@ -31,6 +31,7 @@ obj-$(CONFIG_BLK_CPQ_CISS_DA)  += cciss.
 obj-$(CONFIG_BLK_DEV_DAC960)	+= DAC960.o
 obj-$(CONFIG_BLK_DEV_UMEM)	+= umem.o
 obj-$(CONFIG_BLK_DEV_NBD)	+= nbd.o
+obj-$(CONFIG_BLK_DEV_CARMEL)	+= carmel.o
 
 subdir-$(CONFIG_PARIDE) += paride
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/carmel.c linux-2.4.27-pre3/drivers/block/carmel.c
--- linux-2.4.26/drivers/block/carmel.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/block/carmel.c	2004-05-18 16:52:22.000000000 +0000
@@ -0,0 +1,2083 @@
+/*
+ *  carmel.c: Driver for Promise SATA SX8 looks-like-I2O hardware
+ *
+ *  Copyright 2004 Red Hat, Inc.
+ *
+ *  Author/maintainer:  Jeff Garzik <jgarzik@pobox.com>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file "COPYING" in the main directory of this archive
+ *  for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/compiler.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/hdreg.h>
+#include <linux/fs.h>
+#include <linux/blkpg.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Promise SATA SX8 (carmel) block driver");
+
+#if 0
+#define CARM_DEBUG
+#define CARM_VERBOSE_DEBUG
+#else
+#undef CARM_DEBUG
+#undef CARM_VERBOSE_DEBUG
+#endif
+#undef CARM_NDEBUG
+
+#define DRV_NAME "carmel"
+#define DRV_VERSION "0.8-24.1"
+#define PFX DRV_NAME ": "
+
+#define NEXT_RESP(idx)	((idx + 1) % RMSG_Q_LEN)
+
+/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */
+#define TAG_ENCODE(tag)	(((tag) << 16) | 0xf)
+#define TAG_DECODE(tag)	(((tag) >> 16) & 0x1f)
+#define TAG_VALID(tag)	((((tag) & 0xf) == 0xf) && (TAG_DECODE(tag) < 32))
+
+/* note: prints function name for you */
+#ifdef CARM_DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#ifdef CARM_VERBOSE_DEBUG
+#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define VPRINTK(fmt, args...)
+#endif	/* CARM_VERBOSE_DEBUG */
+#else
+#define DPRINTK(fmt, args...)
+#define VPRINTK(fmt, args...)
+#endif	/* CARM_DEBUG */
+
+#ifdef CARM_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+        if(unlikely(!(expr))) {                                   \
+        printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
+        #expr,__FILE__,__FUNCTION__,__LINE__);          \
+        }
+#endif
+
+/* defines only for the constants which don't work well as enums */
+struct carm_host;
+
+enum {
+	/* adapter-wide limits */
+	CARM_MAX_PORTS		= 8,
+	CARM_SHM_SIZE		= (4096 << 7),
+	CARM_PART_SHIFT		= 5,
+	CARM_MINORS_PER_MAJOR	= (1 << CARM_PART_SHIFT),
+	CARM_MAX_WAIT_Q		= CARM_MAX_PORTS + 1,
+
+	/* command message queue limits */
+	CARM_MAX_REQ		= 64,	       /* max command msgs per host */
+	CARM_MAX_Q		= 1,		   /* one command at a time */
+	CARM_MSG_LOW_WATER	= (CARM_MAX_REQ / 4),	     /* refill mark */
+
+	/* S/G limits, host-wide and per-request */
+	CARM_MAX_REQ_SG		= 32,	     /* max s/g entries per request */
+	CARM_SG_BOUNDARY	= 0xffffUL,	    /* s/g segment boundary */
+	CARM_MAX_HOST_SG	= 600,		/* max s/g entries per host */
+	CARM_SG_LOW_WATER	= (CARM_MAX_HOST_SG / 4),   /* re-fill mark */
+
+	/* hardware registers */
+	CARM_IHQP		= 0x1c,
+	CARM_INT_STAT		= 0x10, /* interrupt status */
+	CARM_INT_MASK		= 0x14, /* interrupt mask */
+	CARM_HMUC		= 0x18, /* host message unit control */
+	RBUF_ADDR_LO		= 0x20, /* response msg DMA buf low 32 bits */
+	RBUF_ADDR_HI		= 0x24, /* response msg DMA buf high 32 bits */
+	RBUF_BYTE_SZ		= 0x28,
+	CARM_RESP_IDX		= 0x2c,
+	CARM_CMS0		= 0x30, /* command message size reg 0 */
+	CARM_LMUC		= 0x48,
+	CARM_HMPHA		= 0x6c,
+	CARM_INITC		= 0xb5,
+
+	/* bits in CARM_INT_{STAT,MASK} */
+	INT_RESERVED		= 0xfffffff0,
+	INT_WATCHDOG		= (1 << 3),	/* watchdog timer */
+	INT_Q_OVERFLOW		= (1 << 2),	/* cmd msg q overflow */
+	INT_Q_AVAILABLE		= (1 << 1),	/* cmd msg q has free space */
+	INT_RESPONSE		= (1 << 0),	/* response msg available */
+	INT_ACK_MASK		= INT_WATCHDOG | INT_Q_OVERFLOW,
+	INT_DEF_MASK		= INT_RESERVED | INT_Q_OVERFLOW |
+				  INT_RESPONSE,
+
+	/* command messages, and related register bits */
+	CARM_HAVE_RESP		= 0x01,
+	CARM_MSG_READ		= 1,
+	CARM_MSG_WRITE		= 2,
+	CARM_MSG_VERIFY		= 3,
+	CARM_MSG_GET_CAPACITY	= 4,
+	CARM_MSG_FLUSH		= 5,
+	CARM_MSG_IOCTL		= 6,
+	CARM_MSG_ARRAY		= 8,
+	CARM_MSG_MISC		= 9,
+	CARM_CME		= (1 << 2),
+	CARM_RME		= (1 << 1),
+	CARM_WZBC		= (1 << 0),
+	CARM_RMI		= (1 << 0),
+	CARM_Q_FULL		= (1 << 3),
+	CARM_MSG_SIZE		= 288,
+	CARM_Q_LEN		= 48,
+
+	/* CARM_MSG_IOCTL messages */
+	CARM_IOC_SCAN_CHAN	= 5,	/* scan channels for devices */
+	CARM_IOC_GET_TCQ	= 13,	/* get tcq/ncq depth */
+	CARM_IOC_SET_TCQ	= 14,	/* set tcq/ncq depth */
+
+	IOC_SCAN_CHAN_NODEV	= 0x1f,
+	IOC_SCAN_CHAN_OFFSET	= 0x40,
+
+	/* CARM_MSG_ARRAY messages */
+	CARM_ARRAY_INFO		= 0,
+
+	ARRAY_NO_EXIST		= (1 << 31),
+
+	/* response messages */
+	RMSG_SZ			= 8,	/* sizeof(struct carm_response) */
+	RMSG_Q_LEN		= 48,	/* resp. msg list length */
+	RMSG_OK			= 1,	/* bit indicating msg was successful */
+					/* length of entire resp. msg buffer */
+	RBUF_LEN		= RMSG_SZ * RMSG_Q_LEN,
+
+	PDC_SHM_SIZE		= (4096 << 7), /* length of entire h/w buffer */
+
+	/* CARM_MSG_MISC messages */
+	MISC_GET_FW_VER		= 2,
+	MISC_ALLOC_MEM		= 3,
+	MISC_SET_TIME		= 5,
+
+	/* MISC_GET_FW_VER feature bits */
+	FW_VER_4PORT		= (1 << 2), /* 1=4 ports, 0=8 ports */
+	FW_VER_NON_RAID		= (1 << 1), /* 1=non-RAID firmware, 0=RAID */
+	FW_VER_ZCR		= (1 << 0), /* zero channel RAID (whatever that is) */
+
+	/* carm_host flags */
+	FL_NON_RAID		= FW_VER_NON_RAID,
+	FL_4PORT		= FW_VER_4PORT,
+	FL_FW_VER_MASK		= (FW_VER_NON_RAID | FW_VER_4PORT),
+	FL_DAC			= (1 << 16),
+	FL_DYN_MAJOR		= (1 << 17),
+};
+
+enum carm_magic_numbers {
+	CARM_MAGIC_HOST		= 0xdeadbeefUL,
+	CARM_MAGIC_PORT		= 0xbedac0edUL,
+};
+
+enum scatter_gather_types {
+	SGT_32BIT		= 0,
+	SGT_64BIT		= 1,
+};
+
+enum host_states {
+	HST_INVALID,		/* invalid state; never used */
+	HST_ALLOC_BUF,		/* setting up master SHM area */
+	HST_ERROR,		/* we never leave here */
+	HST_PORT_SCAN,		/* start dev scan */
+	HST_DEV_SCAN_START,	/* start per-device probe */
+	HST_DEV_SCAN,		/* continue per-device probe */
+	HST_DEV_ACTIVATE,	/* activate devices we found */
+	HST_PROBE_FINISHED,	/* probe is complete */
+	HST_PROBE_START,	/* initiate probe */
+	HST_SYNC_TIME,		/* tell firmware what time it is */
+	HST_GET_FW_VER,		/* get firmware version, adapter port cnt */
+};
+
+#ifdef CARM_DEBUG
+static const char *state_name[] = {
+	"HST_INVALID",
+	"HST_ALLOC_BUF",
+	"HST_ERROR",
+	"HST_PORT_SCAN",
+	"HST_DEV_SCAN_START",
+	"HST_DEV_SCAN",
+	"HST_DEV_ACTIVATE",
+	"HST_PROBE_FINISHED",
+	"HST_PROBE_START",
+	"HST_SYNC_TIME",
+	"HST_GET_FW_VER",
+};
+#endif
+
+struct carm_port {
+	unsigned long			magic;
+	unsigned int			port_no;
+	unsigned int			n_queued;
+	struct carm_host		*host;
+	struct tasklet_struct		tasklet;
+	request_queue_t			q;
+
+	/* attached device characteristics */
+	u64				capacity;
+	char				name[41];
+	u16				dev_geom_head;
+	u16				dev_geom_sect;
+	u16				dev_geom_cyl;
+};
+
+struct carm_request {
+	unsigned int			tag;
+	int				n_elem;
+	unsigned int			msg_type;
+	unsigned int			msg_subtype;
+	unsigned int			msg_bucket;
+	struct request			*rq;
+	struct carm_port		*port;
+	struct request			special_rq;
+	struct scatterlist		sg[CARM_MAX_REQ_SG];
+};
+
+struct carm_host {
+	unsigned long			magic;
+	unsigned long			flags;
+	void				*mmio;
+	void				*shm;
+	dma_addr_t			shm_dma;
+
+	int				major;
+	int				id;
+	char				name[32];
+
+	struct pci_dev			*pdev;
+	unsigned int			state;
+	u32				fw_ver;
+
+	request_queue_t			oob_q;
+	unsigned int			n_oob;
+	struct tasklet_struct		oob_tasklet;
+
+	unsigned int			hw_sg_used;
+
+	unsigned int			resp_idx;
+
+	unsigned int			wait_q_prod;
+	unsigned int			wait_q_cons;
+	request_queue_t			*wait_q[CARM_MAX_WAIT_Q];
+
+	unsigned int			n_msgs;
+	u64				msg_alloc;
+	struct carm_request		req[CARM_MAX_REQ];
+	void				*msg_base;
+	dma_addr_t			msg_dma;
+
+	int				cur_scan_dev;
+	unsigned long			dev_active;
+	unsigned long			dev_present;
+	struct carm_port		port[CARM_MAX_PORTS];
+
+	struct tq_struct		fsm_task;
+
+	struct semaphore		probe_sem;
+
+	struct gendisk			gendisk;
+	struct hd_struct		gendisk_hd[256];
+	int				blk_sizes[256];
+	int				blk_block_sizes[256];
+	int				blk_sect_sizes[256];
+
+	struct list_head		host_list_node;
+};
+
+struct carm_response {
+	u32 ret_handle;
+	u32 status;
+}  __attribute__((packed));
+
+struct carm_msg_sg {
+	u32 start;
+	u32 len;
+}  __attribute__((packed));
+
+struct carm_msg_rw {
+	u8 type;
+	u8 id;
+	u8 sg_count;
+	u8 sg_type;
+	u32 handle;
+	u32 lba;
+	u16 lba_count;
+	u16 lba_high;
+	struct carm_msg_sg sg[32];
+}  __attribute__((packed));
+
+struct carm_msg_allocbuf {
+	u8 type;
+	u8 subtype;
+	u8 n_sg;
+	u8 sg_type;
+	u32 handle;
+	u32 addr;
+	u32 len;
+	u32 evt_pool;
+	u32 n_evt;
+	u32 rbuf_pool;
+	u32 n_rbuf;
+	u32 msg_pool;
+	u32 n_msg;
+	struct carm_msg_sg sg[8];
+}  __attribute__((packed));
+
+struct carm_msg_ioctl {
+	u8 type;
+	u8 subtype;
+	u8 array_id;
+	u8 reserved1;
+	u32 handle;
+	u32 data_addr;
+	u32 reserved2;
+}  __attribute__((packed));
+
+struct carm_msg_sync_time {
+	u8 type;
+	u8 subtype;
+	u16 reserved1;
+	u32 handle;
+	u32 reserved2;
+	u32 timestamp;
+}  __attribute__((packed));
+
+struct carm_msg_get_fw_ver {
+	u8 type;
+	u8 subtype;
+	u16 reserved1;
+	u32 handle;
+	u32 data_addr;
+	u32 reserved2;
+}  __attribute__((packed));
+
+struct carm_fw_ver {
+	u32 version;
+	u8 features;
+	u8 reserved1;
+	u16 reserved2;
+}  __attribute__((packed));
+
+struct carm_array_info {
+	u32 size;
+
+	u16 size_hi;
+	u16 stripe_size;
+
+	u32 mode;
+
+	u16 stripe_blk_sz;
+	u16 reserved1;
+
+	u16 cyl;
+	u16 head;
+
+	u16 sect;
+	u8 array_id;
+	u8 reserved2;
+
+	char name[40];
+
+	u32 array_status;
+
+	/* device list continues beyond this point? */
+}  __attribute__((packed));
+
+static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void carm_remove_one (struct pci_dev *pdev);
+static int carm_bdev_ioctl(struct inode *ino, struct file *fil,
+			   unsigned int cmd, unsigned long arg);
+static request_queue_t *carm_find_queue(kdev_t device);
+static int carm_revalidate_disk(kdev_t dev);
+
+static struct pci_device_id carm_pci_tbl[] = {
+	{ PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{ PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{ }	/* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, carm_pci_tbl);
+
+static struct pci_driver carm_driver = {
+	.name		= DRV_NAME,
+	.id_table	= carm_pci_tbl,
+	.probe		= carm_init_one,
+	.remove		= carm_remove_one,
+};
+
+static struct block_device_operations carm_bd_ops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= carm_bdev_ioctl,
+};
+
+static unsigned int carm_host_id;
+static unsigned long carm_major_alloc;
+
+
+static struct carm_host *carm_from_dev(kdev_t dev, struct carm_port **port_out)
+{
+	struct carm_host *host;
+	struct carm_port *port;
+	request_queue_t *q;
+
+	q = carm_find_queue(dev);
+	if (!q || !q->queuedata) {
+		printk(KERN_ERR PFX "queue not found for major %d minor %d\n",
+			MAJOR(dev), MINOR(dev));
+		return NULL;
+	}
+
+	port = q->queuedata;
+	if (unlikely(port->magic != CARM_MAGIC_PORT)) {
+		printk(KERN_ERR PFX "bad port magic number for major %d minor %d\n",
+			MAJOR(dev), MINOR(dev));
+		return NULL;
+	}
+
+	host = port->host;
+	if (unlikely(host->magic != CARM_MAGIC_HOST)) {
+		printk(KERN_ERR PFX "bad host magic number for major %d minor %d\n",
+			MAJOR(dev), MINOR(dev));
+		return NULL;
+	}
+
+	if (port_out)
+		*port_out = port;
+	return host;
+}
+
+static int carm_bdev_ioctl(struct inode *ino, struct file *fil,
+			   unsigned int cmd, unsigned long arg)
+{
+	void *usermem = (void *) arg;
+	struct carm_port *port = NULL;
+	struct carm_host *host;
+
+	host = carm_from_dev(ino->i_rdev, &port);
+	if (!host)
+		return -EINVAL;
+
+	switch (cmd) {
+	case HDIO_GETGEO: {
+		struct hd_geometry geom;
+
+		if (!usermem)
+			return -EINVAL;
+
+		if (port->dev_geom_cyl) {
+			geom.heads = port->dev_geom_head;
+			geom.sectors = port->dev_geom_sect;
+			geom.cylinders = port->dev_geom_cyl;
+		} else {
+			u32 tmp = ((u32)port->capacity) / (0xff * 0x3f);
+			geom.heads = 0xff;
+			geom.sectors = 0x3f;
+			if (tmp > 65536)
+				geom.cylinders = 0xffff;
+			else
+				geom.cylinders = tmp;
+		}
+		geom.start = host->gendisk_hd[MINOR(ino->i_rdev)].start_sect;
+
+		if (copy_to_user(usermem, &geom, sizeof(geom)))
+			return -EFAULT;
+		return 0;
+	}
+
+	case HDIO_GETGEO_BIG: {
+		struct hd_big_geometry geom;
+
+		if (!usermem)
+			return -EINVAL;
+
+		if (port->dev_geom_cyl) {
+			geom.heads = port->dev_geom_head;
+			geom.sectors = port->dev_geom_sect;
+			geom.cylinders = port->dev_geom_cyl;
+		} else {
+			geom.heads = 0xff;
+			geom.sectors = 0x3f;
+			geom.cylinders = ((u32)port->capacity) / (0xff * 0x3f);
+		}
+		geom.start = host->gendisk_hd[MINOR(ino->i_rdev)].start_sect;
+
+		if (copy_to_user(usermem, &geom, sizeof(geom)))
+			return -EFAULT;
+		return 0;
+	}
+
+	case BLKRRPART:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		return carm_revalidate_disk(ino->i_rdev);
+
+	case BLKGETSIZE:
+	case BLKGETSIZE64:
+	case BLKFLSBUF:
+	case BLKBSZSET:
+	case BLKBSZGET:
+	case BLKROSET:
+	case BLKROGET:
+	case BLKRASET:
+	case BLKRAGET:
+	case BLKPG:
+	case BLKELVGET:
+	case BLKELVSET:
+		return blk_ioctl(ino->i_rdev, cmd, arg);
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static inline unsigned long msecs_to_jiffies(unsigned long msecs)
+{
+	return ((HZ * msecs + 999) / 1000);
+}
+
+static void msleep(unsigned long msecs)
+{
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(msecs_to_jiffies(msecs) + 1);
+}
+
+static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE };
+
+static inline int carm_lookup_bucket(u32 msg_size)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msg_sizes); i++)
+		if (msg_size <= msg_sizes[i])
+			return i;
+	
+	return -ENOENT;
+}
+
+static void carm_init_buckets(void *mmio)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(msg_sizes); i++)
+		writel(msg_sizes[i], mmio + CARM_CMS0 + (4 * i));
+}
+
+static inline void *carm_ref_msg(struct carm_host *host,
+				 unsigned int msg_idx)
+{
+	return host->msg_base + (msg_idx * CARM_MSG_SIZE);
+}
+
+static inline dma_addr_t carm_ref_msg_dma(struct carm_host *host,
+					  unsigned int msg_idx)
+{
+	return host->msg_dma + (msg_idx * CARM_MSG_SIZE);
+}
+
+static int carm_send_msg(struct carm_host *host,
+			 struct carm_request *crq)
+{
+	void *mmio = host->mmio;
+	u32 msg = (u32) carm_ref_msg_dma(host, crq->tag);
+	u32 cm_bucket = crq->msg_bucket;
+	u32 tmp;
+	int rc = 0;
+
+	VPRINTK("ENTER\n");
+
+	tmp = readl(mmio + CARM_HMUC);
+	if (tmp & CARM_Q_FULL) {
+#if 0
+		tmp = readl(mmio + CARM_INT_MASK);
+		tmp |= INT_Q_AVAILABLE;
+		writel(tmp, mmio + CARM_INT_MASK);
+		readl(mmio + CARM_INT_MASK);	/* flush */
+#endif
+		DPRINTK("host msg queue full\n");
+		rc = -EBUSY;
+	} else {
+		writel(msg | (cm_bucket << 1), mmio + CARM_IHQP);
+		readl(mmio + CARM_IHQP);	/* flush */
+	}
+
+	return rc;
+}
+
+static struct carm_request *carm_get_request(struct carm_host *host)
+{
+	unsigned int i;
+
+	/* obey global hardware limit on S/G entries */
+	if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG))
+		return NULL;
+
+	for (i = 0; i < CARM_MAX_Q; i++)
+		if ((host->msg_alloc & (1ULL << i)) == 0) {
+			struct carm_request *crq = &host->req[i];
+			crq->port = NULL;
+			crq->n_elem = 0;
+
+			host->msg_alloc |= (1ULL << i);
+			host->n_msgs++;
+
+			assert(host->n_msgs <= CARM_MAX_REQ);
+			return crq;
+		}
+	
+	DPRINTK("no request available, returning NULL\n");
+	return NULL;
+}
+
+static int carm_put_request(struct carm_host *host, struct carm_request *crq)
+{
+	assert(crq->tag < CARM_MAX_Q);
+
+	if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0))
+		return -EINVAL; /* tried to clear a tag that was not active */
+
+	assert(host->hw_sg_used >= crq->n_elem);
+
+	host->msg_alloc &= ~(1ULL << crq->tag);
+	host->hw_sg_used -= crq->n_elem;
+	host->n_msgs--;
+
+	return 0;
+}
+
+static void carm_insert_special(request_queue_t *q, struct request *rq,
+				void *data, int at_head)
+{
+	unsigned long flags;
+
+	rq->cmd = SPECIAL;
+	rq->special = data;
+	rq->q = NULL;
+	rq->nr_segments = 0;
+	rq->elevator_sequence = 0;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (at_head)
+		list_add(&rq->queue, &q->queue_head);
+	else
+		list_add_tail(&rq->queue, &q->queue_head);
+	q->request_fn(q);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+static struct carm_request *carm_get_special(struct carm_host *host)
+{
+	unsigned long flags;
+	struct carm_request *crq = NULL;
+	int tries = 5000;
+
+	while (tries-- > 0) {
+		spin_lock_irqsave(&io_request_lock, flags);
+		crq = carm_get_request(host);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+
+		if (crq)
+			break;
+		msleep(10);
+	}
+
+	if (!crq)
+		return NULL;
+
+	crq->rq = &crq->special_rq;
+	return crq;
+}
+
+static int carm_array_info (struct carm_host *host, unsigned int array_idx)
+{
+	struct carm_msg_ioctl *ioc;
+	unsigned int idx;
+	u32 msg_data;
+	dma_addr_t msg_dma;
+	struct carm_request *crq;
+	int rc;
+	unsigned long flags;
+
+	crq = carm_get_special(host);
+	if (!crq) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+
+	idx = crq->tag;
+
+	ioc = carm_ref_msg(host, idx);
+	msg_dma = carm_ref_msg_dma(host, idx);
+	msg_data = (u32) (msg_dma + sizeof(struct carm_array_info));
+
+	crq->msg_type = CARM_MSG_ARRAY;
+	crq->msg_subtype = CARM_ARRAY_INFO;
+	rc = carm_lookup_bucket(sizeof(struct carm_msg_ioctl) +
+				sizeof(struct carm_array_info));
+	BUG_ON(rc < 0);
+	crq->msg_bucket = (u32) rc;
+
+	memset(ioc, 0, sizeof(*ioc));
+	ioc->type	= CARM_MSG_ARRAY;
+	ioc->subtype	= CARM_ARRAY_INFO;
+	ioc->array_id	= (u8) array_idx;
+	ioc->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	ioc->data_addr	= cpu_to_le32(msg_data);
+
+	assert(host->state == HST_DEV_SCAN_START ||
+	       host->state == HST_DEV_SCAN);
+
+	DPRINTK("blk_insert_request, tag == %u\n", idx);
+	carm_insert_special(&host->oob_q, crq->rq, crq, 1);
+
+	return 0;
+
+err_out:
+	spin_lock_irqsave(&io_request_lock, flags);
+	host->state = HST_ERROR;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return rc;
+}
+
+typedef unsigned int (*carm_sspc_t)(struct carm_host *, unsigned int, void *);
+
+static int carm_send_special (struct carm_host *host, carm_sspc_t func)
+{
+	struct carm_request *crq;
+	struct carm_msg_ioctl *ioc;
+	void *mem;
+	unsigned int idx, msg_size;
+	int rc;
+
+	crq = carm_get_special(host);
+	if (!crq)
+		return -ENOMEM;
+
+	idx = crq->tag;
+
+	mem = carm_ref_msg(host, idx);
+
+	msg_size = func(host, idx, mem);
+
+	ioc = mem;
+	crq->msg_type = ioc->type;
+	crq->msg_subtype = ioc->subtype;
+	rc = carm_lookup_bucket(msg_size);
+	BUG_ON(rc < 0);
+	crq->msg_bucket = (u32) rc;
+
+	DPRINTK("blk_insert_request, tag == %u\n", idx);
+	carm_insert_special(&host->oob_q, crq->rq, crq, 1);
+
+	return 0;
+}
+
+static unsigned int carm_fill_sync_time(struct carm_host *host,
+					unsigned int idx, void *mem)
+{
+	struct timeval tv;
+	struct carm_msg_sync_time *st = mem;
+
+	do_gettimeofday(&tv);
+
+	memset(st, 0, sizeof(*st));
+	st->type	= CARM_MSG_MISC;
+	st->subtype	= MISC_SET_TIME;
+	st->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	st->timestamp	= cpu_to_le32(tv.tv_sec);
+
+	return sizeof(struct carm_msg_sync_time);
+}
+
+static unsigned int carm_fill_alloc_buf(struct carm_host *host,
+					unsigned int idx, void *mem)
+{
+	struct carm_msg_allocbuf *ab = mem;
+
+	memset(ab, 0, sizeof(*ab));
+	ab->type	= CARM_MSG_MISC;
+	ab->subtype	= MISC_ALLOC_MEM;
+	ab->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	ab->n_sg	= 1;
+	ab->sg_type	= SGT_32BIT;
+	ab->addr	= cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1));
+	ab->len		= cpu_to_le32(PDC_SHM_SIZE >> 1);
+	ab->evt_pool	= cpu_to_le32(host->shm_dma + (16 * 1024));
+	ab->n_evt	= cpu_to_le32(1024);
+	ab->rbuf_pool	= cpu_to_le32(host->shm_dma);
+	ab->n_rbuf	= cpu_to_le32(RMSG_Q_LEN);
+	ab->msg_pool	= cpu_to_le32(host->shm_dma + RBUF_LEN);
+	ab->n_msg	= cpu_to_le32(CARM_Q_LEN);
+	ab->sg[0].start	= cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1));
+	ab->sg[0].len	= cpu_to_le32(65536);
+
+	return sizeof(struct carm_msg_allocbuf);
+}
+
+static unsigned int carm_fill_scan_channels(struct carm_host *host,
+					    unsigned int idx, void *mem)
+{
+	struct carm_msg_ioctl *ioc = mem;
+	u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) +
+			      IOC_SCAN_CHAN_OFFSET);
+
+	memset(ioc, 0, sizeof(*ioc));
+	ioc->type	= CARM_MSG_IOCTL;
+	ioc->subtype	= CARM_IOC_SCAN_CHAN;
+	ioc->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	ioc->data_addr	= cpu_to_le32(msg_data);
+
+	/* fill output data area with "no device" default values */
+	mem += IOC_SCAN_CHAN_OFFSET;
+	memset(mem, IOC_SCAN_CHAN_NODEV, CARM_MAX_PORTS);
+
+	return IOC_SCAN_CHAN_OFFSET + CARM_MAX_PORTS;
+}
+
+static unsigned int carm_fill_get_fw_ver(struct carm_host *host,
+					 unsigned int idx, void *mem)
+{
+	struct carm_msg_get_fw_ver *ioc = mem;
+	u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + sizeof(*ioc));
+
+	memset(ioc, 0, sizeof(*ioc));
+	ioc->type	= CARM_MSG_MISC;
+	ioc->subtype	= MISC_GET_FW_VER;
+	ioc->handle	= cpu_to_le32(TAG_ENCODE(idx));
+	ioc->data_addr	= cpu_to_le32(msg_data);
+
+	return sizeof(struct carm_msg_get_fw_ver) +
+	       sizeof(struct carm_fw_ver);
+}
+
+static void carm_activate_disk(struct carm_host *host,
+			       struct carm_port *port)
+{
+	int minor_start = port->port_no << CARM_PART_SHIFT;
+	int start, end, i;
+
+	host->gendisk_hd[minor_start].nr_sects = port->capacity;
+	host->blk_sizes[minor_start] = port->capacity;
+
+	start = minor_start;
+	end = minor_start + CARM_MINORS_PER_MAJOR;
+	for (i = start; i < end; i++) {
+		invalidate_device(MKDEV(host->major, i), 1);
+		host->gendisk.part[i].start_sect = 0;
+		host->gendisk.part[i].nr_sects = 0;
+		host->blk_block_sizes[i] = 512;
+		host->blk_sect_sizes[i] = 512;
+	}
+
+	grok_partitions(&host->gendisk, port->port_no, 
+			CARM_MINORS_PER_MAJOR,
+			port->capacity);
+}
+
+static int carm_revalidate_disk(kdev_t dev)
+{
+	struct carm_host *host;
+	struct carm_port *port = NULL;
+
+	host = carm_from_dev(dev, &port);
+	if (!host)
+		return -EINVAL;
+
+	carm_activate_disk(host, port);
+
+	return 0;
+}
+
+static inline void complete_buffers(struct buffer_head *bh, int status)
+{
+	struct buffer_head *xbh;
+	
+	while (bh) {
+		xbh = bh->b_reqnext; 
+		bh->b_reqnext = NULL; 
+		blk_finished_io(bh->b_size >> 9);
+		bh->b_end_io(bh, status);
+		bh = xbh;
+	}
+} 
+
+static inline void carm_end_request_queued(struct carm_host *host,
+					   struct carm_request *crq,
+					   int uptodate)
+{
+	struct request *req = crq->rq;
+	int rc;
+
+	complete_buffers(req->bh, uptodate);
+	end_that_request_last(req);
+
+	rc = carm_put_request(host, crq);
+	assert(rc == 0);
+}
+
+static inline void carm_push_q (struct carm_host *host, request_queue_t *q)
+{
+	unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q;
+
+	VPRINTK("STOPPED QUEUE %p\n", q);
+
+	host->wait_q[idx] = q;
+	host->wait_q_prod++;
+	BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */
+}
+
+static inline request_queue_t *carm_pop_q(struct carm_host *host)
+{
+	unsigned int idx;
+
+	if (host->wait_q_prod == host->wait_q_cons)
+		return NULL;
+
+	idx = host->wait_q_cons % CARM_MAX_WAIT_Q;
+	host->wait_q_cons++;
+
+	return host->wait_q[idx];
+}
+
+static inline void carm_round_robin(struct carm_host *host)
+{
+	request_queue_t *q = carm_pop_q(host);
+	if (q) {
+		struct tasklet_struct *tasklet;
+		if (q == &host->oob_q)
+			tasklet = &host->oob_tasklet;
+		else {
+			struct carm_port *port = q->queuedata;
+			tasklet = &port->tasklet;
+		}
+		tasklet_schedule(tasklet);
+		VPRINTK("STARTED QUEUE %p\n", q);
+	}
+}
+
+static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,
+			int is_ok)
+{
+	carm_end_request_queued(host, crq, is_ok);
+	if (CARM_MAX_Q == 1)
+		carm_round_robin(host);
+	else if ((host->n_msgs <= CARM_MSG_LOW_WATER) &&
+		 (host->hw_sg_used <= CARM_SG_LOW_WATER)) {
+		carm_round_robin(host);
+	}
+}
+
+static inline int carm_new_segment(request_queue_t *q, struct request *rq)
+{
+        if (rq->nr_segments < CARM_MAX_REQ_SG) {
+                rq->nr_segments++;
+                return 1;
+        }
+        return 0;
+}
+
+static int carm_back_merge_fn(request_queue_t *q, struct request *rq,
+                             struct buffer_head *bh, int max_segments)
+{
+	if (blk_seg_merge_ok(rq->bhtail, bh))	
+                return 1;
+        return carm_new_segment(q, rq);
+}
+
+static int carm_front_merge_fn(request_queue_t *q, struct request *rq,
+                             struct buffer_head *bh, int max_segments)
+{
+	if (blk_seg_merge_ok(bh, rq->bh))
+                return 1;
+        return carm_new_segment(q, rq);
+}
+
+static int carm_merge_requests_fn(request_queue_t *q, struct request *rq,
+                                 struct request *nxt, int max_segments)
+{
+        int total_segments = rq->nr_segments + nxt->nr_segments;
+
+	if (blk_seg_merge_ok(rq->bhtail, nxt->bh))
+                total_segments--;
+
+        if (total_segments > CARM_MAX_REQ_SG)
+                return 0;
+
+        rq->nr_segments = total_segments;
+        return 1;
+}
+
+static void carm_oob_rq_fn(request_queue_t *q)
+{
+	struct carm_host *host = q->queuedata;
+
+	tasklet_schedule(&host->oob_tasklet);
+}
+
+static void carm_rq_fn(request_queue_t *q)
+{
+	struct carm_port *port = q->queuedata;
+
+	tasklet_schedule(&port->tasklet);
+}
+
+static void carm_oob_tasklet(unsigned long _data)
+{
+	struct carm_host *host = (void *) _data;
+	request_queue_t *q = &host->oob_q;
+	struct carm_request *crq;
+	struct request *rq;
+	int rc, have_work = 1;
+	struct list_head *queue_head = &q->queue_head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (q->plugged || list_empty(queue_head))
+		have_work = 0;
+
+	if (!have_work)
+		goto out;
+
+	while (1) {
+		DPRINTK("get req\n");
+		if (list_empty(queue_head))
+			break;
+
+		rq = blkdev_entry_next_request(queue_head);
+
+		crq = rq->special;
+		assert(crq != NULL);
+		assert(crq->rq == rq);
+
+		crq->n_elem = 0;
+
+		DPRINTK("send req\n");
+		rc = carm_send_msg(host, crq);
+		if (rc) {
+			carm_push_q(host, q);
+			break;		/* call us again later, eventually */
+		} else
+			blkdev_dequeue_request(rq);
+	}
+
+out:
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+static int blk_rq_map_sg(request_queue_t *q, struct request *rq,
+			 struct scatterlist *sg)
+{
+	int n_elem = 0;
+	struct buffer_head *bh = rq->bh;
+	u64 last_phys = ~0ULL;
+
+	while (bh) {
+		if (bh_phys(bh) == last_phys) {
+			sg[n_elem - 1].length += bh->b_size;
+			last_phys += bh->b_size;
+		} else {
+			if (unlikely(n_elem == CARM_MAX_REQ_SG))
+				BUG();
+			sg[n_elem].page = bh->b_page;
+			sg[n_elem].length = bh->b_size;
+			sg[n_elem].offset = bh_offset(bh);
+			last_phys = bh_phys(bh) + bh->b_size;
+			n_elem++;
+		}
+
+		bh = bh->b_reqnext;
+	}
+
+	return n_elem;
+}
+
+static void carm_rw_tasklet(unsigned long _data)
+{
+	struct carm_port *port = (void *) _data;
+	struct carm_host *host = port->host;
+	request_queue_t *q = &port->q;
+	struct carm_msg_rw *msg;
+	struct carm_request *crq;
+	struct request *rq;
+	struct scatterlist *sg;
+	int writing = 0, pci_dir, i, n_elem, rc, have_work = 1;
+	u32 tmp;
+	unsigned int msg_size;
+	unsigned long flags;
+	struct list_head *queue_head = &q->queue_head;
+	unsigned long start_sector;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (q->plugged || list_empty(queue_head))
+		have_work = 0;
+
+	if (!have_work)
+		goto out;
+
+queue_one_request:
+	VPRINTK("get req\n");
+	if (list_empty(queue_head))
+		goto out;
+
+	rq = blkdev_entry_next_request(queue_head);
+
+	crq = carm_get_request(host);
+	if (!crq) {
+		carm_push_q(host, q);
+		goto out;	/* call us again later, eventually */
+	}
+	crq->rq = rq;
+
+	if (rq_data_dir(rq) == WRITE) {
+		writing = 1;
+		pci_dir = PCI_DMA_TODEVICE;
+	} else {
+		pci_dir = PCI_DMA_FROMDEVICE;
+	}
+
+	/* get scatterlist from block layer */
+	sg = &crq->sg[0];
+	n_elem = blk_rq_map_sg(q, rq, sg);
+	if (n_elem <= 0) {
+		carm_end_rq(host, crq, 0);
+		goto out;	/* request with no s/g entries? */
+	}
+
+	/* map scatterlist to PCI bus addresses */
+	n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir);
+	if (n_elem <= 0) {
+		carm_end_rq(host, crq, 0);
+		goto out;	/* request with no s/g entries? */
+	}
+	crq->n_elem = n_elem;
+	crq->port = port;
+	host->hw_sg_used += n_elem;
+
+	/*
+	 * build read/write message
+	 */
+
+	VPRINTK("build msg\n");
+	msg = (struct carm_msg_rw *) carm_ref_msg(host, crq->tag);
+
+	if (writing) {
+		msg->type = CARM_MSG_WRITE;
+		crq->msg_type = CARM_MSG_WRITE;
+	} else {
+		msg->type = CARM_MSG_READ;
+		crq->msg_type = CARM_MSG_READ;
+	}
+
+	start_sector = rq->sector;
+	start_sector += host->gendisk_hd[MINOR(rq->rq_dev)].start_sect;
+
+	msg->id		= port->port_no;
+	msg->sg_count	= n_elem;
+	msg->sg_type	= SGT_32BIT;
+	msg->handle	= cpu_to_le32(TAG_ENCODE(crq->tag));
+	msg->lba	= cpu_to_le32(start_sector & 0xffffffff);
+	tmp		= (start_sector >> 16) >> 16;
+	msg->lba_high	= cpu_to_le16( (u16) tmp );
+	msg->lba_count	= cpu_to_le16(rq->nr_sectors);
+
+	msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg);
+	for (i = 0; i < n_elem; i++) {
+		struct carm_msg_sg *carm_sg = &msg->sg[i];
+		carm_sg->start = cpu_to_le32(sg_dma_address(&crq->sg[i]));
+		carm_sg->len = cpu_to_le32(sg_dma_len(&crq->sg[i]));
+		msg_size += sizeof(struct carm_msg_sg);
+	}
+
+	rc = carm_lookup_bucket(msg_size);
+	BUG_ON(rc < 0);
+	crq->msg_bucket = (u32) rc;
+
+	/*
+	 * queue read/write message to hardware
+	 */
+
+	VPRINTK("send msg, tag == %u\n", crq->tag);
+	rc = carm_send_msg(host, crq);
+	if (rc) {
+		carm_put_request(host, crq);
+		carm_push_q(host, q);
+		goto out;	/* call us again later, eventually */
+	} else
+		blkdev_dequeue_request(rq);
+
+	goto queue_one_request;
+
+out:
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+static void carm_handle_array_info(struct carm_host *host,
+				   struct carm_request *crq, u8 *mem,
+				   int is_ok)
+{
+	struct carm_port *port;
+	u8 *msg_data = mem + sizeof(struct carm_array_info);
+	struct carm_array_info *desc = (struct carm_array_info *) msg_data;
+	u64 lo, hi;
+	int cur_port;
+	size_t slen;
+
+	DPRINTK("ENTER\n");
+
+	carm_end_rq(host, crq, is_ok);
+
+	if (!is_ok)
+		goto out;
+	if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST)
+		goto out;
+
+	cur_port = host->cur_scan_dev;
+
+	/* should never occur */
+	if ((cur_port < 0) || (cur_port >= CARM_MAX_PORTS)) {
+		printk(KERN_ERR PFX "BUG: cur_scan_dev==%d, array_id==%d\n",
+		       cur_port, (int) desc->array_id);
+		goto out;
+	}
+
+	port = &host->port[cur_port];
+
+	lo = (u64) le32_to_cpu(desc->size);
+	hi = (u64) le32_to_cpu(desc->size_hi);
+
+	port->capacity = lo | (hi << 32);
+	port->dev_geom_head = le16_to_cpu(desc->head);
+	port->dev_geom_sect = le16_to_cpu(desc->sect);
+	port->dev_geom_cyl = le16_to_cpu(desc->cyl);
+
+	host->dev_active |= (1 << cur_port);
+
+	strncpy(port->name, desc->name, sizeof(port->name));
+	port->name[sizeof(port->name) - 1] = 0;
+	slen = strlen(port->name);
+	while (slen && (port->name[slen - 1] == ' ')) {
+		port->name[slen - 1] = 0;
+		slen--;
+	}
+
+	printk(KERN_INFO DRV_NAME "(%s): port %u device %Lu sectors\n",
+	       pci_name(host->pdev), port->port_no, port->capacity);
+	printk(KERN_INFO DRV_NAME "(%s): port %u device \"%s\"\n",
+	       pci_name(host->pdev), port->port_no, port->name);
+
+out:
+	assert(host->state == HST_DEV_SCAN);
+	schedule_task(&host->fsm_task);
+}
+
+static void carm_handle_scan_chan(struct carm_host *host,
+				  struct carm_request *crq, u8 *mem,
+				  int is_ok)
+{
+	u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET;
+	unsigned int i, dev_count = 0;
+	int new_state = HST_DEV_SCAN_START;
+
+	DPRINTK("ENTER\n");
+
+	carm_end_rq(host, crq, is_ok);
+
+	if (!is_ok) {
+		new_state = HST_ERROR;
+		goto out;
+	}
+
+	/* TODO: scan and support non-disk devices */
+	for (i = 0; i < 8; i++)
+		if (msg_data[i] == 0) { /* direct-access device (disk) */
+			host->dev_present |= (1 << i);
+			dev_count++;
+		}
+
+	printk(KERN_INFO DRV_NAME "(%s): found %u interesting devices\n",
+	       pci_name(host->pdev), dev_count);
+
+out:
+	assert(host->state == HST_PORT_SCAN);
+	host->state = new_state;
+	schedule_task(&host->fsm_task);
+}
+
+static void carm_handle_generic(struct carm_host *host,
+				struct carm_request *crq, int is_ok,
+				int cur_state, int next_state)
+{
+	DPRINTK("ENTER\n");
+
+	carm_end_rq(host, crq, is_ok);
+
+	assert(host->state == cur_state);
+	if (is_ok)
+		host->state = next_state;
+	else
+		host->state = HST_ERROR;
+	schedule_task(&host->fsm_task);
+}
+
+static inline void carm_handle_rw(struct carm_host *host,
+				  struct carm_request *crq, int is_ok)
+{
+	int pci_dir;
+
+	VPRINTK("ENTER\n");
+
+	if (rq_data_dir(crq->rq) == WRITE)
+		pci_dir = PCI_DMA_TODEVICE;
+	else
+		pci_dir = PCI_DMA_FROMDEVICE;
+
+	pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir);
+
+	carm_end_rq(host, crq, is_ok);
+}
+
+static inline void carm_handle_resp(struct carm_host *host,
+				    u32 ret_handle_le, u32 status)
+{
+	u32 handle = le32_to_cpu(ret_handle_le);
+	unsigned int msg_idx;
+	struct carm_request *crq;
+	int is_ok = (status == RMSG_OK);
+	u8 *mem;
+
+	VPRINTK("ENTER, handle == 0x%x\n", handle);
+
+	if (unlikely(!TAG_VALID(handle))) {
+		printk(KERN_ERR DRV_NAME "(%s): BUG: invalid tag 0x%x\n",
+		       pci_name(host->pdev), handle);
+		return;
+	}
+
+	msg_idx = TAG_DECODE(handle);
+	VPRINTK("tag == %u\n", msg_idx);
+
+	crq = &host->req[msg_idx];
+
+	/* fast path */
+	if (likely(crq->msg_type == CARM_MSG_READ ||
+		   crq->msg_type == CARM_MSG_WRITE)) {
+		carm_handle_rw(host, crq, is_ok);
+		return;
+	}
+
+	mem = carm_ref_msg(host, msg_idx);
+
+	switch (crq->msg_type) {
+	case CARM_MSG_IOCTL: {
+		switch (crq->msg_subtype) {
+		case CARM_IOC_SCAN_CHAN:
+			carm_handle_scan_chan(host, crq, mem, is_ok);
+			break;
+		default:
+			/* unknown / invalid response */
+			goto err_out;
+		}
+		break;
+	}
+
+	case CARM_MSG_MISC: {
+		switch (crq->msg_subtype) {
+		case MISC_ALLOC_MEM:
+			carm_handle_generic(host, crq, is_ok,
+					    HST_ALLOC_BUF, HST_SYNC_TIME);
+			break;
+		case MISC_SET_TIME:
+			carm_handle_generic(host, crq, is_ok,
+					    HST_SYNC_TIME, HST_GET_FW_VER);
+			break;
+		case MISC_GET_FW_VER: {
+			struct carm_fw_ver *ver = (struct carm_fw_ver *)
+				mem + sizeof(struct carm_msg_get_fw_ver);
+			if (is_ok) {
+				host->fw_ver = le32_to_cpu(ver->version);
+				host->flags |= (ver->features & FL_FW_VER_MASK);
+			}
+			carm_handle_generic(host, crq, is_ok,
+					    HST_GET_FW_VER, HST_PORT_SCAN);
+			break;
+		}
+		default:
+			/* unknown / invalid response */
+			goto err_out;
+		}
+		break;
+	}
+
+	case CARM_MSG_ARRAY: {
+		switch (crq->msg_subtype) {
+		case CARM_ARRAY_INFO:
+			carm_handle_array_info(host, crq, mem, is_ok);
+			break;
+		default:
+			/* unknown / invalid response */
+			goto err_out;
+		}
+		break;
+	}
+
+	default:
+		/* unknown / invalid response */
+		goto err_out;
+	}
+
+	return;
+
+err_out:
+	printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n",
+	       pci_name(host->pdev), crq->msg_type, crq->msg_subtype);
+	carm_end_rq(host, crq, 0);
+}
+
+static inline void carm_handle_responses(struct carm_host *host)
+{
+	void *mmio = host->mmio;
+	struct carm_response *resp = (struct carm_response *) host->shm;
+	unsigned int work = 0;
+	unsigned int idx = host->resp_idx % RMSG_Q_LEN;
+
+	while (1) {
+		u32 status = le32_to_cpu(resp[idx].status);
+
+		if (status == 0xffffffff) {
+			VPRINTK("ending response on index %u\n", idx);
+			writel(idx << 3, mmio + CARM_RESP_IDX);
+			break;
+		}
+
+		/* response to a message we sent */
+		else if ((status & (1 << 31)) == 0) {
+			VPRINTK("handling msg response on index %u\n", idx);
+			carm_handle_resp(host, resp[idx].ret_handle, status);
+			resp[idx].status = 0xffffffff;
+		}
+
+		/* asynchronous events the hardware throws our way */
+		else if ((status & 0xff000000) == (1 << 31)) {
+			u8 *evt_type_ptr = (u8 *) &resp[idx];
+			u8 evt_type = *evt_type_ptr;
+			printk(KERN_WARNING DRV_NAME "(%s): unhandled event type %d\n",
+			       pci_name(host->pdev), (int) evt_type);
+			resp[idx].status = 0xffffffff;
+		}
+
+		idx = NEXT_RESP(idx);
+		work++;
+	}
+
+	VPRINTK("EXIT, work==%u\n", work);
+	host->resp_idx += work;
+}
+
+static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs)
+{
+	struct carm_host *host = __host;
+	void *mmio;
+	u32 mask;
+	int handled = 0;
+	unsigned long flags;
+
+	if (!host) {
+		VPRINTK("no host\n");
+		return IRQ_NONE;
+	}
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	mmio = host->mmio;
+
+	/* reading should also clear interrupts */
+	mask = readl(mmio + CARM_INT_STAT);
+
+	if (mask == 0 || mask == 0xffffffff) {
+		VPRINTK("no work, mask == 0x%x\n", mask);
+		goto out;
+	}
+
+	if (mask & INT_ACK_MASK)
+		writel(mask, mmio + CARM_INT_STAT);
+
+	if (unlikely(host->state == HST_INVALID)) {
+		VPRINTK("not initialized yet, mask = 0x%x\n", mask);
+		goto out;
+	}
+
+	if (mask & CARM_HAVE_RESP) {
+		handled = 1;
+		carm_handle_responses(host);
+	}
+
+out:
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	VPRINTK("EXIT\n");
+	return IRQ_RETVAL(handled);
+}
+
+static void carm_fsm_task (void *_data)
+{
+	struct carm_host *host = _data;
+	unsigned long flags;
+	unsigned int state;
+	int rc, i, next_dev;
+	int reschedule = 0;
+	int new_state = HST_INVALID;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	state = host->state;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	DPRINTK("ENTER, state == %s\n", state_name[state]);
+
+	switch (state) {
+	case HST_PROBE_START:
+		new_state = HST_ALLOC_BUF;
+		reschedule = 1;
+		break;
+
+	case HST_ALLOC_BUF:
+		rc = carm_send_special(host, carm_fill_alloc_buf);
+		if (rc) {
+			new_state = HST_ERROR;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_SYNC_TIME:
+		rc = carm_send_special(host, carm_fill_sync_time);
+		if (rc) {
+			new_state = HST_ERROR;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_GET_FW_VER:
+		rc = carm_send_special(host, carm_fill_get_fw_ver);
+		if (rc) {
+			new_state = HST_ERROR;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_PORT_SCAN:
+		rc = carm_send_special(host, carm_fill_scan_channels);
+		if (rc) {
+			new_state = HST_ERROR;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_DEV_SCAN_START:
+		host->cur_scan_dev = -1;
+		new_state = HST_DEV_SCAN;
+		reschedule = 1;
+		break;
+
+	case HST_DEV_SCAN:
+		next_dev = -1;
+		for (i = host->cur_scan_dev + 1; i < CARM_MAX_PORTS; i++)
+			if (host->dev_present & (1 << i)) {
+				next_dev = i;
+				break;
+			}
+
+		if (next_dev >= 0) {
+			host->cur_scan_dev = next_dev;
+			rc = carm_array_info(host, next_dev);
+			if (rc) {
+				new_state = HST_ERROR;
+				reschedule = 1;
+			}
+		} else {
+			new_state = HST_DEV_ACTIVATE;
+			reschedule = 1;
+		}
+		break;
+
+	case HST_DEV_ACTIVATE: {
+		int activated = 0;
+		for (i = 0; i < CARM_MAX_PORTS; i++)
+			if (host->dev_active & (1 << i)) {
+				carm_activate_disk(host, &host->port[i]);
+				activated++;
+			}
+
+		printk(KERN_INFO DRV_NAME "(%s): %d ports activated\n",
+		       pci_name(host->pdev), activated);
+
+		new_state = HST_PROBE_FINISHED;
+		reschedule = 1;
+		break;
+	}
+
+	case HST_PROBE_FINISHED:
+		up(&host->probe_sem);
+		break;
+
+	case HST_ERROR:
+		/* FIXME: TODO */
+		break;
+
+	default:
+		/* should never occur */
+		printk(KERN_ERR PFX "BUG: unknown state %d\n", state);
+		assert(0);
+		break;
+	}
+
+	if (new_state != HST_INVALID) {
+		spin_lock_irqsave(&io_request_lock, flags);
+		host->state = new_state;
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	}
+	if (reschedule)
+		schedule_task(&host->fsm_task);
+}
+
+static int carm_init_wait(void *mmio, u32 bits, unsigned int test_bit)
+{
+	unsigned int i;
+
+	for (i = 0; i < 50000; i++) {
+		u32 tmp = readl(mmio + CARM_LMUC);
+		udelay(100);
+
+		if (test_bit) {
+			if ((tmp & bits) == bits)
+				return 0;
+		} else {
+			if ((tmp & bits) == 0)
+				return 0;
+		}
+
+		cond_resched();
+	}
+
+	printk(KERN_ERR PFX "carm_init_wait timeout, bits == 0x%x, test_bit == %s\n",
+	       bits, test_bit ? "yes" : "no");
+	return -EBUSY;
+}
+
+static void carm_init_responses(struct carm_host *host)
+{
+	void *mmio = host->mmio;
+	unsigned int i;
+	struct carm_response *resp = (struct carm_response *) host->shm;
+
+	for (i = 0; i < RMSG_Q_LEN; i++)
+		resp[i].status = 0xffffffff;
+
+	writel(0, mmio + CARM_RESP_IDX);
+}
+
+static int carm_init_host(struct carm_host *host)
+{
+	void *mmio = host->mmio;
+	u32 tmp;
+	u8 tmp8;
+	int rc;
+	unsigned long flags;
+
+	DPRINTK("ENTER\n");
+
+	writel(0, mmio + CARM_INT_MASK);
+
+	tmp8 = readb(mmio + CARM_INITC);
+	if (tmp8 & 0x01) {
+		tmp8 &= ~0x01;
+		writeb(tmp8, CARM_INITC);
+		readb(mmio + CARM_INITC);	/* flush */
+
+		DPRINTK("snooze...\n");
+		msleep(5000);
+	}
+
+	tmp = readl(mmio + CARM_HMUC);
+	if (tmp & CARM_CME) {
+		DPRINTK("CME bit present, waiting\n");
+		rc = carm_init_wait(mmio, CARM_CME, 1);
+		if (rc) {
+			DPRINTK("EXIT, carm_init_wait 1 failed\n");
+			return rc;
+		}
+	}
+	if (tmp & CARM_RME) {
+		DPRINTK("RME bit present, waiting\n");
+		rc = carm_init_wait(mmio, CARM_RME, 1);
+		if (rc) {
+			DPRINTK("EXIT, carm_init_wait 2 failed\n");
+			return rc;
+		}
+	}
+
+	tmp &= ~(CARM_RME | CARM_CME);
+	writel(tmp, mmio + CARM_HMUC);
+	readl(mmio + CARM_HMUC);	/* flush */
+
+	rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 0);
+	if (rc) {
+		DPRINTK("EXIT, carm_init_wait 3 failed\n");
+		return rc;
+	}
+
+	carm_init_buckets(mmio);
+
+	writel(host->shm_dma & 0xffffffff, mmio + RBUF_ADDR_LO);
+	writel((host->shm_dma >> 16) >> 16, mmio + RBUF_ADDR_HI);
+	writel(RBUF_LEN, mmio + RBUF_BYTE_SZ);
+
+	tmp = readl(mmio + CARM_HMUC);
+	tmp |= (CARM_RME | CARM_CME | CARM_WZBC);
+	writel(tmp, mmio + CARM_HMUC);
+	readl(mmio + CARM_HMUC);	/* flush */
+
+	rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 1);
+	if (rc) {
+		DPRINTK("EXIT, carm_init_wait 4 failed\n");
+		return rc;
+	}
+
+	writel(0, mmio + CARM_HMPHA);
+	writel(INT_DEF_MASK, mmio + CARM_INT_MASK);
+
+	carm_init_responses(host);
+
+	/* start initialization, probing state machine */
+	spin_lock_irqsave(&io_request_lock, flags);
+	assert(host->state == HST_INVALID);
+	host->state = HST_PROBE_START;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	schedule_task(&host->fsm_task);
+
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+static void carm_init_ports (struct carm_host *host)
+{
+	struct carm_port *port;
+	request_queue_t *q;
+	unsigned int i;
+
+	for (i = 0; i < CARM_MAX_PORTS; i++) {
+		port = &host->port[i];
+		port->magic = CARM_MAGIC_PORT;
+		port->host = host;
+		port->port_no = i;
+		tasklet_init(&port->tasklet, carm_rw_tasklet,
+			     (unsigned long) port);
+
+		q = &port->q;
+
+		blk_init_queue(q, carm_rq_fn);
+		q->queuedata = port;
+		blk_queue_bounce_limit(q, host->pdev->dma_mask);
+		blk_queue_headactive(q, 0);
+
+		q->back_merge_fn = carm_back_merge_fn;
+		q->front_merge_fn = carm_front_merge_fn;
+		q->merge_requests_fn = carm_merge_requests_fn;
+	}
+}
+
+static request_queue_t *carm_find_queue(kdev_t device)
+{
+	struct carm_host *host;
+
+	host = blk_dev[MAJOR(device)].data;
+	if (!host)
+		return NULL;
+	if (host->magic != CARM_MAGIC_HOST)
+		return NULL;
+
+	DPRINTK("match: major %d, minor %d\n",
+		MAJOR(device), MINOR(device));
+	return &host->port[MINOR(device) >> CARM_PART_SHIFT].q;
+}
+
+static int carm_init_disks(struct carm_host *host)
+{
+	host->gendisk.major = host->major;
+	host->gendisk.major_name = host->name;
+	host->gendisk.minor_shift = CARM_PART_SHIFT;
+	host->gendisk.max_p = CARM_MINORS_PER_MAJOR;
+	host->gendisk.part = host->gendisk_hd;
+	host->gendisk.sizes = host->blk_sizes;
+	host->gendisk.nr_real = CARM_MAX_PORTS;
+	host->gendisk.fops = &carm_bd_ops;
+
+	blk_dev[host->major].queue = carm_find_queue;
+	blk_dev[host->major].data = host;
+	blk_size[host->major] = host->blk_sizes;
+	blksize_size[host->major] = host->blk_block_sizes;
+	hardsect_size[host->major] = host->blk_sect_sizes;
+
+	add_gendisk(&host->gendisk);
+
+	return 0;
+}
+
+static void carm_free_disks(struct carm_host *host)
+{
+	unsigned int i;
+
+	del_gendisk(&host->gendisk);
+
+	for (i = 0; i < CARM_MAX_PORTS; i++) {
+		struct carm_port *port = &host->port[i];
+
+		blk_cleanup_queue(&port->q);
+	}
+
+	blk_dev[host->major].queue = NULL;
+	blk_dev[host->major].data = NULL;
+	blk_size[host->major] = NULL;
+	blksize_size[host->major] = NULL;
+	hardsect_size[host->major] = NULL;
+}
+
+static void carm_stop_tasklets(struct carm_host *host)
+{
+	unsigned int i;
+
+	tasklet_kill(&host->oob_tasklet);
+
+	for (i = 0; i < CARM_MAX_PORTS; i++) {
+		struct carm_port *port = &host->port[i];
+		tasklet_kill(&port->tasklet);
+	}
+}
+
+static int carm_init_shm(struct carm_host *host)
+{
+	host->shm = pci_alloc_consistent(host->pdev, CARM_SHM_SIZE,
+					 &host->shm_dma);
+	if (!host->shm)
+		return -ENOMEM;
+
+	host->msg_base = host->shm + RBUF_LEN;
+	host->msg_dma = host->shm_dma + RBUF_LEN;
+
+	memset(host->shm, 0xff, RBUF_LEN);
+	memset(host->msg_base, 0, PDC_SHM_SIZE - RBUF_LEN);
+
+	return 0;
+}
+
+static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static unsigned int printed_version;
+	struct carm_host *host;
+	unsigned int pci_dac;
+	int rc;
+	unsigned int i;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
+	rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+	if (!rc) {
+		rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+		if (rc) {
+			printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
+				pci_name(pdev));
+			goto err_out_regions;
+		}
+		pci_dac = 1;
+	} else {
+#endif
+		rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+		if (rc) {
+			printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
+				pci_name(pdev));
+			goto err_out_regions;
+		}
+		pci_dac = 0;
+#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
+	}
+#endif
+
+	host = kmalloc(sizeof(*host), GFP_KERNEL);
+	if (!host) {
+		printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n",
+		       pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(host, 0, sizeof(*host));
+	host->magic = CARM_MAGIC_HOST;
+	host->pdev = pdev;
+	host->flags = pci_dac ? FL_DAC : 0;
+	INIT_TQUEUE(&host->fsm_task, carm_fsm_task, host);
+	INIT_LIST_HEAD(&host->host_list_node);
+	init_MUTEX_LOCKED(&host->probe_sem);
+	tasklet_init(&host->oob_tasklet, carm_oob_tasklet,
+		     (unsigned long) host);
+	carm_init_ports(host);
+
+	for (i = 0; i < ARRAY_SIZE(host->req); i++)
+		host->req[i].tag = i;
+
+	host->mmio = ioremap(pci_resource_start(pdev, 0),
+			     pci_resource_len(pdev, 0));
+	if (!host->mmio) {
+		printk(KERN_ERR DRV_NAME "(%s): MMIO alloc failure\n",
+		       pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_out_kfree;
+	}
+
+	rc = carm_init_shm(host);
+	if (rc) {
+		printk(KERN_ERR DRV_NAME "(%s): DMA SHM alloc failure\n",
+		       pci_name(pdev));
+		goto err_out_iounmap;
+	}
+
+	blk_init_queue(&host->oob_q, carm_oob_rq_fn);
+	host->oob_q.queuedata = host;
+	blk_queue_bounce_limit(&host->oob_q, pdev->dma_mask);
+	blk_queue_headactive(&host->oob_q, 0);
+
+	/*
+	 * Figure out which major to use: 160, 161, or dynamic
+	 */
+	if (!test_and_set_bit(0, &carm_major_alloc))
+		host->major = 160;
+	else if (!test_and_set_bit(1, &carm_major_alloc))
+		host->major = 161;
+	else
+		host->flags |= FL_DYN_MAJOR;
+
+	host->id = carm_host_id;
+	sprintf(host->name, DRV_NAME "%d", carm_host_id);
+
+	rc = register_blkdev(host->major, host->name, &carm_bd_ops);
+	if (rc < 0)
+		goto err_out_free_majors;
+	if (host->flags & FL_DYN_MAJOR)
+		host->major = rc;
+
+	rc = carm_init_disks(host);
+	if (rc)
+		goto err_out_blkdev_disks;
+
+	pci_set_master(pdev);
+
+	rc = request_irq(pdev->irq, carm_interrupt, SA_SHIRQ, DRV_NAME, host);
+	if (rc) {
+		printk(KERN_ERR DRV_NAME "(%s): irq alloc failure\n",
+		       pci_name(pdev));
+		goto err_out_blkdev_disks;
+	}
+
+	rc = carm_init_host(host);
+	if (rc)
+		goto err_out_free_irq;
+
+	DPRINTK("waiting for probe_sem\n");
+	down(&host->probe_sem);
+
+	printk(KERN_INFO "%s: pci %s, ports %d, io %lx, irq %u, major %d\n",
+	       host->name, pci_name(pdev), (int) CARM_MAX_PORTS,
+	       pci_resource_start(pdev, 0), pdev->irq, host->major);
+
+	carm_host_id++;
+	pci_set_drvdata(pdev, host);
+	return 0;
+
+err_out_free_irq:
+	free_irq(pdev->irq, host);
+err_out_blkdev_disks:
+	carm_free_disks(host);
+	unregister_blkdev(host->major, host->name);
+err_out_free_majors:
+	if (host->major == 160)
+		clear_bit(0, &carm_major_alloc);
+	else if (host->major == 161)
+		clear_bit(1, &carm_major_alloc);
+	blk_cleanup_queue(&host->oob_q);
+	pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma);
+err_out_iounmap:
+	iounmap(host->mmio);
+err_out_kfree:
+	kfree(host);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+static void carm_remove_one (struct pci_dev *pdev)
+{
+	struct carm_host *host = pci_get_drvdata(pdev);
+
+	if (!host) {
+		printk(KERN_ERR PFX "BUG: no host data for PCI(%s)\n",
+		       pci_name(pdev));
+		return;
+	}
+
+	free_irq(pdev->irq, host);
+	carm_stop_tasklets(host);
+	carm_free_disks(host);
+	unregister_blkdev(host->major, host->name);
+	if (host->major == 160)
+		clear_bit(0, &carm_major_alloc);
+	else if (host->major == 161)
+		clear_bit(1, &carm_major_alloc);
+	blk_cleanup_queue(&host->oob_q);
+	pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma);
+	iounmap(host->mmio);
+	kfree(host);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int __init carm_init(void)
+{
+	return pci_module_init(&carm_driver);
+}
+
+static void __exit carm_exit(void)
+{
+	pci_unregister_driver(&carm_driver);
+}
+
+module_init(carm_init);
+module_exit(carm_exit);
+
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/cciss.c linux-2.4.27-pre3/drivers/block/cciss.c
--- linux-2.4.26/drivers/block/cciss.c	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/block/cciss.c	2004-05-18 16:55:17.000000000 +0000
@@ -45,13 +45,13 @@
 #include <linux/genhd.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 2.4.50)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,50)
+#define DRIVER_NAME "HP CISS Driver (v 2.4.52)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,52)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.50");
-MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400 6i"); 
+MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.52");
+MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400 6i SA6422 V100"); 
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -78,6 +78,10 @@ const struct pci_device_id cciss_pci_dev
                         0x0E11, 0x409D, 0, 0, 0},
 	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
                         0x0E11, 0x4091, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409E, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x103C, 0x3211, 0, 0, 0},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -98,6 +102,8 @@ static struct board_type products[] = {
 	{ 0x409C0E11, "Smart Array 6400", &SA5_access},
 	{ 0x409D0E11, "Smart Array 6400 EM", &SA5_access},
 	{ 0x40910E11, "Smart Array 6i", &SA5_access},
+	{ 0x409E0E11, "Smart Array 6422", &SA5_access},
+	{ 0x3211103C, "Smart Array V100", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/cciss_scsi.c linux-2.4.27-pre3/drivers/block/cciss_scsi.c
--- linux-2.4.26/drivers/block/cciss_scsi.c	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/block/cciss_scsi.c	2004-05-18 16:50:51.000000000 +0000
@@ -1569,7 +1569,7 @@ static void
 cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
 {
 	int size;
-	unsigned int flags;
+	unsigned long flags;
 
 	*pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/Makefile.lib linux-2.4.27-pre3/drivers/bluetooth/Makefile.lib
--- linux-2.4.26/drivers/bluetooth/Makefile.lib	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-pre3/drivers/bluetooth/Makefile.lib	2004-05-18 16:53:17.000000000 +0000
@@ -1 +1,2 @@
-obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o
+obj-$(CONFIG_BLUEZ_HCIBFUSB)	+= firmware_class.o
+obj-$(CONFIG_BLUEZ_HCIBT3C)	+= firmware_class.o
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/bfusb.c linux-2.4.27-pre3/drivers/bluetooth/bfusb.c
--- linux-2.4.26/drivers/bluetooth/bfusb.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.27-pre3/drivers/bluetooth/bfusb.c	2004-05-18 16:51:17.000000000 +0000
@@ -359,11 +359,11 @@ static void bfusb_rx_complete(struct urb
 
 	BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
 
-	if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
-		return;
-
 	read_lock(&bfusb->lock);
 
+	if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
+		goto unlock;
+
 	if (urb->status || !count)
 		goto resubmit;
 
@@ -414,6 +414,7 @@ resubmit:
 					bfusb->hdev.name, urb, err);
 	}
 
+unlock:
 	read_unlock(&bfusb->lock);
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/bt3c_cs.c linux-2.4.27-pre3/drivers/bluetooth/bt3c_cs.c
--- linux-2.4.26/drivers/bluetooth/bt3c_cs.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.27-pre3/drivers/bluetooth/bt3c_cs.c	2004-05-18 16:52:39.000000000 +0000
@@ -24,8 +24,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 
-#define __KERNEL_SYSCALLS__
-
 #include <linux/kernel.h>
 #include <linux/kmod.h>
 #include <linux/init.h>
@@ -48,6 +46,8 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
+#include <linux/firmware.h>
+
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
@@ -485,78 +485,101 @@ static int bt3c_hci_ioctl(struct hci_dev
 
 
 
-/* ======================== User mode firmware loader ======================== */
+/* ======================== Card services HCI interaction ======================== */
 
 
-#define FW_LOADER  "/sbin/bluefw"
-static int errno;
+static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int count)
+{
+	char *ptr = (char *) firmware;
+	char b[9];
+	unsigned int iobase, size, addr, fcs, tmp;
+	int i, err = 0;
 
+	iobase = info->link.io.BasePort1;
 
-static int bt3c_fw_loader_exec(void *dev)
-{
-	char *argv[] = { FW_LOADER, "pccard", dev, NULL };
-	char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-	int err;
+	/* Reset */
 
-	err = exec_usermodehelper(FW_LOADER, argv, envp);
-	if (err)
-		printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev);
+	bt3c_io_write(iobase, 0x8040, 0x0404);
+	bt3c_io_write(iobase, 0x8040, 0x0400);
 
-	return err;
-}
+	udelay(1);
 
+	bt3c_io_write(iobase, 0x8040, 0x0404);
 
-static int bt3c_firmware_load(bt3c_info_t *info)
-{
-	sigset_t tmpsig;
-	char dev[16];
-	pid_t pid;
-	int result;
+	udelay(17);
 
-	/* Check if root fs is mounted */
-	if (!current->fs->root) {
-		printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n");
-		return -EPERM;
-	}
+	/* Load */
 
-	sprintf(dev, "%04x", info->link.io.BasePort1);
+	while (count) {
+		if (ptr[0] != 'S') {
+			printk(KERN_WARNING "bt3c_cs: Bad address in firmware.\n");
+			err = -EFAULT;
+			goto error;
+		}
 
-	pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0);
-	if (pid < 0) {
-		printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid);
-		return pid;
-	}
+		memset(b, 0, sizeof(b));
+		memcpy(b, ptr + 2, 2);
+		size = simple_strtol(b, NULL, 16);
+
+		memset(b, 0, sizeof(b));
+		memcpy(b, ptr + 4, 8);
+		addr = simple_strtol(b, NULL, 16);
+
+		memset(b, 0, sizeof(b));
+		memcpy(b, ptr + (size * 2) + 2, 2);
+		fcs = simple_strtol(b, NULL, 16);
+
+		memset(b, 0, sizeof(b));
+		for (tmp = 0, i = 0; i < size; i++) {
+			memcpy(b, ptr + (i * 2) + 2, 2);
+			tmp += simple_strtol(b, NULL, 16);
+		}
 
-	/* Block signals, everything but SIGKILL/SIGSTOP */
-	spin_lock_irq(&current->sigmask_lock);
-	tmpsig = current->blocked;
-	siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->sigmask_lock);
+		if (((tmp + fcs) & 0xff) != 0xff) {
+			printk(KERN_WARNING "bt3c_cs: Checksum error in firmware.\n");
+			err = -EILSEQ;
+			goto error;
+		}
 
-	result = waitpid(pid, NULL, __WCLONE);
+		if (ptr[1] == '3') {
+			bt3c_address(iobase, addr);
 
-	/* Allow signals again */
-	spin_lock_irq(&current->sigmask_lock);
-	current->blocked = tmpsig;
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->sigmask_lock);
+			memset(b, 0, sizeof(b));
+			for (i = 0; i < (size - 4) / 2; i++) {
+				memcpy(b, ptr + (i * 4) + 12, 4);
+				tmp = simple_strtol(b, NULL, 16);
+				bt3c_put(iobase, tmp);
+			}
+		}
 
-	if (result != pid) {
-		printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result);
-		return -result;
+		ptr   += (size * 2) + 6;
+		count -= (size * 2) + 6;
 	}
 
-	return 0;
-}
+	udelay(17);
 
+	/* Boot */
 
+	bt3c_address(iobase, 0x3000);
+	outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL);
 
-/* ======================== Card services HCI interaction ======================== */
+error:
+	udelay(17);
+
+	/* Clear */
+
+	bt3c_io_write(iobase, 0x7006, 0x0000);
+	bt3c_io_write(iobase, 0x7005, 0x0000);
+	bt3c_io_write(iobase, 0x7001, 0x0000);
+
+	return err;
+}
 
 
 int bt3c_open(bt3c_info_t *info)
 {
+	const struct firmware *firmware;
+	char device[16];
 	struct hci_dev *hdev;
 	int err;
 
@@ -570,8 +593,22 @@ int bt3c_open(bt3c_info_t *info)
 
 	/* Load firmware */
 
-	if ((err = bt3c_firmware_load(info)) < 0)
+	snprintf(device, sizeof(device), "bt3c%4.4x", info->link.io.BasePort1);
+
+	err = request_firmware(&firmware, "BT3CPCC.bin", device);
+	if (err < 0) {
+		printk(KERN_WARNING "bt3c_cs: Firmware request failed.\n");
+		return err;
+	}
+
+	err = bt3c_load_firmware(info, firmware->data, firmware->size);
+
+	release_firmware(firmware);
+
+	if (err < 0) {
+		printk(KERN_WARNING "bt3c_cs: Firmware loading failed.\n");
 		return err;
+	}
 
 	/* Timeout before it is safe to send the first HCI packet */
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/hci_uart.h linux-2.4.27-pre3/drivers/bluetooth/hci_uart.h
--- linux-2.4.26/drivers/bluetooth/hci_uart.h	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.27-pre3/drivers/bluetooth/hci_uart.h	2004-05-18 16:53:39.000000000 +0000
@@ -35,11 +35,12 @@
 #define HCIUARTGETPROTO	_IOR('U', 201, int)
 
 /* UART protocols */
-#define HCI_UART_MAX_PROTO	3
+#define HCI_UART_MAX_PROTO	4
 
 #define HCI_UART_H4	0
 #define HCI_UART_BCSP	1
-#define HCI_UART_NCSP	2
+#define HCI_UART_3WIRE	2
+#define HCI_UART_H4DS	3
 
 #ifdef __KERNEL__
 struct hci_uart;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/hci_usb.c linux-2.4.27-pre3/drivers/bluetooth/hci_usb.c
--- linux-2.4.26/drivers/bluetooth/hci_usb.c	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/bluetooth/hci_usb.c	2004-05-18 16:55:07.000000000 +0000
@@ -699,11 +699,11 @@ static void hci_usb_rx_complete(struct u
 	BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
 			_urb->type, urb->status, count, urb->transfer_flags);
 
-	if (!test_bit(HCI_RUNNING, &hdev->flags))
-		return;
-
 	read_lock(&husb->completion_lock);
 
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		goto unlock;
+
 	if (urb->status || !count)
 		goto resubmit;
 
@@ -740,6 +740,8 @@ resubmit:
 		BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
 				_urb->type, err);
 	}
+
+unlock:
 	read_unlock(&husb->completion_lock);
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/Config.in linux-2.4.27-pre3/drivers/char/Config.in
--- linux-2.4.26/drivers/char/Config.in	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/char/Config.in	2004-05-18 16:51:52.000000000 +0000
@@ -273,7 +273,6 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
    if [ "$CONFIG_SGI_IP22" = "y" ]; then
       dep_tristate '  Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22
    fi
-   dep_tristate '  AMD 766/768 TCO Timer/Watchdog' CONFIG_AMD7XX_TCO $CONFIG_EXPERIMENTAL
    if [ "$CONFIG_8xx" = "y" ]; then
       tristate '  MPC8xx Watchdog Timer' CONFIG_8xx_WDT
    fi
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/Makefile linux-2.4.27-pre3/drivers/char/Makefile
--- linux-2.4.26/drivers/char/Makefile	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/char/Makefile	2004-05-18 16:55:10.000000000 +0000
@@ -320,7 +320,6 @@ obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
-obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
 obj-$(CONFIG_INDYDOG) += indydog.o
 obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/agp/agp.h linux-2.4.27-pre3/drivers/char/agp/agp.h
--- linux-2.4.26/drivers/char/agp/agp.h	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/char/agp/agp.h	2004-05-18 16:52:51.000000000 +0000
@@ -316,6 +316,9 @@ struct agp_bridge_data {
 #ifndef PCI_DEVICE_ID_ATI_RS200
 #define PCI_DEVICE_ID_ATI_RS200		0xcab2
 #endif
+#ifndef PCI_DEVICE_ID_ATI_RS200_REV2
+#define PCI_DEVICE_ID_ATI_RS200_REV2	0xcbb2
+#endif
 #ifndef PCI_DEVICE_ID_ATI_RS250
 #define PCI_DEVICE_ID_ATI_RS250		0xcab3
 #endif
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/agp/agpgart_be.c linux-2.4.27-pre3/drivers/char/agp/agpgart_be.c
--- linux-2.4.26/drivers/char/agp/agpgart_be.c	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/char/agp/agpgart_be.c	2004-05-18 16:51:33.000000000 +0000
@@ -5738,6 +5738,7 @@ static int ati_create_gatt_table(void)
 
 	if ((agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS100) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200) ||
+	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_REV2) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_B) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS250)) {
 		pci_read_config_dword(agp_bridge.dev, ATI_RS100_APSIZE, &temp);
@@ -5792,6 +5793,7 @@ static int ati_fetch_size(void)
 
 	if ((agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS100) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200) ||
+	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_REV2) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_B) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS250)) {
 		pci_read_config_dword(agp_bridge.dev, ATI_RS100_APSIZE, &temp);
@@ -5825,6 +5827,7 @@ static int ati_configure(void)
 
 	if ((agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS100) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200) ||
+	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_REV2) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_B) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS250)) {
         	pci_write_config_dword(agp_bridge.dev, ATI_RS100_IG_AGPMODE, 0x20000);
@@ -5863,6 +5866,7 @@ static void ati_cleanup(void)
 	/* Write back the previous size and disable gart translation */
 	if ((agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS100) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200) ||
+	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_REV2) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_B) ||
 	    (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS250)) {
 		pci_read_config_dword(agp_bridge.dev, ATI_RS100_APSIZE, &temp);
@@ -6426,6 +6430,12 @@ static struct {
 	  "ATI",
 	  "IGP330/340/345/350/M",
 	  ati_generic_setup },
+	{ PCI_DEVICE_ID_ATI_RS200_REV2,
+          PCI_VENDOR_ID_ATI,
+          ATI_RS200,
+          "ATI",
+          "IGP345M (rev 2)",
+          ati_generic_setup },
 	{ PCI_DEVICE_ID_ATI_RS200_B,
 	  PCI_VENDOR_ID_ATI,
 	  ATI_RS200,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/amd7xx_tco.c linux-2.4.27-pre3/drivers/char/amd7xx_tco.c
--- linux-2.4.26/drivers/char/amd7xx_tco.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/char/amd7xx_tco.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,387 +0,0 @@
-/*
- *	AMD 766/768 TCO Timer Driver
- *	(c) Copyright 2002 Zwane Mwaikambo <zwane@holomorphy.com>
- *	All Rights Reserved.
- *
- *	Parts from;
- *	Hardware driver for the AMD 768 Random Number Generator (RNG)
- *	(c) Copyright 2001 Red Hat Inc <alan@redhat.com>
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License version 2
- *	as published by the Free Software Foundation.
- *
- *	The author(s) of this software shall not be held liable for damages
- *	of any nature resulting due to the use of this software. This
- *	software is provided AS-IS with no warranties.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/kernel.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <asm/semaphore.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#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, although the system will only
-				 * reset itself after the second timeout */
-
-/* pmbase registers */
-#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 "\n";
-static int timeout = 38;
-static u32 pmbase;		/* PMxx I/O base */
-static struct pci_dev *dev;
-static struct semaphore open_sem;
-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;
-	int status = 0;
-
-	reg = inb(pmbase+TCO_CTRL1_REG);
-	if ((reg & TCO_HALT) == 0)
-		status |= WDIOF_KEEPALIVEPING;
-
-	reg = inb(pmbase+TCO_STATUS2_REG);
-	if (reg & BOOT_STS)
-		status |= WDIOF_CARDRESET;
-
-	return status;
-}
-
-static inline void amdtco_ping(void)
-{
-	outb(1, pmbase+TCO_RELOAD_REG);
-}
-
-static inline int amdtco_gettimeout(void)
-{
-	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 = seconds_to_ticks(timeout) & TCO_TIMEOUT_MASK;
-	outb(reg, pmbase+TCO_INITVAL_REG);
-}
-
-static inline void amdtco_global_enable(void)
-{
-	u16 reg;
-
-	spin_lock(&amdtco_lock);
-
-	/* 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);
-}
-
-static inline void amdtco_enable(void)
-{
-	u16 reg;
-	
-	spin_lock(&amdtco_lock);
-	reg = inw(pmbase+TCO_CTRL1_REG);
-	reg &= ~TCO_HALT;
-	outw(reg, pmbase+TCO_CTRL1_REG);
-	spin_unlock(&amdtco_lock);
-}
-
-static inline void amdtco_disable(void)
-{
-	u16 reg;
-
-	spin_lock(&amdtco_lock);
-	reg = inw(pmbase+TCO_CTRL1_REG);
-	reg |= TCO_HALT;
-	outw(reg, pmbase+TCO_CTRL1_REG);
-	spin_unlock(&amdtco_lock);
-}
-
-static int amdtco_fop_open(struct inode *inode, struct file *file)
-{
-	if (down_trylock(&open_sem))
-		return -EBUSY;
-
-#ifdef CONFIG_WATCHDOG_NOWAYOUT	
-	MOD_INC_USE_COUNT;
-#endif
-
-	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 = %ds of %ds\n",
-		amdtco_gettimeout(), timeout);
-	
-	return 0;
-}
-
-
-static int amdtco_fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	int new_timeout;
-	int tmp;
-
-	static struct watchdog_info ident = {
-		options:	WDIOF_SETTIMEOUT | WDIOF_CARDRESET,
-		identity:	"AMD 766/768"
-	};
-
-	switch (cmd) {
-		default:
-			return -ENOTTY;	
-
-		case WDIOC_GETSUPPORT:
-			if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident))
-				return -EFAULT;
-			return 0;
-
-		case WDIOC_GETSTATUS:
-			return put_user(amdtco_status(), (int *)arg);
-	
-		case WDIOC_KEEPALIVE:
-			amdtco_ping();
-			return 0;
-
-		case WDIOC_SETTIMEOUT:
-			if (get_user(new_timeout, (int *)arg))
-				return -EFAULT;
-			
-			if (new_timeout < 0)
-				return -EINVAL;
-		
-			if (new_timeout > MAX_TIMEOUT)
-				new_timeout = MAX_TIMEOUT;
-
-			timeout = new_timeout;
-			amdtco_settimeout(timeout);
-			/* fall through and return the new timeout */
-
-		case WDIOC_GETTIMEOUT:
-			return put_user(amdtco_gettimeout(), (int *)arg);
-		
-		case WDIOC_SETOPTIONS:
-			if (copy_from_user(&tmp, (int *)arg, sizeof tmp))
-                                return -EFAULT;
-
-			if (tmp & WDIOS_DISABLECARD)
-				amdtco_disable();
-
-			if (tmp & WDIOS_ENABLECARD)
-				amdtco_enable();
-			
-			return 0;
-	}
-}
-
-
-static int amdtco_fop_release(struct inode *inode, struct file *file)
-{
-	if (expect_close) {
-		amdtco_disable();	
-		printk(KERN_INFO PFX "Watchdog disabled\n");
-	} else {
-		amdtco_ping();
-		printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds\n", timeout);
-	}	
-	
-	up(&open_sem);
-	return 0;
-}
-
-
-static ssize_t amdtco_fop_write(struct file *file, const char *data, size_t len, loff_t *ppos)
-{
-	if (ppos != &file->f_pos)
-		return -ESPIPE;
-	
-	if (len) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t i;
-		char c;
-		expect_close = 0;
-		
-		for (i = 0; i != len; i++) {
-			if (get_user(c, data + i))
-				return -EFAULT;
-
-			if (c == 'V')
-				expect_close = 1;
-		}
-#endif
-		amdtco_ping();
-	}
-
-	return len;
-}
-
-
-static int amdtco_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
-{
-	if (code == SYS_DOWN || code == SYS_HALT)
-		amdtco_disable();
-
-	return NOTIFY_DONE;
-}
-
-
-static struct notifier_block amdtco_notifier =
-{
-	notifier_call:	amdtco_notify_sys
-};
-
-static struct file_operations amdtco_fops =
-{
-	owner:		THIS_MODULE,
-	write:		amdtco_fop_write,
-	ioctl:		amdtco_fop_ioctl,
-	open:		amdtco_fop_open,
-	release:	amdtco_fop_release
-};
-
-static struct miscdevice amdtco_miscdev =
-{
-	minor:		WATCHDOG_MINOR,
-	name:		"watchdog",
-	fops:		&amdtco_fops
-};
-
-static struct pci_device_id amdtco_pci_tbl[] __initdata = {
-	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, },
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE (pci, amdtco_pci_tbl);
-
-static int __init amdtco_init(void)
-{
-	int ret;
-
-	sema_init(&open_sem, 1);
-	spin_lock_init(&amdtco_lock);
-
-	pci_for_each_dev(dev) {
-		if (pci_match_device (amdtco_pci_tbl, dev) != NULL)
-			goto found_one;
-	}
-
-	return -ENODEV;
-
-found_one:
-	
-	if ((ret = register_reboot_notifier(&amdtco_notifier))) {
-		printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret);
-		goto out_clean;
-	}
-
-	if ((ret = misc_register(&amdtco_miscdev))) {
-		printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
-		goto out_unreg_reboot;
-	}
-
-	pci_read_config_dword(dev, 0x58, &pmbase);
-	pmbase &= 0x0000FF00;
-
-	if (pmbase == 0) {
-		printk (KERN_ERR PFX "power management base not set\n");
-		ret = -EIO;
-		goto out_unreg_misc;
-	}
-
-	/* ret = 0; */
-	printk(banner);
-	goto out_clean;
-
-out_unreg_misc:
-	misc_deregister(&amdtco_miscdev);
-out_unreg_reboot:
-	unregister_reboot_notifier(&amdtco_notifier);
-out_clean:
-	return ret;
-}
-
-static void __exit amdtco_exit(void)
-{
-	misc_deregister(&amdtco_miscdev);
-	unregister_reboot_notifier(&amdtco_notifier);
-}
-
-
-#ifndef MODULE
-static int __init amdtco_setup(char *str)
-{
-	int ints[4];
-
-	str = get_options (str, ARRAY_SIZE(ints), ints);
-	if (ints[0] > 0)
-		timeout = ints[1];
-
-	if (!timeout || timeout > 38)
-		timeout = MAX_TIMEOUT;
-
-	return 1;
-}
-
-__setup("amd7xx_tco=", amdtco_setup);
-#endif
-
-module_init(amdtco_init);
-module_exit(amdtco_exit);
-
-MODULE_AUTHOR("Zwane Mwaikambo <zwane@holomorphy.com>");
-MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver");
-MODULE_LICENSE("GPL");
-EXPORT_NO_SYMBOLS;
-
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/drm/drmP.h linux-2.4.27-pre3/drivers/char/drm/drmP.h
--- linux-2.4.26/drivers/char/drm/drmP.h	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/char/drm/drmP.h	2004-05-18 16:54:24.000000000 +0000
@@ -52,6 +52,7 @@
 #include <linux/version.h>
 #include <linux/sched.h>
 #include <linux/smp_lock.h>	/* For (un)lock_kernel */
+#include <asm/system.h>	/* for cmpxchg() */
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #if defined(__alpha__) || defined(__powerpc__)
@@ -174,38 +175,7 @@ __cmpxchg(volatile void *ptr, unsigned l
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
-#elif __i386__
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
-{
-	unsigned long prev;
-	switch (size) {
-	case 1:
-		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
-				     : "=a"(prev)
-				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
-				     : "memory");
-		return prev;
-	case 2:
-		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
-				     : "=a"(prev)
-				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
-				     : "memory");
-		return prev;
-	case 4:
-		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
-				     : "=a"(prev)
-				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
-				     : "memory");
-		return prev;
-	}
-	return old;
-}
-
-#define cmpxchg(ptr,o,n)						\
-  ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),		\
-				 (unsigned long)(n),sizeof(*(ptr))))
-#endif /* i386 & alpha */
+#endif /* alpha */
 #endif
 #define __REALLY_HAVE_SG	(__HAVE_SG)
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/tipar.c linux-2.4.27-pre3/drivers/char/tipar.c
--- linux-2.4.26/drivers/char/tipar.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/char/tipar.c	2004-05-18 16:52:26.000000000 +0000
@@ -66,7 +66,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "1.18"
+#define DRIVER_VERSION "1.19"
 #define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org>"
 #define DRIVER_DESC    "Device driver for TI/PC parallel link cables"
 #define DRIVER_LICENSE "GPL"
@@ -124,7 +124,7 @@ init_ti_parallel(int minor)
 
 /* ----- global defines ----------------------------------------------- */
 
-#define START(x) { x=jiffies+HZ/(timeout/10); }
+#define START(x) { x = jiffies + (HZ * timeout) / 10; }
 #define WAIT(x)  { \
   if (time_before((x), jiffies)) return -1; \
   if (need_resched()) schedule(); }
@@ -366,11 +366,14 @@ tipar_ioctl(struct inode *inode, struct 
 
 	switch (cmd) {
 	case IOCTL_TIPAR_DELAY:
-	  delay = (int)arg;    //get_user(delay, &arg);
-	  break;
+		delay = (int)arg;    //get_user(delay, &arg);
+		break;
 	case IOCTL_TIPAR_TIMEOUT:
-	  timeout = (int)arg;  //get_user(timeout, &arg);
-	  break;
+		if (arg != 0)
+                        timeout = (int)arg;
+                else
+                        retval = -EINVAL;
+		break;
 	default:
 		retval = -ENOTTY;
 		break;
@@ -404,7 +407,10 @@ tipar_setup(char *str)
 	str = get_options(str, ARRAY_SIZE(ints), ints);
 
 	if (ints[0] > 0) {
-		timeout = ints[1];
+		if (ints[1] != 0)
+                        timeout = ints[1];
+                else
+                        printk("tipar: wrong timeout value (0), using default value instead.");
 		if (ints[0] > 1) {
 			delay = ints[2];
 		}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/Config.in linux-2.4.27-pre3/drivers/hotplug/Config.in
--- linux-2.4.26/drivers/hotplug/Config.in	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/Config.in	2004-05-18 16:51:39.000000000 +0000
@@ -14,4 +14,11 @@ fi
 if [ "$CONFIG_ACPI_INTERPRETER" = "y" ]; then
    dep_tristate '  ACPI PCI Hotplug driver' CONFIG_HOTPLUG_PCI_ACPI $CONFIG_HOTPLUG_PCI
 fi
+dep_tristate '  SHPC PCI Hotplug driver' CONFIG_HOTPLUG_PCI_SHPC $CONFIG_HOTPLUG_PCI
+dep_mbool '    Use polling mechanism for hot-plug events (for testing purpose)' CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE $CONFIG_HOTPLUG_PCI_SHPC
+if [ "$CONFIG_ACPI" = "n" ]; then
+dep_mbool '    For AMD SHPC only: Use $HRT for resource/configuration' CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY $CONFIG_HOTPLUG_PCI_SHPC 
+fi
+dep_tristate '  PCI Express Hotplug driver' CONFIG_HOTPLUG_PCI_PCIE $CONFIG_HOTPLUG_PCI
+dep_mbool '    Use polling mechanism for hot-plug events (for testing purpose)' CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE $CONFIG_HOTPLUG_PCI_PCIE
 endmenu
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/Makefile linux-2.4.27-pre3/drivers/hotplug/Makefile
--- linux-2.4.26/drivers/hotplug/Makefile	2003-08-25 11:44:41.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/Makefile	2004-05-18 16:54:16.000000000 +0000
@@ -4,7 +4,7 @@
 
 O_TARGET	:= vmlinux-obj.o
 
-list-multi	:= cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o 
+list-multi	:= cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o shpchp.o pciehp.o 
 
 export-objs	:= pci_hotplug_core.o pci_hotplug_util.o
 
@@ -12,6 +12,8 @@ obj-$(CONFIG_HOTPLUG_PCI)		+= pci_hotplu
 obj-$(CONFIG_HOTPLUG_PCI_COMPAQ)	+= cpqphp.o
 obj-$(CONFIG_HOTPLUG_PCI_IBM)		+= ibmphp.o
 obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= acpiphp.o
+obj-$(CONFIG_HOTPLUG_PCI_SHPC)		+= shpchp.o
+obj-$(CONFIG_HOTPLUG_PCI_PCIE)		+= pciehp.o
 
 pci_hotplug-objs	:=	pci_hotplug_core.o	\
 				pci_hotplug_util.o
@@ -32,11 +34,36 @@ acpiphp_objs		:=	acpiphp_core.o	\
 				acpiphp_pci.o	\
 				acpiphp_res.o
 
+pciehp-objs		:=	pciehp_core.o	\
+				pciehp_ctrl.o	\
+				pciehp_hpc.o	\
+				pciehp_pci.o
+ifdef CONFIG_ACPI_INTERPRETER
+  pciehp-objs += pciehprm_acpi.o
+else
+  pciehp-objs += pciehprm_nonacpi.o
+  EXTRA_CFLAGS  += -D_LINUX -I$(TOPDIR)/drivers/acpi 
+endif
+
+shpchp-objs		:=	shpchp_core.o	\
+				shpchp_ctrl.o	\
+				shpchp_hpc.o	\
+				shpchp_pci.o
+ifdef CONFIG_ACPI_INTERPRETER
+  shpchp-objs += shpchprm_acpi.o
+  EXTRA_CFLAGS  += -D_LINUX -I$(TOPDIR)/drivers/acpi 
+else
+  ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY
+    shpchp-objs += shpchprm_legacy.o
+  else
+    shpchp-objs += shpchprm_nonacpi.o
+  endif
+endif
+
 ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y)
 	cpqphp-objs += cpqphp_nvram.o
 endif
 
-
 include $(TOPDIR)/Rules.make
 
 pci_hotplug.o: $(pci_hotplug-objs)
@@ -50,3 +77,10 @@ ibmphp.o: $(ibmphp-objs)
 
 acpiphp.o: $(acpiphp_objs)
 	$(LD) -r -o $@ $(acpiphp_objs)
+
+pciehp.o: $(pciehp-objs)
+	$(LD) -r -o $@ $(pciehp-objs)
+
+shpchp.o: $(shpchp-objs)
+	$(LD) -r -o $@ $(shpchp-objs)
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp.h linux-2.4.27-pre3/drivers/hotplug/acpiphp.h
--- linux-2.4.26/drivers/hotplug/acpiphp.h	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/acpiphp.h	2004-05-18 16:50:54.000000000 +0000
@@ -36,63 +36,7 @@
 #include <linux/acpi.h>
 #include "pci_hotplug.h"
 
-#if ACPI_CA_VERSION < 0x20020201
-/* until we get a new version of the ACPI driver for both ia32 and ia64 ... */
-#define acpi_util_eval_error(h,p,s)
-
-static acpi_status
-acpi_evaluate_integer (
-	acpi_handle		handle,
-	acpi_string		pathname,
-	acpi_object_list	*arguments,
-	unsigned long		*data)
-{
-	acpi_status		status = AE_OK;
-	acpi_object		element;
-	acpi_buffer		buffer = {sizeof(acpi_object), &element};
-
-	if (!data)
-		return AE_BAD_PARAMETER;
-
-	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
-	if (ACPI_FAILURE(status)) {
-		acpi_util_eval_error(handle, pathname, status);
-		return status;
-	}
-
-	if (element.type != ACPI_TYPE_INTEGER) {
-		acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
-		return AE_BAD_DATA;
-	}
-
-	*data = element.integer.value;
-
-	return AE_OK;
-}
-#else  /* ACPI_CA_VERSION < 0x20020201 */
 #include <acpi/acpi_bus.h>
-#endif
-
-/* compatibility stuff for ACPI CA */
-#ifndef ACPI_MEMORY_RANGE
-#define ACPI_MEMORY_RANGE MEMORY_RANGE
-#endif
-
-#ifndef ACPI_IO_RANGE
-#define ACPI_IO_RANGE IO_RANGE
-#endif
-
-#ifndef ACPI_BUS_NUMBER_RANGE
-#define ACPI_BUS_NUMBER_RANGE BUS_NUMBER_RANGE
-#endif
-
-#ifndef ACPI_PREFETCHABLE_MEMORY
-#define ACPI_PREFETCHABLE_MEMORY PREFETCHABLE_MEMORY
-#endif
-
-#ifndef ACPI_PRODUCER
-#define ACPI_PRODUCER PRODUCER
-#endif
 
 #define dbg(format, arg...)					\
 	do {							\
@@ -258,7 +202,7 @@ struct acpiphp_func {
 
 #define SLOT_POWEREDON		(0x00000001)
 #define SLOT_ENABLED		(0x00000002)
-#define SLOT_MULTIFUNCTION	(x000000004)
+#define SLOT_MULTIFUNCTION	(0x00000004)
 
 /* function flags */
 
@@ -269,8 +213,6 @@ struct acpiphp_func {
 #define FUNC_HAS_PS2		(0x00000040)
 #define FUNC_HAS_PS3		(0x00000080)
 
-#define FUNC_EXISTS		(0x10000000) /* to make sure we call _EJ0 only for existing funcs */
-
 /* function prototypes */
 
 /* acpiphp_glue.c */
@@ -288,6 +230,7 @@ extern u8 acpiphp_get_power_status (stru
 extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot);
 extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
 extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
+extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
 
 /* acpiphp_pci.c */
 extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp_core.c linux-2.4.27-pre3/drivers/hotplug/acpiphp_core.c
--- linux-2.4.26/drivers/hotplug/acpiphp_core.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/acpiphp_core.c	2004-05-18 16:54:46.000000000 +0000
@@ -30,14 +30,14 @@
  *
  */
 
-#include <linux/config.h>
-#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/module.h>
+
+#include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/init.h>
 #include "pci_hotplug.h"
 #include "acpiphp.h"
 
@@ -73,6 +73,7 @@ static int get_power_status	(struct hotp
 static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_address		(struct hotplug_slot *slot, u32 *value);
 static int get_max_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
 static int get_cur_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
 
@@ -86,6 +87,7 @@ static struct hotplug_slot_ops acpi_hotp
 	.get_attention_status	= get_attention_status,
 	.get_latch_status	= get_latch_status,
 	.get_adapter_status	= get_adapter_status,
+	.get_address		= get_address,
 	.get_max_bus_speed	= get_max_bus_speed,
 	.get_cur_bus_speed	= get_cur_bus_speed,
 };
@@ -322,6 +324,28 @@ static int get_adapter_status (struct ho
 }
 
 
+/**
+ * get_address - get pci address of a slot
+ * @hotplug_slot: slot to get status
+ * @busdev: pointer to struct pci_busdev (seg, bus, dev)
+ *
+ */
+static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+	int retval = 0;
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_address(slot->acpi_slot);
+
+	return retval;
+}
+
+
 /* return dummy value because ACPI doesn't provide any method... */
 static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp_glue.c linux-2.4.27-pre3/drivers/hotplug/acpiphp_glue.c
--- linux-2.4.26/drivers/hotplug/acpiphp_glue.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/acpiphp_glue.c	2004-05-18 16:54:47.000000000 +0000
@@ -26,12 +26,12 @@
  *
  */
 
-#include <linux/config.h>
-#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/module.h>
+
+#include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
-#include <linux/init.h>
 #include <asm/semaphore.h>
 
 #include "pci_hotplug.h"
@@ -389,12 +389,8 @@ static struct pci_bus *find_pci_bus(cons
 static void decode_hpp(struct acpiphp_bridge *bridge)
 {
 	acpi_status status;
-#if ACPI_CA_VERSION < 0x20020201
-	acpi_buffer buffer;
-#else
 	struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER,
 				      .pointer = NULL};
-#endif
 	union acpi_object *package;
 	int i;
 
@@ -404,21 +400,7 @@ static void decode_hpp(struct acpiphp_br
 	bridge->hpp.enable_SERR = 0;
 	bridge->hpp.enable_PERR = 0;
 
-#if ACPI_CA_VERSION < 0x20020201
-	buffer.length = 0;
-	buffer.pointer = NULL;
-
-	status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
-
-	if (status == AE_BUFFER_OVERFLOW) {
-		buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
-		if (!buffer.pointer)
-			return;
-		status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
-	}
-#else
 	status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
-#endif
 
 	if (ACPI_FAILURE(status)) {
 		dbg("_HPP evaluation failed\n");
@@ -494,12 +476,8 @@ static void init_bridge_misc (struct acp
 static void add_host_bridge (acpi_handle *handle, int seg, int bus)
 {
 	acpi_status status;
-#if ACPI_CA_VERSION < 0x20020201
-	acpi_buffer buffer;
-#else
 	struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER,
 				      .pointer = NULL};
-#endif
 	struct acpiphp_bridge *bridge;
 
 	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
@@ -522,22 +500,8 @@ static void add_host_bridge (acpi_handle
 
 	/* decode resources */
 
-#if ACPI_CA_VERSION < 0x20020201
-	buffer.length = 0;
-	buffer.pointer = NULL;
-
 	status = acpi_get_current_resources(handle, &buffer);
 
-	if (status == AE_BUFFER_OVERFLOW) {
-		buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
-		if (!buffer.pointer)
-			return;
-		status = acpi_get_current_resources(handle, &buffer);
-	}
-#else
-	status = acpi_get_current_resources(handle, &buffer);
-#endif
-
 	if (ACPI_FAILURE(status)) {
 		err("failed to decode bridge resources\n");
 		kfree(bridge);
@@ -819,7 +783,7 @@ static int power_on_slot (struct acpiphp
 	struct list_head *l;
 	int retval = 0;
 
-	/* is this already enabled? */
+	/* if already enabled, just skip */
 	if (slot->flags & SLOT_POWEREDON)
 		goto err_exit;
 
@@ -827,14 +791,14 @@ static int power_on_slot (struct acpiphp
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_PS0) {
-			dbg("%s: executing _PS0 on %s\n", __FUNCTION__,
-			    func->pci_dev->slot_name);
+			dbg("%s: executing _PS0\n", __FUNCTION__);
 			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _PS0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
+			} else
+				break;
 		}
 	}
 
@@ -857,20 +821,21 @@ static int power_off_slot (struct acpiph
 
 	int retval = 0;
 
-	/* is this already enabled? */
+	/* if already disabled, just skip */
 	if ((slot->flags & SLOT_POWEREDON) == 0)
 		goto err_exit;
 
 	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
-		if (func->flags & (FUNC_HAS_PS3 | FUNC_EXISTS)) {
+		if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) {
 			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _PS3 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
+			} else
+				break;
 		}
 	}
 
@@ -878,20 +843,19 @@ static int power_off_slot (struct acpiph
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		/* We don't want to call _EJ0 on non-existing functions. */
-		if (func->flags & (FUNC_HAS_EJ0 | FUNC_EXISTS)) {
+		if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) {
 			/* _EJ0 method take one argument */
 			arg_list.count = 1;
 			arg_list.pointer = &arg;
 			arg.type = ACPI_TYPE_INTEGER;
 			arg.integer.value = 1;
-
 			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _EJ0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
-			func->flags &= (~FUNC_EXISTS);
+			} else
+				break;
 		}
 	}
 
@@ -973,8 +937,6 @@ static int enable_device (struct acpiphp
 		retval = acpiphp_configure_function(func);
 		if (retval)
 			goto err_exit;
-
-		func->flags |= FUNC_EXISTS;
 	}
 
 	slot->flags |= SLOT_ENABLED;
@@ -1003,15 +965,12 @@ static int disable_device (struct acpiph
 	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
-		if (func->pci_dev) {
-			if (acpiphp_unconfigure_function(func) == 0) {
-				func->pci_dev = NULL;
-			} else {
+		if (func->pci_dev)
+			if (acpiphp_unconfigure_function(func)) {
 				err("failed to unconfigure device\n");
 				retval = -1;
 				goto err_exit;
 			}
-		}
 	}
 
 	slot->flags &= (~SLOT_ENABLED);
@@ -1391,7 +1350,7 @@ int acpiphp_check_bridge (struct acpiphp
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
-				enabled++;
+				disabled++;
 			}
 		} else {
 			/* if disabled but present, enable */
@@ -1402,7 +1361,7 @@ int acpiphp_check_bridge (struct acpiphp
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
-				disabled++;
+				enabled++;
 			}
 		}
 	}
@@ -1468,3 +1427,18 @@ u8 acpiphp_get_adapter_status (struct ac
 
 	return (sta == 0) ? 0 : 1;
 }
+
+
+/*
+ * pci address (seg/bus/dev)
+ */
+u32 acpiphp_get_address (struct acpiphp_slot *slot)
+{
+	u32 address;
+
+	address = ((slot->bridge->seg) << 16) |
+		  ((slot->bridge->bus) << 8) |
+		  slot->device;
+
+	return address;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp_pci.c linux-2.4.27-pre3/drivers/hotplug/acpiphp_pci.c
--- linux-2.4.26/drivers/hotplug/acpiphp_pci.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/acpiphp_pci.c	2004-05-18 16:52:57.000000000 +0000
@@ -29,11 +29,11 @@
  *
  */
 
-#include <linux/config.h>
-#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/module.h>
+
+#include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include "pci_hotplug.h"
 #include "acpiphp.h"
 
@@ -78,8 +78,8 @@ static int init_config_space (struct acp
 		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
 
-			len = bar & 0xFFFFFFFC;
-			len = ~len + 1;
+			len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
 
 			dbg("len in IO %x, BAR %d\n", len, count);
 
@@ -340,8 +340,8 @@ static int detect_used_resource (struct 
 		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
 			base = bar & 0xFFFFFFFC;
-			len &= 0xFFFFFFFC;
-			len = ~len + 1;
+			len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
 
 			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
@@ -465,8 +465,8 @@ int acpiphp_init_func_resource (struct a
 		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
 			base = bar & 0xFFFFFFFC;
-			len &= 0xFFFFFFFC;
-			len = ~len + 1;
+			len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
 
 			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp_res.c linux-2.4.27-pre3/drivers/hotplug/acpiphp_res.c
--- linux-2.4.26/drivers/hotplug/acpiphp_res.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/acpiphp_res.c	2004-05-18 16:53:08.000000000 +0000
@@ -29,7 +29,7 @@
  *
  */
 
-#include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -39,7 +39,6 @@
 #include <linux/pci.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/init.h>
 
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -225,7 +224,7 @@ struct pci_resource *acpiphp_get_io_reso
 		}  /* End of too big on top end */
 
 		/* For IO make sure it's not in the ISA aliasing space */
-		if (node->base & 0x300L)
+		if ((node->base & 0x300L) && !(node->base & 0xfffff000))
 			continue;
 
 		/* If we got here, then it is the right size
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pci_hotplug.h linux-2.4.27-pre3/drivers/hotplug/pci_hotplug.h
--- linux-2.4.26/drivers/hotplug/pci_hotplug.h	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pci_hotplug.h	2004-05-18 16:52:37.000000000 +0000
@@ -36,15 +36,36 @@ enum pci_bus_speed {
 	PCI_SPEED_66MHz_PCIX		= 0x02,
 	PCI_SPEED_100MHz_PCIX		= 0x03,
 	PCI_SPEED_133MHz_PCIX		= 0x04,
+ 	PCI_SPEED_66MHz_PCIX_ECC	= 0x05,
+ 	PCI_SPEED_100MHz_PCIX_ECC	= 0x06,
+ 	PCI_SPEED_133MHz_PCIX_ECC	= 0x07,
 	PCI_SPEED_66MHz_PCIX_266	= 0x09,
 	PCI_SPEED_100MHz_PCIX_266	= 0x0a,
 	PCI_SPEED_133MHz_PCIX_266	= 0x0b,
 	PCI_SPEED_66MHz_PCIX_533	= 0x11,
-	PCI_SPEED_100MHz_PCIX_533	= 0X12,
+	PCI_SPEED_100MHz_PCIX_533	= 0x12,
 	PCI_SPEED_133MHz_PCIX_533	= 0x13,
 	PCI_SPEED_UNKNOWN		= 0xff,
 };
 
+/* These values come from the PCI Express Spec */
+enum pcie_link_width {
+ 	PCIE_LNK_WIDTH_RESRV	= 0x00,
+ 	PCIE_LNK_X1		= 0x01,
+ 	PCIE_LNK_X2		= 0x02,
+ 	PCIE_LNK_X4		= 0x04,
+ 	PCIE_LNK_X8		= 0x08,
+ 	PCIE_LNK_X12		= 0x0C,
+ 	PCIE_LNK_X16		= 0x10,
+ 	PCIE_LNK_X32		= 0x20,
+ 	PCIE_LNK_WIDTH_UNKNOWN	= 0xFF,
+};
+
+enum pcie_link_speed {
+ 	PCIE_2PT5GB		= 0x14,
+ 	PCIE_LNK_SPEED_UNKNOWN	= 0xFF,
+};
+
 struct hotplug_slot;
 struct hotplug_slot_core;
 
@@ -69,6 +90,9 @@ struct hotplug_slot_core;
  * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
+ * @get_address: Called to get pci address of a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
  * @get_max_bus_speed: Called to get the max bus speed for a slot.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
@@ -91,6 +115,7 @@ struct hotplug_slot_ops {
 	int (*get_attention_status)	(struct hotplug_slot *slot, u8 *value);
 	int (*get_latch_status)		(struct hotplug_slot *slot, u8 *value);
 	int (*get_adapter_status)	(struct hotplug_slot *slot, u8 *value);
+	int (*get_address)		(struct hotplug_slot *slot, u32 *value);
 	int (*get_max_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 	int (*get_cur_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 };
@@ -101,6 +126,7 @@ struct hotplug_slot_ops {
  * @attention_status: if the attention light is enabled or not (1/0)
  * @latch_status: if the latch (if any) is open or closed (1/0)
  * @adapter_present: if there is a pci board present in the slot or not (1/0)
+ * @address: (domain << 16 | bus << 8 | dev)
  *
  * Used to notify the hotplug pci core of the status of a specific slot.
  */
@@ -109,6 +135,7 @@ struct hotplug_slot_info {
 	u8	attention_status;
 	u8	latch_status;
 	u8	adapter_status;
+	u32	address;
 	enum pci_bus_speed	max_bus_speed;
 	enum pci_bus_speed	cur_bus_speed;
 };
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pci_hotplug_core.c linux-2.4.27-pre3/drivers/hotplug/pci_hotplug_core.c
--- linux-2.4.26/drivers/hotplug/pci_hotplug_core.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pci_hotplug_core.c	2004-05-18 16:54:41.000000000 +0000
@@ -74,6 +74,7 @@ struct hotplug_slot_core {
 	struct dentry	*attention_dentry;
 	struct dentry	*latch_dentry;
 	struct dentry	*adapter_dentry;
+	struct dentry	*address_dentry;
 	struct dentry	*test_dentry;
 	struct dentry	*max_bus_speed_dentry;
 	struct dentry	*cur_bus_speed_dentry;
@@ -111,6 +112,7 @@ static char *pci_bus_speed_strings[] = {
 	"66 MHz PCIX 533",	/* 0x11 */
 	"100 MHz PCIX 533",	/* 0x12 */
 	"133 MHz PCIX 533",	/* 0x13 */
+ 	"25 GBps PCI-E",	/* 0x14 */
 };
 
 static int pcihpfs_statfs (struct super_block *sb, struct statfs *buf)
@@ -312,6 +314,15 @@ static struct file_operations presence_f
 	llseek:		default_file_lseek,
 };
 
+/* file ops for the "address" files */
+static ssize_t address_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations address_file_operations = {
+	read:		address_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+};
+
 /* file ops for the "max bus speed" files */
 static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
 static struct file_operations max_bus_speed_file_operations = {
@@ -566,6 +577,7 @@ GET_STATUS(power_status, u8)
 GET_STATUS(attention_status, u8)
 GET_STATUS(latch_status, u8)
 GET_STATUS(adapter_status, u8)
+GET_STATUS(address, u32)
 GET_STATUS(max_bus_speed, enum pci_bus_speed)
 GET_STATUS(cur_bus_speed, enum pci_bus_speed)
 
@@ -859,6 +871,52 @@ exit:
 	return retval;
 }
 
+static ssize_t address_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	int retval;
+	int len;
+	u32 address;
+
+	dbg("count = %d, offset = %lld\n", count, *offset);
+
+	if (*offset < 0)
+		return -EINVAL;
+	if (count <= 0)
+		return 0;
+	if (*offset != 0)
+		return 0;
+
+	if (slot == NULL) {
+		dbg("slot == NULL???\n");
+		return -ENODEV;
+	}
+
+	page = (unsigned char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = get_address (slot, &address);
+	if (retval)
+		goto exit;
+	len = sprintf (page, "%04x:%02x:%02x\n",
+		       (address >> 16) & 0xffff,
+		       (address >> 8) & 0xff,
+		       address & 0xff);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	return retval;
+}
+
 static char *unknown_speed = "Unknown bus speed";
 
 static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
@@ -1055,6 +1113,13 @@ static int fs_add_slot (struct hotplug_s
 						core->dir_dentry, slot,
 						&presence_file_operations);
 
+		if (slot->ops->get_address)
+			core->address_dentry = 
+				fs_create_file ("address",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&address_file_operations);
+
 		if (slot->ops->get_max_bus_speed)
 			core->max_bus_speed_dentry = 
 				fs_create_file ("max_bus_speed",
@@ -1092,6 +1157,8 @@ static void fs_remove_slot (struct hotpl
 			fs_remove_file (core->latch_dentry);
 		if (core->adapter_dentry)
 			fs_remove_file (core->adapter_dentry);
+		if (core->address_dentry)
+			fs_remove_file (core->address_dentry);
 		if (core->max_bus_speed_dentry)
 			fs_remove_file (core->max_bus_speed_dentry);
 		if (core->cur_bus_speed_dentry)
@@ -1243,6 +1310,9 @@ int pci_hp_change_slot_info (const char 
 	if ((core->adapter_dentry) &&
 	    (temp->info->adapter_status != info->adapter_status))
 		update_dentry_inode_time (core->adapter_dentry);
+	if ((core->address_dentry) &&
+	    (temp->info->address != info->address))
+		update_dentry_inode_time (core->address_dentry);
 	if ((core->cur_bus_speed_dentry) &&
 	    (temp->info->cur_bus_speed != info->cur_bus_speed))
 		update_dentry_inode_time (core->cur_bus_speed_dentry);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp.h linux-2.4.27-pre3/drivers/hotplug/pciehp.h
--- linux-2.4.26/drivers/hotplug/pciehp.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pciehp.h	2004-05-18 16:55:33.000000000 +0000
@@ -0,0 +1,383 @@
+/*
+ * PCI Express 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) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+#ifndef _PCIEHP_H
+#define _PCIEHP_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>		
+#include "pci_hotplug.h"
+
+#if !defined(CONFIG_HOTPLUG_PCI_PCIE_MODULE)
+	#define MY_NAME	"pciehp.o"
+#else
+	#define MY_NAME	THIS_MODULE->name
+#endif
+
+extern int pciehp_poll_mode;
+extern int pciehp_poll_time;
+extern int pciehp_debug;
+
+extern int pciehp_msi_quirk;
+
+/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
+#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## 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)
+
+struct pci_func {
+	struct pci_func *next;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 is_a_board;
+	u16 status;
+	u8 configured;
+	u8 switch_save;
+	u8 presence_save;
+	u32 base_length[0x06];
+	u8 base_type[0x06];
+	u16 reserved2;
+	u32 config_space[0x20];
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev* pci_dev;
+};
+
+#define SLOT_MAGIC	0x67267321
+struct slot {
+	u32 magic;
+	struct slot *next;
+	u8 bus;
+	u8 device;
+	u32 number;
+	u8 is_a_board;
+	u8 configured;
+	u8 state;
+	u8 switch_save;
+	u8 presence_save;
+	u32 capabilities;
+	u16 reserved2;
+	struct timer_list task_event;
+	u8 hp_slot;
+	struct controller *ctrl;
+	struct hpc_ops *hpc_ops;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head	slot_list;
+};
+
+struct pci_resource {
+	struct pci_resource * next;
+	u32 base;
+	u32 length;
+};
+
+struct event_info {
+	u32 event_type;
+	u8 hp_slot;
+};
+
+struct controller {
+	struct controller *next;
+	struct semaphore crit_sect;	/* critical section semaphore */
+	void * hpc_ctlr_handle;		/* HPC controller handle */
+	int num_slots;			/* Number of slots on ctlr */
+	int slot_num_inc;			/* 1 or -1 */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev *pci_dev;
+	struct pci_bus *pci_bus;
+	struct event_info event_queue[10];
+	struct slot *slot;
+	struct hpc_ops *hpc_ops;
+	wait_queue_head_t queue;	/* sleep & wake process */
+	u8 next_event;
+	u8 seg;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 rev;
+	u8 slot_device_offset;
+	u8 add_support;
+	enum pci_bus_speed speed;
+	u32 first_slot;		/* First physical slot number;  PCI-E only has 1 slot */
+	u8 slot_bus;		/* Bus where the slots handled by this controller sit */
+	u8 push_flag;
+	u16 ctlrcap;
+	u16 vendor_id;
+};
+
+struct irq_mapping {
+	u8 barber_pole;
+	u8 valid_INT;
+	u8 interrupt[4];
+};
+
+struct resource_lists {
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct irq_mapping *irqs;
+};
+
+#define INT_BUTTON_IGNORE		0
+#define INT_PRESENCE_ON			1
+#define INT_PRESENCE_OFF		2
+#define INT_SWITCH_CLOSE		3
+#define INT_SWITCH_OPEN			4
+#define INT_POWER_FAULT			5
+#define INT_POWER_FAULT_CLEAR		6
+#define INT_BUTTON_PRESS		7
+#define INT_BUTTON_RELEASE		8
+#define INT_BUTTON_CANCEL		9
+
+#define STATIC_STATE			0
+#define BLINKINGON_STATE		1
+#define BLINKINGOFF_STATE		2
+#define POWERON_STATE			3
+#define POWEROFF_STATE			4
+
+#define PCI_TO_PCI_BRIDGE_CLASS		0x00060400
+
+/* Error messages */
+#define INTERLOCK_OPEN			0x00000002
+#define ADD_NOT_SUPPORTED		0x00000003
+#define CARD_FUNCTIONING		0x00000005
+#define ADAPTER_NOT_SAME		0x00000006
+#define NO_ADAPTER_PRESENT		0x00000009
+#define NOT_ENOUGH_RESOURCES		0x0000000B
+#define DEVICE_TYPE_NOT_SUPPORTED	0x0000000C
+#define WRONG_BUS_FREQUENCY		0x0000000D
+#define POWER_FAILURE			0x0000000E
+
+#define REMOVE_NOT_SUPPORTED		0x00000003
+
+#define DISABLE_CARD			1
+
+/*
+ * error Messages
+ */
+#define msg_initialization_err	"Initialization failure, error=%d\n"
+#define msg_HPC_rev_error	"Unsupported revision of the PCI hot plug controller found.\n"
+#define msg_HPC_non_pcie	"The PCI hot plug controller is not supported by this driver.\n"
+#define msg_HPC_not_supported	"This system is not supported by this version of pciephd mdoule. Upgrade to a newer version of pciehpd\n"
+#define msg_unable_to_save	"Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n"
+#define msg_button_on		"PCI slot #%d - powering on due to button press.\n"
+#define msg_button_off		"PCI slot #%d - powering off due to button press.\n"
+#define msg_button_cancel	"PCI slot #%d - action canceled due to button press.\n"
+#define msg_button_ignore	"PCI slot #%d - button press ignored.  (action in progress...)\n"
+
+/* controller functions */
+extern void	pciehp_pushbutton_thread	(unsigned long event_pointer);
+extern int	pciehprm_find_available_resources	(struct controller *ctrl);
+extern int	pciehp_event_start_thread	(void);
+extern void	pciehp_event_stop_thread	(void);
+extern struct pci_func *pciehp_slot_create	(unsigned char busnumber);
+extern struct pci_func *pciehp_slot_find	(unsigned char bus, unsigned char device, unsigned char index);
+extern int	pciehp_enable_slot		(struct slot *slot);
+extern int	pciehp_disable_slot		(struct slot *slot);
+
+extern u8	pciehp_handle_attention_button	(u8 hp_slot, void *inst_id);
+extern u8	pciehp_handle_switch_change	(u8 hp_slot, void *inst_id);
+extern u8	pciehp_handle_presence_change	(u8 hp_slot, void *inst_id);
+extern u8	pciehp_handle_power_fault	(u8 hp_slot, void *inst_id);
+/* extern void	long_delay (int delay); */
+
+/* resource functions */
+extern int	pciehp_resource_sort_and_combine	(struct pci_resource **head);
+
+/* pci functions */
+extern int	pciehp_set_irq			(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
+extern int	pciehp_save_config	 	(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
+extern int	pciehp_save_used_resources	(struct controller *ctrl, struct pci_func * func, int flag);
+extern int	pciehp_save_slot_config		(struct controller *ctrl, struct pci_func * new_slot);
+extern void	pciehp_destroy_board_resources	(struct pci_func * func);
+extern int	pciehp_return_board_resources	(struct pci_func * func, struct resource_lists * resources);
+extern void	pciehp_destroy_resource_list	(struct resource_lists * resources);
+extern int	pciehp_configure_device		(struct controller* ctrl, struct pci_func* func);
+extern int	pciehp_unconfigure_device	(struct pci_func* func);
+
+
+/* Global variables */
+extern struct controller *pciehp_ctrl_list;
+extern struct pci_func *pciehp_slot_list[256];
+
+/* Inline functions */
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check (struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL", function);
+		return -1;
+	}
+	if (slot->magic != SLOT_MAGIC) {
+		dbg("%s - bad magic number for slot", function);
+		return -1;
+	}
+	if (!slot->hotplug_slot) {
+		dbg("%s - slot->hotplug_slot == NULL!", function);
+		return -1;
+	}
+	return 0;
+}
+
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
+{ 
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL\n", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot->private;
+	if (slot_paranoia_check (slot, function))
+                return NULL;
+	return slot;
+}
+
+static inline struct slot *pciehp_find_slot (struct controller *ctrl, u8 device)
+{
+	struct slot *p_slot, *tmp_slot = NULL;
+
+	if (!ctrl)
+		return NULL;
+
+	p_slot = ctrl->slot;
+
+	dbg("p_slot = %p\n", p_slot);
+
+	while (p_slot && (p_slot->device != device)) {
+		tmp_slot = p_slot;
+		p_slot = p_slot->next;
+		dbg("In while loop, p_slot = %p\n", p_slot);
+	}
+	if (p_slot == NULL) {
+		err("ERROR: pciehp_find_slot device=0x%x\n", device);
+		p_slot = tmp_slot;
+	}
+
+	return (p_slot);
+}
+
+static inline int wait_for_ctrl_irq (struct controller *ctrl)
+{
+	int retval = 0;
+
+		DECLARE_WAITQUEUE(wait, current);
+
+		dbg("%s : start\n", __FUNCTION__);
+		add_wait_queue(&ctrl->queue, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!pciehp_poll_mode) {
+			/* Sleep for up to 1 second */
+			schedule_timeout(1*HZ);
+		} else
+			schedule_timeout(2.5*HZ);
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&ctrl->queue, &wait);
+		if (signal_pending(current))
+			retval =  -EINTR;
+
+		dbg("%s : end\n", __FUNCTION__);
+
+	return retval;
+}
+
+
+/* Puts node back in the resource list pointed to by head */
+static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
+{
+	if (!node || !head)
+		return;
+	node->next = *head;
+	*head = node;
+}
+
+#define SLOT_NAME_SIZE 10
+
+static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
+{
+	snprintf(buffer, buffer_size, "%d", slot->number);
+}
+
+enum php_ctlr_type {
+	PCI,
+	ISA,
+	ACPI
+};
+
+typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id);
+
+int pcie_init( struct controller *ctrl, struct pci_dev *pdev,
+		php_intr_callback_t attention_button_callback,
+		php_intr_callback_t switch_change_callback,
+		php_intr_callback_t presence_change_callback,
+		php_intr_callback_t power_fault_callback);
+
+/* This has no meaning for PCI Express, as there is only 1 slot per port */
+int pcie_get_ctlr_slot_config( struct controller *ctrl,
+		int *num_ctlr_slots,
+		int *first_device_num,
+		int *physical_slot_num,
+		int *updown,
+		int *flags);
+
+struct hpc_ops {
+	int	(*power_on_slot )	(struct slot *slot);
+	int	(*power_off_slot )	(struct slot *slot);
+	int	(*get_power_status)	(struct slot *slot, u8 *status);
+	int	(*get_attention_status)	(struct slot *slot, u8 *status);
+	int	(*set_attention_status)	(struct slot *slot, u8 status);
+	int	(*get_latch_status)	(struct slot *slot, u8 *status);
+	int	(*get_adapter_status)	(struct slot *slot, u8 *status);
+
+	int	(*get_max_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_cur_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_max_lnk_width)	(struct slot *slot, enum pcie_link_width *value);
+	int	(*get_cur_lnk_width)	(struct slot *slot, enum pcie_link_width *value);
+
+	int	(*query_power_fault)	(struct slot *slot);
+	void 	(*green_led_on)		(struct slot *slot);
+	void	(*green_led_off)	(struct slot *slot);
+	void	(*green_led_blink)	(struct slot *slot);
+	void	(*release_ctlr)		(struct controller *ctrl);
+	int (*check_lnk_status)		(struct controller *ctrl);
+};
+
+#endif				/* _PCIEHP_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp_core.c linux-2.4.27-pre3/drivers/hotplug/pciehp_core.c
--- linux-2.4.26/drivers/hotplug/pciehp_core.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pciehp_core.c	2004-05-18 16:54:21.000000000 +0000
@@ -0,0 +1,703 @@
+/*
+ * PCI Express 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) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/tqueue.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include "pciehp.h"
+#include "pciehprm.h"
+
+/* Global variables */
+int pciehp_debug;
+int pciehp_poll_mode;
+int pciehp_poll_time;
+struct controller *pciehp_ctrl_list;	/* = NULL */
+struct pci_func *pciehp_slot_list[256];
+
+#define DRIVER_VERSION	"0.5"
+#define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
+#define DRIVER_DESC	"PCI Express Hot Plug Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(pciehp_debug, "i");
+MODULE_PARM(pciehp_poll_mode, "i");
+MODULE_PARM(pciehp_poll_time, "i");
+MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
+MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
+MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
+
+#define PCIE_MODULE_NAME "pciehp.o"
+
+static int pcie_start_thread (void);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int hardware_test	(struct hotplug_slot *slot, u32 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+
+static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
+	.owner =		THIS_MODULE,
+	.set_attention_status =	set_attention_status,
+	.enable_slot =		enable_slot,
+	.disable_slot =		disable_slot,
+	.hardware_test =	hardware_test,
+	.get_power_status =	get_power_status,
+	.get_attention_status =	get_attention_status,
+	.get_latch_status =		get_latch_status,
+	.get_adapter_status =	get_adapter_status,
+  	.get_max_bus_speed =	get_max_bus_speed,
+  	.get_cur_bus_speed =	get_cur_bus_speed,
+};
+
+static int init_slots(struct controller *ctrl)
+{
+	struct slot *new_slot;
+	u8 number_of_slots;
+	u8 slot_device;
+	u32 slot_number;
+	int result;
+
+	dbg("%s\n",__FUNCTION__);
+
+	number_of_slots = ctrl->num_slots;
+	slot_device = ctrl->slot_device_offset;
+	slot_number = ctrl->first_slot;
+
+	while (number_of_slots) {
+		new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL);
+		if (!new_slot)
+			return -ENOMEM;
+
+		memset(new_slot, 0, sizeof(struct slot));
+		new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		if (!new_slot->hotplug_slot) {
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+		memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+
+		new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if (!new_slot->hotplug_slot->info) {
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+		memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+		new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!new_slot->hotplug_slot->name) {
+			kfree (new_slot->hotplug_slot->info);
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+
+		new_slot->magic = SLOT_MAGIC;
+		new_slot->ctrl = ctrl;
+		new_slot->bus = ctrl->slot_bus;
+		new_slot->device = slot_device;
+		new_slot->hpc_ops = ctrl->hpc_ops;
+
+		new_slot->number = ctrl->first_slot;
+		new_slot->hp_slot = slot_device - ctrl->slot_device_offset;
+
+		/* register this slot with the hotplug pci core */
+		new_slot->hotplug_slot->private = new_slot;
+		make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
+		new_slot->hotplug_slot->ops = &pciehp_hotplug_slot_ops;
+
+		new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status));
+		new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status));
+		new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status));
+		new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status));
+
+		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", 
+			new_slot->bus, new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset);
+		result = pci_hp_register (new_slot->hotplug_slot);
+		if (result) {
+			err ("pci_hp_register failed with error %d\n", result);
+			kfree (new_slot->hotplug_slot->info);
+			kfree (new_slot->hotplug_slot->name);
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
+			return result;
+		}
+
+		new_slot->next = ctrl->slot;
+		ctrl->slot = new_slot;
+
+		number_of_slots--;
+		slot_device++;
+		slot_number += ctrl->slot_num_inc;
+	}
+
+	return(0);
+}
+
+
+static int cleanup_slots (struct controller * ctrl)
+{
+	struct slot *old_slot, *next_slot;
+
+	old_slot = ctrl->slot;
+	ctrl->slot = NULL;
+
+	while (old_slot) {
+		next_slot = old_slot->next;
+		pci_hp_deregister (old_slot->hotplug_slot);
+		kfree(old_slot->hotplug_slot->info);
+		kfree(old_slot->hotplug_slot->name);
+		kfree(old_slot->hotplug_slot);
+		kfree(old_slot);
+		old_slot = next_slot;
+	}
+
+
+	return(0);
+}
+
+static int get_ctlr_slot_config(struct controller *ctrl)
+{
+	int num_ctlr_slots;		/* Not needed; PCI Express has 1 slot per port */
+	int first_device_num;	 	/* Not needed */
+	int physical_slot_num;
+	int updown;			/* Not needed */
+	int rc;
+	int flags;			/* Not needed */
+
+	rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &updown, &flags);
+	if (rc) {
+		err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
+		return (-1);
+	}
+
+	ctrl->num_slots = num_ctlr_slots;	/* PCI Express has 1 slot per port */
+	ctrl->slot_device_offset = first_device_num;
+	ctrl->first_slot = physical_slot_num;
+	ctrl->slot_num_inc = updown; 		/* Not needed */	/* either -1 or 1 */
+
+	dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n",
+		__FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, updown, 
+		ctrl->bus, ctrl->device);
+
+	return (0);
+}
+
+
+/*
+ * set_attention_status - Turns the Amber LED for a slot on, off or blink
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	hotplug_slot->info->attention_status = status;
+	slot->hpc_ops->set_attention_status(slot, status);
+
+
+	return 0;
+}
+
+
+static int enable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	return pciehp_enable_slot(slot);
+}
+
+
+static int disable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	return pciehp_disable_slot(slot);
+}
+
+
+static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
+{
+	return 0;
+}
+
+
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_power_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->power_status;
+
+	return 0;
+}
+
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_attention_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->attention_status;
+
+	return 0;
+}
+
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_latch_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->latch_status;
+
+	return 0;
+}
+
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_adapter_status(slot, value);
+
+	if (retval < 0)
+		*value = hotplug_slot->info->adapter_status;
+
+	return 0;
+}
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+	
+	retval = slot->hpc_ops->get_max_bus_speed(slot, value);
+	if (retval < 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+	
+	retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
+	if (retval < 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int pcie_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc;
+	struct controller *ctrl;
+	struct slot *t_slot;
+	int first_device_num = 0;	/* first PCI device number supported by this PCIE */  
+	int num_ctlr_slots;		/* number of slots supported by this HPC */
+	u8 value;
+
+	ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
+	if (!ctrl) {
+		err("%s : out of memory\n", __FUNCTION__);
+		goto err_out_none;
+	}
+	memset(ctrl, 0, sizeof(struct controller));
+
+	dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid);
+
+	rc = pcie_init(ctrl, pdev,
+		(php_intr_callback_t) pciehp_handle_attention_button,
+		(php_intr_callback_t) pciehp_handle_switch_change,
+		(php_intr_callback_t) pciehp_handle_presence_change,
+		(php_intr_callback_t) pciehp_handle_power_fault);
+	if (rc) {
+		dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME);
+		goto err_out_free_ctrl;
+	}
+
+	ctrl->pci_dev = pdev;
+
+	ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);
+	if (!ctrl->pci_bus) {
+		err("%s: out of memory\n", __FUNCTION__);
+		rc = -ENOMEM;
+		goto err_out_unmap_mmio_region;
+	}
+	dbg("%s: ctrl->pci_bus %p\n", __FUNCTION__, ctrl->pci_bus);
+	memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
+
+	ctrl->bus = pdev->bus->number;  /* ctrl bus */
+	ctrl->slot_bus = pdev->subordinate->number;  /* bus controlled by this HPC */
+
+	ctrl->device = PCI_SLOT(pdev->devfn);
+	ctrl->function = PCI_FUNC(pdev->devfn);
+	dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
+		ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
+
+	/*
+	 *	Save configuration headers for this and subordinate PCI buses
+	 */
+
+	rc = get_ctlr_slot_config(ctrl);
+	if (rc) {
+		err(msg_initialization_err, rc);
+		goto err_out_free_ctrl_bus;
+	}
+	
+	first_device_num = ctrl->slot_device_offset; 
+	num_ctlr_slots = ctrl->num_slots; 
+	
+
+	/* Store PCI Config Space for all devices on this bus */
+	dbg("%s: Before calling pciehp_save_config, ctrl->bus %x,ctrl->slot_bus %x\n", 
+		__FUNCTION__,ctrl->bus, ctrl->slot_bus);
+	rc = pciehp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num); 
+	if (rc) {
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Get IO, memory, and IRQ resources for new devices */
+	rc = pciehprm_find_available_resources(ctrl);
+
+	ctrl->add_support = !rc;
+	if (rc) {
+		dbg("pciehprm_find_available_resources = %#x\n", rc);
+		err("unable to locate PCI configuration resources for hot plug add.\n");
+		goto err_out_free_ctrl_bus;
+	}
+	/* Setup the slot information structures */
+	rc = init_slots(ctrl);
+	if (rc) {
+		err(msg_initialization_err, 6);
+		goto err_out_free_ctrl_slot;
+	}
+
+	t_slot = pciehp_find_slot(ctrl, first_device_num);
+	dbg("%s: t_slot %p\n", __FUNCTION__, t_slot);
+
+	/* Finish setting up the hot plug ctrl device */
+	ctrl->next_event = 0;
+
+	if (!pciehp_ctrl_list) {
+		pciehp_ctrl_list = ctrl;
+		ctrl->next = NULL;
+	} else {
+		ctrl->next = pciehp_ctrl_list;
+		pciehp_ctrl_list = ctrl;
+	}
+
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
+	dbg("%s: adapter value %x\n", __FUNCTION__, value);
+	if (!value) {
+		rc = t_slot->hpc_ops->power_off_slot(t_slot);  /* Power off slot if not occupied*/
+		if (rc) {
+			up(&ctrl->crit_sect);
+			goto err_out_free_ctrl_slot;
+		} else
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (ctrl);
+		}
+	
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	return 0;
+
+err_out_free_ctrl_slot:
+	cleanup_slots(ctrl);
+err_out_free_ctrl_bus:
+	kfree(ctrl->pci_bus);
+err_out_unmap_mmio_region:
+	ctrl->hpc_ops->release_ctlr(ctrl);
+err_out_free_ctrl:
+	kfree(ctrl);
+err_out_none:
+	return -ENODEV;
+}
+
+
+static int pcie_start_thread(void)
+{
+	int loop;
+	int retval = 0;
+	
+	dbg("Initialize + Start the notification/polling mechanism \n");
+
+	retval = pciehp_event_start_thread();
+	if (retval) {
+		dbg("pciehp_event_start_thread() failed\n");
+		return retval;
+	}
+
+	dbg("Initialize slot lists\n");
+	/* One slot list for each bus in the system */
+	for (loop = 0; loop < 256; loop++) {
+		pciehp_slot_list[loop] = NULL;
+	}
+
+	return retval;
+}
+
+
+static void unload_pciehpd(void)
+{
+	struct pci_func *next;
+	struct pci_func *TempSlot;
+	int loop;
+	struct controller *ctrl;
+	struct controller *tctrl;
+	struct pci_resource *res;
+	struct pci_resource *tres;
+
+	ctrl = pciehp_ctrl_list;
+	while (ctrl) {
+		cleanup_slots(ctrl);
+
+		res = ctrl->io_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		res = ctrl->mem_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		res = ctrl->p_mem_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		res = ctrl->bus_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		kfree (ctrl->pci_bus);
+
+		ctrl->hpc_ops->release_ctlr(ctrl);
+
+		tctrl = ctrl;
+		ctrl = ctrl->next;
+
+		kfree(tctrl);
+	}
+
+	for (loop = 0; loop < 256; loop++) {
+		next = pciehp_slot_list[loop];
+		while (next != NULL) {
+			res = next->io_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			res = next->mem_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			res = next->p_mem_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			res = next->bus_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			TempSlot = next;
+			next = next->next;
+			kfree(TempSlot);
+		}
+	}
+
+	/* Stop the notification mechanism */
+	pciehp_event_stop_thread();
+
+}
+
+
+static struct pci_device_id pcied_pci_tbl[] __devinitdata = {
+	{
+	class:      	((PCI_CLASS_BRIDGE_PCI << 8) | 0x00),
+	class_mask:	~0,
+	vendor:		PCI_ANY_ID,
+	device:     	PCI_ANY_ID,
+	subvendor:   	PCI_ANY_ID,
+	subdevice:    	PCI_ANY_ID,
+	},
+	{ /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, pcied_pci_tbl);
+
+
+
+static struct pci_driver pcie_driver = {
+	.name		=	PCIE_MODULE_NAME,
+	.id_table	=	pcied_pci_tbl,
+	.probe		=	pcie_probe,
+	/* remove:	pcie_remove_one, */
+};
+
+
+
+static int __init pcied_init(void)
+{
+	int retval = 0;
+
+#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
+	pciehp_poll_mode = 1;
+#endif
+	retval = pcie_start_thread();
+	if (retval)
+		goto error_hpc_init;
+
+	retval = pciehprm_init(PCI);
+	if (!retval) {
+		retval = pci_module_init(&pcie_driver);
+		dbg("pci_module_init = %d\n", retval);
+		info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+	}
+
+error_hpc_init:
+	if (retval) {
+		pciehprm_cleanup();
+		pciehp_event_stop_thread();
+	} 
+
+	return retval;
+}
+
+static void __exit pcied_cleanup(void)
+{
+	dbg("unload_pciehpd()\n");
+	unload_pciehpd();
+
+	pciehprm_cleanup();
+
+	dbg("pci_unregister_driver\n");
+	pci_unregister_driver(&pcie_driver);
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
+}
+
+
+module_init(pcied_init);
+module_exit(pcied_cleanup);
+
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp_ctrl.c linux-2.4.27-pre3/drivers/hotplug/pciehp_ctrl.c
--- linux-2.4.26/drivers/hotplug/pciehp_ctrl.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pciehp_ctrl.c	2004-05-18 16:51:33.000000000 +0000
@@ -0,0 +1,2629 @@
+/*
+ * PCI Express 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) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include "pciehp.h"
+#include "pciehprm.h"
+
+static u32 configure_new_device(struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static int configure_new_function( struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static void interrupt_event_handler(struct controller *ctrl);
+
+static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
+static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
+static int event_finished;
+static unsigned long pushbutton_pending;	/* = 0 */
+
+u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Attention Button Change */
+	dbg("pciehp:  Attention button interrupt received.\n");
+	
+	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread what to do */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+
+	/*
+	 *  Button pressed - See if need to TAKE ACTION!!!
+	 */
+	info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	taskInfo->event_type = INT_BUTTON_PRESS;
+
+	if ((p_slot->state == BLINKINGON_STATE)
+	    || (p_slot->state == BLINKINGOFF_STATE)) {
+		/* Cancel if we are still blinking; this means that we press the
+		 * attention again before the 5 sec. limit expires to cancel hot-add
+		 * or hot-remove
+		 */
+		taskInfo->event_type = INT_BUTTON_CANCEL;
+		info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	} else if ((p_slot->state == POWERON_STATE)
+		   || (p_slot->state == POWEROFF_STATE)) {
+		/* Ignore if the slot is on power-on or power-off state; this 
+		 * means that the previous attention button action to hot-add or
+		 * hot-remove is undergoing
+		 */
+		taskInfo->event_type = INT_BUTTON_IGNORE;
+		info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	}
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return 0;
+
+}
+
+u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Switch Change */
+	dbg("pciehp:  Switch interrupt received.\n");
+
+	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* this is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+
+	if (getstatus) {
+		/*
+		 * Switch opened
+		 */
+		info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->switch_save = 0;
+		taskInfo->event_type = INT_SWITCH_OPEN;
+	} else {
+		/*
+		 *  Switch closed
+		 */
+		info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->switch_save = 0x10;
+		taskInfo->event_type = INT_SWITCH_CLOSE;
+	}
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Presence Change */
+	dbg("pciehp:  Presence/Notify input change.\n");
+
+	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	/* Switch is open, assume a presence change
+	 * Save the presence state
+	 */
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	if (func->presence_save) {
+		/*
+		 * Card Present
+		 */
+		info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_PRESENCE_ON;
+	} else {
+		/*
+		 * Not Present
+		 */
+		info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_PRESENCE_OFF;
+	}
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* power fault */
+	dbg("pciehp:  Power fault interrupt received.\n");
+
+	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
+		/*
+		 * Power fault cleared
+		 */
+		info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->status = 0x00;
+		taskInfo->event_type = INT_POWER_FAULT_CLEAR;
+	} else {
+		/*
+		 *   Power fault
+		 */
+		info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_POWER_FAULT;
+		/* Set power fault status for this board */
+		func->status = 0xFF;
+		info("power fault bit %x set\n", hp_slot);
+	}
+	if (rc)
+		up(&event_semaphore);	/* Signal event thread that new event is posted */
+
+	return rc;
+}
+
+
+/*
+ * sort_by_size
+ *
+ * Sorts nodes on the list by their length.
+ * Smallest first.
+ *
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)->next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length > (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length > current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * sort_by_max_size
+ *
+ * Sorts nodes on the list by their length.
+ * Largest first.
+ *
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)->next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length < (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length < current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * do_pre_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 rc;
+	u32 temp_dword;
+	dbg("do_pre_bridge_resource_split\n");
+
+	if (!(*head) || !(*orig_head))
+		return(NULL);
+
+	rc = pciehp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	if ((*head)->base != (*orig_head)->base)
+		return(NULL);
+
+	if ((*head)->length == (*orig_head)->length)
+		return(NULL);
+
+
+	/* If we got here, there the bridge requires some of the resource, but
+	 *  we may be able to split some off of the front
+	 */	
+	node = *head;
+
+	if (node->length & (alignment -1)) {
+		/* This one isn't an aligned length, so we'll make a new entry
+		 * and split it up.
+		 */
+		split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+		if (!split_node)
+			return(NULL);
+
+		temp_dword = (node->length | (alignment-1)) + 1 - alignment;
+
+		split_node->base = node->base;
+		split_node->length = temp_dword;
+
+		node->length -= temp_dword;
+		node->base += split_node->length;
+
+		/* Put it in the list */
+		*head = split_node;
+		split_node->next = node;
+	}
+
+	if (node->length < alignment) {
+		return(NULL);
+	}
+
+	/* Now unlink it */
+	if (*head == node) {
+		*head = node->next;
+		node->next = NULL;
+	} else {
+		prevnode = *head;
+		while (prevnode->next != node)
+			prevnode = prevnode->next;
+
+		prevnode->next = node->next;
+		node->next = NULL;
+	}
+
+	return(node);
+}
+
+
+/*
+ * do_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	u32 rc;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	rc = pciehp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	node = *head;
+
+	while (node->next) {
+		prevnode = node;
+		node = node->next;
+		kfree(prevnode);
+	}
+
+	if (node->length < alignment) {
+		kfree(node);
+		return(NULL);
+	}
+
+	if (node->base & (alignment - 1)) {
+		/* Short circuit if adjusted size is too small */
+		temp_dword = (node->base | (alignment-1)) + 1;
+		if ((node->length - (temp_dword - node->base)) < alignment) {
+			kfree(node);
+			return(NULL);
+		}
+
+		node->length -= (temp_dword - node->base);
+		node->base = temp_dword;
+	}
+
+	if (node->length & (alignment - 1)) {
+		/* There's stuff in use after this node */
+		kfree(node);
+		return(NULL);
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_io_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length that is not in the
+ * ISA aliasing window.  If it finds a node larger than "size"
+ * it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node = NULL;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( pciehp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node->next) {
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			/* 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;
+
+			/*/ Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			/* 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);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if (node->base & 0x300L)
+			continue;
+
+		/* If we got here, then it is the right size 
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_max_resource
+ *
+ * Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M
+ *  This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot.
+ */
+static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+	u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 };
+	int i;
+
+	if (!(*head))
+		return(NULL);
+
+	if (pciehp_resource_sort_and_combine(head))
+		return(NULL);
+
+	if (sort_by_max_size(head))
+		return(NULL);
+
+	for (max = *head;max; max = max->next) {
+
+		/* If not big enough we could probably just bail, 
+		   instead we'll continue to the next. */
+		if (max->length < size)
+			continue;
+
+		if (max->base & (size - 1)) {
+			/* This one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (max->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max->length - (temp_dword - max->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = max->base;
+			split_node->length = temp_dword - max->base;
+			max->base = temp_dword;
+			max->length -= split_node->length;
+
+			/* Put it next in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		if ((max->base + max->length) & (size - 1)) {
+			/* This one isn't end aligned properly at the top
+			   so we'll make a new entry and split it up */
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+			temp_dword = ((max->base + max->length) & ~(size - 1));
+			split_node->base = temp_dword;
+			split_node->length = max->length + max->base
+					     - split_node->base;
+			max->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max->length < size)
+			continue;
+
+		for ( i = 0; max_size[i] > size; i++) {
+			if (max->length > max_size[i]) {
+				split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!split_node)
+					break;	/* return (NULL); */
+				split_node->base = max->base + max_size[i];
+				split_node->length = max->length - max_size[i];
+				max->length = max_size[i];
+				/* Put it next in the list */
+				split_node->next = max->next;
+				max->next = split_node;
+				break;
+			}
+		}
+
+		/* Now take it out of the list */
+		temp = (struct pci_resource*) *head;
+		if (temp == max) {
+			*head = max->next;
+		} else {
+			while (temp && temp->next != max) {
+				temp = temp->next;
+			}
+
+			temp->next = max->next;
+		}
+
+		max->next = NULL;
+		return(max);
+	}
+
+	/* If we get here, we couldn't find one */
+	return(NULL);
+}
+
+
+/*
+ * get_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( pciehp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node->next) {
+		dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n",
+		    __FUNCTION__, size, node, node->base, node->length);
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			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;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			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);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		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) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return(node);
+}
+
+
+/*
+ * pciehp_resource_sort_and_combine
+ *
+ * Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int pciehp_resource_sort_and_combine(struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
+
+	if (!(*head))
+		return(1);
+
+	dbg("*head->next = %p\n",(*head)->next);
+
+	if (!(*head)->next)
+		return(0);	/* Only one item on the list, already sorted! */
+
+	dbg("*head->base = 0x%x\n",(*head)->base);
+	dbg("*head->next->base = 0x%x\n",(*head)->next->base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->base > (*head)->next->base)) {
+			node1 = *head;
+			(*head) = (*head)->next;
+			node1->next = (*head)->next;
+			(*head)->next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1->next && node1->next->next) {
+			if (node1->next->base > node1->next->next->base) {
+				out_of_order++;
+				node2 = node1->next;
+				node1->next = node1->next->next;
+				node1 = node1->next;
+				node2->next = node1->next;
+				node1->next = node2;
+			} else
+				node1 = node1->next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 && node1->next) {
+		if ((node1->base + node1->length) == node1->next->base) {
+			/* Combine */
+			dbg("8..\n");
+			node1->length += node1->next->length;
+			node2 = node1->next;
+			node1->next = node1->next->next;
+			kfree(node2);
+		} else
+			node1 = node1->next;
+	}
+
+	return(0);
+}
+
+
+/**
+ * pciehp_slot_create - Creates a node and adds it to the proper bus.
+ * @busnumber - bus where new node is to be located
+ *
+ * Returns pointer to the new node or NULL if unsuccessful
+ */
+struct pci_func *pciehp_slot_create(u8 busnumber)
+{
+	struct pci_func *new_slot;
+	struct pci_func *next;
+	dbg("%s: busnumber %x\n", __FUNCTION__, busnumber);
+	new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL);
+
+	if (new_slot == NULL) {
+		return(new_slot);
+	}
+
+	memset(new_slot, 0, sizeof(struct pci_func));
+
+	new_slot->next = NULL;
+	new_slot->configured = 1;
+
+	if (pciehp_slot_list[busnumber] == NULL) {
+		pciehp_slot_list[busnumber] = new_slot;
+	} else {
+		next = pciehp_slot_list[busnumber];
+		while (next->next != NULL)
+			next = next->next;
+		next->next = new_slot;
+	}
+	return(new_slot);
+}
+
+
+/*
+ * slot_remove - Removes a node from the linked list of slots.
+ * @old_slot: slot to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int slot_remove(struct pci_func * old_slot)
+{
+	struct pci_func *next;
+
+	if (old_slot == NULL)
+		return(1);
+
+	next = pciehp_slot_list[old_slot->bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == old_slot) {
+		pciehp_slot_list[old_slot->bus] = old_slot->next;
+		pciehp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	}
+
+	while ((next->next != old_slot) && (next->next != NULL)) {
+		next = next->next;
+	}
+
+	if (next->next == old_slot) {
+		next->next = old_slot->next;
+		pciehp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * bridge_slot_remove - Removes a node from the linked list of slots.
+ * @bridge: bridge to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int bridge_slot_remove(struct pci_func *bridge)
+{
+	u8 subordinateBus, secondaryBus;
+	u8 tempBus;
+	struct pci_func *next;
+
+	if (bridge == NULL)
+		return(1);
+
+	secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
+	subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
+
+	for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
+		next = pciehp_slot_list[tempBus];
+
+		while (!slot_remove(next)) {
+			next = pciehp_slot_list[tempBus];
+		}
+	}
+
+	next = pciehp_slot_list[bridge->bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == bridge) {
+		pciehp_slot_list[bridge->bus] = bridge->next;
+		kfree(bridge);
+		return(0);
+	}
+
+	while ((next->next != bridge) && (next->next != NULL)) {
+		next = next->next;
+	}
+
+	if (next->next == bridge) {
+		next->next = bridge->next;
+		kfree(bridge);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * pciehp_slot_find - Looks for a node by bus, and device, multiple functions accessed
+ * @bus: bus to find
+ * @device: device to find
+ * @index: is 0 for first function found, 1 for the second...
+ *
+ * Returns pointer to the node if successful, %NULL otherwise.
+ */
+struct pci_func *pciehp_slot_find(u8 bus, u8 device, u8 index)
+{
+	int found = -1;
+	struct pci_func *func;
+
+	func = pciehp_slot_list[bus];
+	dbg("%s: bus %x device %x index %x\n",
+		__FUNCTION__, bus, device, index);
+	if (func != NULL) {
+		dbg("%s: func-> bus %x device %x function %x pci_dev %p\n",
+			__FUNCTION__, func->bus, func->device, func->function,
+			func->pci_dev);
+	} else
+		dbg("%s: func == NULL\n", __FUNCTION__);
+	
+	if ((func == NULL) || ((func->device == device) && (index == 0)))
+		return(func);
+
+	if (func->device == device)
+		found++;
+
+	while (func->next != NULL) {
+		func = func->next;
+
+		dbg("%s: In while loop, func-> bus %x device %x function %x pci_dev %p\n",
+			__FUNCTION__, func->bus, func->device, func->function,
+			func->pci_dev);
+		if (func->device == device)
+			found++;
+		dbg("%s: while loop, found %d, index %d\n", __FUNCTION__,
+			found, index);
+
+		if ((found == index) ||(func->function == index)) {
+			dbg("%s: Found bus %x dev %x func %x\n", __FUNCTION__,
+			func->bus, func->device, func->function);
+			return(func);
+		}
+	}
+
+	return(NULL);
+}
+
+static int is_bridge(struct pci_func * func)
+{
+	/* Check the header type */
+	if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* the following routines constitute the bulk of the 
+   hotplug controller logic
+ */
+
+
+/**
+ * board_added - Called after a board has been added to the system.
+ *
+ * Turns power on for the board
+ * Configures board
+ *
+ */
+static u32 board_added(struct pci_func * func, struct controller * ctrl)
+{
+	u8 hp_slot;
+	int index;
+	u32 temp_register = 0xFFFFFFFF;
+	u32 retval, rc = 0;
+	struct pci_func *new_func = NULL;
+	struct slot *p_slot;
+	struct resource_lists res_lists;
+
+	p_slot = pciehp_find_slot(ctrl, func->device);
+	hp_slot = func->device - ctrl->slot_device_offset;
+
+	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);
+	
+	/* Power on slot */
+	rc = p_slot->hpc_ops->power_on_slot(p_slot);
+	if (rc)
+		return -1;
+
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq(ctrl);
+	
+	dbg("%s: after power on\n", __FUNCTION__);
+
+	p_slot->hpc_ops->green_led_blink(p_slot);
+			
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq(ctrl);
+	dbg("%s: after green_led_blink", __FUNCTION__);
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	/* Wait for ~1 second */
+	dbg("%s: before long_delay\n", __FUNCTION__);
+	wait_for_ctrl_irq (ctrl);
+	dbg("%s: afterlong_delay\n", __FUNCTION__);
+
+	dbg("%s: before check link status", __FUNCTION__);
+	/*  Make this to check for link training status */
+	rc = p_slot->hpc_ops->check_lnk_status(ctrl);  
+	if (rc) {
+		err("%s: Failed to check link status\n", __FUNCTION__);
+		return -1;
+	}
+
+	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("%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_bus_read_config_dword (ctrl->pci_dev->subordinate, 
+			PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register);
+		dbg("%s: pci_bus_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("%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;
+	}
+
+	/* All F's is an empty slot or an invalid board */
+	if (temp_register != 0xFFFFFFFF) {	  /* Check for a board in the slot */
+		res_lists.io_head = ctrl->io_head;
+		res_lists.mem_head = ctrl->mem_head;
+		res_lists.p_mem_head = ctrl->p_mem_head;
+		res_lists.bus_head = ctrl->bus_head;
+		res_lists.irqs = NULL;
+
+		rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0);
+		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;
+		ctrl->bus_head = res_lists.bus_head;
+
+		pciehp_resource_sort_and_combine(&(ctrl->mem_head));
+		pciehp_resource_sort_and_combine(&(ctrl->p_mem_head));
+		pciehp_resource_sort_and_combine(&(ctrl->io_head));
+		pciehp_resource_sort_and_combine(&(ctrl->bus_head));
+
+		if (rc) {
+			/* Wait for exclusive access to hardware */
+			down(&ctrl->crit_sect);
+
+			/* Turn off slot, turn on Amber LED, turn off Green LED */
+			retval = p_slot->hpc_ops->power_off_slot(p_slot);   
+			/* In PCI Express, just power off slot */
+			if (retval) {
+				err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
+				return retval;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq(ctrl);
+
+			p_slot->hpc_ops->green_led_off(p_slot);   
+			
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq(ctrl);
+
+			/* Turn on Amber LED */
+			retval = p_slot->hpc_ops->set_attention_status(p_slot, 1);   
+			if (retval) {
+				err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
+				return retval;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq(ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&ctrl->crit_sect);
+
+			return(rc);
+		}
+		pciehp_save_slot_config(ctrl, func);
+
+		func->status = 0;
+		func->switch_save = 0x10;
+		func->is_a_board = 0x01;
+
+		/* Next, we will instantiate the linux pci_dev structures 
+		 * (with appropriate driver notification, if already present) 
+		 */
+		index = 0;
+		do {
+			new_func = pciehp_slot_find(ctrl->slot_bus, func->device, index++);
+			if (new_func && !new_func->pci_dev) {
+				dbg("%s:call pci_hp_configure_dev, func %x\n", 
+					__FUNCTION__, index);
+				pciehp_configure_device(ctrl, new_func);
+			}
+		} while (new_func);
+
+		/* Wait for exclusive access to hardware */
+		down(&ctrl->crit_sect);
+
+		p_slot->hpc_ops->green_led_on(p_slot);
+
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq(ctrl);
+
+
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+
+	} else {
+		/* Wait for exclusive access to hardware */
+		down(&ctrl->crit_sect);
+
+		/* Turn off slot, turn on Amber LED, turn off Green LED */
+		retval = p_slot->hpc_ops->power_off_slot(p_slot);   
+		/* In PCI Express, just power off slot */
+		if (retval) {
+			err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
+			return retval;
+		}
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq(ctrl);
+
+		p_slot->hpc_ops->green_led_off(p_slot);   
+		
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq(ctrl);
+
+		/* Turn on Amber LED */
+		retval = p_slot->hpc_ops->set_attention_status(p_slot, 1);   
+		if (retval) {
+			err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
+			return retval;
+		}
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq(ctrl);
+
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+
+		return(rc);
+	}
+	return 0;
+}
+
+
+/**
+ * remove_board - Turns off slot and LED's
+ *
+ */
+static u32 remove_board(struct pci_func *func, struct controller *ctrl)
+{
+	int index;
+	u8 skip = 0;
+	u8 device;
+	u8 hp_slot;
+	u32 rc;
+	struct resource_lists res_lists;
+	struct pci_func *temp_func;
+	struct slot *p_slot;
+
+	if (func == NULL)
+		return(1);
+
+	if (pciehp_unconfigure_device(func))
+		return(1);
+
+	device = func->device;
+
+	hp_slot = func->device - ctrl->slot_device_offset;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+
+	if ((ctrl->add_support) &&
+		!(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) {
+		/* Here we check to see if we've saved any of the board's
+		 * resources already.  If so, we'll skip the attempt to
+		 * determine what's being used.
+		 */
+		index = 0;
+
+		temp_func = func;
+
+		while ((temp_func = pciehp_slot_find(temp_func->bus, temp_func->device, 
+			index++))) {
+			if (temp_func->bus_head || temp_func->mem_head
+			    || temp_func->p_mem_head || temp_func->io_head) {
+				skip = 1;
+				break;
+			}
+		}
+
+		if (!skip)
+			rc = pciehp_save_used_resources(ctrl, func, DISABLE_CARD);
+	}
+	/* Change status to shutdown */
+	if (func->is_a_board)
+		func->status = 0x01;
+	func->configured = 0;
+
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	/* Power off slot */
+	rc = p_slot->hpc_ops->power_off_slot(p_slot);
+	if (rc) {
+		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq(ctrl);
+
+	/* Turn off Green LED */
+	p_slot->hpc_ops->green_led_off(p_slot);
+	
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq(ctrl);
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	if (ctrl->add_support) {
+		while (func) {
+			res_lists.io_head = ctrl->io_head;
+			res_lists.mem_head = ctrl->mem_head;
+			res_lists.p_mem_head = ctrl->p_mem_head;
+			res_lists.bus_head = ctrl->bus_head;
+
+			dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n",
+				 func->bus, func->device, func->function);
+
+			pciehp_return_board_resources(func, &res_lists);
+
+			ctrl->io_head = res_lists.io_head;
+			ctrl->mem_head = res_lists.mem_head;
+			ctrl->p_mem_head = res_lists.p_mem_head;
+			ctrl->bus_head = res_lists.bus_head;
+
+			pciehp_resource_sort_and_combine(&(ctrl->mem_head));
+			pciehp_resource_sort_and_combine(&(ctrl->p_mem_head));
+			pciehp_resource_sort_and_combine(&(ctrl->io_head));
+			pciehp_resource_sort_and_combine(&(ctrl->bus_head));
+
+			if (is_bridge(func)) {
+				dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
+					ctrl->seg, func->bus, func->device, func->function);
+				bridge_slot_remove(func);
+			} else
+				dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n",
+					 ctrl->seg, func->bus, func->device, func->function);
+				slot_remove(func);
+
+			func = pciehp_slot_find(ctrl->slot_bus, device, 0);
+		}
+
+		/* Setup slot structure with entry for empty slot */
+		func = pciehp_slot_create(ctrl->slot_bus);
+
+		if (func == NULL) {
+			return(1);
+		}
+
+		func->bus = ctrl->slot_bus;
+		func->device = device;
+		func->function = 0;
+		func->configured = 0;
+		func->switch_save = 0x10;
+		func->is_a_board = 0;
+	}
+	return 0;
+}
+
+
+static void pushbutton_helper_thread (unsigned long data)
+{
+	pushbutton_pending = data;
+	up(&event_semaphore);
+}
+
+
+/* this is the main worker thread */
+static int event_thread(void* data)
+{
+	struct controller *ctrl;
+	lock_kernel();
+	daemonize();
+
+	/* New name */
+	strcpy(current->comm, "pciehpd_event");
+	
+	unlock_kernel();
+
+	while (1) {
+		dbg("!!!!event_thread sleeping\n");
+		down_interruptible (&event_semaphore);
+		dbg("event_thread woken finished = %d\n", event_finished);
+		if (event_finished || signal_pending(current))
+			break;
+		/* Do stuff here */
+		if (pushbutton_pending)
+			pciehp_pushbutton_thread(pushbutton_pending);
+		else
+			for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
+				interrupt_event_handler(ctrl);
+	}
+	dbg("event_thread signals exit\n");
+	up(&event_exit);
+	return 0;
+}
+
+int pciehp_event_start_thread (void)
+{
+	int pid;
+
+	/* Initialize our semaphores */
+	init_MUTEX_LOCKED(&event_exit);
+	event_finished=0;
+
+	init_MUTEX_LOCKED(&event_semaphore);
+	pid = kernel_thread(event_thread, 0, 0);
+
+	if (pid < 0) {
+		err ("Can't start up our event thread\n");
+		return -1;
+	}
+	dbg("Our event thread pid = %d\n", pid);
+	return 0;
+}
+
+
+void pciehp_event_stop_thread (void)
+{
+	event_finished = 1;
+	dbg("event_thread finish command given\n");
+	up(&event_semaphore);
+	dbg("wait for event_thread to exit\n");
+	down(&event_exit);
+}
+
+
+static int update_slot_info (struct slot *slot)
+{
+	struct hotplug_slot_info *info;
+	char buffer[SLOT_NAME_SIZE];
+	int result;
+
+	info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot);
+
+	slot->hpc_ops->get_power_status(slot, &(info->power_status));
+	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
+	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
+	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
+
+	result = pci_hp_change_slot_info(buffer, info);
+	kfree (info);
+	return result;
+}
+
+static void interrupt_event_handler(struct controller *ctrl)
+{
+	int loop = 0;
+	int change = 1;
+	struct pci_func *func;
+	u8 hp_slot;
+	u8 getstatus;
+	struct slot *p_slot;
+
+	while (change) {
+		change = 0;
+
+		for (loop = 0; loop < 10; loop++) {
+			if (ctrl->event_queue[loop].event_type != 0) {
+				hp_slot = ctrl->event_queue[loop].hp_slot;
+
+				func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+				p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+				dbg("hp_slot %d, func %p, p_slot %p\n", hp_slot, func, p_slot);
+
+				if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
+					dbg("button cancel\n");
+					del_timer(&p_slot->task_event);
+
+					switch (p_slot->state) {
+					case BLINKINGOFF_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+
+						p_slot->hpc_ops->green_led_on(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq(ctrl);
+
+						p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq(ctrl);
+
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+						break;
+					case BLINKINGON_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+
+						p_slot->hpc_ops->green_led_off(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq(ctrl);
+
+						p_slot->hpc_ops->set_attention_status(p_slot, 0);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq(ctrl);
+
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+
+						break;
+					default:
+						warn("Not a valid state\n");
+						return;
+					}
+					info(msg_button_cancel, p_slot->number);
+					p_slot->state = STATIC_STATE;
+				}
+				/* ***********Button Pressed (No action on 1st press...) */
+				else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
+					dbg("Button pressed\n");
+
+					p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+					if (getstatus) {
+						/* Slot is on */
+						dbg("Slot is on\n");
+						p_slot->state = BLINKINGOFF_STATE;
+						info(msg_button_off, p_slot->number);
+					} else {
+						/* Slot is off */
+						dbg("Slot is off\n");
+						p_slot->state = BLINKINGON_STATE;
+						info(msg_button_on, p_slot->number);
+					}
+
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					/* blink green LED and turn off amber */
+					p_slot->hpc_ops->green_led_blink(p_slot);
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq(ctrl);
+					
+					p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq(ctrl);
+
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+
+					init_timer(&p_slot->task_event);
+					p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
+					p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
+					p_slot->task_event.data = (unsigned long) p_slot;
+
+					dbg("add_timer p_slot = %p\n", (void *) p_slot);
+					add_timer(&p_slot->task_event);
+				}
+				/***********POWER FAULT********************/
+				else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
+					dbg("power fault\n");
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					p_slot->hpc_ops->set_attention_status(p_slot, 1);
+					p_slot->hpc_ops->green_led_off(p_slot);
+
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+				} else {
+					/* refresh notification */
+					if (p_slot)
+						update_slot_info(p_slot);
+				}
+
+				ctrl->event_queue[loop].event_type = 0;
+
+				change = 1;
+			}
+		}		/* End of FOR loop */
+	}
+
+	return;
+}
+
+
+/**
+ * pciehp_pushbutton_thread
+ *
+ * Scheduled procedure to handle blocking stuff for the pushbuttons
+ * Handles all pending events and exits.
+ *
+ */
+void pciehp_pushbutton_thread (unsigned long slot)
+{
+	struct slot *p_slot = (struct slot *) slot;
+	u8 getstatus;
+	int rc;
+	
+	pushbutton_pending = 0;
+
+	if (!p_slot) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return;
+	}
+
+	p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (getstatus) {
+		p_slot->state = POWEROFF_STATE;
+		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		if (pciehp_disable_slot(p_slot)) {
+			/* Wait for exclusive access to hardware */
+			down(&p_slot->ctrl->crit_sect);
+
+			/* Turn on the Attention LED */
+			rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
+			if (rc) {
+				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
+				return;
+			}
+	
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot->ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&p_slot->ctrl->crit_sect);
+		}
+		p_slot->state = STATIC_STATE;
+	} else {
+		p_slot->state = POWERON_STATE;
+		dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		if (pciehp_enable_slot(p_slot)) {
+			/* Wait for exclusive access to hardware */
+			down(&p_slot->ctrl->crit_sect);
+
+			/* Turn off the green LED */
+			rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
+			if (rc) {
+				err("%s: Issue of Set Attn Indicator On command failed\n", __FUNCTION__);
+				return;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot->ctrl);
+			
+			p_slot->hpc_ops->green_led_off(p_slot);
+
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot->ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&p_slot->ctrl->crit_sect);
+		}
+		p_slot->state = STATIC_STATE;
+	}
+
+	return;
+}
+
+
+int pciehp_enable_slot (struct slot *p_slot)
+{
+	u8 getstatus = 0;
+	int rc;
+	struct pci_func *func;
+
+	func = pciehp_slot_find(p_slot->bus, p_slot->device, 0);
+	if (!func) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return (1);
+	}
+
+	/* Check to see if (latch closed, card present, power off) */
+	down(&p_slot->ctrl->crit_sect);
+	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (rc || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+
+	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	if (rc || getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+
+	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (rc || getstatus) {
+		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+	up(&p_slot->ctrl->crit_sect);
+
+	slot_remove(func);
+
+	func = pciehp_slot_create(p_slot->bus);
+	if (func == NULL)
+		return (1);
+
+	func->bus = p_slot->bus;
+	func->device = p_slot->device;
+	func->function = 0;
+	func->configured = 0;
+	func->is_a_board = 1;
+
+	/* We have to save the presence info for these slots */
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	func->switch_save = !getstatus? 0x10:0;
+
+	rc = board_added(func, p_slot->ctrl);
+	if (rc) {
+		if (is_bridge(func))
+			bridge_slot_remove(func);
+		else
+			slot_remove(func);
+
+		/* Setup slot structure with entry for empty slot */
+		func = pciehp_slot_create(p_slot->bus);
+		if (func == NULL)
+			return (1);	/* Out of memory */
+
+		func->bus = p_slot->bus;
+		func->device = p_slot->device;
+		func->function = 0;
+		func->configured = 0;
+		func->is_a_board = 1;
+
+		/* We have to save the presence info for these slots */
+		p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+		func->switch_save = !getstatus? 0x10:0;
+	}
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return rc;
+}
+
+
+int pciehp_disable_slot (struct slot *p_slot)
+{
+	u8 class_code, header_type, BCR;
+	u8 index = 0;
+	u8 getstatus = 0;
+	u32 rc = 0;
+	int ret = 0;
+	unsigned int devfn;
+	struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate;
+	struct pci_func *func;
+
+	if (!p_slot->ctrl)
+		return (1);
+
+	/* Check to see if (latch closed, card present, power on) */
+	down(&p_slot->ctrl->crit_sect);
+
+	ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (ret || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+
+	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	if (ret || getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+
+	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (ret || !getstatus) {
+		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+	up(&p_slot->ctrl->crit_sect);
+
+	func = pciehp_slot_find(p_slot->bus, p_slot->device, index++);
+
+	/* Make sure there are no video controllers here
+	 * for all func of p_slot
+	 */
+	while (func && !rc) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		/* Check the Class Code */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+		if (rc)
+			return rc;
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY) {
+			/* Display/Video adapter (not supported) */
+			rc = REMOVE_NOT_SUPPORTED;
+		} else {
+			/* See if it's a bridge */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+			if (rc)
+				return rc;
+
+			/* If it's a bridge, check the VGA Enable bit */
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
+				if (rc)
+					return rc;
+
+				/* If the VGA Enable bit is set, remove isn't supported */
+				if (BCR & PCI_BRIDGE_CTL_VGA) {
+					rc = REMOVE_NOT_SUPPORTED;
+				}
+			}
+		}
+
+		func = pciehp_slot_find(p_slot->bus, p_slot->device, index++);
+	}
+
+	func = pciehp_slot_find(p_slot->bus, p_slot->device, 0);
+	if ((func != NULL) && !rc) {
+		rc = remove_board(func, p_slot->ctrl);
+	} else if (!rc)
+		rc = 1;
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return(rc);
+}
+
+
+/**
+ * configure_new_device - Configures the PCI header information of one board.
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Returns 0 if success
+ *
+ */
+static u32 configure_new_device (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev)
+{
+	u8 temp_byte, function, max_functions, stop_it;
+	int rc;
+	u32 ID;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	int index;
+
+	new_slot = func;
+
+	dbg("%s\n", __FUNCTION__);
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+
+	/* Check for Multi-function device */
+	rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte);
+	if (rc) {
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if (temp_byte & 0x80)	/* Multi-function device */
+		max_functions = 8;
+	else
+		max_functions = 1;
+
+	function = 0;
+
+	do {
+		rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev);
+
+		if (rc) {
+			dbg("configure_new_function failed %d\n",rc);
+			index = 0;
+
+			while (new_slot) {
+				new_slot = pciehp_slot_find(new_slot->bus, new_slot->device, index++);
+
+				if (new_slot)
+					pciehp_return_board_resources(new_slot, resources);
+			}
+
+			return(rc);
+		}
+
+		function++;
+
+		stop_it = 0;
+
+		/*  The following loop skips to the next present function
+		 *  and creates a board structure
+		 */
+
+		while ((function < max_functions) && (!stop_it)) {
+			pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
+
+			if (ID == 0xFFFFFFFF) {	  /* There's nothing there. */
+				function++;
+			} else {  /* There's something there */
+				/* Setup slot structure. */
+				new_slot = pciehp_slot_create(func->bus);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					return(1);
+				}
+
+				new_slot->bus = func->bus;
+				new_slot->device = func->device;
+				new_slot->function = function;
+				new_slot->is_a_board = 1;
+				new_slot->status = 0;
+
+				stop_it++;
+			}
+		}
+
+	} while (function < max_functions);
+	dbg("returning from configure_new_device\n");
+
+	return 0;
+}
+
+
+/*
+ * Configuration logic that involves the hotplug data structures and 
+ * their bookkeeping
+ */
+
+
+/**
+ * configure_new_function - Configures the PCI header information of one device
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Calls itself recursively for bridged devices.
+ * Returns 0 if success
+ *
+ */
+static int configure_new_function (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev)
+{
+	int cloop;
+	u8 temp_byte;
+	u8 device;
+	u8 class_code;
+	u16 temp_word;
+	u32 rc;
+	u32 temp_register;
+	u32 base;
+	u32 ID;
+	unsigned int devfn;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_resource *hold_mem_node;
+	struct pci_resource *hold_p_mem_node;
+	struct pci_resource *hold_IO_node;
+	struct pci_resource *hold_bus_node;
+	struct irq_mapping irqs;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct resource_lists temp_resources;
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	/* Check for Bridge */
+	rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte);
+	if (rc)
+		return rc;
+	dbg("%s: bus %x dev %x func %x temp_byte = %x\n", __FUNCTION__,
+		func->bus, func->device, func->function, temp_byte);
+
+	if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+		/* Set Primary bus */
+		dbg("set Primary bus = 0x%x\n", func->bus);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
+		if (rc)
+			return rc;
+
+		/* Find range of busses to use */
+		bus_node = get_max_resource(&resources->bus_head, 1L);
+
+		/* If we don't have any busses to allocate, we can't continue */
+		if (!bus_node) {
+			err("Got NO bus resource to use\n");
+			return -ENOMEM;
+		}
+		dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length);
+
+		/* Set Secondary bus */
+		dbg("set Secondary bus = 0x%x\n", temp_byte);
+		dbg("func->bus %x\n", func->bus);
+
+		temp_byte = (u8)bus_node->base;
+		dbg("set Secondary bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* set subordinate bus */
+		temp_byte = (u8)(bus_node->base + bus_node->length - 1);
+		dbg("set subordinate bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+		if (rc)
+			return rc;
+
+		/* Setup the IO, memory, and prefetchable windows */
+
+		io_node = get_max_resource(&(resources->io_head), 0x1000L);
+		if (io_node) {
+			dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next);
+		}
+
+		mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+		if (mem_node) {
+			dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next);
+		}
+
+		if (resources->p_mem_head)
+			p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L);
+		else {
+			/*
+			 * In some platform implementation, MEM and PMEM are not
+			 *  distinguished, and hence ACPI _CRS has only MEM entries
+			 *  for both MEM and PMEM.
+			 */
+			dbg("using MEM for PMEM\n");
+			p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+		}
+		if (p_mem_node) {
+			dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next);
+		}
+
+		/* Set up the IRQ info */
+		if (!resources->irqs) {
+			irqs.barber_pole = 0;
+			irqs.interrupt[0] = 0;
+			irqs.interrupt[1] = 0;
+			irqs.interrupt[2] = 0;
+			irqs.interrupt[3] = 0;
+			irqs.valid_INT = 0;
+		} else {
+			irqs.barber_pole = resources->irqs->barber_pole;
+			irqs.interrupt[0] = resources->irqs->interrupt[0];
+			irqs.interrupt[1] = resources->irqs->interrupt[1];
+			irqs.interrupt[2] = resources->irqs->interrupt[2];
+			irqs.interrupt[3] = resources->irqs->interrupt[3];
+			irqs.valid_INT = resources->irqs->valid_INT;
+		}
+
+		/* Set up resource lists that are now aligned on top and bottom
+		 * for anything behind the bridge.
+		 */
+		temp_resources.bus_head = bus_node;
+		temp_resources.io_head = io_node;
+		temp_resources.mem_head = mem_node;
+		temp_resources.p_mem_head = p_mem_node;
+		temp_resources.irqs = &irqs;
+
+		/* Make copies of the nodes we are going to pass down so that
+		 * if there is a problem,we can just use these to free resources
+		 */
+		hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+		if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
+			if (hold_bus_node)
+				kfree(hold_bus_node);
+			if (hold_IO_node)
+				kfree(hold_IO_node);
+			if (hold_mem_node)
+				kfree(hold_mem_node);
+			if (hold_p_mem_node)
+				kfree(hold_p_mem_node);
+
+			return(1);
+		}
+
+		memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
+
+		bus_node->base += 1;
+		bus_node->length -= 1;
+		bus_node->next = NULL;
+
+		/* If we have IO resources copy them and fill in the bridge's
+		 * IO range registers
+		 */
+		if (io_node) {
+			memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
+			io_node->next = NULL;
+
+			/* set IO base and Limit registers */
+			RES_CHECK(io_node->base, 8);
+			temp_byte = (u8)(io_node->base >> 8);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+			RES_CHECK(io_node->base + io_node->length - 1, 8);
+			temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+		} else {
+			kfree(hold_IO_node);
+			hold_IO_node = NULL;
+		}
+
+		/* If we have memory resources copy them and fill in the bridge's
+		 * memory range registers.  Otherwise, fill in the range
+		 * registers with values that disable them.
+		 */
+		if (mem_node) {
+			memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
+			mem_node->next = NULL;
+
+			/* set Mem base and Limit registers */
+			RES_CHECK(mem_node->base, 16);
+			temp_word = (u32)(mem_node->base >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			RES_CHECK(mem_node->base + mem_node->length - 1, 16);
+			temp_word = (u32)((mem_node->base + mem_node->length - 1) >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_mem_node);
+			hold_mem_node = NULL;
+		}
+
+		/* If we have prefetchable memory resources copy them and 
+		 * fill in the bridge's memory range registers.  Otherwise,
+		 * fill in the range registers with values that disable them.
+		 */
+		if (p_mem_node) {
+			memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
+			p_mem_node->next = NULL;
+
+			/* Set Pre Mem base and Limit registers */
+			RES_CHECK(p_mem_node->base, 16);
+			temp_word = (u32)(p_mem_node->base >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16);
+			temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_p_mem_node);
+			hold_p_mem_node = NULL;
+		}
+
+		/* Adjust this to compensate for extra adjustment in first loop */
+		irqs.barber_pole--;
+
+		rc = 0;
+
+		/* Here we actually find the devices and configure them */
+		for (device = 0; (device <= 0x1F) && !rc; device++) {
+			irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
+
+			ID = 0xFFFFFFFF;
+			pci_bus->number = hold_bus_node->base;
+			pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
+			pci_bus->number = func->bus;
+
+			if (ID != 0xFFFFFFFF) {	  /*  device Present */
+				/* Setup slot structure. */
+				new_slot = pciehp_slot_create(hold_bus_node->base);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					rc = -ENOMEM;
+					continue;
+				}
+
+				new_slot->bus = hold_bus_node->base;
+				new_slot->device = device;
+				new_slot->function = 0;
+				new_slot->is_a_board = 1;
+				new_slot->status = 0;
+
+				rc = configure_new_device(ctrl, new_slot, 1, &temp_resources, func->bus, func->device);
+				dbg("configure_new_device rc=0x%x\n",rc);
+			}	/* End of IF (device in slot?) */
+		}		/* End of FOR loop */
+
+		if (rc) {
+			pciehp_destroy_resource_list(&temp_resources);
+
+			return_resource(&(resources->bus_head), hold_bus_node);
+			return_resource(&(resources->io_head), hold_IO_node);
+			return_resource(&(resources->mem_head), hold_mem_node);
+			return_resource(&(resources->p_mem_head), hold_p_mem_node);
+			return(rc);
+		}
+
+		/* Save the interrupt routing information */
+		if (resources->irqs) {
+			resources->irqs->interrupt[0] = irqs.interrupt[0];
+			resources->irqs->interrupt[1] = irqs.interrupt[1];
+			resources->irqs->interrupt[2] = irqs.interrupt[2];
+			resources->irqs->interrupt[3] = irqs.interrupt[3];
+			resources->irqs->valid_INT = irqs.valid_INT;
+		} else if (!behind_bridge) {
+			/* We need to hook up the interrupts here */
+			for (cloop = 0; cloop < 4; cloop++) {
+				if (irqs.valid_INT & (0x01 << cloop)) {
+					rc = pciehp_set_irq(func->bus, func->device,
+							   0x0A + cloop, irqs.interrupt[cloop]);
+					if (rc) {
+						pciehp_destroy_resource_list (&temp_resources);
+						return_resource(&(resources->bus_head), hold_bus_node);
+						return_resource(&(resources->io_head), hold_IO_node);
+						return_resource(&(resources->mem_head), hold_mem_node);
+						return_resource(&(resources->p_mem_head), hold_p_mem_node);
+						return rc;
+					}
+				}
+			}	/* end of for loop */
+		}
+
+		/* Return unused bus resources
+		 * First use the temporary node to store information for the board
+		 */
+		if (hold_bus_node && bus_node && temp_resources.bus_head) {
+			hold_bus_node->length = bus_node->base - hold_bus_node->base;
+
+			hold_bus_node->next = func->bus_head;
+			func->bus_head = hold_bus_node;
+
+			temp_byte = (u8)(temp_resources.bus_head->base - 1);
+
+			/* Set subordinate bus */
+			dbg("re-set subordinate bus = 0x%x\n", temp_byte);
+
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+
+			if (temp_resources.bus_head->length == 0) {
+				kfree(temp_resources.bus_head);
+				temp_resources.bus_head = NULL;
+			} else {
+				dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
+					func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length);
+				return_resource(&(resources->bus_head), temp_resources.bus_head);
+			}
+		}
+
+		/* If we have IO space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_IO_node && temp_resources.io_head) {
+			io_node = do_pre_bridge_resource_split(&(temp_resources.io_head),
+							       &hold_IO_node, 0x1000);
+
+			/* Check if we were able to split something off */
+			if (io_node) {
+				hold_IO_node->base = io_node->base + io_node->length;
+
+				RES_CHECK(hold_IO_node->base, 8);
+				temp_byte = (u8)((hold_IO_node->base) >> 8);
+				rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+				return_resource(&(resources->io_head), io_node);
+			}
+
+			io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000);
+
+			/*  Check if we were able to split something off */
+			if (io_node) {
+				/* First use the temporary node to store information for the board */
+				hold_IO_node->length = io_node->base - hold_IO_node->base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_IO_node->length) {
+					hold_IO_node->next = func->io_head;
+					func->io_head = hold_IO_node;
+
+					RES_CHECK(io_node->base - 1, 8);
+					temp_byte = (u8)((io_node->base - 1) >> 8);
+					rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&(resources->io_head), io_node);
+				} else {
+					/* It doesn't need any IO */
+					temp_byte = 0x00;
+					rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&(resources->io_head), io_node);
+					kfree(hold_IO_node);
+				}
+			} else {
+				/* It used most of the range */
+				hold_IO_node->next = func->io_head;
+				func->io_head = hold_IO_node;
+			}
+		} else if (hold_IO_node) {
+			/* It used the whole range */
+			hold_IO_node->next = func->io_head;
+			func->io_head = hold_IO_node;
+		}
+
+		/* If we have memory space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_mem_node && temp_resources.mem_head) {
+			mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				hold_mem_node->base = mem_node->base + mem_node->length;
+
+				RES_CHECK(hold_mem_node->base, 16);
+				temp_word = (u32)((hold_mem_node->base) >> 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+				return_resource(&(resources->mem_head), mem_node);
+			}
+
+			mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_mem_node->length = mem_node->base - hold_mem_node->base;
+
+				if (hold_mem_node->length) {
+					hold_mem_node->next = func->mem_head;
+					func->mem_head = hold_mem_node;
+
+					/* Configure end address */
+					RES_CHECK(mem_node->base - 1, 16);
+					temp_word = (u32)((mem_node->base - 1) >> 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					/* Return unused resources to the pool */
+					return_resource(&(resources->mem_head), mem_node);
+				} else {
+					/* It doesn't need any Mem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->mem_head), mem_node);
+					kfree(hold_mem_node);
+				}
+			} else {
+				/* It used most of the range */
+				hold_mem_node->next = func->mem_head;
+				func->mem_head = hold_mem_node;
+			}
+		} else if (hold_mem_node) {
+			/* It used the whole range */
+			hold_mem_node->next = func->mem_head;
+			func->mem_head = hold_mem_node;
+		}
+
+		/* If we have prefetchable memory space available and there is some 
+		 * left at the end, return the unused portion
+		 */
+		if (hold_p_mem_node && temp_resources.p_mem_head) {
+			p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
+								  &hold_p_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				hold_p_mem_node->base = p_mem_node->base + p_mem_node->length;
+
+				RES_CHECK(hold_p_mem_node->base, 16);
+				temp_word = (u32)((hold_p_mem_node->base) >> 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+				return_resource(&(resources->p_mem_head), p_mem_node);
+			}
+
+			p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_p_mem_node->length) {
+					hold_p_mem_node->next = func->p_mem_head;
+					func->p_mem_head = hold_p_mem_node;
+
+					RES_CHECK(p_mem_node->base - 1, 16);
+					temp_word = (u32)((p_mem_node->base - 1) >> 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->p_mem_head), p_mem_node);
+				} else {
+					/* It doesn't need any PMem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->p_mem_head), p_mem_node);
+					kfree(hold_p_mem_node);
+				}
+			} else {
+				/* It used the most of the range */
+				hold_p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = hold_p_mem_node;
+			}
+		} else if (hold_p_mem_node) {
+			/* It used the whole range */
+			hold_p_mem_node->next = func->p_mem_head;
+			func->p_mem_head = hold_p_mem_node;
+		}
+
+		/* We should be configuring an IRQ and the bridge's base address
+		 * registers if it needs them.  Although we have never seen such
+		 * a device
+		 */
+
+		pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+
+		dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, 
+			func->device, func->function);
+	} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+		/* Standard device */
+		u64	base64;
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY)
+			return (DEVICE_TYPE_NOT_SUPPORTED);
+
+		/* Figure out IO and memory needs */
+		for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
+			temp_register = 0xFFFFFFFF;
+
+			rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+			rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register);
+			dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, func->bus, func->device, func->function);
+
+			if (!temp_register)
+				continue;
+
+			base64 = 0L;
+			if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) {
+				/* Map IO */
+
+				/* Set base = amount of IO space */
+				base = temp_register & 0xFFFFFFFC;
+				base = ~base + 1;
+
+				dbg("NEED IO length(0x%x)\n", base);
+				io_node = get_io_resource(&(resources->io_head),(ulong)base);
+
+				/* Allocate the resource to the board */
+				if (io_node) {
+					dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length);
+					base = (u32)io_node->base;
+					io_node->next = func->io_head;
+					func->io_head = io_node;
+				} else {
+					err("Got NO IO resource(length=0x%x)\n", base);
+					return -ENOMEM;
+				}
+			} else {	/* Map MEM */
+				int prefetchable = 1;
+				struct pci_resource **res_node = &func->p_mem_head;
+				char *res_type_str = "PMEM";
+				u32	temp_register2;
+
+				if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) {
+					prefetchable = 0;
+					res_node = &func->mem_head;
+					res_type_str++;
+				}
+
+				base = temp_register & 0xFFFFFFF0;
+				base = ~base + 1;
+
+				switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+				case PCI_BASE_ADDRESS_MEM_TYPE_32:
+					dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base);
+
+					if (prefetchable && resources->p_mem_head)
+						mem_node=get_resource(&(resources->p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node=get_resource(&(resources->mem_head), (ulong)base);
+					}
+
+					/* Allocate the resource to the board */
+					if (mem_node) {
+						base = (u32)mem_node->base; 
+						mem_node->next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+					} else {
+						err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				case PCI_BASE_ADDRESS_MEM_TYPE_64:
+					rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+					dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, temp_register, base);
+
+					if (prefetchable && resources->p_mem_head)
+						mem_node = get_resource(&(resources->p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node = get_resource(&(resources->mem_head), (ulong)base);
+					}
+
+					/* Allocate the resource to the board */
+					if (mem_node) {
+						base64 = mem_node->base; 
+						mem_node->next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), (u32)base64, mem_node->length);
+					} else {
+						err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				default:
+					dbg("reserved BAR type=0x%x\n", temp_register);
+					break;
+				}
+
+			}
+
+			if (base64) {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+				cloop += 4;
+				base64 >>= 32;
+
+				if (base64) {
+					dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64);
+					base64 = 0x0L;
+				}
+
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+			} else {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base);
+			}
+		}		/* End of base register loop */
+
+		/* Disable ROM base Address */
+		temp_word = 0x00L;
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word);
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+		if (rc)
+			return rc;
+
+		pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+
+		dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function);
+	}			/* End of Not-A-Bridge else */
+	else {
+		/* It's some strange type of PCI adapter (Cardbus?) */
+		return(DEVICE_TYPE_NOT_SUPPORTED);
+	}
+
+	func->configured = 1;
+	
+	dbg("%s: exit\n", __FUNCTION__);
+
+	return 0;
+}
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp_hpc.c linux-2.4.27-pre3/drivers/hotplug/pciehp_hpc.c
--- linux-2.4.26/drivers/hotplug/pciehp_hpc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pciehp_hpc.c	2004-05-18 16:52:46.000000000 +0000
@@ -0,0 +1,1504 @@
+/*
+ * PCI Express PCI Hot Plug Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include "pciehp.h"
+
+#ifdef DEBUG
+#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
+#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
+#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
+#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
+#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
+#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
+/* Redefine this flagword to set debug level */
+#define DEBUG_LEVEL            DBG_K_STANDARD
+
+#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
+
+#define DBG_PRINT( dbg_flags, args... )              	 \
+	do {                                             \
+	  if ( DEBUG_LEVEL & ( dbg_flags ) )             \
+	  {                                              \
+	    int len;                                     \
+	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
+		  __FILE__, __LINE__, __FUNCTION__ );    \
+	    sprintf( __dbg_str_buf + len, args );        \
+	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
+	  }                                              \
+	} while (0)
+
+#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
+#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
+#else
+#define DEFINE_DBG_BUFFER
+#define DBG_ENTER_ROUTINE
+#define DBG_LEAVE_ROUTINE
+#endif				/* DEBUG */
+
+struct ctrl_reg {
+	u8 cap_id;
+	u8 nxt_ptr;
+	u16 cap_reg;
+	u32 dev_cap;
+	u16 dev_ctrl;
+	u16 dev_status;
+	u32 lnk_cap;
+	u16 lnk_ctrl;
+	u16 lnk_status;
+	u32 slot_cap;
+	u16 slot_ctrl;
+	u16 slot_status;
+	u16 root_ctrl;
+	u16 rsvp;
+	u32 root_status;
+} __attribute__ ((packed));
+
+/* offsets to the controller registers based on the above structure layout */
+enum ctrl_offsets {
+	PCIECAPID	=	offsetof(struct ctrl_reg, cap_id),
+	NXTCAPPTR	=	offsetof(struct ctrl_reg, nxt_ptr),
+	CAPREG		=	offsetof(struct ctrl_reg, cap_reg),
+	DEVCAP		=	offsetof(struct ctrl_reg, dev_cap),
+	DEVCTRL		=	offsetof(struct ctrl_reg, dev_ctrl),
+	DEVSTATUS	=	offsetof(struct ctrl_reg, dev_status),
+	LNKCAP		=	offsetof(struct ctrl_reg, lnk_cap),
+	LNKCTRL		=	offsetof(struct ctrl_reg, lnk_ctrl),
+	LNKSTATUS	=	offsetof(struct ctrl_reg, lnk_status),
+	SLOTCAP		=	offsetof(struct ctrl_reg, slot_cap),
+	SLOTCTRL	=	offsetof(struct ctrl_reg, slot_ctrl),
+	SLOTSTATUS	=	offsetof(struct ctrl_reg, slot_status),
+	ROOTCTRL	=	offsetof(struct ctrl_reg, root_ctrl),
+	ROOTSTATUS	=	offsetof(struct ctrl_reg, root_status),
+};
+static int pcie_cap_base = 0;	/* Base of the PCI Express capability item structure */
+
+#define PCIE_CAP_ID	( pcie_cap_base + PCIECAPID )
+#define NXT_CAP_PTR	( pcie_cap_base + NXTCAPPTR )
+#define CAP_REG		( pcie_cap_base + CAPREG )
+#define DEV_CAP		( pcie_cap_base + DEVCAP )
+#define DEV_CTRL	( pcie_cap_base + DEVCTRL )
+#define DEV_STATUS	( pcie_cap_base + DEVSTATUS )
+#define LNK_CAP		( pcie_cap_base + LNKCAP )
+#define LNK_CTRL	( pcie_cap_base + LNKCTRL )
+#define LNK_STATUS	( pcie_cap_base + LNKSTATUS )
+#define SLOT_CAP	( pcie_cap_base + SLOTCAP )
+#define SLOT_CTRL	( pcie_cap_base + SLOTCTRL )
+#define SLOT_STATUS	( pcie_cap_base + SLOTSTATUS )
+#define ROOT_CTRL	( pcie_cap_base + ROOTCTRL )
+#define ROOT_STATUS	( pcie_cap_base + ROOTSTATUS )
+
+#define hp_register_read_word(pdev, reg , value)		\
+	pci_read_config_word(pdev, reg, &value)
+
+#define hp_register_read_dword(pdev, reg , value)		\
+	pci_read_config_dword(pdev, reg, &value)
+ 
+#define hp_register_write_word(pdev, reg , value)		\
+	pci_write_config_word(pdev, reg, value)
+
+#define hp_register_dwrite_word(pdev, reg , value)		\
+	pci_write_config_dword(pdev, reg, value)
+
+/* Field definitions in PCI Express Capabilities Register */
+#define CAP_VER		0x000F
+#define DEV_PORT_TYPE	0x00F0
+#define SLOT_IMPL	0x0100
+#define MSG_NUM		0x3E00
+
+/* Device or Port Type */
+#define NAT_ENDPT	0x00
+#define LEG_ENDPT	0x01
+#define ROOT_PORT	0x04
+#define UP_STREAM	0x05
+#define	DN_STREAM	0x06
+#define PCIE_PCI_BRDG	0x07
+#define PCI_PCIE_BRDG	0x10
+
+/* Field definitions in Device Capabilities Register */
+#define DATTN_BUTTN_PRSN	0x1000
+#define DATTN_LED_PRSN	0x2000
+#define DPWR_LED_PRSN	0x4000
+
+/* Field definitions in Link Capabilities Register */
+#define MAX_LNK_SPEED	0x000F
+#define MAX_LNK_WIDTH	0x03F0
+
+/* Link Width Encoding */
+#define LNK_X1		0x01
+#define LNK_X2		0x02
+#define LNK_X4		0x04	
+#define LNK_X8		0x08
+#define LNK_X12		0x0C
+#define LNK_X16		0x10	
+#define LNK_X32		0x20
+
+/*Field definitions of Link Status Register */
+#define LNK_SPEED	0x000F
+#define NEG_LINK_WD	0x03F0
+#define LNK_TRN_ERR	0x0400
+#define	LNK_TRN		0x0800
+#define SLOT_CLK_CONF	0x1000
+
+/* Field definitions in Slot Capabilities Register */
+#define ATTN_BUTTN_PRSN	0x00000001
+#define	PWR_CTRL_PRSN	0x00000002
+#define MRL_SENS_PRSN	0x00000004
+#define ATTN_LED_PRSN	0x00000008
+#define PWR_LED_PRSN	0x00000010
+#define HP_SUPR_RM	0x00000020
+#define HP_CAP		0x00000040
+#define SLOT_PWR_VALUE	0x000003F8
+#define SLOT_PWR_LIMIT	0x00000C00
+#define PSN		0xFFF80000	/* PSN: Physical Slot Number */
+
+/* Field definitions in Slot Control Register */
+#define ATTN_BUTTN_ENABLE		0x0001
+#define PWR_FAULT_DETECT_ENABLE		0x0002
+#define MRL_DETECT_ENABLE		0x0004
+#define PRSN_DETECT_ENABLE		0x0008
+#define CMD_CMPL_INTR_ENABLE		0x0010
+#define HP_INTR_ENABLE			0x0020
+#define ATTN_LED_CTRL			0x00C0
+#define PWR_LED_CTRL			0x0300
+#define PWR_CTRL			0x0400
+
+/* Attention indicator and Power indicator states */
+#define LED_ON		0x01
+#define LED_BLINK	0x10
+#define LED_OFF		0x11
+
+/* Power Control Command */
+#define POWER_ON	0
+#define POWER_OFF 	0x0400	
+
+/* Field definitions in Slot Status Register */
+#define ATTN_BUTTN_PRESSED	0x0001
+#define PWR_FAULT_DETECTED	0x0002
+#define MRL_SENS_CHANGED	0x0004
+#define PRSN_DETECT_CHANGED	0x0008
+#define CMD_COMPLETED		0x0010
+#define MRL_STATE		0x0020
+#define PRSN_STATE		0x0040
+
+struct php_ctlr_state_s {
+	struct php_ctlr_state_s *pnext;
+	struct pci_dev *pci_dev;
+	unsigned int irq;
+	unsigned long flags;				/* spinlock's */
+	u32 slot_device_offset;
+	u32 num_slots;
+	struct timer_list	int_poll_timer;	/* Added for poll event */
+	php_intr_callback_t attention_button_callback;
+	php_intr_callback_t switch_change_callback;
+	php_intr_callback_t presence_change_callback;
+	php_intr_callback_t power_fault_callback;
+	void *callback_instance_id;
+	struct ctrl_reg *creg;				/* Ptr to controller register space */
+};
+
+static spinlock_t hpc_event_lock;
+
+DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
+static struct php_ctlr_state_s *php_ctlr_list_head = 0;	/* HPC state linked list */
+static int ctlr_seq_num = 0;	/* Controller sequence # */
+static spinlock_t list_lock;
+static void pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs);
+
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+
+/* This is the interrupt polling timeout function. */
+static void int_poll_timeout(unsigned long lphp_ctlr)
+{
+    struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+
+    DBG_ENTER_ROUTINE
+
+    if ( !php_ctlr ) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+    }
+
+    /* Poll for interrupt events.  regs == NULL => polling */
+    pcie_isr( 0, (void *)php_ctlr, NULL );
+
+    init_timer(&php_ctlr->int_poll_timer);
+
+	if (!pciehp_poll_time)
+		pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+
+    start_int_poll_timer(php_ctlr, pciehp_poll_time);
+	
+	return;
+}
+
+/* This function starts the interrupt polling timer. */
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+{
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+	}
+
+	if ( ( seconds <= 0 ) || ( seconds > 60 ) )
+		seconds = 2;            /* Clamp to sane value */
+
+	php_ctlr->int_poll_timer.function = &int_poll_timeout;
+	php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
+	php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
+	add_timer(&php_ctlr->int_poll_timer);
+
+	return;
+}
+
+static int pcie_write_cmd(struct slot *slot, u16 cmd)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	int retval = 0;
+	u16 slot_status;
+
+	DBG_ENTER_ROUTINE 
+	
+	dbg("%s : Enter\n", __FUNCTION__);
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (retval) {
+			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+			return retval;
+		}
+	dbg("%s : hp_register_read_word SLOT_STATUS %x\n", __FUNCTION__, slot_status);
+	
+	if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { 
+		/* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue 
+		   the next command according to spec.  Just print out the error message */
+		dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
+	}
+
+	dbg("%s : Before hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd);
+	retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, cmd | CMD_CMPL_INTR_ENABLE);
+	if (retval) {
+		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s : hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd|CMD_CMPL_INTR_ENABLE);
+	dbg("%s : Exit\n", __FUNCTION__);
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_check_lnk_status(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+	u16 lnk_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+	
+	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	if ( (lnk_status & (LNK_TRN | LNK_TRN_ERR)) == 0x0C00) {
+		err("%s : Link Training Error occurs \n", __FUNCTION__);
+		retval = -1;
+		return retval;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_attention_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_ctrl;
+	u8 atten_led_state;
+	int retval = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL, slot_ctrl);
+
+	atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
+	//atten_led_state = (slot_ctrl & PWR_LED_CTRL) >> 8;
+
+	switch (atten_led_state) {
+	case 0:
+		*status = 0xFF;	/* Reserved */
+		break;
+	case 1:
+		*status = 1;	/* On */
+		break;
+	case 2:
+		*status = 2;	/* Blink */
+		break;
+	case 3:
+		*status = 0;	/* Off */
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_power_status(struct slot * slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_ctrl;
+	u8 pwr_state;
+	int	retval = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+
+	pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
+
+	switch (pwr_state) {
+	case 0:
+		*status = 1; 
+		break;
+	case 1:
+		*status = 0; 	
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_latch_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	*status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;  
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_adapter_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_status;
+	u8 card_state;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+	card_state = (u8)((slot_status & PRSN_STATE) >> 6);
+	*status = (card_state == 1) ? 1 : 0;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+
+static int hpc_query_power_fault(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_status;
+	u8 pwr_fault;
+	int retval = 0;
+	u8 status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+	pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
+	status = (pwr_fault != 1) ? 1 : 0;
+	
+	DBG_LEAVE_ROUTINE
+	/* Note: Logic 0 => fault */
+	return status;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd = 0;
+	u16 slot_ctrl;
+	int rc = 0;
+
+	dbg("%s: \n", __FUNCTION__);	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return rc;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+
+	switch (value) {
+		case 0 :	/* turn off */
+			slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00C0;
+			//slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300;
+			break;
+		case 1:		/* turn on */
+			slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040;
+			//slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
+			break;
+		case 2:		/* turn blink */
+			slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080;
+			//slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200; 
+			break;
+		default:
+			return -1;
+	}
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	pcie_write_cmd(slot, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", 
+		__FUNCTION__, SLOT_CTRL, slot_cmd);
+	
+	return rc;
+}
+
+
+static void hpc_set_green_led_on(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+	int rc = 0;
+       
+	dbg("%s: \n", __FUNCTION__);	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return ;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
+	//slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+ 
+	pcie_write_cmd(slot, slot_cmd);
+
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", 
+		__FUNCTION__, SLOT_CTRL, slot_cmd);
+	return;
+}
+
+static void hpc_set_green_led_off(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+	int rc = 0;
+
+	dbg("%s: \n", __FUNCTION__);	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+
+	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300;
+	//slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00c0;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+	pcie_write_cmd(slot, slot_cmd);
+
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", 
+		__FUNCTION__, SLOT_CTRL, slot_cmd);
+	return;
+}
+
+static void hpc_set_green_led_blink(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+	int rc = 0; 
+	
+	dbg("%s: \n", __FUNCTION__);	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+
+	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200;
+	//slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+	pcie_write_cmd(slot, slot_cmd);
+
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", 
+		__FUNCTION__, SLOT_CTRL, slot_cmd);
+	return;
+}
+
+int pcie_get_ctlr_slot_config(struct controller *ctrl,
+	int *num_ctlr_slots,	/* number of slots in this HPC; only 1 in PCIE	*/
+	int *first_device_num,	/* PCI dev num of the first slot in this PCIE	*/
+	int *physical_slot_num,	/* phy slot num of the first slot in this PCIE	*/
+	int *updown,		/* physical_slot_num increament: 1 or -1 */
+	int *flags)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+	u32 slot_cap;
+	int rc = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	*first_device_num = 0;
+	*num_ctlr_slots = 1; 
+
+	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap);
+	if (rc) {
+		err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
+		return -1;
+	}
+
+	*physical_slot_num = slot_cap >> 19;
+	*updown = -1;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static void hpc_release_ctlr(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+	struct php_ctlr_state_s *p, *p_prev;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (pciehp_poll_mode) {
+	    del_timer(&php_ctlr->int_poll_timer);
+	} else {	
+		if (php_ctlr->irq) {
+			free_irq(php_ctlr->irq, ctrl);
+			php_ctlr->irq = 0;
+		}
+	}
+	if (php_ctlr->pci_dev)
+		php_ctlr->pci_dev = 0;
+
+	spin_lock(&list_lock);	
+	p = php_ctlr_list_head;
+	p_prev = NULL;
+	while (p) {
+		if (p == php_ctlr) {
+			if (p_prev)
+				p_prev->pnext = p->pnext;
+			else
+				php_ctlr_list_head = p->pnext;
+			break;
+		} else {
+			p_prev = p;
+			p = p->pnext;
+		}
+	}
+	spin_unlock(&list_lock);
+
+	kfree(php_ctlr);
+
+	DBG_LEAVE_ROUTINE
+			  
+}
+
+static int hpc_power_on_slot(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	dbg("%s: \n", __FUNCTION__);	
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+	dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL, 
+		slot_ctrl);
+
+	slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	retval = pcie_write_cmd(slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
+		return -1;
+	}
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", 
+		__FUNCTION__, SLOT_CTRL, slot_cmd);
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static int hpc_power_off_slot(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	dbg("%s: \n", __FUNCTION__);	
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+	
+	dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
+	slot->hp_slot = 0;
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL, 
+		slot_ctrl);
+
+	slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+	
+	retval = pcie_write_cmd(slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", 
+		__FUNCTION__, SLOT_CTRL, slot_cmd);
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static void pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
+{
+	struct controller *ctrl = NULL; 
+	struct php_ctlr_state_s *php_ctlr;
+	u8 schedule_flag = 0;
+	u16 slot_status, intr_detect, intr_loc;
+	u16 temp_word;
+	int hp_slot = 0;	/* only 1 slot per PCI Express port */
+	int rc = 0;
+
+	if (!dev_id) {
+		dbg("%s: dev_id == NULL\n", __FUNCTION__);
+		return;
+	}
+
+	if (!pciehp_poll_mode) { 
+		ctrl = (struct controller *)dev_id;
+		php_ctlr = ctrl->hpc_ctlr_handle;
+	} else { 
+		php_ctlr = (struct php_ctlr_state_s *) dev_id;
+		ctrl = (struct controller *)php_ctlr->callback_instance_id;
+	}
+
+	if (!ctrl) {
+		dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id);
+		return;
+	}
+	if (!php_ctlr) {
+		dbg("%s: php_ctlr == NULL\n", __FUNCTION__);
+		return;
+	}
+	
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return;
+	}
+	/* dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); */
+
+	intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED |
+					PRSN_DETECT_CHANGED | CMD_COMPLETED );
+
+	intr_loc = slot_status & intr_detect;
+	
+	/* Check to see if it was our interrupt */
+	if ( !intr_loc ) 
+		return;
+	
+	dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
+	
+	/* Mask Hot-plug Interrupt Enable */
+	if (!pciehp_poll_mode) {
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+			return;
+		}
+
+		dbg("%s: Set Mask Hot-plug Interrupt Enable\n", __FUNCTION__);
+		dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+		temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+			return;
+		}
+		dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+		
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+			return;
+		}
+		dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); 
+		
+		/* Clear command complete interrupt caused by this write */
+		temp_word = 0x1f;
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+			return;
+		}
+		dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); 	
+	}
+
+	if (intr_loc & CMD_COMPLETED) {
+		/* 
+		 * Command Complete Interrupt Pending 
+		 */
+		dbg("%s: In Command Complete Interrupt Pending\n", __FUNCTION__);
+		wake_up_interruptible(&ctrl->queue);
+	}
+	if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED))
+		schedule_flag += php_ctlr->switch_change_callback(
+			hp_slot, php_ctlr->callback_instance_id);
+	if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED))
+		schedule_flag += php_ctlr->attention_button_callback(
+			hp_slot, php_ctlr->callback_instance_id);
+	if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED))
+		schedule_flag += php_ctlr->presence_change_callback(
+			hp_slot , php_ctlr->callback_instance_id);
+	if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED))
+		schedule_flag += php_ctlr->power_fault_callback(
+			hp_slot, php_ctlr->callback_instance_id);
+
+	/* Clear all events after serving them */
+	temp_word = 0x1F;
+	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		return;
+	}
+
+	/* Unmask Hot-plug Interrupt Enable */
+	if (!pciehp_poll_mode) {
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+			return;
+		}
+		dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
+		dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
+
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+			return;
+		}	
+		dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); 	
+	
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+			return;
+		}
+		dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); 
+		
+		/* Clear command complete interrupt caused by this write */
+		temp_word = 0x1F;
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+			return;
+		}
+		dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); 	
+	}
+	return;
+}
+
+static int hpc_get_max_lnk_speed (struct slot *slot, enum pcie_link_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	enum pcie_link_speed lnk_speed;
+	u32	lnk_cap;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap);
+
+	if (retval) {
+		err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	switch (lnk_cap & 0x000F) {
+	case 1:
+		lnk_speed = PCIE_2PT5GB;
+		break;
+	default:
+		lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_speed;
+	dbg("Max link speed = %d\n", lnk_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	enum pcie_link_width lnk_wdth;
+	u32	lnk_cap;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap);
+
+	if (retval) {
+		err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	switch ((lnk_cap & 0x03F0) >> 4){
+	case 0:
+		lnk_wdth = PCIE_LNK_WIDTH_RESRV;
+		break;
+	case 1:
+		lnk_wdth = PCIE_LNK_X1;
+		break;
+	case 2:
+		lnk_wdth = PCIE_LNK_X2;
+		break;
+	case 4:
+		lnk_wdth = PCIE_LNK_X4;
+		break;
+	case 8:
+		lnk_wdth = PCIE_LNK_X8;
+		break;
+	case 12:
+		lnk_wdth = PCIE_LNK_X12;
+		break;
+	case 16:
+		lnk_wdth = PCIE_LNK_X16;
+		break;
+	case 32:
+		lnk_wdth = PCIE_LNK_X32;
+		break;
+	default:
+		lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_wdth;
+	dbg("Max link width = %d\n", lnk_wdth);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_cur_lnk_speed (struct slot *slot, enum pcie_link_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
+	int retval = 0;
+	u16 lnk_status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	switch (lnk_status & 0x0F) {
+	case 1:
+		lnk_speed = PCIE_2PT5GB;
+		break;
+	default:
+		lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_speed;
+	dbg("Current link speed = %d\n", lnk_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
+	int retval = 0;
+	u16 lnk_status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+	
+	switch ((lnk_status & 0x03F0) >> 4){
+	case 0:
+		lnk_wdth = PCIE_LNK_WIDTH_RESRV;
+		break;
+	case 1:
+		lnk_wdth = PCIE_LNK_X1;
+		break;
+	case 2:
+		lnk_wdth = PCIE_LNK_X2;
+		break;
+	case 4:
+		lnk_wdth = PCIE_LNK_X4;
+		break;
+	case 8:
+		lnk_wdth = PCIE_LNK_X8;
+		break;
+	case 12:
+		lnk_wdth = PCIE_LNK_X12;
+		break;
+	case 16:
+		lnk_wdth = PCIE_LNK_X16;
+		break;
+	case 32:
+		lnk_wdth = PCIE_LNK_X32;
+		break;
+	default:
+		lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_wdth;
+	dbg("Current link width = %d\n", lnk_wdth);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static struct hpc_ops pciehp_hpc_ops = {
+	.power_on_slot		= hpc_power_on_slot,
+	.power_off_slot		= hpc_power_off_slot,
+	.set_attention_status	= hpc_set_attention_status,
+	.get_power_status	= hpc_get_power_status,
+	.get_attention_status	= hpc_get_attention_status,
+	.get_latch_status	= hpc_get_latch_status,
+	.get_adapter_status	= hpc_get_adapter_status,
+
+	.get_max_bus_speed	= hpc_get_max_lnk_speed,
+	.get_cur_bus_speed	= hpc_get_cur_lnk_speed,
+	.get_max_lnk_width	= hpc_get_max_lnk_width,
+	.get_cur_lnk_width	= hpc_get_cur_lnk_width,
+
+	.query_power_fault	= hpc_query_power_fault,
+	.green_led_on		= hpc_set_green_led_on,
+	.green_led_off		= hpc_set_green_led_off,
+	.green_led_blink	= hpc_set_green_led_blink,
+	
+	.release_ctlr		= hpc_release_ctlr,
+	.check_lnk_status	= hpc_check_lnk_status,
+};
+
+int pcie_init(struct controller * ctrl,
+	struct pci_dev * pdev,
+	php_intr_callback_t attention_button_callback,
+	php_intr_callback_t switch_change_callback,
+	php_intr_callback_t presence_change_callback,
+	php_intr_callback_t power_fault_callback)
+{
+	struct php_ctlr_state_s *php_ctlr, *p;
+	void *instance_id = ctrl;
+	int rc;
+	static int first = 1;
+	u16 temp_word;
+	u16 cap_reg;
+	u16 intr_enable;
+	u32 slot_cap;
+	int cap_base, saved_cap_base;
+	u16 slot_status, slot_ctrl;
+
+	DBG_ENTER_ROUTINE
+	
+	spin_lock_init(&list_lock);
+	php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
+
+	if (!php_ctlr) {	/* Allocate controller state data */
+		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
+		goto abort;
+	}
+
+	memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
+
+	php_ctlr->pci_dev = pdev;	/* Save pci_dev in context */
+
+	dbg("%s: pdev->vendor %x pdev->device %x\n", __FUNCTION__, 
+		pdev->vendor, pdev->device);
+
+	saved_cap_base = pcie_cap_base;
+
+	if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
+		dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	pcie_cap_base = cap_base;
+
+	dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
+
+	rc = hp_register_read_word(pdev, CAP_REG, cap_reg);
+	if (rc) {
+		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG, cap_reg);
+
+	if (((cap_reg & SLOT_IMPL) == 0) || ((cap_reg & DEV_PORT_TYPE) != 0x0040)){
+		dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	
+	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap);
+	if (rc) {
+		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP, slot_cap);
+
+	if (!(slot_cap & HP_CAP)) {
+		dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	/* For debugging purpose */
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status);
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+
+	if (first) {
+		spin_lock_init(&hpc_event_lock);
+		first = 0;
+	}
+
+	dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, 
+		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->irq);
+	for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+		if (pci_resource_len(pdev, rc) > 0)
+			dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc,
+				pci_resource_start(pdev, rc), pci_resource_len(pdev, rc));
+
+	dbg("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, 
+		pdev->subsystem_vendor, pdev->subsystem_device);
+
+	init_MUTEX(&ctrl->crit_sect);
+	/* Setup wait queue */
+	init_waitqueue_head(&ctrl->queue);
+
+	/* Find the IRQ */
+	php_ctlr->irq = pdev->irq;
+	dbg("HPC interrupt = %d\n", php_ctlr->irq);
+
+	/* Save interrupt callback info */
+	php_ctlr->attention_button_callback = attention_button_callback;
+	php_ctlr->switch_change_callback = switch_change_callback;
+	php_ctlr->presence_change_callback = presence_change_callback;
+	php_ctlr->power_fault_callback = power_fault_callback;
+	php_ctlr->callback_instance_id = instance_id;
+
+	/* Return PCI Controller Info */
+	php_ctlr->slot_device_offset = 0;
+	php_ctlr->num_slots = 1;
+
+	/* Mask Hot-plug Interrupt Enable */
+	rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
+	temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+
+	rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, 
+		SLOT_STATUS, slot_status);
+	
+	temp_word = 0x1F; /* Clear all events */
+	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word);
+
+	if (pciehp_poll_mode)  {/* Install interrupt polling code */
+		/* Install and start the interrupt polling timer */
+		init_timer(&php_ctlr->int_poll_timer);
+		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
+	} else {
+		/* Installs the interrupt handler */
+#ifdef CONFIG_PCI_USE_VECTOR 
+		if (!pciehp_msi_quirk) {	
+			rc = pci_enable_msi(pdev);
+			if (rc) {
+				info("Can't get msi for the hotplug controller\n");
+				info("Use INTx for the hotplug controller\n");
+				dbg("%s: rc = %x\n", __FUNCTION__, rc);
+			} else
+				php_ctlr->irq = pdev->irq;
+		}
+#endif
+		rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+		if (rc) {
+			err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+			goto abort_free_ctlr;
+		}
+	}
+
+	rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
+
+	intr_enable = ATTN_BUTTN_ENABLE | PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+			PRSN_DETECT_ENABLE;
+
+	temp_word = (temp_word & ~intr_enable) | intr_enable; 
+
+	if (pciehp_poll_mode) {
+		temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
+	} else {
+		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
+	}
+	dbg("%s: temp_word %x\n", __FUNCTION__, temp_word);
+
+	/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
+	rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word);
+	
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, 
+		SLOT_STATUS, slot_status);
+	
+	temp_word =  0x1F; /* Clear all events */
+	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word);
+	
+	/*  Add this HPC instance into the HPC list */
+	spin_lock(&list_lock);
+	if (php_ctlr_list_head == 0) {
+		php_ctlr_list_head = php_ctlr;
+		p = php_ctlr_list_head;
+		p->pnext = 0;
+	} else {
+		p = php_ctlr_list_head;
+
+		while (p->pnext)
+			p = p->pnext;
+
+		p->pnext = php_ctlr;
+	}
+	spin_unlock(&list_lock);
+
+	ctlr_seq_num++;
+	ctrl->hpc_ctlr_handle = php_ctlr;
+	ctrl->hpc_ops = &pciehp_hpc_ops;
+
+	DBG_LEAVE_ROUTINE
+	return 0;
+
+	/* We end up here for the many possible ways to fail this API.  */
+abort_free_ctlr:
+	pcie_cap_base = saved_cap_base;
+	kfree(php_ctlr);
+abort:
+	DBG_LEAVE_ROUTINE
+	return -1;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp_pci.c linux-2.4.27-pre3/drivers/hotplug/pciehp_pci.c
--- linux-2.4.26/drivers/hotplug/pciehp_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pciehp_pci.c	2004-05-18 16:54:14.000000000 +0000
@@ -0,0 +1,1052 @@
+/*
+ * PCI Express 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) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/tqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include "pciehp.h"
+#ifndef CONFIG_IA64
+#include "../../arch/i386/kernel/pci-i386.h"    /* horrible hack showing how processor dependant we are... */
+#endif
+
+static int is_pci_dev_in_use(struct pci_dev* dev) 
+{
+	/* 
+	 * dev->driver will be set if the device is in use by a new-style 
+	 * driver -- otherwise, check the device's regions to see if any
+	 * driver has claimed them
+	 */
+
+	int i, inuse=0;
+
+	if (dev->driver) return 1; /* Assume driver feels responsible */
+
+	for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
+		if (!pci_resource_start(dev, i))
+			continue;
+
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO)
+			inuse = check_region(pci_resource_start(dev, i),
+					     pci_resource_len(dev, i));
+		else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+			inuse = check_mem_region(pci_resource_start(dev, i),
+						 pci_resource_len(dev, i));
+	}
+
+	return inuse;
+
+}
+
+
+static int pci_hp_remove_device(struct pci_dev *dev)
+{
+	if (is_pci_dev_in_use(dev)) {
+		err("***Cannot safely power down device -- "
+		       "it appears to be in use***\n");
+		return -EBUSY;
+	}
+	dbg("%s: dev %p\n", __FUNCTION__, dev);
+	pci_remove_device(dev);
+	return 0;
+}
+
+
+static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) 
+{
+	struct pci_bus* bus = wrapped_bus->bus;
+	struct pci_dev* dev = wrapped_dev->dev;
+	struct pci_func *temp_func;
+	int i=0;
+
+	/* We need to fix up the hotplug function representation with the linux representation */
+	do {
+		temp_func = pciehp_slot_find(dev->bus->number, dev->devfn >> 3, i++);
+	} while (temp_func && (temp_func->function != (dev->devfn & 0x07)));
+
+	if (temp_func) {
+		temp_func->pci_dev = dev;
+	} else {
+		/* 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("@@@@@@@@@@@ pciehp_slot_create in %s\n", __FUNCTION__);
+		temp_func = pciehp_slot_create(bus->number);
+		if (temp_func == NULL)
+			return -ENOMEM;
+		temp_func->pci_dev = dev;
+	}
+
+	/* Create /proc/bus/pci proc entry for this device and bus device is on */
+	/* Notify the drivers of the change */
+	if (temp_func->pci_dev) {
+		dbg("%s: PCI_ID=%04X:%04X\n", __FUNCTION__, temp_func->pci_dev->vendor,
+			temp_func->pci_dev->device); 
+		dbg("%s: PCI BUS %x DEVFN %x\n", __FUNCTION__, 
+			temp_func->pci_dev->bus->number, temp_func->pci_dev->devfn); 
+		dbg("%s: PCI_SLOT_NAME=%s\n", __FUNCTION__, 
+			temp_func->pci_dev->slot_name);
+		//pci_enable_device(temp_func->pci_dev);
+		//dbg("%s: after calling pci_enable_device, irq = %x\n", 
+		//	__FUNCTION__, temp_func->pci_dev->irq); 
+		pci_proc_attach_device(temp_func->pci_dev);
+		pci_announce_device_to_drivers(temp_func->pci_dev);
+	}
+
+	return 0;
+}
+
+
+static int unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) 
+{
+	struct pci_dev* dev = wrapped_dev->dev;
+
+	struct pci_func *temp_func;
+	int i=0;
+
+	dbg("%s: dev %p dev->bus->number %x bus->number %x\n", __FUNCTION__, wrapped_dev, 
+		dev->bus->number, wrapped_bus->bus->number);
+
+	/* We need to remove the hotplug function representation with the linux representation */
+	do {
+		temp_func = pciehp_slot_find(dev->bus->number, dev->devfn >> 3, i++);
+		if (temp_func) {
+			dbg("%s: temp_func->function = %d\n", __FUNCTION__, temp_func->function);
+		}
+	} while (temp_func && (temp_func->function != (dev->devfn & 0x07)));
+
+	/* Now, remove the Linux Representation */
+	if (dev) {
+		if (pci_hp_remove_device(dev) == 0) {
+			kfree(dev); /* Now, remove */
+		} else {
+			return -1; /* problems while freeing, abort visitation */
+		}
+	}
+
+	if (temp_func) {
+		temp_func->pci_dev = NULL;
+	} else {
+		dbg("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
+	}
+
+	return 0;
+}
+
+
+static int unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev) 
+{
+	struct pci_bus* bus = wrapped_bus->bus;
+
+	/* The cleanup code for proc entries regarding buses should be in the kernel...*/
+	if (bus->procdir)
+		dbg("detach_pci_bus %s\n", bus->procdir->name);
+	pci_proc_detach_bus(bus);
+	/* The cleanup code should live in the kernel... */
+	bus->self->subordinate = NULL;
+	/* unlink from parent bus */
+	list_del(&bus->node);
+
+	/* Now, remove */
+	if (bus)
+		kfree(bus);
+
+	return 0;
+}
+
+
+static int unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) 
+{
+	struct pci_dev* dev = wrapped_dev->dev;
+	int rc;
+
+	dbg("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	/* Now, remove the Linux Driver Representation */
+	if (dev->driver) {
+		if (dev->driver->remove) {
+			dev->driver->remove(dev);
+			dbg("driver was properly removed\n");
+		}
+		dev->driver = NULL;
+	}
+
+	rc = is_pci_dev_in_use(dev);
+	if (rc)
+		info("%s: device still in use\n", __FUNCTION__);
+	return rc;
+}
+
+
+static struct pci_visit configure_functions = {
+	.visit_pci_dev =	configure_visit_pci_dev,
+};
+
+
+static struct pci_visit unconfigure_functions_phase1 = {
+	.post_visit_pci_dev =	unconfigure_visit_pci_dev_phase1
+};
+
+static struct pci_visit unconfigure_functions_phase2 = {
+	.post_visit_pci_bus =	unconfigure_visit_pci_bus_phase2,               
+	.post_visit_pci_dev =	unconfigure_visit_pci_dev_phase2
+};
+
+
+int pciehp_configure_device (struct controller* ctrl, struct pci_func* func)  
+{
+	unsigned char bus;
+	struct pci_dev dev0;
+	struct pci_bus *child;
+	struct pci_dev* temp;
+	int rc = 0;
+
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+
+	memset(&dev0, 0, sizeof(struct pci_dev));
+	
+	dbg("%s: func->pci_dev %p bus %x dev %x func %x\n", __FUNCTION__,
+		func->pci_dev, func->bus, func->device, func->function);
+	if (func->pci_dev == NULL)
+		func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7));
+	dbg("%s: func->pci_dev %p bus %x dev %x func %x\n", __FUNCTION__,
+		func->pci_dev, func->bus, func->device, func->function);
+	if (func->pci_dev != NULL) {
+		dbg("%s: pci_dev %p bus %x devfn %x\n", __FUNCTION__,
+			func->pci_dev, func->pci_dev->bus->number, func->pci_dev->devfn);
+	}
+	/* Still NULL ? Well then scan for it ! */
+	if (func->pci_dev == NULL) {
+		dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__);
+		dev0.bus = ctrl->pci_dev->subordinate;
+		dbg("%s: dev0.bus %p\n", __FUNCTION__, dev0.bus);
+		dev0.bus->number = func->bus;
+		dbg("%s: dev0.bus->number %x\n", __FUNCTION__, func->bus);
+		dev0.devfn = PCI_DEVFN(func->device, func->function);
+		dev0.sysdata = ctrl->pci_dev->sysdata;
+
+		/* This will generate pci_dev structures for all functions, 
+		 * but we will only call this case when lookup fails
+		 */
+		func->pci_dev = pci_scan_slot(&dev0);
+		dbg("%s: func->pci_dev %p\n", __FUNCTION__, func->pci_dev);
+		if (func->pci_dev == NULL) {
+			dbg("ERROR: pci_dev still null\n");
+			return 0;
+		}
+	}
+
+	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
+		child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
+		dbg("%s: bridge device - func->pci_dev->bus %p func->pci_dev %p bus %x\n", 
+			__FUNCTION__, func->pci_dev->bus,func->pci_dev,bus);
+		pci_do_scan_bus(child);
+
+	}
+
+	temp = func->pci_dev;
+
+	if (temp) {
+		wrapped_dev.dev = temp;
+		wrapped_bus.bus = temp->bus;
+		rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
+	}
+	return rc;
+}
+
+
+int pciehp_unconfigure_device(struct pci_func* func) 
+{
+	int rc = 0;
+	int j;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	
+	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+
+	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);
+		dbg("%s: temp %p\n", __FUNCTION__, temp);
+		if (temp) {
+			wrapped_dev.dev = temp;
+			wrapped_bus.bus = temp->bus;
+			rc = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus);
+			if (rc)
+				break;
+
+			rc = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus);
+			if (rc)
+				break;
+		}
+	}
+	return rc;
+}
+
+/*
+ * pciehp_set_irq
+ *
+ * @bus_num: bus number of PCI device
+ * @dev_num: device number of PCI device
+ * @slot: pointer to u8 where slot number will be returned
+ */
+int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
+{
+#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
+	int rc;
+	u16 temp_word;
+	struct pci_dev fakedev;
+	struct pci_bus fakebus;
+
+	fakedev.devfn = dev_num << 3;
+	fakedev.bus = &fakebus;
+	fakebus.number = bus_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("%s: rc %d\n", __FUNCTION__, rc);
+	if (!rc)
+		return !rc;
+
+	/* set the Edge Level Control Register (ELCR) */
+	temp_word = inb(0x4d0);
+	temp_word |= inb(0x4d1) << 8;
+
+	temp_word |= 0x01 << irq_num;
+
+	/* This should only be for x86 as it sets the Edge Level Control Register */
+	outb((u8) (temp_word & 0xFF), 0x4d0);
+	outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
+#endif
+	return 0;
+}
+
+/* More PCI configuration routines; this time centered around hotplug controller */
+
+
+/*
+ * pciehp_save_config
+ *
+ * Reads configuration for all slots in a PCI bus and saves info.
+ *
+ * Note:  For non-hot plug busses, the slot # saved is the device #
+ *
+ * returns 0 if success
+ */
+int pciehp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num) 
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	struct pci_func *new_slot;
+	int sub_bus;
+	int max_functions;
+	int function;
+	u8 DevError;
+	int device = 0;
+	int cloop = 0;
+	int stop_it;
+	int index;
+	int is_hot_plug = num_ctlr_slots || first_device_num; 
+	struct pci_bus lpci_bus, *pci_bus;
+	int FirstSupported, LastSupported;
+	
+	dbg("%s: Enter\n", __FUNCTION__);
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+
+	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, 
+		first_device_num);
+
+	/*   Decide which slots are supported */
+	if (is_hot_plug) {
+		/*********************************
+		 *  is_hot_plug is the slot mask
+		 *********************************/
+		FirstSupported = first_device_num;
+		LastSupported = FirstSupported + num_ctlr_slots - 1;
+	} else {
+		FirstSupported = 0;
+		LastSupported = 0x1F;
+	}
+
+	dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, LastSupported);
+
+	/*   Save PCI configuration space for all devices in supported slots */
+	dbg("%s: pci_bus->number = %x\n", __FUNCTION__, pci_bus->number);
+	pci_bus->number = busnumber;
+	dbg("%s: bus = %x, dev = %x\n", __FUNCTION__, busnumber, device);
+	for (device = FirstSupported; device <= LastSupported; device++) { 
+		ID = 0xFFFFFFFF;
+		rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
+		/* dbg("%s: ID = %x\n", __FUNCTION__, ID);*/
+
+		if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+			dbg("%s: ID = %x\n", __FUNCTION__, ID);
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
+			if (rc)
+				return rc;
+
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, 
+				&header_type);
+			if (rc)
+				return rc;
+
+			dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+
+			/* If multi-function device, set max_functions to 8 */
+			if (header_type & 0x80)
+				max_functions = 8;
+			else
+				max_functions = 1;
+
+			function = 0;
+
+			do {
+				DevError = 0;
+				dbg("%s: In do loop\n", __FUNCTION__);
+
+				if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   /* P-P Bridge */
+					/* Recurse the subordinate bus
+					 * get the subordinate bus number
+					 */
+					rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 
+						PCI_SECONDARY_BUS, &secondary_bus);
+					if (rc) {
+						return rc;
+					} else {
+						sub_bus = (int) secondary_bus;
+
+						/* Save secondary bus cfg spc with this recursive call. */
+						rc = pciehp_save_config(ctrl, sub_bus, 0, 0); 
+						if (rc)
+							return rc;
+					}
+				}
+
+				index = 0;
+				new_slot = pciehp_slot_find(busnumber, device, index++);
+
+				dbg("%s: new_slot = %p bus %x dev %x fun %x\n",
+				__FUNCTION__, new_slot, busnumber, device, index-1);
+
+				while (new_slot && (new_slot->function != (u8) function)) {
+					new_slot = pciehp_slot_find(busnumber, device, index++);
+					dbg("%s: while loop, new_slot = %p bus %x dev %x fun %x\n",
+					__FUNCTION__, new_slot, busnumber, device, index-1);
+				}
+				if (!new_slot) {
+					/* Setup slot structure. */
+					new_slot = pciehp_slot_create(busnumber);
+					dbg("%s: if, new_slot = %p bus %x dev %x fun %x\n",
+					__FUNCTION__, new_slot, busnumber, device, function);
+
+					if (new_slot == NULL)
+						return(1);
+				}
+
+				new_slot->bus = (u8) busnumber;
+				new_slot->device = (u8) device;
+				new_slot->function = (u8) function;
+				new_slot->is_a_board = 1;
+				new_slot->switch_save = 0x10;
+				/* In case of unsupported board */
+				new_slot->status = DevError;
+				new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function);
+				dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev);
+
+				for (cloop = 0; cloop < 0x20; cloop++) {
+					rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop]));
+					/* dbg("new_slot->config_space[%x] = %x\n", cloop, new_slot->config_space[cloop]); */
+					if (rc)
+						return rc;
+				}
+
+				function++;
+
+				stop_it = 0;
+
+				/*  This loop skips to the next present function
+				 *  reading in Class Code and Header type.
+				 */
+
+				while ((function < max_functions)&&(!stop_it)) {
+					dbg("%s: In while loop \n", __FUNCTION__);
+					rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
+
+					if (ID == 0xFFFFFFFF) {  /* Nothing there. */
+						function++;
+						dbg("Nothing there\n");
+					} else {  /* Something there */
+						rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
+						if (rc)
+							return rc;
+
+						rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
+						if (rc)
+							return rc;
+
+						dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+						stop_it++;
+					}
+				}
+
+			} while (function < max_functions);
+		}		/* End of IF (device in slot?) */
+		else if (is_hot_plug) {
+			/* Setup slot structure with entry for empty slot */
+			new_slot = pciehp_slot_create(busnumber);
+
+			if (new_slot == NULL) {
+				return(1);
+			}
+			dbg("new_slot = %p, bus = %x, dev = %x, fun = %x\n", new_slot,
+				new_slot->bus, new_slot->device, new_slot->function);
+
+			new_slot->bus = (u8) busnumber;
+			new_slot->device = (u8) device;
+			new_slot->function = 0;
+			new_slot->is_a_board = 0;
+			new_slot->presence_save = 0;
+			new_slot->switch_save = 0;
+		}
+		/* dbg("%s: End of For loop\n", __FUNCTION__); */
+	 } 			/* End of FOR loop */
+
+	dbg("%s: Exit\n", __FUNCTION__);
+	return(0);
+}
+
+
+/*
+ * pciehp_save_slot_config
+ *
+ * Saves configuration info for all PCI devices in a given slot
+ * including subordinate busses.
+ *
+ * returns 0 if success
+ */
+int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	int sub_bus;
+	int max_functions;
+	int function;
+	int cloop = 0;
+	int stop_it;
+	struct pci_bus lpci_bus, *pci_bus;
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = new_slot->bus;
+
+	ID = 0xFFFFFFFF;
+
+	pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
+
+	if (ID != 0xFFFFFFFF) {	  /*  Device in slot */
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
+
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
+
+		if (header_type & 0x80)	/* Multi-function device */
+			max_functions = 8;
+		else 
+			max_functions = 1;
+
+		function = 0;
+
+		do {
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  /* PCI-PCI Bridge */
+				/*  Recurse the subordinate bus */
+				pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
+
+				sub_bus = (int) secondary_bus;
+
+				/* Save the config headers for the secondary bus. */
+				rc = pciehp_save_config(ctrl, sub_bus, 0, 0); 
+
+				if (rc)
+					return(rc);
+
+			}	/* End of IF */
+
+			new_slot->status = 0;
+
+			for (cloop = 0; cloop < 0x20; cloop++) {
+				pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop]));
+			}
+
+			function++;
+
+			stop_it = 0;
+
+			/*  this loop skips to the next present function
+			 *  reading in the Class Code and the Header type.
+			 */
+
+			while ((function < max_functions) && (!stop_it)) {
+				pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
+
+				if (ID == 0xFFFFFFFF) {	 /* Nothing there. */
+					function++;
+				} else {  /* Something there */
+					pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
+
+					pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
+
+					stop_it++;
+				}
+			}
+
+		} while (function < max_functions);
+	}			/* End of IF (device in slot?) */
+	else {
+		return(2);
+	}
+
+	return(0);
+}
+
+
+/*
+ * pciehp_save_used_resources
+ *
+ * Stores used resource information for existing boards.  this is
+ * for boards that were in the system when this driver was loaded.
+ * this function is for hot plug ADD
+ *
+ * returns 0 if success
+ * if disable  == 1(DISABLE_CARD),
+ *  it loops for all functions of the slot and disables them.
+ * else, it just get resources of the function and return.
+ */
+int pciehp_save_used_resources (struct controller *ctrl, struct pci_func *func, int disable)
+{
+	u8 cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	u8 temp_byte;
+	u16 command;
+	u16 save_command;
+	u16 w_base, w_length;
+	u32 temp_register;
+	u32 save_base;
+	u32 base, length;
+	u64 base64 = 0;
+	int index = 0;
+	unsigned int devfn;
+	struct pci_resource *mem_node = NULL;
+	struct pci_resource *p_mem_node = NULL;
+	struct pci_resource *t_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_bus lpci_bus, *pci_bus;
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+
+	if (disable)
+		func = pciehp_slot_find(func->bus, func->device, index++);
+
+	while ((func != NULL) && func->is_a_board) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		/* Save the command register */
+		pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command);
+
+		if (disable) {
+			/* Disable card */
+			command = 0x00;
+			pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+		}
+
+		/* Check for Bridge */
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+
+		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {     /* PCI-PCI Bridge */
+			dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command);
+			if (disable) {
+				/* Clear Bridge Control Register */
+				command = 0x00;
+				pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+			}
+
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
+
+			bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node->base = (ulong)secondary_bus;
+			bus_node->length = (ulong)(temp_byte - secondary_bus + 1);
+
+			bus_node->next = func->bus_head;
+			func->bus_head = bus_node;
+
+			/* Save IO base and Limit registers */
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &temp_byte);
+			base = temp_byte;
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &temp_byte);
+			length = temp_byte;
+
+			if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) {
+				io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!io_node)
+					return -ENOMEM;
+
+				io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8;
+				io_node->length = (ulong)(length - base + 0x10) << 8;
+
+				io_node->next = func->io_head;
+				func->io_head = io_node;
+			}
+
+			/* Save memory base and Limit registers */
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+				mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!mem_node)
+					return -ENOMEM;
+
+				mem_node->base = (ulong)w_base << 16;
+				mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
+
+				mem_node->next = func->mem_head;
+				func->mem_head = mem_node;
+			}
+			/* Save prefetchable memory base and Limit registers */
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+				p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!p_mem_node)
+					return -ENOMEM;
+
+				p_mem_node->base = (ulong)w_base << 16;
+				p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
+
+				p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = p_mem_node;
+			}
+		} else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+			dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command);
+
+			/* Figure out IO and memory base lengths */
+			for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);
+
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register);
+
+				if (!disable) {
+					pci_bus_write_config_dword (pci_bus, devfn, cloop, save_base);
+				}
+
+				if (!temp_register)
+					continue;
+
+				base = temp_register;
+
+				if ((base & PCI_BASE_ADDRESS_SPACE_IO) && (!disable || (save_command & PCI_COMMAND_IO))) {
+					/* IO base */
+					/* Set temp_register = amount of IO space requested */
+					base = base & 0xFFFFFFFCL;
+					base = (~base) + 1;
+
+					io_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+					if (!io_node)
+						return -ENOMEM;
+
+					io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK;
+					io_node->length = (ulong)base;
+					dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", io_node->base, io_node->length);
+
+					io_node->next = func->io_head;
+					func->io_head = io_node;
+				} else {  /* Map Memory */
+					int prefetchable = 1;
+					/* struct pci_resources **res_node; */
+					char *res_type_str = "PMEM";
+					u32 temp_register2;
+
+					t_mem_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+					if (!t_mem_node)
+						return -ENOMEM;
+
+					if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+						prefetchable = 0;
+						mem_node = t_mem_node;
+						res_type_str++;
+					} else
+						p_mem_node = t_mem_node;
+
+					base = base & 0xFFFFFFF0L;
+					base = (~base) + 1;
+
+					switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+					case PCI_BASE_ADDRESS_MEM_TYPE_32:
+						if (prefetchable) {
+							p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node->length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length);
+
+							p_mem_node->next = func->p_mem_head;
+							func->p_mem_head = p_mem_node;
+						} else {
+							mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node->length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+
+							mem_node->next = func->mem_head;
+							func->mem_head = mem_node;
+						}
+						break;
+					case PCI_BASE_ADDRESS_MEM_TYPE_64:
+						pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+						base64 = temp_register2;
+						base64 = (base64 << 32) | save_base;
+
+						if (temp_register2) {
+							dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", res_type_str, temp_register2, (u32)base64);
+							base64 &= 0x00000000FFFFFFFFL;
+						}
+
+						if (prefetchable) {
+							p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node->length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length);
+
+							p_mem_node->next = func->p_mem_head;
+							func->p_mem_head = p_mem_node;
+						} else {
+							mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node->length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+
+							mem_node->next = func->mem_head;
+							func->mem_head = mem_node;
+						}
+						cloop += 4;
+						break;
+					default:
+						dbg("asur: reserved BAR type=0x%x\n", temp_register);
+						break;
+					}
+				} 
+			}	/* End of base register loop */
+		} else {	/* Some other unknown header type */
+			dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", func->bus, func->device);
+		}
+
+		/* Find the next device in this slot */
+		if (!disable)
+			break;
+		func = pciehp_slot_find(func->bus, func->device, index++);
+	}
+
+	return(0);
+}
+
+
+/*
+ * pciehp_return_board_resources
+ *
+ * this routine returns all resources allocated to a board to
+ * the available pool.
+ *
+ * returns 0 if success
+ */
+int pciehp_return_board_resources(struct pci_func * func, struct resource_lists * resources)
+{
+	int rc = 0;
+	struct pci_resource *node;
+	struct pci_resource *t_node;
+	dbg("%s\n", __FUNCTION__);
+
+	if (!func)
+		return(1);
+
+	node = func->io_head;
+	func->io_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->io_head), node);
+		node = t_node;
+	}
+
+	node = func->mem_head;
+	func->mem_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->mem_head), node);
+		node = t_node;
+	}
+
+	node = func->p_mem_head;
+	func->p_mem_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->p_mem_head), node);
+		node = t_node;
+	}
+
+	node = func->bus_head;
+	func->bus_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->bus_head), node);
+		node = t_node;
+	}
+
+	rc |= pciehp_resource_sort_and_combine(&(resources->mem_head));
+	rc |= pciehp_resource_sort_and_combine(&(resources->p_mem_head));
+	rc |= pciehp_resource_sort_and_combine(&(resources->io_head));
+	rc |= pciehp_resource_sort_and_combine(&(resources->bus_head));
+
+	return(rc);
+}
+
+
+/*
+ * pciehp_destroy_resource_list
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void pciehp_destroy_resource_list (struct resource_lists * resources)
+{
+	struct pci_resource *res, *tres;
+
+	res = resources->io_head;
+	resources->io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = resources->mem_head;
+	resources->mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = resources->p_mem_head;
+	resources->p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = resources->bus_head;
+	resources->bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
+
+/*
+ * pciehp_destroy_board_resources
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void pciehp_destroy_board_resources (struct pci_func * func)
+{
+	struct pci_resource *res, *tres;
+
+	res = func->io_head;
+	func->io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = func->mem_head;
+	func->mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = func->p_mem_head;
+	func->p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = func->bus_head;
+	func->bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehprm.h linux-2.4.27-pre3/drivers/hotplug/pciehprm.h
--- linux-2.4.26/drivers/hotplug/pciehprm.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pciehprm.h	2004-05-18 16:53:47.000000000 +0000
@@ -0,0 +1,54 @@
+/*
+ * PCIEHPRM : PCIEHP Resource Manager for ACPI/non-ACPI platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _PCIEHPRM_H_
+#define _PCIEHPRM_H_
+
+#ifdef	CONFIG_HOTPLUG_PCI_PCIE_PHPRM_NONACPI
+#include "pciehprm_nonacpi.h"
+#endif
+
+int pciehprm_init(enum php_ctlr_type ct);
+void pciehprm_cleanup(void);
+int pciehprm_print_pirt(void);
+void *pciehprm_get_slot(struct slot *slot);
+int pciehprm_find_available_resources(struct controller *ctrl);
+int pciehprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type);
+void pciehprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type);
+int pciehprm_get_interrupt(int seg, int bus, int device, int pin, int *irq);
+
+#ifdef	DEBUG
+#define RES_CHECK(this, bits)	\
+	{ if (((this) & (bits - 1))) \
+		printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); }
+#else
+#define RES_CHECK(this, bits)
+#endif
+
+#endif			/* _PCIEHPRM_H_ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehprm_acpi.c linux-2.4.27-pre3/drivers/hotplug/pciehprm_acpi.c
--- linux-2.4.26/drivers/hotplug/pciehprm_acpi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pciehprm_acpi.c	2004-05-18 16:54:59.000000000 +0000
@@ -0,0 +1,1696 @@
+/*
+ * PCIEHPRM ACPI: PHP Resource Manager for ACPI platform
+ *
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/efi.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#ifdef	CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/actypes.h>
+#include "pciehp.h"
+#include "pciehprm.h"
+
+#define	PCI_MAX_BUS		0x100
+#define	ACPI_STA_DEVICE_PRESENT	0x01
+
+#define	METHOD_NAME__SUN	"_SUN"
+#define	METHOD_NAME__HPP	"_HPP"
+#define	METHOD_NAME_OSHP	"OSHP"
+
+#define	PHP_RES_BUS		0xA0
+#define	PHP_RES_IO		0xA1
+#define	PHP_RES_MEM		0xA2
+#define	PHP_RES_PMEM		0xA3
+
+#define	BRIDGE_TYPE_P2P		0x00
+#define	BRIDGE_TYPE_HOST	0x01
+
+/* this should go to drivers/acpi/include/ */
+struct acpi__hpp {
+	u8	cache_line_size;
+	u8	latency_timer;
+	u8	enable_serr;
+	u8	enable_perr;
+};
+
+struct acpi_php_slot {
+	struct acpi_php_slot	*next;
+	struct acpi_bridge	*bridge;
+	acpi_handle	handle;
+	int	seg;
+	int	bus;
+	int	dev;
+	int	fun;
+	u32	sun;
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	void	*slot_ops;	/* _STA, _EJx, etc */
+	struct slot *slot;
+};		/* per func */
+
+struct acpi_bridge {
+	struct acpi_bridge	*parent;
+	struct acpi_bridge	*next;
+	struct acpi_bridge	*child;
+	acpi_handle	handle;
+	int seg;
+	int pbus;				/* pdev->bus->number		*/
+	int pdevice;				/* PCI_SLOT(pdev->devfn)	*/
+	int pfunction;				/* PCI_DEVFN(pdev->devfn)	*/
+	int bus;				/* pdev->subordinate->number	*/
+	struct acpi__hpp	*_hpp;
+	struct acpi_php_slot	*slots;
+	struct pci_resource 	*tmem_head;	/* total from crs	*/
+	struct pci_resource 	*tp_mem_head;	/* total from crs	*/
+	struct pci_resource 	*tio_head;	/* total from crs	*/
+	struct pci_resource 	*tbus_head;	/* total from crs	*/
+	struct pci_resource 	*mem_head;	/* available	*/
+	struct pci_resource 	*p_mem_head;	/* available	*/
+	struct pci_resource 	*io_head;	/* available	*/
+	struct pci_resource 	*bus_head;	/* available	*/
+	int scanned;
+	int type;
+};
+
+static struct acpi_bridge *acpi_bridges_head;
+
+static u8 * acpi_path_name( acpi_handle	handle)
+{
+	acpi_status		status;
+	static u8		path_name[ACPI_PATHNAME_MAX];
+	struct acpi_buffer	ret_buf = { ACPI_PATHNAME_MAX, path_name };
+
+	memset(path_name, 0, sizeof (path_name));
+	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);
+
+	if (ACPI_FAILURE(status))
+		return NULL;
+	else
+		return path_name;	
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab);
+static void acpi_run_oshp ( struct acpi_bridge	*ab);
+
+static int acpi_add_slot_to_php_slots(
+	struct acpi_bridge	*ab,
+	int				bus_num,
+	acpi_handle		handle,
+	u32				adr,
+	u32				sun
+	)
+{
+	struct acpi_php_slot	*aps;
+	static long	samesun = -1;
+
+	aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);
+	if (!aps) {
+		err ("acpi_pciehprm: alloc for aps fail\n");
+		return -1;
+	}
+	memset(aps, 0, sizeof(struct acpi_php_slot));
+
+	aps->handle = handle;
+	aps->bus = bus_num;
+	aps->dev = (adr >> 16) & 0xffff;
+	aps->fun = adr & 0xffff;
+	aps->sun = sun;
+
+	aps->next = ab->slots;	/* cling to the bridge */
+	aps->bridge = ab;
+	ab->slots = aps;
+
+	ab->scanned += 1;
+	if (!ab->_hpp)
+		acpi_get__hpp(ab);
+	
+	acpi_run_oshp(ab);
+	if (sun != samesun) {
+		info("acpi_pciehprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", 
+			aps->sun, ab->seg, aps->bus, aps->dev, aps->fun);
+		samesun = sun;
+	}
+	return 0;
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			nui[4];
+	struct acpi_buffer	ret_buf = { 0, NULL};
+	union acpi_object	*ext_obj, *package;
+	u8			*path_name = acpi_path_name(ab->handle);
+	int			i, len = 0;
+
+	/* Get _hpp */
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
+		if (!ret_buf.pointer) {
+			err ("acpi_pciehprm:%s alloc for _HPP fail\n", path_name);
+			return;
+		}
+		status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+		if (ACPI_SUCCESS(status))
+			break;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_pciehprm:%s _HPP fail=0x%x\n", path_name, status);
+			return;
+		}
+	}
+
+	ext_obj = (union acpi_object *) ret_buf.pointer;
+	if (ext_obj->type != ACPI_TYPE_PACKAGE) {
+		err ("acpi_pciehprm:%s _HPP obj not a package\n", path_name);
+		goto free_and_return;
+	}
+
+	len = ext_obj->package.count;
+	package = (union acpi_object *) ret_buf.pointer;
+	for ( i = 0; (i < len) || (i < 4); i++) {
+		ext_obj = (union acpi_object *) &package->package.elements[i];
+		switch (ext_obj->type) {
+		case ACPI_TYPE_INTEGER:
+			nui[i] = (u8)ext_obj->integer.value;
+			break;
+		default:
+			err ("acpi_pciehprm:%s _HPP obj type incorrect\n", path_name);
+			goto free_and_return;
+		}
+	}
+
+	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
+
+	ab->_hpp->cache_line_size	= nui[0];
+	ab->_hpp->latency_timer		= nui[1];
+	ab->_hpp->enable_serr		= nui[2];
+	ab->_hpp->enable_perr		= nui[3];
+
+	dbg("  _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
+	dbg("  _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
+	dbg("  _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
+	dbg("  _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+
+free_and_return:
+	kfree(ret_buf.pointer);
+}
+static void acpi_run_oshp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(ab->handle);
+	struct acpi_buffer		ret_buf = { 0, NULL};
+
+	/* Run OSHP */
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, &ret_buf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
+	} else
+		dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);
+	return;
+}
+
+static acpi_status acpi_evaluate_crs(
+	acpi_handle		handle,
+	struct acpi_resource	**retbuf
+	)
+{
+	acpi_status		status;
+	struct acpi_buffer		crsbuf;
+	u8			*path_name = acpi_path_name(handle);
+
+	crsbuf.length  = 0;
+	crsbuf.pointer = NULL;
+
+	status = acpi_get_current_resources (handle, &crsbuf);
+
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		break;		/* Found */
+	case AE_NOT_FOUND:
+		dbg("acpi_pciehprm:%s _CRS not found\n", path_name);
+		return status;
+	default:
+		err ("acpi_pciehprm:%s _CRS fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL);
+	if (!crsbuf.pointer) {
+		err ("acpi_pciehprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name);
+		return AE_NO_MEMORY;
+	}
+
+	status = acpi_get_current_resources (handle, &crsbuf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm: %s _CRS fail=0x%x.\n", path_name, status);
+		kfree(crsbuf.pointer);
+		return status;
+	}
+
+	*retbuf = crsbuf.pointer;
+
+	return status;
+}
+
+static void free_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res, *next;
+
+	for (res = aprh; res; res = next) {
+		next = res->next;
+		kfree(res);
+	}
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res->next)
+		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
+}
+
+static void print_slot_resources( struct acpi_php_slot	*aps)
+{
+	if (aps->bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (aps->bus_head);
+	}
+
+	if (aps->io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (aps->io_head);
+	}
+
+	if (aps->mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (aps->mem_head);
+	}
+
+	if (aps->p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (aps->p_mem_head);
+	}
+}
+
+static void print_pci_resources( struct acpi_bridge	*ab)
+{
+	if (ab->tbus_head) {
+		dbg("    Total BUS Resources:\n");
+		print_pci_resource (ab->tbus_head);
+	}
+	if (ab->bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (ab->bus_head);
+	}
+
+	if (ab->tio_head) {
+		dbg("    Total IO Resources:\n");
+		print_pci_resource (ab->tio_head);
+	}
+	if (ab->io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (ab->io_head);
+	}
+
+	if (ab->tmem_head) {
+		dbg("    Total MEM Resources:\n");
+		print_pci_resource (ab->tmem_head);
+	}
+	if (ab->mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (ab->mem_head);
+	}
+
+	if (ab->tp_mem_head) {
+		dbg("    Total PMEM Resources:\n");
+		print_pci_resource (ab->tp_mem_head);
+	}
+	if (ab->p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (ab->p_mem_head);
+	}
+	if (ab->_hpp) {
+		dbg("    _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
+		dbg("    _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
+		dbg("    _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
+		dbg("    _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+	}
+}
+
+static int pciehprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	pciehp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+static int pciehprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res->next)
+		pciehprm_delete_resource(aprh, res->base, res->length);
+
+	return 0;
+}
+
+static int pciehprm_add_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+
+	for (res = *aprh; res; res = res->next) {
+		if ((res->base + res->length) == base) {
+			res->length += size;
+			size = 0L;
+			break;
+		}
+		if (res->next == *aprh)
+			break;
+	}
+
+	if (size) {
+		res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		if (!res) {
+			err ("acpi_pciehprm: alloc for res fail\n");
+			return -ENOMEM;
+		}
+		memset(res, 0, sizeof (struct pci_resource));
+
+		res->base = base;
+		res->length = size;
+		res->next = *aprh;
+		*aprh = res;
+	}
+
+	return 0;
+}
+
+static int pciehprm_add_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+	int	rc = 0;
+
+	for (res = this; res && !rc; res = res->next)
+		rc = pciehprm_add_resource(aprh, res->base, res->length);
+
+	return rc;
+}
+
+static void acpi_parse_io (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_io	*dataio;
+	dataio = (struct acpi_resource_io *) data;
+
+	dbg("Io Resource\n");
+	dbg("  %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10);
+	dbg("  Range minimum base: %08X\n", dataio->min_base_address);
+	dbg("  Range maximum base: %08X\n", dataio->max_base_address);
+	dbg("  Alignment: %08X\n", dataio->alignment);
+	dbg("  Range Length: %08X\n", dataio->range_length);
+}
+
+static void acpi_parse_fixed_io (
+	struct acpi_bridge	*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_fixed_io  *datafio;
+	datafio = (struct acpi_resource_fixed_io *) data;
+
+	dbg("Fixed Io Resource\n");
+	dbg("  Range base address: %08X", datafio->base_address);
+	dbg("  Range length: %08X", datafio->range_length);
+}
+
+static void acpi_parse_address16_32 (
+	struct acpi_bridge	*ab,
+	union acpi_resource_data	*data,
+	acpi_resource_type	id
+	)
+{
+	/* 
+	 * acpi_resource_address16 == acpi_resource_address32
+	 * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data;
+	 */
+	struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data;
+	struct pci_resource **aprh, **tprh;
+
+	if (id == ACPI_RSTYPE_ADDRESS16)
+		dbg("acpi_pciehprm:16-Bit Address Space Resource\n");
+	else
+		dbg("acpi_pciehprm:32-Bit Address Space Resource\n");
+
+	switch (data32->resource_type) {
+	case ACPI_MEMORY_RANGE: 
+		dbg("  Resource Type: Memory Range\n");
+		aprh = &ab->mem_head;
+		tprh = &ab->tmem_head;
+
+		switch (data32->attribute.memory.cache_attribute) {
+		case ACPI_NON_CACHEABLE_MEMORY:
+			dbg("  Type Specific: Noncacheable memory\n");
+			break; 
+		case ACPI_CACHABLE_MEMORY:
+			dbg("  Type Specific: Cacheable memory\n");
+			break; 
+		case ACPI_WRITE_COMBINING_MEMORY:
+			dbg("  Type Specific: Write-combining memory\n");
+			break; 
+		case ACPI_PREFETCHABLE_MEMORY:
+			aprh = &ab->p_mem_head;
+			dbg("  Type Specific: Prefetchable memory\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid cache attribute\n");
+			break;
+		}
+
+		dbg("  Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only");
+		break;
+
+	case ACPI_IO_RANGE: 
+		dbg("  Resource Type: I/O Range\n");
+		aprh = &ab->io_head;
+		tprh = &ab->tio_head;
+
+		switch (data32->attribute.io.range_attribute) {
+		case ACPI_NON_ISA_ONLY_RANGES:
+			dbg("  Type Specific: Non-ISA Io Addresses\n");
+			break; 
+		case ACPI_ISA_ONLY_RANGES:
+			dbg("  Type Specific: ISA Io Addresses\n");
+			break; 
+		case ACPI_ENTIRE_RANGE:
+			dbg("  Type Specific: ISA and non-ISA Io Addresses\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid range attribute\n");
+			break;
+		}
+		break;
+
+	case ACPI_BUS_NUMBER_RANGE: 
+		dbg("  Resource Type: Bus Number Range(fixed)\n");
+		/* Fixup to be compatible with the rest of php driver */
+		data32->min_address_range++;
+		data32->address_length--;
+		aprh = &ab->bus_head;
+		tprh = &ab->tbus_head;
+		break; 
+	default: 
+		dbg("  Resource Type: Invalid resource type. Exiting.\n");
+		return;
+	}
+
+	dbg("  Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer");
+	dbg("  %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive");
+	dbg("  Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not");
+	dbg("  Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not");
+	dbg("  Granularity: %08X\n", data32->granularity);
+	dbg("  Address range min: %08X\n", data32->min_address_range);
+	dbg("  Address range max: %08X\n", data32->max_address_range);
+	dbg("  Address translation offset: %08X\n", data32->address_translation_offset);
+	dbg("  Address Length: %08X\n", data32->address_length);
+
+	if (0xFF != data32->resource_source.index) {
+		dbg("  Resource Source Index: %X\n", data32->resource_source.index);
+		/* dbg("  Resource Source: %s\n", data32->resource_source.string_ptr); */
+	}
+
+	pciehprm_add_resource(aprh, data32->min_address_range, data32->address_length);
+}
+
+static acpi_status acpi_parse_crs(
+	struct acpi_bridge	*ab,
+	struct acpi_resource	*crsbuf
+	)
+{
+	acpi_status		status = AE_OK;
+	struct acpi_resource	*resource = crsbuf;
+	u8				count = 0;
+	u8				done = 0;
+
+	while (!done) {
+		dbg("acpi_pciehprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++);
+		switch (resource->id) {
+		case ACPI_RSTYPE_IRQ:
+			dbg("Irq -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_DMA:
+			dbg("DMA -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_START_DPF:
+			dbg("Start DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_DPF:
+			dbg("End DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_IO:
+			acpi_parse_io (ab, &resource->data);
+			break; 
+		case ACPI_RSTYPE_FIXED_IO:
+			acpi_parse_fixed_io (ab, &resource->data);
+			break; 
+		case ACPI_RSTYPE_VENDOR:
+			dbg("Vendor -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_TAG:
+			dbg("End_tag -------- Resource\n");
+			done = 1;
+			break; 
+		case ACPI_RSTYPE_MEM24:
+			dbg("Mem24 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_MEM32:
+			dbg("Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_FIXED_MEM32:
+			dbg("Fixed Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_ADDRESS16:
+			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16);
+			break; 
+		case ACPI_RSTYPE_ADDRESS32:
+			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32);
+			break; 
+		case ACPI_RSTYPE_ADDRESS64:
+			info("Address64 -------- Resource unparsed\n");
+			break; 
+		case ACPI_RSTYPE_EXT_IRQ:
+			dbg("Ext Irq -------- Resource\n");
+			break; 
+		default:
+			dbg("Invalid -------- resource type 0x%x\n", resource->id);
+			break;
+		}
+
+		resource = (struct acpi_resource *) ((char *)resource + resource->length);
+	}
+
+	return status;
+}
+
+static acpi_status acpi_get_crs( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	struct acpi_resource	*crsbuf;
+
+	status = acpi_evaluate_crs(ab->handle, &crsbuf);
+	if (ACPI_SUCCESS(status)) {
+		status = acpi_parse_crs(ab, crsbuf);
+		kfree(crsbuf);
+
+		pciehp_resource_sort_and_combine(&ab->bus_head);
+		pciehp_resource_sort_and_combine(&ab->io_head);
+		pciehp_resource_sort_and_combine(&ab->mem_head);
+		pciehp_resource_sort_and_combine(&ab->p_mem_head);
+
+		pciehprm_add_resources (&ab->tbus_head, ab->bus_head);
+		pciehprm_add_resources (&ab->tio_head, ab->io_head);
+		pciehprm_add_resources (&ab->tmem_head, ab->mem_head);
+		pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
+	}
+
+	return status;
+}
+
+/* find acpi_bridge downword from ab.  */
+static struct acpi_bridge *
+find_acpi_bridge_by_bus(
+	struct acpi_bridge *ab,
+	int seg,
+	int bus		/* pdev->subordinate->number */
+	)
+{
+	struct acpi_bridge	*lab = NULL;
+
+	if (!ab)
+		return NULL;
+
+	if ((ab->bus == bus) && (ab->seg == seg))
+		return ab;
+
+	if (ab->child)
+		lab = find_acpi_bridge_by_bus(ab->child, seg, bus);
+
+	if (!lab)
+	if (ab->next)
+		lab = find_acpi_bridge_by_bus(ab->next, seg, bus);
+
+	return lab;
+}
+
+/*
+ * Build a device tree of ACPI PCI Bridges
+ */
+static void pciehprm_acpi_register_a_bridge (
+	struct acpi_bridge	**head,
+	struct acpi_bridge	*pab,	/* parent bridge to which child bridge is added */
+	struct acpi_bridge	*cab	/* child bridge to add */
+	)
+{
+	struct acpi_bridge	*lpab;
+	struct acpi_bridge	*lcab;
+
+	lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus);
+	if (!lpab) {
+		if (!(pab->type & BRIDGE_TYPE_HOST))
+			warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus);
+		pab->next = *head;
+		*head = pab;
+		lpab = pab;
+	}
+
+	if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab))
+		return;
+
+	lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus);
+	if (lcab) {
+		if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus))
+			err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus);
+		return;
+	} else
+		lcab = cab;
+
+	lcab->parent = lpab;
+	lcab->next = lpab->child;
+	lpab->child = lcab;
+}
+
+static acpi_status pciehprm_acpi_build_php_slots_callback(
+	acpi_handle	handle,
+	u32		Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		bus_num;
+	ulong		seg_num;
+	ulong		sun, adr;
+	ulong		padr = 0;
+	acpi_handle		phandle = NULL;
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*lab;
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* Get _SUN */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun);
+	switch(status) {
+	case AE_NOT_FOUND:
+		return AE_OK;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_pciehprm:%s _SUN fail=0x%x\n", path_name, status);
+			return status;
+		}
+	}
+
+	/* Get _ADR. _ADR must exist if _SUN exists */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	dbg("acpi_pciehprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr);
+
+	status = acpi_get_parent(handle, &phandle);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s get_parent fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	bus_num = pab->bus;
+	seg_num = pab->seg;
+
+	if (pab->bus == bus_num) {
+		lab = pab;
+	} else {
+		dbg("WARN: pab is not parent\n");
+		lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num);
+		if (!lab) {
+			dbg("acpi_pciehprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+			lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL);
+			if (!lab) {
+				err("acpi_pciehprm: alloc for ab fail\n");
+				return AE_NO_MEMORY;
+			}
+			memset(lab, 0, sizeof(struct acpi_bridge));
+
+			lab->handle = phandle;
+			lab->pbus = pab->bus;
+			lab->pdevice = (int)(padr >> 16) & 0xffff;
+			lab->pfunction = (int)(padr & 0xffff);
+			lab->bus = (int)bus_num;
+			lab->scanned = 0;
+			lab->type = BRIDGE_TYPE_P2P;
+
+			pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab);
+		} else
+			dbg("acpi_pciehprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+	}
+
+	acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun);
+
+	return (status);
+}
+
+static int pciehprm_acpi_build_php_slots(
+	struct acpi_bridge	*ab,
+	u32			depth
+	)
+{
+	acpi_status	status;
+	u8		*path_name = acpi_path_name(ab->handle);
+
+	/* Walk down this pci bridge to get _SUNs if any behind P2P */
+	status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+				ab->handle,
+				depth,
+				pciehprm_acpi_build_php_slots_callback,
+				ab,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		dbg("acpi_pciehprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", 
+			path_name, ab->seg, ab->bus, status);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void build_a_bridge(
+	struct acpi_bridge	*pab,
+	struct acpi_bridge	*ab
+	)
+{
+	u8		*path_name = acpi_path_name(ab->handle);
+
+	pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab);
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("acpi_pciehprm: Registered PCI HOST Bridge(%02x)    on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("acpi_pciehprm: Registered PCI  P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
+		break;
+	};
+
+	/* build any immediate PHP slots under this pci bridge */
+	pciehprm_acpi_build_php_slots(ab, 1);
+}
+
+static struct acpi_bridge * add_p2p_bridge(
+	acpi_handle 		handle,
+	struct acpi_bridge	*pab,	/* parent */
+	ulong			adr
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_dev		*pdev;
+	ulong			devnum, funcnum;
+	u8			*path_name = acpi_path_name(handle);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_pciehprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	devnum = (adr >> 16) & 0xffff;
+	funcnum = adr & 0xffff;
+
+	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev || !pdev->subordinate) {
+		err("acpi_pciehprm:%s is not a P2P Bridge\n", path_name);
+		kfree(ab);
+		return NULL;
+	}
+
+	ab->handle = handle;
+	ab->seg = pab->seg;
+	ab->pbus = pab->bus;		/* or pdev->bus->number */
+	ab->pdevice = devnum;		/* or PCI_SLOT(pdev->devfn) */
+	ab->pfunction = funcnum;	/* or PCI_FUNC(pdev->devfn) */
+	ab->bus = pdev->subordinate->number;
+	ab->scanned = 0;
+	ab->type = BRIDGE_TYPE_P2P;
+
+	dbg("acpi_pciehprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n",
+		pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+		pab->bus, (u32)devnum, (u32)funcnum, path_name);
+
+	build_a_bridge(pab, ab);
+
+	return ab;
+}
+
+static acpi_status scan_p2p_bridge(
+	acpi_handle		handle,
+	u32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*ab;
+	acpi_status		status;
+	ulong			adr = 0;
+	u8			*path_name = acpi_path_name(handle);
+	ulong			devnum, funcnum;
+	struct pci_dev		*pdev;
+
+	/* Get device, function */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND)
+			err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
+		return AE_OK;
+	}
+
+	devnum = (adr >> 16) & 0xffff;
+	funcnum = adr & 0xffff;
+
+	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev)
+		return AE_OK;
+	if (!pdev->subordinate)
+		return AE_OK;
+
+	ab = add_p2p_bridge(handle, pab, adr);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					(u32)1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static struct acpi_bridge * add_host_bridge(
+	acpi_handle handle,
+	ulong	segnum,
+	ulong	busnum
+	)
+{
+	ulong		adr = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get device, function: host br adr is always 0000 though.  */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
+		return NULL;
+	}
+	dbg("acpi_pciehprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, 
+		(u32)busnum, (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_pciehprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	ab->handle = handle;
+	ab->seg = (int)segnum;
+	ab->bus = ab->pbus = (int)busnum;
+	ab->pdevice = (int)(adr >> 16) & 0xffff;
+	ab->pfunction = (int)(adr & 0xffff);
+	ab->scanned = 0;
+	ab->type = BRIDGE_TYPE_HOST;
+
+	/* get root pci bridge's current resources */
+	status = acpi_get_crs(ab);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s evaluate _CRS fail=0x%x\n", path_name, status);
+		kfree(ab);
+		return NULL;
+	}
+	build_a_bridge(ab, ab);
+
+	return ab;
+}
+
+static acpi_status acpi_scan_from_root_pci_callback (
+	acpi_handle	handle,
+	u32		Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		segnum = 0;
+	ulong		busnum = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* Get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			err("acpi_pciehprm:%s evaluate _SEG fail=0x%x\n", path_name, status);
+			return status;
+		}
+		segnum = 0;
+	}
+
+	/* Get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s evaluate _BBN fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	ab = add_host_bridge(handle, segnum, busnum);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static int pciehprm_acpi_scan_pci (void)
+{
+	acpi_status	status;
+
+	/*
+	 * TBD: traverse LDM device tree with the help of
+	 *  unified ACPI augmented for php device population.
+	 */
+	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
+				acpi_scan_from_root_pci_callback,
+				NULL,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:get_device PCI ROOT HID fail=0x%x\n", status);
+		return -1;
+	}
+
+	return 0;
+}
+
+int pciehprm_init(enum php_ctlr_type ctlr_type)
+{
+	int	rc;
+
+	if (ctlr_type != PCI)
+		return -ENODEV;
+
+	dbg("pciehprm ACPI init <enter>\n");
+	acpi_bridges_head = NULL;
+
+	/* Construct PCI bus:device tree of acpi_handles */
+	rc = pciehprm_acpi_scan_pci();
+	if (rc)
+		return rc;
+
+	dbg("pciehprm ACPI init %s\n", (rc)?"fail":"success");
+	return rc;
+}
+
+static void free_a_slot(struct acpi_php_slot *aps)
+{
+	dbg("        free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun);
+
+	free_pci_resource (aps->io_head);
+	free_pci_resource (aps->bus_head);
+	free_pci_resource (aps->mem_head);
+	free_pci_resource (aps->p_mem_head);
+
+	kfree(aps);
+}
+
+static void free_a_bridge( struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot	*aps, *next;
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
+		break;
+	};
+
+	/* Free slots first */
+	for (aps = ab->slots; aps; aps = next) {
+		next = aps->next;
+		free_a_slot(aps);
+	}
+
+	free_pci_resource (ab->io_head);
+	free_pci_resource (ab->tio_head);
+	free_pci_resource (ab->bus_head);
+	free_pci_resource (ab->tbus_head);
+	free_pci_resource (ab->mem_head);
+	free_pci_resource (ab->tmem_head);
+	free_pci_resource (ab->p_mem_head);
+	free_pci_resource (ab->tp_mem_head);
+
+	kfree(ab);
+}
+
+static void pciehprm_free_bridges ( struct acpi_bridge	*ab)
+{
+	if (!ab)
+		return;
+
+	if (ab->child)
+		pciehprm_free_bridges (ab->child);
+
+	if (ab->next)
+		pciehprm_free_bridges (ab->next);
+
+	free_a_bridge(ab);
+}
+
+void pciehprm_cleanup(void)
+{
+	pciehprm_free_bridges (acpi_bridges_head);
+}
+
+static int get_number_of_slots (
+	struct acpi_bridge	*ab,
+	int			selfonly
+	)
+{
+	struct acpi_php_slot	*aps;
+	int	prev_slot = -1;
+	int	slot_num = 0;
+
+	for ( aps = ab->slots; aps; aps = aps->next)
+		if (aps->dev != prev_slot) {
+			prev_slot = aps->dev;
+			slot_num++;
+		}
+
+	if (ab->child)
+		slot_num += get_number_of_slots (ab->child, 0);
+
+	if (selfonly)
+		return slot_num;
+
+	if (ab->next)
+		slot_num += get_number_of_slots (ab->next, 0);
+
+	return slot_num;
+}
+
+static int print_acpi_resources (struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot		*aps;
+	int	i;
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle));
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle));
+		break;
+	};
+
+	print_pci_resources (ab);
+
+	for ( i = -1, aps = ab->slots; aps; aps = aps->next) {
+		if (aps->dev == i)
+			continue;
+		dbg("  Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, 
+			aps->dev, aps->fun);
+		print_slot_resources(aps);
+		i = aps->dev;
+	}
+
+	if (ab->child)
+		print_acpi_resources (ab->child);
+
+	if (ab->next)
+		print_acpi_resources (ab->next);
+
+	return 0;
+}
+
+int pciehprm_print_pirt(void)
+{
+	dbg("PCIEHPRM ACPI Slots\n");
+	if (acpi_bridges_head)
+		print_acpi_resources (acpi_bridges_head);
+
+	return 0;
+}
+
+static struct acpi_php_slot * get_acpi_slot (
+	struct acpi_bridge *ab,
+	u32 sun
+	)
+{
+	struct acpi_php_slot	*aps = NULL;
+
+	for ( aps = ab->slots; aps; aps = aps->next)
+		if (aps->sun == sun)
+			return aps;
+
+	if (!aps && ab->child) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun);
+		if (aps)
+			return aps;
+	}
+
+	if (!aps && ab->next) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun);
+		if (aps)
+			return aps;
+	}
+
+	return aps;
+
+}
+
+void * pciehprm_get_slot(struct slot *slot)
+{
+	struct acpi_bridge	*ab = acpi_bridges_head;
+	struct acpi_php_slot	*aps = get_acpi_slot (ab, slot->number);
+
+	aps->slot = slot;
+
+	dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, 
+		aps->dev, aps->fun);
+
+	return (void *)aps;
+}
+
+static void pciehprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func->bus_head);
+	}
+	if (func->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func->io_head);
+	}
+	if (func->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func->mem_head);
+	}
+	if (func->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func->p_mem_head);
+	}
+}
+
+static void pciehprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl->bus_head);
+	}
+	if (ctrl->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl->io_head);
+	}
+	if (ctrl->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl->mem_head);
+	}
+	if (ctrl->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl->p_mem_head);
+	}
+}
+
+static int pciehprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* See how much resources the func has used. */
+	rc = pciehprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* Subtract the resources used by the func from ctrl resources */
+		rc  = pciehprm_delete_resources (&ctrl->bus_head, func->bus_head);
+		rc |= pciehprm_delete_resources (&ctrl->io_head, func->io_head);
+		rc |= pciehprm_delete_resources (&ctrl->mem_head, func->mem_head);
+		rc |= pciehprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func;
+	int busn = ctrl->slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn < 32; devn++) {
+		for (funn = 0; funn < 8; funn++) {
+			/*
+			if (devn == ctrl->device && funn == ctrl->function)
+				continue;
+			*/
+			/* Find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+			pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), 
+				PCI_VENDOR_ID, &vid);
+
+			if (vid != 0xFFFFFFFF) {
+				dbg("%s: vid = %x\n", __FUNCTION__, vid);
+				func = pciehp_slot_find(busn, devn, funn);
+				if (!func)
+					continue;
+				configure_existing_function(ctrl, func);
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
+				pciehprm_dump_func_res(func);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int bind_pci_resources(
+	struct controller *ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int		status = 0;
+
+	if (ab->bus_head) {
+		dbg("bapr:  BUS Resources add on PCI 0x%x\n", ab->bus);
+		status = pciehprm_add_resources (&ctrl->bus_head, ab->bus_head);
+		if (pciehprm_delete_resources (&ab->bus_head, ctrl->bus_head))
+			warn("bapr:  cannot sub BUS Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No BUS Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->io_head) {
+		dbg("bapr:  IO Resources add on PCI 0x%x\n", ab->bus);
+		status = pciehprm_add_resources (&ctrl->io_head, ab->io_head);
+		if (pciehprm_delete_resources (&ab->io_head, ctrl->io_head))
+			warn("bapr:  cannot sub IO Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No  IO Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->mem_head) {
+		dbg("bapr:  MEM Resources add on PCI 0x%x\n", ab->bus);
+		status = pciehprm_add_resources (&ctrl->mem_head, ab->mem_head);
+		if (pciehprm_delete_resources (&ab->mem_head, ctrl->mem_head))
+			warn("bapr:  cannot sub MEM Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No MEM Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->p_mem_head) {
+		dbg("bapr:  PMEM Resources add on PCI 0x%x\n", ab->bus);
+		status = pciehprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head);
+		if (pciehprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head))
+			warn("bapr:  cannot sub PMEM Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No PMEM Resource on PCI 0x%x.\n", ab->bus);
+
+	return status;
+}
+
+static int no_pci_resources( struct acpi_bridge *ab)
+{
+	return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head);
+}
+
+static int find_pci_bridge_resources (
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+	struct pci_func func;
+
+	memset(&func, 0, sizeof(struct pci_func));
+
+	func.bus = ab->pbus;
+	func.device = ab->pdevice;
+	func.function = ab->pfunction;
+	func.is_a_board = 1;
+
+	/* Get used resources for this PCI bridge */
+	rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD);
+
+	ab->io_head = func.io_head;
+	ab->mem_head = func.mem_head;
+	ab->p_mem_head = func.p_mem_head;
+	ab->bus_head = func.bus_head;
+	if (ab->bus_head)
+		pciehprm_delete_resource(&ab->bus_head, ctrl->pci_dev->subordinate->number, 1);
+	return rc;
+}
+
+static int get_pci_resources_from_bridge(
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+
+	dbg("grfb:  Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus);
+
+	rc = find_pci_bridge_resources (ctrl, ab);
+
+	pciehp_resource_sort_and_combine(&ab->bus_head);
+	pciehp_resource_sort_and_combine(&ab->io_head);
+	pciehp_resource_sort_and_combine(&ab->mem_head);
+	pciehp_resource_sort_and_combine(&ab->p_mem_head);
+
+	pciehprm_add_resources (&ab->tbus_head, ab->bus_head);
+	pciehprm_add_resources (&ab->tio_head, ab->io_head);
+	pciehprm_add_resources (&ab->tmem_head, ab->mem_head);
+	pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
+
+	return rc;
+}
+
+static int get_pci_resources(
+	struct controller	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int	rc = 0;
+
+	if (no_pci_resources(ab)) {
+		dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus);
+		rc = get_pci_resources_from_bridge(ctrl, ab);
+	}
+
+	return rc;
+}
+
+/*
+ * Get resources for this ctrl.
+ *  1. get total resources from ACPI _CRS or bridge (this ctrl)
+ *  2. find used resources of existing adapters
+ *  3. subtract used resources from total resources
+ */
+int pciehprm_find_available_resources( struct controller *ctrl)
+{
+	int rc = 0;
+	struct acpi_bridge	*ab;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number);
+	if (!ab) {
+		err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number);
+		return -1;
+	}
+	if (no_pci_resources(ab)) {
+		rc = get_pci_resources(ctrl, ab);
+		if (rc) {
+			err("pfar:cannot get pci resources of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number);
+			return -1;
+		}
+	}
+
+	rc = bind_pci_resources(ctrl, ab);
+	dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
+	pciehprm_dump_ctrl_res(ctrl);
+
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
+	pciehprm_dump_ctrl_res(ctrl);
+
+	return rc;
+}
+
+int pciehprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_bus 		lpci_bus, *pci_bus;
+	int			rc = 0;
+	unsigned int		devfn;
+	u8			cls= 0x08;	/* default cache line size	*/
+	u8			lt = 0x40;	/* default latency timer	*/
+	u8			ep = 0;
+	u8			es = 0;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+
+	if (ab) {
+		if (ab->_hpp) {
+			lt  = (u8)ab->_hpp->latency_timer;
+			cls = (u8)ab->_hpp->cache_line_size;
+			ep  = (u8)ab->_hpp->enable_perr;
+			es  = (u8)ab->_hpp->enable_serr;
+		} else
+			dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", 
+				func->bus, func->device, func->function);
+	} else
+		dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", 
+				func->bus, func->device, func->function);
+
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* Set subordinate Latency Timer */
+		rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt);
+	}
+
+	/* Set base Latency Timer */
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt);
+	dbg("  set latency timer  =0x%02x: %x\n", lt, rc);
+
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls);
+	dbg("  set cache_line_size=0x%02x: %x\n", cls, rc);
+
+	return rc;
+}
+
+void pciehprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, cmd, bcommand, bcmd;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct acpi_bridge	*ab;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+	}
+
+	cmd = command  = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	bcmd = bcommand  = bcommand | PCI_BRIDGE_CTL_NO_ISA;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+	if (ab) {
+		if (ab->_hpp) {
+			if (ab->_hpp->enable_perr) {
+				command |= PCI_COMMAND_PARITY;
+				bcommand |= PCI_BRIDGE_CTL_PARITY;
+			} else {
+				command &= ~PCI_COMMAND_PARITY;
+				bcommand &= ~PCI_BRIDGE_CTL_PARITY;
+			}
+			if (ab->_hpp->enable_serr) {
+				command |= PCI_COMMAND_SERR;
+				bcommand |= PCI_BRIDGE_CTL_SERR;
+			} else {
+				command &= ~PCI_COMMAND_SERR;
+				bcommand &= ~PCI_BRIDGE_CTL_SERR;
+			}
+		} else
+			dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
+	} else
+		dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
+
+	if (command != cmd) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+	}
+	if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehprm_nonacpi.c linux-2.4.27-pre3/drivers/hotplug/pciehprm_nonacpi.c
--- linux-2.4.26/drivers/hotplug/pciehprm_nonacpi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pciehprm_nonacpi.c	2004-05-18 16:51:12.000000000 +0000
@@ -0,0 +1,497 @@
+/*
+ * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include "pciehp.h"
+#include "pciehprm.h"
+#include "pciehprm_nonacpi.h"
+
+
+void pciehprm_cleanup(void)
+{
+	return;
+}
+
+int pciehprm_print_pirt(void)
+{
+	return 0;
+}
+
+
+void * pciehprm_get_slot(struct slot *slot)
+{
+	return NULL;
+}
+
+int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+
+	*sun = (u8) (ctrl->first_slot);
+	return 0;
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res->next)
+		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
+}
+
+
+static void phprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func->bus_head);
+	}
+	if (func->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func->io_head);
+	}
+	if (func->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func->mem_head);
+	}
+	if (func->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func->p_mem_head);
+	}
+}
+
+static int phprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int phprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	pciehp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int phprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res->next)
+		phprm_delete_resource(aprh, res->base, res->length);
+
+	return 0;
+}
+
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* See how much resources the func has used. */
+	rc = phprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* Subtract the resources used by the func from ctrl resources */
+		rc  = phprm_delete_resources (&ctrl->bus_head, func->bus_head);
+		rc |= phprm_delete_resources (&ctrl->io_head, func->io_head);
+		rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head);
+		rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int pciehprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	pciehp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func;
+	int busn = ctrl->slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn < 32; devn++) {
+		for (funn = 0; funn < 8; funn++) {
+			/*
+			if (devn == ctrl->device && funn == ctrl->function)
+				continue;
+			*/
+			/* Find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+
+			pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid);
+			if (vid != 0xFFFFFFFF) {
+				dbg("%s: vid = %x bus %x dev %x fun %x\n", __FUNCTION__,
+				vid, busn, devn, funn);
+				func = pciehp_slot_find(busn, devn, funn);
+				dbg("%s: func = %p\n", __FUNCTION__,func);
+				if (!func)
+					continue;
+				configure_existing_function(ctrl, func);
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
+				phprm_dump_func_res(func);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void phprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl->bus_head);
+	}
+	if (ctrl->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl->io_head);
+	}
+	if (ctrl->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl->mem_head);
+	}
+	if (ctrl->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl->p_mem_head);
+	}
+}
+
+/*
+ * phprm_find_available_resources
+ *
+ *  Finds available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *  this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */
+int pciehprm_find_available_resources(struct controller *ctrl)
+{
+	struct pci_func func;
+	u32 rc;
+
+	memset(&func, 0, sizeof(struct pci_func));
+
+	func.bus = ctrl->bus;
+	func.device = ctrl->device;
+	func.function = ctrl->function;
+	func.is_a_board = 1;
+
+	/* Get resources for this PCI bridge */
+	rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD);
+	dbg("%s: pciehp_save_used_resources rc = %d\n", __FUNCTION__, rc);
+
+	if (func.mem_head)
+		func.mem_head->next = ctrl->mem_head;
+	ctrl->mem_head = func.mem_head;
+
+	if (func.p_mem_head)
+		func.p_mem_head->next = ctrl->p_mem_head;
+	ctrl->p_mem_head = func.p_mem_head;
+
+	if (func.io_head)
+		func.io_head->next = ctrl->io_head;
+	ctrl->io_head = func.io_head;
+
+	if (func.bus_head)
+		func.bus_head->next = ctrl->bus_head;
+	ctrl->bus_head = func.bus_head;
+	if (ctrl->bus_head)
+		pciehprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1);
+	
+	dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
+	phprm_dump_ctrl_res(ctrl);
+
+	dbg("%s: before bind_pci_resources_to slots\n", __FUNCTION__);
+	
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
+	phprm_dump_ctrl_res(ctrl);
+
+	return (rc);
+}
+
+int pciehprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type)
+{
+	u32 rc;
+	u8 temp_byte;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int	devfn;
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	temp_byte = 0x40;	/* Hard coded value for LT */
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* Set subordinate Latency Timer */
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+
+		if (rc) {
+			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+			return rc;
+		}
+	}
+
+	/* Set base Latency Timer */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+
+	if (rc) {
+		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, 
+			func->device, func->function);
+		return rc;
+	}
+
+	/* set Cache Line size */
+	temp_byte = 0x08;	/* hard coded value for CLS */
+
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+
+	if (rc) {
+		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, 
+			func->device, func->function);
+	}
+
+	/* set enable_perr */
+	/* set enable_serr */
+
+	return rc;
+}
+
+void pciehprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, bcommand;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+
+	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
+		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+
+	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+
+		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
+			| PCI_BRIDGE_CTL_NO_ISA;
+
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
+static int legacy_pciehprm_init_pci(void)
+{
+	return 0;
+}
+
+int pciehprm_init(enum php_ctlr_type ctrl_type)
+{
+	int retval;
+
+	switch (ctrl_type) {
+	case PCI:
+		retval = legacy_pciehprm_init_pci();
+		break;
+	default:
+		retval = -ENODEV;
+		break;
+	}
+
+	return retval;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehprm_nonacpi.h linux-2.4.27-pre3/drivers/hotplug/pciehprm_nonacpi.h
--- linux-2.4.26/drivers/hotplug/pciehprm_nonacpi.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/pciehprm_nonacpi.h	2004-05-18 16:53:00.000000000 +0000
@@ -0,0 +1,56 @@
+/*
+ * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _PCIEHPRM_NONACPI_H_
+#define _PCIEHPRM_NONACPI_H_
+
+struct irq_info {
+	u8 bus, devfn;		/* bus, device and function */
+	struct {
+		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;	/* Available IRQs */
+	} __attribute__ ((packed)) irq[4];
+	u8 slot;		/* slot number, 0=onboard */
+	u8 rfu;
+} __attribute__ ((packed));
+
+struct irq_routing_table {
+	u32 signature;		/* PIRQ_SIGNATURE should be here */
+	u16 version;		/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
+	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;	/* Crap */
+	u8 rfu[11];
+	u8 checksum;		/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__ ((packed));
+
+#endif				/* _PCIEHPRM_NONACPI_H_ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp.h linux-2.4.27-pre3/drivers/hotplug/shpchp.h
--- linux-2.4.26/drivers/hotplug/shpchp.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchp.h	2004-05-18 16:52:35.000000000 +0000
@@ -0,0 +1,464 @@
+/*
+ * Standard 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) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>,<dely.l.sy@intel.com>
+ *
+ */
+#ifndef _SHPCHP_H
+#define _SHPCHP_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>		
+#include "pci_hotplug.h"
+
+#if !defined(CONFIG_HOTPLUG_PCI_SHPC_MODULE)
+	#define MY_NAME	"shpchp.o"
+#else
+	#define MY_NAME	THIS_MODULE->name
+#endif
+
+extern int shpchp_poll_mode;
+extern int shpchp_poll_time;
+extern int shpchp_debug;
+
+/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
+#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## 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)
+
+struct pci_func {
+	struct pci_func *next;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 is_a_board;
+	u16 status;
+	u8 configured;
+	u8 switch_save;
+	u8 presence_save;
+	u32 base_length[0x06];
+	u8 base_type[0x06];
+	u16 reserved2;
+	u32 config_space[0x20];
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev* pci_dev;
+};
+
+#define SLOT_MAGIC	0x67267321
+struct slot {
+	u32 magic;
+	struct slot *next;
+	u8 bus;
+	u8 device;
+	u32 number;
+	u8 is_a_board;
+	u8 configured;
+	u8 state;
+	u8 switch_save;
+	u8 presence_save;
+	u32 capabilities;
+	u16 reserved2;
+	struct timer_list task_event;
+	u8 hp_slot;
+	struct controller *ctrl;
+	struct hpc_ops *hpc_ops;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head	slot_list;
+};
+
+struct pci_resource {
+	struct pci_resource * next;
+	u32 base;
+	u32 length;
+};
+
+struct event_info {
+	u32 event_type;
+	u8 hp_slot;
+};
+
+struct controller {
+	struct controller *next;
+	struct semaphore crit_sect;	/* critical section semaphore */
+	void * hpc_ctlr_handle;		/* HPC controller handle */
+	int num_slots;			/* Number of slots on ctlr */
+	int slot_num_inc;		/* 1 or -1 */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev *pci_dev;
+	struct pci_bus *pci_bus;
+	struct event_info event_queue[10];
+	struct slot *slot;
+	struct hpc_ops *hpc_ops;
+	wait_queue_head_t queue;	/* sleep & wake process */
+	u8 next_event;
+	u8 seg;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 rev;
+	u8 slot_device_offset;
+	u8 add_support;
+	enum pci_bus_speed speed;
+	u32 first_slot;			/* First physical slot number */
+	u8 slot_bus;			/* Bus where the slots handled by this controller sit */
+	u8 push_flag;
+	u16 ctlrcap;
+	u16 vendor_id;
+};
+
+struct irq_mapping {
+	u8 barber_pole;
+	u8 valid_INT;
+	u8 interrupt[4];
+};
+
+struct resource_lists {
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct irq_mapping *irqs;
+};
+
+/* Define AMD SHPC ID  */
+#define PCI_DEVICE_ID_AMD_GOLAM_7450	0x7450 
+
+/* Define SHPC CAP ID - not defined in kernel yet */
+#define PCI_CAP_ID_SHPC			0x0C 
+
+#define INT_BUTTON_IGNORE		0
+#define INT_PRESENCE_ON			1
+#define INT_PRESENCE_OFF		2
+#define INT_SWITCH_CLOSE		3
+#define INT_SWITCH_OPEN			4
+#define INT_POWER_FAULT			5
+#define INT_POWER_FAULT_CLEAR		6
+#define INT_BUTTON_PRESS		7
+#define INT_BUTTON_RELEASE		8
+#define INT_BUTTON_CANCEL		9
+
+#define STATIC_STATE			0
+#define BLINKINGON_STATE		1
+#define BLINKINGOFF_STATE		2
+#define POWERON_STATE			3
+#define POWEROFF_STATE			4
+
+#define PCI_TO_PCI_BRIDGE_CLASS		0x00060400
+
+/* Error messages */
+#define INTERLOCK_OPEN			0x00000002
+#define ADD_NOT_SUPPORTED		0x00000003
+#define CARD_FUNCTIONING		0x00000005
+#define ADAPTER_NOT_SAME		0x00000006
+#define NO_ADAPTER_PRESENT		0x00000009
+#define NOT_ENOUGH_RESOURCES		0x0000000B
+#define DEVICE_TYPE_NOT_SUPPORTED	0x0000000C
+#define WRONG_BUS_FREQUENCY		0x0000000D
+#define POWER_FAILURE			0x0000000E
+
+#define REMOVE_NOT_SUPPORTED		0x00000003
+
+#define DISABLE_CARD			1
+
+/*
+ * error Messages
+ */
+#define msg_initialization_err	"Initialization failure, error=%d\n"
+#define msg_HPC_rev_error	"Unsupported revision of the PCI hot plug controller found.\n"
+#define msg_HPC_non_shpc	"The PCI hot plug controller is not supported by this driver.\n"
+#define msg_HPC_not_supported	"This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n"
+#define msg_unable_to_save	"Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n"
+#define msg_button_on		"PCI slot #%d - powering on due to button press.\n"
+#define msg_button_off		"PCI slot #%d - powering off due to button press.\n"
+#define msg_button_cancel	"PCI slot #%d - action canceled due to button press.\n"
+#define msg_button_ignore	"PCI slot #%d - button press ignored.  (action in progress...)\n"
+
+/* controller functions */
+extern void	shpchp_pushbutton_thread	(unsigned long event_pointer);
+extern int	shpchprm_find_available_resources	(struct controller *ctrl);
+extern int	shpchp_event_start_thread	(void);
+extern void	shpchp_event_stop_thread	(void);
+extern struct pci_func *shpchp_slot_create	(unsigned char busnumber);
+extern struct pci_func *shpchp_slot_find	(unsigned char bus, unsigned char device, unsigned char index);
+extern int	shpchp_enable_slot		(struct slot *slot);
+extern int	shpchp_disable_slot		(struct slot *slot);
+
+extern u8	shpchp_handle_attention_button	(u8 hp_slot, void *inst_id);
+extern u8	shpchp_handle_switch_change	(u8 hp_slot, void *inst_id);
+extern u8	shpchp_handle_presence_change	(u8 hp_slot, void *inst_id);
+extern u8	shpchp_handle_power_fault	(u8 hp_slot, void *inst_id);
+
+/* resource functions */
+extern int	shpchp_resource_sort_and_combine	(struct pci_resource **head);
+
+/* pci functions */
+extern int	shpchp_set_irq			(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
+extern int	shpchp_get_bus_dev		(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);
+extern int	shpchp_save_config	 	(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
+extern int	shpchp_save_used_resources	(struct controller *ctrl, struct pci_func * func, int flag);
+extern int	shpchp_save_slot_config		(struct controller *ctrl, struct pci_func * new_slot);
+extern void	shpchp_destroy_board_resources	(struct pci_func * func);
+extern int	shpchp_return_board_resources	(struct pci_func * func, struct resource_lists * resources);
+extern void	shpchp_destroy_resource_list	(struct resource_lists * resources);
+extern int	shpchp_configure_device		(struct controller* ctrl, struct pci_func* func);
+extern int	shpchp_unconfigure_device	(struct pci_func* func);
+
+
+/* Global variables */
+extern struct controller *shpchp_ctrl_list;
+extern struct pci_func *shpchp_slot_list[256];
+
+/* These are added to support AMD SHPC */
+extern u8 shpchp_nic_irq;
+extern u8 shpchp_disk_irq;
+
+struct ctrl_reg {
+	volatile u32 base_offset;
+	volatile u32 slot_avail1;
+	volatile u32 slot_avail2;
+	volatile u32 slot_config;
+	volatile u16 sec_bus_config;
+	volatile u8  msi_ctrl;
+	volatile u8  prog_interface;
+	volatile u16 cmd;
+	volatile u16 cmd_status;
+	volatile u32 intr_loc;
+	volatile u32 serr_loc;
+	volatile u32 serr_intr_enable;
+	volatile u32 slot1;
+	volatile u32 slot2;
+	volatile u32 slot3;
+	volatile u32 slot4;
+	volatile u32 slot5;
+	volatile u32 slot6;
+	volatile u32 slot7;
+	volatile u32 slot8;
+	volatile u32 slot9;
+	volatile u32 slot10;
+	volatile u32 slot11;
+	volatile u32 slot12;
+} __attribute__ ((packed));
+
+/* Offsets to the controller registers based on the above structure layout */
+enum ctrl_offsets {
+	BASE_OFFSET =		offsetof(struct ctrl_reg, base_offset),
+	SLOT_AVAIL1 =		offsetof(struct ctrl_reg, slot_avail1),
+	SLOT_AVAIL2 =		offsetof(struct ctrl_reg, slot_avail2),
+	SLOT_CONFIG =		offsetof(struct ctrl_reg, slot_config),
+	SEC_BUS_CONFIG =	offsetof(struct ctrl_reg, sec_bus_config),
+	MSI_CTRL =		offsetof(struct ctrl_reg, msi_ctrl),
+	PROG_INTERFACE =	offsetof(struct ctrl_reg, prog_interface),
+	CMD =			offsetof(struct ctrl_reg, cmd),
+	CMD_STATUS =		offsetof(struct ctrl_reg, cmd_status),
+	INTR_LOC = 		offsetof(struct ctrl_reg, intr_loc),
+	SERR_LOC = 		offsetof(struct ctrl_reg, serr_loc),
+	SERR_INTR_ENABLE =	offsetof(struct ctrl_reg, serr_intr_enable),
+	SLOT1 =			offsetof(struct ctrl_reg, slot1),
+	SLOT2 =			offsetof(struct ctrl_reg, slot2),
+	SLOT3 =			offsetof(struct ctrl_reg, slot3),
+	SLOT4 =			offsetof(struct ctrl_reg, slot4),
+	SLOT5 =			offsetof(struct ctrl_reg, slot5),
+	SLOT6 =			offsetof(struct ctrl_reg, slot6),
+	SLOT7 =			offsetof(struct ctrl_reg, slot7),
+	SLOT8 =			offsetof(struct ctrl_reg, slot8),
+	SLOT9 =			offsetof(struct ctrl_reg, slot9),
+	SLOT10 =		offsetof(struct ctrl_reg, slot10),
+	SLOT11 =		offsetof(struct ctrl_reg, slot11),
+	SLOT12 =		offsetof(struct ctrl_reg, slot12),
+};
+typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id);
+struct php_ctlr_state_s {
+	struct php_ctlr_state_s *pnext;
+	struct pci_dev *pci_dev;
+	unsigned int irq;
+	unsigned long flags;			/* spinlock's */
+	u32 slot_device_offset;
+	u32 num_slots;
+    	struct timer_list int_poll_timer;	/* Added for poll event */
+	php_intr_callback_t attention_button_callback;
+	php_intr_callback_t switch_change_callback;
+	php_intr_callback_t presence_change_callback;
+	php_intr_callback_t power_fault_callback;
+	void *callback_instance_id;
+	void *creg;				/* Ptr to controller register space */
+};
+/* Inline functions */
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check (struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL", function);
+		return -1;
+	}
+	if (slot->magic != SLOT_MAGIC) {
+		dbg("%s - bad magic number for slot", function);
+		return -1;
+	}
+	if (!slot->hotplug_slot) {
+		dbg("%s - slot->hotplug_slot == NULL!", function);
+		return -1;
+	}
+	return 0;
+}
+
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
+{ 
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL\n", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot->private;
+	if (slot_paranoia_check (slot, function))
+                return NULL;
+	return slot;
+}
+
+static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device)
+{
+	struct slot *p_slot, *tmp_slot = NULL;
+
+	if (!ctrl)
+		return NULL;
+
+	p_slot = ctrl->slot;
+
+	dbg("p_slot = %p\n", p_slot);
+
+	while (p_slot && (p_slot->device != device)) {
+		tmp_slot = p_slot;
+		p_slot = p_slot->next;
+		dbg("In while loop, p_slot = %p\n", p_slot);
+	}
+	if (p_slot == NULL) {
+		err("ERROR: shpchp_find_slot device=0x%x\n", device);
+		p_slot = tmp_slot;
+	}
+
+	return (p_slot);
+}
+
+static inline int wait_for_ctrl_irq (struct controller *ctrl)
+{
+    DECLARE_WAITQUEUE(wait, current);
+	int retval = 0;
+
+	dbg("%s : start\n",__FUNCTION__);
+
+	add_wait_queue(&ctrl->queue, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	if (!shpchp_poll_mode) {
+		/* Sleep for up to 1 second */
+		schedule_timeout(1*HZ);
+	} else {
+		/* Sleep for up to 2 second */
+		schedule_timeout(2*HZ);
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&ctrl->queue, &wait);
+	if (signal_pending(current))
+		retval =  -EINTR;
+
+	dbg("%s : end\n", __FUNCTION__);
+	return retval;
+}
+
+/* Puts node back in the resource list pointed to by head */
+static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
+{
+	if (!node || !head)
+		return;
+	node->next = *head;
+	*head = node;
+}
+
+#define SLOT_NAME_SIZE 10
+
+static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
+{
+	snprintf(buffer, buffer_size, "%d", slot->number);
+}
+
+enum php_ctlr_type {
+	PCI,
+	ISA,
+	ACPI
+};
+
+int shpc_init( struct controller *ctrl, struct pci_dev *pdev,
+		php_intr_callback_t attention_button_callback,
+		php_intr_callback_t switch_change_callback,
+		php_intr_callback_t presence_change_callback,
+		php_intr_callback_t power_fault_callback);
+
+
+int shpc_get_ctlr_slot_config( struct controller *ctrl,
+		int *num_ctlr_slots,
+		int *first_device_num,
+		int *physical_slot_num,
+		int *updown,
+		int *flags);
+
+struct hpc_ops {
+	int	(*power_on_slot )	(struct slot *slot);
+	int	(*slot_enable )		(struct slot *slot);
+	int	(*slot_disable )	(struct slot *slot);
+	int	(*enable_all_slots)	(struct slot *slot);
+	int	(*pwr_on_all_slots)	(struct slot *slot);
+	int	(*set_bus_speed_mode)	(struct slot *slot, enum pci_bus_speed speed);
+	int	(*get_power_status)	(struct slot *slot, u8 *status);
+	int	(*get_attention_status)	(struct slot *slot, u8 *status);
+	int	(*set_attention_status)	(struct slot *slot, u8 status);
+	int	(*get_latch_status)	(struct slot *slot, u8 *status);
+	int	(*get_adapter_status)	(struct slot *slot, u8 *status);
+
+	int	(*get_max_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_cur_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_adapter_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_mode1_ECC_cap)	(struct slot *slot, u8 *mode);
+	int	(*get_prog_int)		(struct slot *slot, u8 *prog_int);
+
+	int	(*query_power_fault)	(struct slot *slot);
+	void	(*green_led_on)		(struct slot *slot);
+	void	(*green_led_off)	(struct slot *slot);
+	void	(*green_led_blink)	(struct slot *slot);
+	void	(*release_ctlr)		(struct controller *ctrl);
+	int (*check_cmd_status)		(struct controller *ctrl);
+};
+
+#endif				/* _SHPCHP_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp_core.c linux-2.4.27-pre3/drivers/hotplug/shpchp_core.c
--- linux-2.4.26/drivers/hotplug/shpchp_core.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchp_core.c	2004-05-18 16:51:39.000000000 +0000
@@ -0,0 +1,700 @@
+/*
+ * Standard 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) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/tqueue.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include "shpchp.h"
+#include "shpchprm.h"
+
+/* Global variables */
+int shpchp_debug;
+int shpchp_poll_mode;
+int shpchp_poll_time;
+struct controller *shpchp_ctrl_list;	/* = NULL */
+struct pci_func *shpchp_slot_list[256];
+
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
+#define DRIVER_DESC	"Standard Hot Plug PCI Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(shpchp_debug, "i");
+MODULE_PARM(shpchp_poll_mode, "i");
+MODULE_PARM(shpchp_poll_time, "i");
+MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not");
+MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not");
+MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
+
+#define SHPC_MODULE_NAME "shpchp.o"
+
+static int shpc_start_thread (void);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int hardware_test	(struct hotplug_slot *slot, u32 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+
+static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
+	.owner =		THIS_MODULE,
+	.set_attention_status =	set_attention_status,
+	.enable_slot =		enable_slot,
+	.disable_slot =		disable_slot,
+	.hardware_test =	hardware_test,
+	.get_power_status =	get_power_status,
+	.get_attention_status =	get_attention_status,
+	.get_latch_status =	get_latch_status,
+	.get_adapter_status =	get_adapter_status,
+  	.get_max_bus_speed =	get_max_bus_speed,
+  	.get_cur_bus_speed =	get_cur_bus_speed,
+};
+
+static int init_slots(struct controller *ctrl)
+{
+	struct slot *new_slot;
+	u8 number_of_slots;
+	u8 slot_device;
+	u32 slot_number, sun;
+	int result;
+
+	dbg("%s\n",__FUNCTION__);
+
+	number_of_slots = ctrl->num_slots;
+	slot_device = ctrl->slot_device_offset;
+	slot_number = ctrl->first_slot;
+
+	while (number_of_slots) {
+		new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL);
+		if (!new_slot)
+			return -ENOMEM;
+
+		memset(new_slot, 0, sizeof(struct slot));
+		new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		if (!new_slot->hotplug_slot) {
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+		memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+
+		new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if (!new_slot->hotplug_slot->info) {
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+		memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+		new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!new_slot->hotplug_slot->name) {
+			kfree (new_slot->hotplug_slot->info);
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+
+		new_slot->magic = SLOT_MAGIC;
+		new_slot->ctrl = ctrl;
+		new_slot->bus = ctrl->slot_bus;
+		new_slot->device = slot_device;
+		new_slot->hpc_ops = ctrl->hpc_ops;
+
+		if (shpchprm_get_physical_slot_number(ctrl, &sun, new_slot->bus, new_slot->device)) {
+			kfree (new_slot->hotplug_slot->info);
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+
+		new_slot->number = sun;
+		new_slot->hp_slot = slot_device - ctrl->slot_device_offset;
+
+		/* Register this slot with the hotplug pci core */
+		new_slot->hotplug_slot->private = new_slot;
+		make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
+		new_slot->hotplug_slot->ops = &shpchp_hotplug_slot_ops;
+
+		new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status));
+		new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status));
+		new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status));
+		new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status));
+
+		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", new_slot->bus, new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset);
+		result = pci_hp_register (new_slot->hotplug_slot);
+		if (result) {
+			err ("pci_hp_register failed with error %d\n", result);
+			kfree (new_slot->hotplug_slot->info);
+			kfree (new_slot->hotplug_slot->name);
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
+			return result;
+		}
+
+		new_slot->next = ctrl->slot;
+		ctrl->slot = new_slot;
+
+		number_of_slots--;
+		slot_device++;
+		slot_number += ctrl->slot_num_inc;
+	}
+
+	return(0);
+}
+
+
+static int cleanup_slots (struct controller * ctrl)
+{
+	struct slot *old_slot, *next_slot;
+
+	old_slot = ctrl->slot;
+	ctrl->slot = NULL;
+
+	while (old_slot) {
+		next_slot = old_slot->next;
+		pci_hp_deregister (old_slot->hotplug_slot);
+		kfree(old_slot->hotplug_slot->info);
+		kfree(old_slot->hotplug_slot->name);
+		kfree(old_slot->hotplug_slot);
+		kfree(old_slot);
+		old_slot = next_slot;
+	}
+
+
+	return(0);
+}
+
+static int get_ctlr_slot_config(struct controller *ctrl)
+{
+	int num_ctlr_slots;
+	int first_device_num;
+	int physical_slot_num;
+	int updown;
+	int rc;
+	int flags;
+
+	rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, 
+		&updown, &flags);
+	if (rc) {
+		err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
+		return (-1);
+	}
+
+	ctrl->num_slots = num_ctlr_slots;
+	ctrl->slot_device_offset = first_device_num;
+	ctrl->first_slot = physical_slot_num;
+	ctrl->slot_num_inc = updown;		/* either -1 or 1 */
+
+	dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n",
+		__FUNCTION__, num_ctlr_slots, first_device_num, physical_slot_num, updown, 
+		ctrl->bus, ctrl->device);
+
+	return (0);
+}
+
+
+/*
+ * set_attention_status - Turns the Amber LED for a slot on, off or blink
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	hotplug_slot->info->attention_status = status;
+	slot->hpc_ops->set_attention_status(slot, status);
+
+
+	return 0;
+}
+
+
+static int enable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	return shpchp_enable_slot(slot);
+}
+
+
+static int disable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	return shpchp_disable_slot(slot);
+}
+
+
+static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
+{
+	return 0;
+}
+
+
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_power_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->power_status;
+
+	return 0;
+}
+
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_attention_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->attention_status;
+
+	return 0;
+}
+
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_latch_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->latch_status;
+
+	return 0;
+}
+
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_adapter_status(slot, value);
+
+	if (retval < 0)
+		*value = hotplug_slot->info->adapter_status;
+
+	return 0;
+}
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+	
+	retval = slot->hpc_ops->get_max_bus_speed(slot, value);
+	if (retval < 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+	
+	retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
+	if (retval < 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc;
+	struct controller *ctrl;
+	struct slot *t_slot;
+	int first_device_num;	/* first PCI device number supported by this SHPC */
+	int num_ctlr_slots;		/* number of slots supported by this SHPC */
+
+	ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
+	if (!ctrl) {
+		err("%s : out of memory\n", __FUNCTION__);
+		goto err_out_none;
+	}
+	memset(ctrl, 0, sizeof(struct controller));
+
+	dbg("DRV_thread pid = %d\n", current->pid);
+
+	rc = shpc_init(ctrl, pdev,
+		(php_intr_callback_t) shpchp_handle_attention_button,
+		(php_intr_callback_t) shpchp_handle_switch_change,
+		(php_intr_callback_t) shpchp_handle_presence_change,
+		(php_intr_callback_t) shpchp_handle_power_fault);
+	if (rc) {
+		dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME);
+		goto err_out_free_ctrl;
+	}
+
+	dbg("%s: controller initialization success\n", __FUNCTION__);
+	ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
+
+	ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);
+	if (!ctrl->pci_bus) {
+		err("out of memory\n");
+		rc = -ENOMEM;
+		goto err_out_unmap_mmio_region;
+	}
+	memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
+	ctrl->bus = pdev->bus->number;
+	ctrl->slot_bus = pdev->subordinate->number;
+
+	ctrl->device = PCI_SLOT(pdev->devfn);
+	ctrl->function = PCI_FUNC(pdev->devfn);
+	dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", ctrl->bus, ctrl->device, 
+		ctrl->function, pdev->irq);
+
+	/*
+	 *	Save configuration headers for this and subordinate PCI buses
+	 */
+
+	rc = get_ctlr_slot_config(ctrl);
+	if (rc) {
+		err(msg_initialization_err, rc);
+		goto err_out_free_ctrl_bus;
+	}
+	first_device_num = ctrl->slot_device_offset;
+	num_ctlr_slots = ctrl->num_slots;
+
+	/* Store PCI Config Space for all devices on this bus */
+	rc = shpchp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num);
+	if (rc) {
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Get IO, memory, and IRQ resources for new devices */
+	rc = shpchprm_find_available_resources(ctrl);
+	ctrl->add_support = !rc;
+	
+	if (rc) {
+		dbg("shpchprm_find_available_resources = %#x\n", rc);
+		err("unable to locate PCI configuration resources for hot plug add.\n");
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Setup the slot information structures */
+	rc = init_slots(ctrl);
+	if (rc) {
+		err(msg_initialization_err, 6);
+		goto err_out_free_ctrl_slot;
+	}
+
+	/* Now hpc_functions (slot->hpc_ops->functions) are ready  */
+	t_slot = shpchp_find_slot(ctrl, first_device_num);
+
+	/* Check for operation bus speed */
+	rc = t_slot->hpc_ops->get_cur_bus_speed(t_slot, &ctrl->speed);
+	dbg("%s: t_slot->hp_slot %x\n", __FUNCTION__,t_slot->hp_slot);
+
+	if (rc || ctrl->speed == PCI_SPEED_UNKNOWN) {
+		err(SHPC_MODULE_NAME ": Can't get current bus speed. Set to 33MHz PCI.\n");
+		ctrl->speed = PCI_SPEED_33MHz;
+	}
+
+	/* Finish setting up the hot plug ctrl device */
+	ctrl->next_event = 0;
+
+	if (!shpchp_ctrl_list) {
+		shpchp_ctrl_list = ctrl;
+		ctrl->next = NULL;
+	} else {
+		ctrl->next = shpchp_ctrl_list;
+		shpchp_ctrl_list = ctrl;
+	}
+
+	return 0;
+
+err_out_free_ctrl_slot:
+	cleanup_slots(ctrl);
+err_out_free_ctrl_bus:
+	kfree(ctrl->pci_bus);
+err_out_unmap_mmio_region:
+	ctrl->hpc_ops->release_ctlr(ctrl);
+err_out_free_ctrl:
+	kfree(ctrl);
+err_out_none:
+	return -ENODEV;
+}
+
+
+static int shpc_start_thread(void)
+{
+	int loop;
+	int retval = 0;
+	
+	dbg("Initialize + Start the notification/polling mechanism \n");
+
+	retval = shpchp_event_start_thread();
+	if (retval) {
+		dbg("shpchp_event_start_thread() failed\n");
+		return retval;
+	}
+
+	dbg("Initialize slot lists\n");
+	/* One slot list for each bus in the system */
+	for (loop = 0; loop < 256; loop++) {
+		shpchp_slot_list[loop] = NULL;
+	}
+
+	return retval;
+}
+
+
+static void unload_shpchpd(void)
+{
+	struct pci_func *next;
+	struct pci_func *TempSlot;
+	int loop;
+	struct controller *ctrl;
+	struct controller *tctrl;
+	struct pci_resource *res;
+	struct pci_resource *tres;
+
+	ctrl = shpchp_ctrl_list;
+
+	while (ctrl) {
+		cleanup_slots(ctrl);
+
+		res = ctrl->io_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		res = ctrl->mem_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		res = ctrl->p_mem_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		res = ctrl->bus_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		kfree (ctrl->pci_bus);
+
+		dbg("%s: calling release_ctlr\n", __FUNCTION__);
+		ctrl->hpc_ops->release_ctlr(ctrl);
+
+		tctrl = ctrl;
+		ctrl = ctrl->next;
+
+		kfree(tctrl);
+	}
+
+	for (loop = 0; loop < 256; loop++) {
+		next = shpchp_slot_list[loop];
+		while (next != NULL) {
+			res = next->io_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			res = next->mem_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			res = next->p_mem_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			res = next->bus_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			TempSlot = next;
+			next = next->next;
+			kfree(TempSlot);
+		}
+	}
+
+	/* Stop the notification mechanism */
+	shpchp_event_stop_thread();
+
+}
+
+
+static struct pci_device_id shpcd_pci_tbl[] __devinitdata = {
+	{
+	.class =        ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00),
+	.class_mask =	~0,	
+	.vendor =       PCI_ANY_ID,
+	.device =       PCI_ANY_ID,
+	.subvendor =    PCI_ANY_ID,
+	.subdevice =    PCI_ANY_ID,
+	},
+	{ /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl);
+
+
+
+static struct pci_driver shpc_driver = {
+	.name =		SHPC_MODULE_NAME,
+	.id_table =	shpcd_pci_tbl,
+	.probe =	shpc_probe,
+	/* remove:	shpc_remove_one, */
+};
+
+
+
+static int __init shpcd_init(void)
+{
+	int retval = 0;
+
+#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
+	shpchp_poll_mode = 1;
+#endif
+
+	retval = shpc_start_thread();
+	if (retval)
+		goto error_hpc_init;
+
+	retval = shpchprm_init(PCI);
+	if (!retval) {
+		retval = pci_module_init(&shpc_driver);
+		dbg("%s: pci_module_init = %d\n", __FUNCTION__,retval);
+		info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+	}
+
+error_hpc_init:
+	if (retval) {
+		shpchprm_cleanup();
+		shpchp_event_stop_thread();
+	} else
+			shpchprm_print_pirt();
+
+	return retval;
+}
+
+static void __exit shpcd_cleanup(void)
+{
+	dbg("unload_shpchpd()\n");
+	unload_shpchpd();
+
+	shpchprm_cleanup();
+
+	dbg("pci_unregister_driver\n");
+	pci_unregister_driver(&shpc_driver);
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
+}
+
+
+module_init(shpcd_init);
+module_exit(shpcd_cleanup);
+
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp_ctrl.c linux-2.4.27-pre3/drivers/hotplug/shpchp_ctrl.c
--- linux-2.4.26/drivers/hotplug/shpchp_ctrl.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchp_ctrl.c	2004-05-18 16:55:11.000000000 +0000
@@ -0,0 +1,3071 @@
+/*
+ * Standard 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) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include "shpchp.h"
+#include "shpchprm.h"
+
+static u32 configure_new_device(struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static int configure_new_function( struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static void interrupt_event_handler(struct controller *ctrl);
+
+static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
+static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
+static int event_finished;
+static unsigned long pushbutton_pending;	/* = 0 */
+
+u8 shpchp_disk_irq;
+u8 shpchp_nic_irq;
+
+u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Attention Button Change */
+	dbg("shpchp:  Attention button interrupt received.\n");
+	
+	func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread what to do */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+
+	/*
+	 *  Button pressed - See if need to TAKE ACTION!!!
+	 */
+	info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	taskInfo->event_type = INT_BUTTON_PRESS;
+
+	if ((p_slot->state == BLINKINGON_STATE)
+	    || (p_slot->state == BLINKINGOFF_STATE)) {
+		/* Cancel if we are still blinking; this means that we press the
+		 * attention again before the 5 sec. limit expires to cancel hot-add
+		 * or hot-remove
+		 */
+		taskInfo->event_type = INT_BUTTON_CANCEL;
+		info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	} else if ((p_slot->state == POWERON_STATE)
+		   || (p_slot->state == POWEROFF_STATE)) {
+		/* Ignore if the slot is on power-on or power-off state; this 
+		 * means that the previous attention button action to hot-add or
+		 * hot-remove is undergoing
+		 */
+		taskInfo->event_type = INT_BUTTON_IGNORE;
+		info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	}
+
+	if (rc)
+		up(&event_semaphore);	/* Signal event thread that new event is posted */
+
+	return 0;
+
+}
+
+u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Switch Change */
+	dbg("shpchp:  Switch interrupt received.\n");
+
+	func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+
+	if (getstatus) {
+		/*
+		 * Switch opened
+		 */
+		info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->switch_save = 0;
+		taskInfo->event_type = INT_SWITCH_OPEN;
+	} else {
+		/*
+		 *  Switch closed
+		 */
+		info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->switch_save = 0x10;
+		taskInfo->event_type = INT_SWITCH_CLOSE;
+	}
+
+	if (rc)
+		up(&event_semaphore);	/* Signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Presence Change */
+	dbg("shpchp:  Presence/Notify input change.\n");
+
+	func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	/* 
+	 * Save the presence state
+	 */
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	if (func->presence_save) {
+		/*
+		 * Card Present
+		 */
+		info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_PRESENCE_ON;
+	} else {
+		/*
+		 * Not Present
+		 */
+		info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_PRESENCE_OFF;
+	}
+
+	if (rc)
+		up(&event_semaphore);	/* Signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Power fault */
+	dbg("shpchp:  Power fault interrupt received.\n");
+
+	func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
+		/*
+		 * Power fault Cleared
+		 */
+		info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->status = 0x00;
+		taskInfo->event_type = INT_POWER_FAULT_CLEAR;
+	} else {
+		/*
+		 *  Power fault
+		 */
+		info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_POWER_FAULT;
+		/* Set power fault status for this board */
+		func->status = 0xFF;
+		info("power fault bit %x set\n", hp_slot);
+	}
+	if (rc)
+		up(&event_semaphore);	/* Signal event thread that new event is posted */
+
+	return rc;
+}
+
+
+/*
+ * sort_by_size
+ *
+ * Sorts nodes on the list by their length.
+ * Smallest first.
+ *
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)->next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length > (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length > current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * sort_by_max_size
+ *
+ * Sorts nodes on the list by their length.
+ * Largest first.
+ *
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)->next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length < (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length < current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * do_pre_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 rc;
+	u32 temp_dword;
+	dbg("do_pre_bridge_resource_split\n");
+
+	if (!(*head) || !(*orig_head))
+		return(NULL);
+
+	rc = shpchp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	if ((*head)->base != (*orig_head)->base)
+		return(NULL);
+
+	if ((*head)->length == (*orig_head)->length)
+		return(NULL);
+
+
+	/* If we got here, there the bridge requires some of the resource, but
+	 *  we may be able to split some off of the front
+	 */	
+	node = *head;
+
+	if (node->length & (alignment -1)) {
+		/* This one isn't an aligned length, so we'll make a new entry
+		 * and split it up.
+		 */
+		split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+		if (!split_node)
+			return(NULL);
+
+		temp_dword = (node->length | (alignment-1)) + 1 - alignment;
+
+		split_node->base = node->base;
+		split_node->length = temp_dword;
+
+		node->length -= temp_dword;
+		node->base += split_node->length;
+
+		/* Put it in the list */
+		*head = split_node;
+		split_node->next = node;
+	}
+
+	if (node->length < alignment) {
+		return(NULL);
+	}
+
+	/* Now unlink it */
+	if (*head == node) {
+		*head = node->next;
+		node->next = NULL;
+	} else {
+		prevnode = *head;
+		while (prevnode->next != node)
+			prevnode = prevnode->next;
+
+		prevnode->next = node->next;
+		node->next = NULL;
+	}
+
+	return(node);
+}
+
+
+/*
+ * do_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	u32 rc;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	rc = shpchp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	node = *head;
+
+	while (node->next) {
+		prevnode = node;
+		node = node->next;
+		kfree(prevnode);
+	}
+
+	if (node->length < alignment) {
+		kfree(node);
+		return(NULL);
+	}
+
+	if (node->base & (alignment - 1)) {
+		/* Short circuit if adjusted size is too small */
+		temp_dword = (node->base | (alignment-1)) + 1;
+		if ((node->length - (temp_dword - node->base)) < alignment) {
+			kfree(node);
+			return(NULL);
+		}
+
+		node->length -= (temp_dword - node->base);
+		node->base = temp_dword;
+	}
+
+	if (node->length & (alignment - 1)) {
+		/* There's stuff in use after this node */
+		kfree(node);
+		return(NULL);
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_io_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length that is not in the
+ * ISA aliasing window.  If it finds a node larger than "size"
+ * it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node = NULL;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( shpchp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node->next) {
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			/* 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;
+
+			/*/ Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			/* 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);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if (node->base & 0x300L)
+			continue;
+
+		/* If we got here, then it is the right size 
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_max_resource
+ *
+ * Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M
+ *  This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot.
+ */
+static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+	u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 };
+	int i;
+
+	if (!(*head))
+		return(NULL);
+
+	if (shpchp_resource_sort_and_combine(head))
+		return(NULL);
+
+	if (sort_by_max_size(head))
+		return(NULL);
+
+	for (max = *head;max; max = max->next) {
+
+		/* If not big enough we could probably just bail, 
+		   instead we'll continue to the next. */
+		if (max->length < size)
+			continue;
+
+		if (max->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (max->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max->length - (temp_dword - max->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = max->base;
+			split_node->length = temp_dword - max->base;
+			max->base = temp_dword;
+			max->length -= split_node->length;
+
+			/* Put it next in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		if ((max->base + max->length) & (size - 1)) {
+			/* this one isn't end aligned properly at the top
+			   so we'll make a new entry and split it up */
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+			temp_dword = ((max->base + max->length) & ~(size - 1));
+			split_node->base = temp_dword;
+			split_node->length = max->length + max->base
+					     - split_node->base;
+			max->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max->length < size)
+			continue;
+
+		for ( i = 0; max_size[i] > size; i++) {
+			if (max->length > max_size[i]) {
+				split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), 
+					GFP_KERNEL);
+				if (!split_node)
+					break;	/* return (NULL); */
+				split_node->base = max->base + max_size[i];
+				split_node->length = max->length - max_size[i];
+				max->length = max_size[i];
+				/* Put it next in the list */
+				split_node->next = max->next;
+				max->next = split_node;
+				break;
+			}
+		}
+
+		/* Now take it out of the list */
+		temp = (struct pci_resource*) *head;
+		if (temp == max) {
+			*head = max->next;
+		} else {
+			while (temp && temp->next != max) {
+				temp = temp->next;
+			}
+
+			temp->next = max->next;
+		}
+
+		max->next = NULL;
+		return(max);
+	}
+
+	/* If we get here, we couldn't find one */
+	return(NULL);
+}
+
+
+/*
+ * get_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( shpchp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node->next) {
+		dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n",
+		    __FUNCTION__, size, node, node->base, node->length);
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			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;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			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);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		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) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return(node);
+}
+
+
+/*
+ * shpchp_resource_sort_and_combine
+ *
+ * Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int shpchp_resource_sort_and_combine(struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
+
+	if (!(*head))
+		return(1);
+
+	dbg("*head->next = %p\n",(*head)->next);
+
+	if (!(*head)->next)
+		return(0);	/* only one item on the list, already sorted! */
+
+	dbg("*head->base = 0x%x\n",(*head)->base);
+	dbg("*head->next->base = 0x%x\n",(*head)->next->base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->base > (*head)->next->base)) {
+			node1 = *head;
+			(*head) = (*head)->next;
+			node1->next = (*head)->next;
+			(*head)->next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1->next && node1->next->next) {
+			if (node1->next->base > node1->next->next->base) {
+				out_of_order++;
+				node2 = node1->next;
+				node1->next = node1->next->next;
+				node1 = node1->next;
+				node2->next = node1->next;
+				node1->next = node2;
+			} else
+				node1 = node1->next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 && node1->next) {
+		if ((node1->base + node1->length) == node1->next->base) {
+			/* Combine */
+			dbg("8..\n");
+			node1->length += node1->next->length;
+			node2 = node1->next;
+			node1->next = node1->next->next;
+			kfree(node2);
+		} else
+			node1 = node1->next;
+	}
+
+	return(0);
+}
+
+
+/**
+ * shpchp_slot_create - Creates a node and adds it to the proper bus.
+ * @busnumber - bus where new node is to be located
+ *
+ * Returns pointer to the new node or NULL if unsuccessful
+ */
+struct pci_func *shpchp_slot_create(u8 busnumber)
+{
+	struct pci_func *new_slot;
+	struct pci_func *next;
+
+	new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL);
+
+	if (new_slot == NULL) {
+		return(new_slot);
+	}
+
+	memset(new_slot, 0, sizeof(struct pci_func));
+
+	new_slot->next = NULL;
+	new_slot->configured = 1;
+
+	if (shpchp_slot_list[busnumber] == NULL) {
+		shpchp_slot_list[busnumber] = new_slot;
+	} else {
+		next = shpchp_slot_list[busnumber];
+		while (next->next != NULL)
+			next = next->next;
+		next->next = new_slot;
+	}
+	return(new_slot);
+}
+
+
+/*
+ * slot_remove - Removes a node from the linked list of slots.
+ * @old_slot: slot to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int slot_remove(struct pci_func * old_slot)
+{
+	struct pci_func *next;
+
+	if (old_slot == NULL)
+		return(1);
+
+	next = shpchp_slot_list[old_slot->bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == old_slot) {
+		shpchp_slot_list[old_slot->bus] = old_slot->next;
+		shpchp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	}
+
+	while ((next->next != old_slot) && (next->next != NULL)) {
+		next = next->next;
+	}
+
+	if (next->next == old_slot) {
+		next->next = old_slot->next;
+		shpchp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * bridge_slot_remove - Removes a node from the linked list of slots.
+ * @bridge: bridge to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int bridge_slot_remove(struct pci_func *bridge)
+{
+	u8 subordinateBus, secondaryBus;
+	u8 tempBus;
+	struct pci_func *next;
+
+	if (bridge == NULL)
+		return(1);
+
+	secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
+	subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
+
+	for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
+		next = shpchp_slot_list[tempBus];
+
+		while (!slot_remove(next)) {
+			next = shpchp_slot_list[tempBus];
+		}
+	}
+
+	next = shpchp_slot_list[bridge->bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == bridge) {
+		shpchp_slot_list[bridge->bus] = bridge->next;
+		kfree(bridge);
+		return(0);
+	}
+
+	while ((next->next != bridge) && (next->next != NULL)) {
+		next = next->next;
+	}
+
+	if (next->next == bridge) {
+		next->next = bridge->next;
+		kfree(bridge);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * shpchp_slot_find - Looks for a node by bus, and device, multiple functions accessed
+ * @bus: bus to find
+ * @device: device to find
+ * @index: is 0 for first function found, 1 for the second...
+ *
+ * Returns pointer to the node if successful, %NULL otherwise.
+ */
+struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index)
+{
+	int found = -1;
+	struct pci_func *func;
+
+	func = shpchp_slot_list[bus];
+
+	if ((func == NULL) || ((func->device == device) && (index == 0)))
+		return(func);
+
+	if (func->device == device)
+		found++;
+
+	while (func->next != NULL) {
+		func = func->next;
+
+		if (func->device == device)
+			found++;
+
+		if (found == index)
+			return(func);
+	}
+
+	return(NULL);
+}
+
+static int is_bridge(struct pci_func * func)
+{
+	/* Check the header type */
+	if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) {
+		dbg("%s: Is a bridge\n", __FUNCTION__);
+		return 1;
+	} else {
+		dbg("%s: Not a bridge\n", __FUNCTION__);
+		return 0;
+	}
+}
+
+
+/* the following routines constitute the bulk of the 
+   hotplug controller logic
+ */
+
+
+/**
+ * board_added - Called after a board has been added to the system.
+ *
+ * Turns power on for the board
+ * Configures board
+ *
+ */
+static u32 board_added(struct pci_func * func, struct controller * ctrl)
+{
+	u8 hp_slot, slot;
+	u8 slots_not_empty = 0;
+	int index;
+	u32 temp_register = 0xFFFFFFFF;
+	u32 retval, rc = 0;
+	struct pci_func *new_func = NULL;
+	struct pci_func *t_func = NULL;
+	struct slot *p_slot, *pslot;
+	struct resource_lists res_lists;
+	enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed;
+	u8 pi, mode;
+
+	p_slot = shpchp_find_slot(ctrl, func->device);
+	hp_slot = func->device - ctrl->slot_device_offset;
+
+	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);
+	
+	/* Power on slot without connecting to bus */
+	rc = p_slot->hpc_ops->power_on_slot(p_slot);
+	if (rc) {
+		err("%s: Failed to power on slot\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return -1;
+	}
+			
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq(ctrl);
+	
+	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+	if (rc) {
+		err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return -1;
+	}
+
+	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
+	/* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */
+	/* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC,  0xa = PCI-X 133 Mhz 266, */
+	/* 0xd = PCI-X 133 Mhz 533 */
+	/* This encoding is different from the one used in cur_bus_speed & */
+	/* max_bus_speed */
+
+	if (rc  || adapter_speed == PCI_SPEED_UNKNOWN) {
+		err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return WRONG_BUS_FREQUENCY;
+	}
+
+	rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed);
+	if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
+		err("%s: Can't get bus operation speed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return WRONG_BUS_FREQUENCY;
+	}
+
+	rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed);
+	if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
+		err("%s: Can't get max bus operation speed\n", __FUNCTION__);
+		max_bus_speed = bus_speed;
+	}
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	rc  = p_slot->hpc_ops->get_prog_int(p_slot, &pi);
+	if (rc) {
+		err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
+		pi = 1;
+	}
+
+	if (pi == 2) {
+		for ( slot = 0; slot < ctrl->num_slots; slot++) {
+			if (slot != hp_slot) {
+				pslot = shpchp_find_slot(ctrl, slot + ctrl->slot_device_offset);
+				t_func = shpchp_slot_find(pslot->bus, pslot->device, 0);
+				slots_not_empty |= t_func->is_a_board;
+			}
+		}
+
+		switch (adapter_speed) {
+		case PCI_SPEED_133MHz_PCIX_533:	
+		case PCI_SPEED_133MHz_PCIX_266:
+			if ((( bus_speed < 0xa ) || (bus_speed < 0xd)) && (max_bus_speed > bus_speed) &&
+				((max_bus_speed <= 0xa) || (max_bus_speed <= 0xd)) && (!slots_not_empty)) {
+			
+				/* Wait for exclusive access to hardware */
+				down(&ctrl->crit_sect);
+
+				rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
+				if (rc) {
+					err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);				
+					return WRONG_BUS_FREQUENCY;
+				}
+				
+				/* Wait for the command to complete */
+				wait_for_ctrl_irq (ctrl);
+		
+				rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+				if (rc) {
+					err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
+							  __FUNCTION__);
+					err("%s: Error code (%d)\n", __FUNCTION__, rc);
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);				
+					return WRONG_BUS_FREQUENCY;
+				}
+				/* Done with exclusive hardware access */
+				up(&ctrl->crit_sect);
+			}
+			break;
+		case PCI_SPEED_133MHz_PCIX_ECC:
+		case PCI_SPEED_133MHz_PCIX:
+
+			rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode);
+
+			if (rc) {
+				err("%s: PI is 1 \n", __FUNCTION__);
+				return WRONG_BUS_FREQUENCY;
+			}
+
+			if (mode) { /* Bus - Mode 1 ECC */
+
+				if (bus_speed > 0x7)  {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+
+				if ((bus_speed < 0x7) && (max_bus_speed <= 0x7) &&
+					(bus_speed < max_bus_speed) && (!slots_not_empty)) {
+
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
+							  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+				}
+			} else {
+				if (bus_speed > 0x4)  {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+
+				if ((bus_speed < 0x4) && (max_bus_speed <= 0x4) &&
+					(bus_speed < max_bus_speed) && (!slots_not_empty)) {
+
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
+							  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+				}
+			}
+			break;
+		case PCI_SPEED_66MHz_PCIX_ECC:
+		case PCI_SPEED_66MHz_PCIX:
+
+			rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode);
+
+			if (rc) {
+				err("%s: PI is 1 \n", __FUNCTION__);
+				return WRONG_BUS_FREQUENCY;
+			}
+
+			if (mode) { /* Bus - Mode 1 ECC */
+
+				if (bus_speed > 0x5)  {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+
+				if ((bus_speed < 0x5) && (max_bus_speed <= 0x5) &&
+					(bus_speed < max_bus_speed) && (!slots_not_empty)) {
+
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
+							  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+				}
+			} else {
+				if (bus_speed > 0x2) {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+
+				if ((bus_speed < 0x2) && (max_bus_speed <= 0x2) &&
+					(bus_speed < max_bus_speed) && (!slots_not_empty)) {
+
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
+							  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+				}
+			}
+			break;
+		case PCI_SPEED_66MHz:
+			if (bus_speed > 0x1) {
+				err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+				return WRONG_BUS_FREQUENCY;
+			}
+			if (bus_speed == 0x1)
+				;
+			if ((bus_speed == 0x0) && ( max_bus_speed == 0x1))  {
+				/* Wait for exclusive access to hardware */
+				down(&ctrl->crit_sect);
+
+				rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
+				if (rc) {
+					err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);				
+					return WRONG_BUS_FREQUENCY;
+				}
+				
+				/* Wait for the command to complete */
+				wait_for_ctrl_irq (ctrl);
+		
+				rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+				if (rc) {
+					err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
+							  __FUNCTION__);
+					err("%s: Error code (%d)\n", __FUNCTION__, rc);
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);				
+					return WRONG_BUS_FREQUENCY;
+				}
+				/* Done with exclusive hardware access */
+				up(&ctrl->crit_sect);
+			}
+			break;	
+		case PCI_SPEED_33MHz:
+			if (bus_speed > 0x0) {
+				err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+				return WRONG_BUS_FREQUENCY;
+			}
+			break;
+		default:
+			err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+			return WRONG_BUS_FREQUENCY;
+		}
+	} else {
+		/* if adpater_speed == bus_speed, nothing to do here */
+		if (adapter_speed != bus_speed) {
+			for ( slot = 0; slot < ctrl->num_slots; slot++) {
+				if (slot != hp_slot) {
+					pslot = shpchp_find_slot(ctrl, slot + ctrl->slot_device_offset);
+					t_func = shpchp_slot_find(pslot->bus, pslot->device, 0);
+					slots_not_empty |= t_func->is_a_board;
+				}
+			}
+
+			if (slots_not_empty != 0) { /* Other slots on the same bus are occupied */
+				if ( adapter_speed < bus_speed ) {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+				/* Do nothing if adapter_speed >= bus_speed */
+			}
+		}
+			
+		if ((adapter_speed != bus_speed) && (slots_not_empty == 0))  {
+			/* Other slots on the same bus are empty */
+			
+			rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed);
+			if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
+				err("%s: Can't get max bus operation speed\n", __FUNCTION__);
+				max_bus_speed = bus_speed;
+			}
+
+			if (max_bus_speed == bus_speed) {
+				/* if adapter_speed >= bus_speed, do nothing */
+				if (adapter_speed < bus_speed) {
+				/* 
+				 * Try to lower bus speed to accommodate the adapter if other slots 
+				 * on the same controller are empty
+				 */
+					
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
+								  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+
+				} 
+			} else {
+				/* Wait for exclusive access to hardware */
+				down(&ctrl->crit_sect);
+
+				/* max_bus_speed != bus_speed. Note: max_bus_speed should be > than bus_speed */
+				if (adapter_speed < max_bus_speed) 
+					rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed);
+				else  
+					rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
+				
+				if (rc) {
+					err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+					return WRONG_BUS_FREQUENCY;
+				}
+				
+				/* Wait for the command to complete */
+				wait_for_ctrl_irq (ctrl);
+		
+				rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+				if (rc) {
+					err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", 
+						__FUNCTION__);
+					err("%s: Error code (%d)\n", __FUNCTION__, rc);
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+					return WRONG_BUS_FREQUENCY;
+				}
+				/* Done with exclusive hardware access */
+				up(&ctrl->crit_sect);
+
+			}
+		}
+	}
+
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	/* Turn on board, blink green LED, turn off Amber LED */
+	rc = p_slot->hpc_ops->slot_enable(p_slot);
+	
+	if (rc) {
+		err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+
+	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+	if (rc) {
+		err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return rc;  
+	}
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	/* Wait for ~1 second */
+	dbg("%s: before long_delay\n", __FUNCTION__);
+	wait_for_ctrl_irq (ctrl);
+	dbg("%s: afterlong_delay\n", __FUNCTION__);
+
+	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("%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_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register);
+		dbg("%s: pci_bus_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("%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;
+	}
+
+	/* All F's is an empty slot or an invalid board */
+	if (temp_register != 0xFFFFFFFF) {	  /* Check for a board in the slot */
+		res_lists.io_head = ctrl->io_head;
+		res_lists.mem_head = ctrl->mem_head;
+		res_lists.p_mem_head = ctrl->p_mem_head;
+		res_lists.bus_head = ctrl->bus_head;
+		res_lists.irqs = NULL;
+
+		rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0);
+		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;
+		ctrl->bus_head = res_lists.bus_head;
+
+		shpchp_resource_sort_and_combine(&(ctrl->mem_head));
+		shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
+		shpchp_resource_sort_and_combine(&(ctrl->io_head));
+		shpchp_resource_sort_and_combine(&(ctrl->bus_head));
+
+		if (rc) {
+			/* Wait for exclusive access to hardware */
+			down(&ctrl->crit_sect);
+
+			/* turn off slot, turn on Amber LED, turn off Green LED */
+			retval = p_slot->hpc_ops->slot_disable(p_slot);
+			if (retval) {
+				err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
+				/* Done with exclusive hardware access */
+				up(&ctrl->crit_sect);
+				return retval;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq(ctrl);
+			
+			retval = p_slot->hpc_ops->check_cmd_status(ctrl);
+			if (retval) {
+				err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
+				/* Done with exclusive hardware access */
+				up(&ctrl->crit_sect);
+				return retval;  
+			}
+
+			/* Done with exclusive hardware access */
+			up(&ctrl->crit_sect);
+
+			return(rc);
+		}
+		shpchp_save_slot_config(ctrl, func);
+
+		func->status = 0;
+		func->switch_save = 0x10;
+		func->is_a_board = 0x01;
+
+		/* Next, we will instantiate the linux pci_dev structures 
+		 * (with appropriate driver notification, if already present) 
+		 */
+		index = 0;
+		do {
+			new_func = shpchp_slot_find(ctrl->slot_bus, func->device, index++);
+			if (new_func && !new_func->pci_dev) {
+				dbg("%s:call pci_hp_configure_dev\n", __FUNCTION__);
+				shpchp_configure_device(ctrl, new_func);
+			}
+		} while (new_func);
+
+		/* Wait for exclusive access to hardware */
+		down(&ctrl->crit_sect);
+
+		p_slot->hpc_ops->green_led_on(p_slot);
+
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq(ctrl); 
+
+
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+
+	} else {
+		/* Wait for exclusive access to hardware */
+		down(&ctrl->crit_sect);
+
+		/* turn off slot, turn on Amber LED, turn off Green LED */
+		rc = p_slot->hpc_ops->slot_disable(p_slot);
+		if (rc) {
+			err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+			/* Done with exclusive hardware access */
+			up(&ctrl->crit_sect);
+			return rc;
+		}
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq(ctrl); 
+
+		rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+		if (rc) {
+			err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
+			/* Done with exclusive hardware access */
+			up(&ctrl->crit_sect);
+			return rc;  
+		}
+
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+
+		return(rc);
+	}
+	return 0;
+}
+
+
+/**
+ * remove_board - Turns off slot and LED's
+ *
+ */
+static u32 remove_board(struct pci_func *func, struct controller *ctrl)
+{
+	int index;
+	u8 skip = 0;
+	u8 device;
+	u8 hp_slot;
+	u32 rc;
+	struct resource_lists res_lists;
+	struct pci_func *temp_func;
+	struct slot *p_slot;
+
+	if (func == NULL)
+		return(1);
+
+	if (shpchp_unconfigure_device(func))
+		return(1);
+
+	device = func->device;
+
+	hp_slot = func->device - ctrl->slot_device_offset;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+
+	if ((ctrl->add_support) &&
+		!(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) {
+		/* Here we check to see if we've saved any of the board's
+		 * resources already.  If so, we'll skip the attempt to
+		 * determine what's being used.
+		 */
+		index = 0;
+
+		temp_func = func;
+
+		while ((temp_func = shpchp_slot_find(temp_func->bus, temp_func->device, index++))) {
+			if (temp_func->bus_head || temp_func->mem_head
+			    || temp_func->p_mem_head || temp_func->io_head) {
+				skip = 1;
+				break;
+			}
+		}
+
+		if (!skip)
+			rc = shpchp_save_used_resources(ctrl, func, DISABLE_CARD);
+	}
+	/* Change status to shutdown */
+	if (func->is_a_board)
+		func->status = 0x01;
+	func->configured = 0;
+
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	/* Turn off slot, turn on Amber LED, turn off Green LED */
+	rc = p_slot->hpc_ops->slot_disable(p_slot);
+	if (rc) {
+		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq(ctrl); 
+
+	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+	if (rc) {
+		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return rc;  
+	}
+	
+	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
+	if (rc) {
+		err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq(ctrl); 
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	if (ctrl->add_support) {
+		while (func) {
+			res_lists.io_head = ctrl->io_head;
+			res_lists.mem_head = ctrl->mem_head;
+			res_lists.p_mem_head = ctrl->p_mem_head;
+			res_lists.bus_head = ctrl->bus_head;
+
+			dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", 
+				func->bus, func->device, func->function);
+
+			shpchp_return_board_resources(func, &res_lists);
+
+			ctrl->io_head = res_lists.io_head;
+			ctrl->mem_head = res_lists.mem_head;
+			ctrl->p_mem_head = res_lists.p_mem_head;
+			ctrl->bus_head = res_lists.bus_head;
+
+			shpchp_resource_sort_and_combine(&(ctrl->mem_head));
+			shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
+			shpchp_resource_sort_and_combine(&(ctrl->io_head));
+			shpchp_resource_sort_and_combine(&(ctrl->bus_head));
+
+			if (is_bridge(func)) {
+				dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
+					ctrl->seg, func->bus, func->device, func->function);
+				bridge_slot_remove(func);
+			} else {
+				dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
+					ctrl->seg, func->bus, func->device, func->function);
+				slot_remove(func);
+			}
+
+			func = shpchp_slot_find(ctrl->slot_bus, device, 0);
+		}
+
+		/* Setup slot structure with entry for empty slot */
+		func = shpchp_slot_create(ctrl->slot_bus);
+
+		if (func == NULL) {
+			return(1);
+		}
+
+		func->bus = ctrl->slot_bus;
+		func->device = device;
+		func->function = 0;
+		func->configured = 0;
+		func->switch_save = 0x10;
+		func->is_a_board = 0;
+	}
+
+	return 0;
+}
+
+
+static void pushbutton_helper_thread (unsigned long data)
+{
+	pushbutton_pending = data;
+
+	up(&event_semaphore);
+}
+
+
+/* This is the main worker thread */
+static int event_thread(void* data)
+{
+	struct controller *ctrl;
+	lock_kernel();
+	daemonize();
+
+	/* New name */
+	strcpy(current->comm, "shpchpd_event");
+	
+	unlock_kernel();
+
+	while (1) {
+		dbg("!!!!event_thread sleeping\n");
+		down_interruptible (&event_semaphore);
+		dbg("event_thread woken finished = %d\n", event_finished);
+		if (event_finished || signal_pending(current))
+			break;
+		/* Do stuff here */
+		if (pushbutton_pending)
+			shpchp_pushbutton_thread(pushbutton_pending);
+		else
+			for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next)
+				interrupt_event_handler(ctrl);
+	}
+	dbg("event_thread signals exit\n");
+	up(&event_exit);
+	return 0;
+}
+
+int shpchp_event_start_thread (void)
+{
+	int pid;
+
+	/* Initialize our semaphores */
+	init_MUTEX_LOCKED(&event_exit);
+	event_finished=0;
+
+	init_MUTEX_LOCKED(&event_semaphore);
+	pid = kernel_thread(event_thread, 0, 0);
+
+	if (pid < 0) {
+		err ("Can't start up our event thread\n");
+		return -1;
+	}
+	dbg("Our event thread pid = %d\n", pid);
+	return 0;
+}
+
+
+void shpchp_event_stop_thread (void)
+{
+	event_finished = 1;
+	dbg("event_thread finish command given\n");
+	up(&event_semaphore);
+	dbg("wait for event_thread to exit\n");
+	down(&event_exit);
+}
+
+
+static int update_slot_info (struct slot *slot)
+{
+	struct hotplug_slot_info *info;
+	char buffer[SLOT_NAME_SIZE];
+	int result;
+
+	info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot);
+
+	slot->hpc_ops->get_power_status(slot, &(info->power_status));
+	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
+	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
+	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
+
+	result = pci_hp_change_slot_info(buffer, info);
+	kfree (info);
+	return result;
+}
+
+static void interrupt_event_handler(struct controller *ctrl)
+{
+	int loop = 0;
+	int change = 1;
+	struct pci_func *func;
+	u8 hp_slot;
+	u8 getstatus;
+	struct slot *p_slot;
+	
+	dbg("%s:\n", __FUNCTION__);
+	while (change) {
+		change = 0;
+
+		for (loop = 0; loop < 10; loop++) {
+			if (ctrl->event_queue[loop].event_type != 0) {
+				dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop, 
+					ctrl->event_queue[loop].event_type);
+				hp_slot = ctrl->event_queue[loop].hp_slot;
+
+				func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+				p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+				dbg("%s:hp_slot %d, func %p, p_slot %p\n", __FUNCTION__,hp_slot, func, p_slot);
+
+				if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
+					dbg("%s: button cancel\n", __FUNCTION__);
+					del_timer(&p_slot->task_event);
+
+					switch (p_slot->state) {
+					case BLINKINGOFF_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+
+						p_slot->hpc_ops->green_led_on(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq(ctrl); 
+
+						p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq(ctrl); 
+
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+						break;
+					case BLINKINGON_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+
+						p_slot->hpc_ops->green_led_off(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq(ctrl); 
+
+						p_slot->hpc_ops->set_attention_status(p_slot, 0);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq(ctrl); 
+
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+
+						break;
+					default:
+						warn("Not a valid state\n");
+						return;
+					}
+					info(msg_button_cancel, p_slot->number);
+					p_slot->state = STATIC_STATE;
+				}
+				/* Button Pressed (No action on 1st press...) */
+				else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
+					dbg("%s: Button pressed\n", __FUNCTION__);
+
+					p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+					if (getstatus) {
+						/* slot is on */
+						dbg("%s: slot is on\n", __FUNCTION__);
+						p_slot->state = BLINKINGOFF_STATE;
+						info(msg_button_off, p_slot->number);
+					} else {
+						/* slot is off */
+						dbg("%s: slot is off\n", __FUNCTION__);
+						p_slot->state = BLINKINGON_STATE;
+						info(msg_button_on, p_slot->number);
+					}
+
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					/* blink green LED and turn off amber */
+					p_slot->hpc_ops->green_led_blink(p_slot);
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq(ctrl); 
+					
+					p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq(ctrl); 
+
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+
+					init_timer(&p_slot->task_event);
+					p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
+					p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
+					p_slot->task_event.data = (unsigned long) p_slot;
+
+					dbg("%s: add_timer p_slot = %p\n", __FUNCTION__, (void *) p_slot);
+					add_timer(&p_slot->task_event);
+				}
+				/***********POWER FAULT********************/
+				else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
+					dbg("%s: power fault\n", __FUNCTION__);
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					p_slot->hpc_ops->set_attention_status(p_slot, 1);
+					
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq(ctrl); 
+
+					p_slot->hpc_ops->green_led_off(p_slot);
+
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq(ctrl); 
+					
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+				} else {
+					/* refresh notification */
+					if (p_slot)
+						update_slot_info(p_slot);
+				}
+
+				ctrl->event_queue[loop].event_type = 0;
+
+				change = 1;
+			}
+		}		/* End of FOR loop */
+	}
+
+	return;
+}
+
+
+/**
+ * shpchp_pushbutton_thread
+ *
+ * Scheduled procedure to handle blocking stuff for the pushbuttons
+ * Handles all pending events and exits.
+ *
+ */
+void shpchp_pushbutton_thread (unsigned long slot)
+{
+	struct slot *p_slot = (struct slot *) slot;
+	u8 getstatus;
+	int rc;
+	
+	pushbutton_pending = 0;
+
+	if (!p_slot) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return;
+	}
+
+	p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (getstatus) {
+		p_slot->state = POWEROFF_STATE;
+		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		if (shpchp_disable_slot(p_slot)) {
+			/* Wait for exclusive access to hardware */
+			down(&p_slot->ctrl->crit_sect);
+
+			/* Turn on the Attention LED */
+			rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
+			if (rc) {
+				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
+				return;
+			}
+	
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq(p_slot->ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&p_slot->ctrl->crit_sect);
+		}
+		p_slot->state = STATIC_STATE;
+	} else {
+		p_slot->state = POWERON_STATE;
+		dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		if (shpchp_enable_slot(p_slot)) {
+			/* Wait for exclusive access to hardware */
+			down(&p_slot->ctrl->crit_sect);
+
+			/* Turn off the green LED */
+			rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
+			if (rc) {
+				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
+				return;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq(p_slot->ctrl);
+			
+			p_slot->hpc_ops->green_led_off(p_slot);
+
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq(p_slot->ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&p_slot->ctrl->crit_sect);
+		}
+		p_slot->state = STATIC_STATE;
+	}
+
+	return;
+}
+
+
+int shpchp_enable_slot (struct slot *p_slot)
+{
+	u8 getstatus = 0;
+	int rc;
+	struct pci_func *func;
+
+	func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
+	if (!func) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return (1);
+	}
+
+	/* Check to see if (latch closed, card present, power off) */
+	down(&p_slot->ctrl->crit_sect);
+	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (rc || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	if (rc || getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (rc || getstatus) {
+		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+	up(&p_slot->ctrl->crit_sect);
+
+	slot_remove(func);
+
+	func = shpchp_slot_create(p_slot->bus);
+	if (func == NULL)
+		return (1);
+
+	func->bus = p_slot->bus;
+	func->device = p_slot->device;
+	func->function = 0;
+	func->configured = 0;
+	func->is_a_board = 1;
+
+	/* We have to save the presence info for these slots */
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	func->switch_save = !getstatus? 0x10:0;
+
+	rc = board_added(func, p_slot->ctrl);
+	if (rc) {
+		if (is_bridge(func))
+			bridge_slot_remove(func);
+		else
+			slot_remove(func);
+
+		/* Setup slot structure with entry for empty slot */
+		func = shpchp_slot_create(p_slot->bus);
+		if (func == NULL)
+			return (1);	/* Out of memory */
+
+		func->bus = p_slot->bus;
+		func->device = p_slot->device;
+		func->function = 0;
+		func->configured = 0;
+		func->is_a_board = 1;
+
+		/* We have to save the presence info for these slots */
+		p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+		func->switch_save = !getstatus? 0x10:0;
+	}
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return rc;
+}
+
+
+int shpchp_disable_slot (struct slot *p_slot)
+{
+	u8 class_code, header_type, BCR;
+	u8 index = 0;
+	u8 getstatus = 0;
+	u32 rc = 0;
+	int ret = 0;
+	unsigned int devfn;
+	struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate;
+	struct pci_func *func;
+
+	if (!p_slot->ctrl)
+		return (1);
+
+	/* Check to see if (latch closed, card present, power on) */
+	down(&p_slot->ctrl->crit_sect);
+
+	ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (ret || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	if (ret || getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (ret || !getstatus) {
+		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return (0);
+	}
+	up(&p_slot->ctrl->crit_sect);
+
+	func = shpchp_slot_find(p_slot->bus, p_slot->device, index++);
+
+	/* Make sure there are no video controllers here
+	 * for all func of p_slot
+	 */
+	while (func && !rc) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		/* Check the Class Code */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+		if (rc)
+			return rc;
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY) {
+			/* Display/Video adapter (not supported) */
+			rc = REMOVE_NOT_SUPPORTED;
+		} else {
+			/* See if it's a bridge */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+			if (rc)
+				return rc;
+
+			/* If it's a bridge, check the VGA Enable bit */
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
+				if (rc)
+					return rc;
+
+				/* If the VGA Enable bit is set, remove isn't supported */
+				if (BCR & PCI_BRIDGE_CTL_VGA) {
+					rc = REMOVE_NOT_SUPPORTED;
+				}
+			}
+		}
+
+		func = shpchp_slot_find(p_slot->bus, p_slot->device, index++);
+	}
+
+	func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
+	if ((func != NULL) && !rc) {
+		rc = remove_board(func, p_slot->ctrl);
+	} else if (!rc)
+		rc = 1;
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return(rc);
+}
+
+
+/**
+ * configure_new_device - Configures the PCI header information of one board.
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Returns 0 if success
+ *
+ */
+static u32 configure_new_device (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev)
+{
+	u8 temp_byte, function, max_functions, stop_it;
+	int rc;
+	u32 ID;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	int index;
+
+	new_slot = func;
+
+	dbg("%s\n", __FUNCTION__);
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+
+	/* Check for Multi-function device */
+	rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte);
+	if (rc) {
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if (temp_byte & 0x80)	/* Multi-function device */
+		max_functions = 8;
+	else
+		max_functions = 1;
+
+	function = 0;
+
+	do {
+		rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev);
+
+		if (rc) {
+			dbg("configure_new_function failed %d\n",rc);
+			index = 0;
+
+			while (new_slot) {
+				new_slot = shpchp_slot_find(new_slot->bus, new_slot->device, index++);
+
+				if (new_slot)
+					shpchp_return_board_resources(new_slot, resources);
+			}
+
+			return(rc);
+		}
+
+		function++;
+
+		stop_it = 0;
+
+		/*  The following loop skips to the next present function
+		 *  and creates a board structure
+		 */
+
+		while ((function < max_functions) && (!stop_it)) {
+			pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
+
+			if (ID == 0xFFFFFFFF) {	  /* There's nothing there. */
+				function++;
+			} else {  /* There's something there */
+				/* Setup slot structure. */
+				new_slot = shpchp_slot_create(func->bus);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					return(1);
+				}
+
+				new_slot->bus = func->bus;
+				new_slot->device = func->device;
+				new_slot->function = function;
+				new_slot->is_a_board = 1;
+				new_slot->status = 0;
+
+				stop_it++;
+			}
+		}
+
+	} while (function < max_functions);
+	dbg("returning from configure_new_device\n");
+
+	return 0;
+}
+
+
+/*
+ * Configuration logic that involves the hotplug data structures and 
+ * their bookkeeping
+ */
+
+
+/**
+ * configure_new_function - Configures the PCI header information of one device
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Calls itself recursively for bridged devices.
+ * Returns 0 if success
+ *
+ */
+static int configure_new_function (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev)
+{
+	int cloop;
+	u8 temp_byte;
+	u8 device;
+	u8 class_code;
+	u16 temp_word;
+	u32 rc;
+	u32 temp_register;
+	u32 base;
+	u32 ID;
+	unsigned int devfn;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_resource *hold_mem_node;
+	struct pci_resource *hold_p_mem_node;
+	struct pci_resource *hold_IO_node;
+	struct pci_resource *hold_bus_node;
+	struct irq_mapping irqs;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct resource_lists temp_resources;
+#if defined(CONFIG_X86_64)
+	u8 IRQ = 0;
+#endif
+	
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	/* Check for Bridge */
+	rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte);
+	if (rc)
+		return rc;
+
+	if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+		/* set Primary bus */
+		dbg("set Primary bus = 0x%x\n", func->bus);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
+		if (rc)
+			return rc;
+
+		/* find range of busses to use */
+		bus_node = get_max_resource(&resources->bus_head, 1L);
+
+		/* If we don't have any busses to allocate, we can't continue */
+		if (!bus_node) {
+			err("Got NO bus resource to use\n");
+			return -ENOMEM;
+		}
+		dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length);
+
+		/* set Secondary bus */
+		temp_byte = (u8)bus_node->base;
+		dbg("set Secondary bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* set subordinate bus */
+		temp_byte = (u8)(bus_node->base + bus_node->length - 1);
+		dbg("set subordinate bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+		if (rc)
+			return rc;
+
+		/* Setup the IO, memory, and prefetchable windows */
+
+		io_node = get_max_resource(&(resources->io_head), 0x1000L);
+		if (io_node) {
+			dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next);
+		}
+
+		mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+		if (mem_node) {
+			dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next);
+		}
+
+		if (resources->p_mem_head)
+			p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L);
+		else {
+			/*
+			 * In some platform implementation, MEM and PMEM are not
+			 *  distinguished, and hence ACPI _CRS has only MEM entries
+			 *  for both MEM and PMEM.
+			 */
+			dbg("using MEM for PMEM\n");
+			p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+		}
+		if (p_mem_node) {
+			dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next);
+		}
+
+		/* Set up the IRQ info */
+		if (!resources->irqs) {
+			irqs.barber_pole = 0;
+			irqs.interrupt[0] = 0;
+			irqs.interrupt[1] = 0;
+			irqs.interrupt[2] = 0;
+			irqs.interrupt[3] = 0;
+			irqs.valid_INT = 0;
+		} else {
+			irqs.barber_pole = resources->irqs->barber_pole;
+			irqs.interrupt[0] = resources->irqs->interrupt[0];
+			irqs.interrupt[1] = resources->irqs->interrupt[1];
+			irqs.interrupt[2] = resources->irqs->interrupt[2];
+			irqs.interrupt[3] = resources->irqs->interrupt[3];
+			irqs.valid_INT = resources->irqs->valid_INT;
+		}
+
+		/* Set up resource lists that are now aligned on top and bottom
+		 * for anything behind the bridge.
+		 */
+		temp_resources.bus_head = bus_node;
+		temp_resources.io_head = io_node;
+		temp_resources.mem_head = mem_node;
+		temp_resources.p_mem_head = p_mem_node;
+		temp_resources.irqs = &irqs;
+
+		/* Make copies of the nodes we are going to pass down so that
+		 * if there is a problem,we can just use these to free resources
+		 */
+		hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+		if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
+			if (hold_bus_node)
+				kfree(hold_bus_node);
+			if (hold_IO_node)
+				kfree(hold_IO_node);
+			if (hold_mem_node)
+				kfree(hold_mem_node);
+			if (hold_p_mem_node)
+				kfree(hold_p_mem_node);
+
+			return(1);
+		}
+
+		memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
+
+		bus_node->base += 1;
+		bus_node->length -= 1;
+		bus_node->next = NULL;
+
+		/* If we have IO resources copy them and fill in the bridge's
+		 * IO range registers
+		 */
+		if (io_node) {
+			memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
+			io_node->next = NULL;
+
+			/* Set IO base and Limit registers */
+			RES_CHECK(io_node->base, 8);
+			temp_byte = (u8)(io_node->base >> 8);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+			RES_CHECK(io_node->base + io_node->length - 1, 8);
+			temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+		} else {
+			kfree(hold_IO_node);
+			hold_IO_node = NULL;
+		}
+
+		/* If we have memory resources copy them and fill in the bridge's
+		 * memory range registers.  Otherwise, fill in the range
+		 * registers with values that disable them.
+		 */
+		if (mem_node) {
+			memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
+			mem_node->next = NULL;
+
+			/* Set Mem base and Limit registers */
+			RES_CHECK(mem_node->base, 16);
+			temp_word = (u32)(mem_node->base >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			RES_CHECK(mem_node->base + mem_node->length - 1, 16);
+			temp_word = (u32)((mem_node->base + mem_node->length - 1) >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_mem_node);
+			hold_mem_node = NULL;
+		}
+
+		/* If we have prefetchable memory resources copy them and 
+		 * fill in the bridge's memory range registers.  Otherwise,
+		 * fill in the range registers with values that disable them.
+		 */
+		if (p_mem_node) {
+			memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
+			p_mem_node->next = NULL;
+
+			/* Set Pre Mem base and Limit registers */
+			RES_CHECK(p_mem_node->base, 16);
+			temp_word = (u32)(p_mem_node->base >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16);
+			temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_p_mem_node);
+			hold_p_mem_node = NULL;
+		}
+
+		/* Adjust this to compensate for extra adjustment in first loop */
+		irqs.barber_pole--;
+
+		rc = 0;
+
+		/* Here we actually find the devices and configure them */
+		for (device = 0; (device <= 0x1F) && !rc; device++) {
+			irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
+
+			ID = 0xFFFFFFFF;
+			pci_bus->number = hold_bus_node->base;
+			pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
+			pci_bus->number = func->bus;
+
+			if (ID != 0xFFFFFFFF) {	  /*  device Present */
+				/* Setup slot structure. */
+				new_slot = shpchp_slot_create(hold_bus_node->base);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					rc = -ENOMEM;
+					continue;
+				}
+
+				new_slot->bus = hold_bus_node->base;
+				new_slot->device = device;
+				new_slot->function = 0;
+				new_slot->is_a_board = 1;
+				new_slot->status = 0;
+
+				rc = configure_new_device(ctrl, new_slot, 1, &temp_resources, func->bus, func->device);
+				dbg("configure_new_device rc=0x%x\n",rc);
+			}	/* End of IF (device in slot?) */
+		}		/* End of FOR loop */
+
+		if (rc) {
+			shpchp_destroy_resource_list(&temp_resources);
+
+			return_resource(&(resources->bus_head), hold_bus_node);
+			return_resource(&(resources->io_head), hold_IO_node);
+			return_resource(&(resources->mem_head), hold_mem_node);
+			return_resource(&(resources->p_mem_head), hold_p_mem_node);
+			return(rc);
+		}
+
+		/* save the interrupt routing information */
+		if (resources->irqs) {
+			resources->irqs->interrupt[0] = irqs.interrupt[0];
+			resources->irqs->interrupt[1] = irqs.interrupt[1];
+			resources->irqs->interrupt[2] = irqs.interrupt[2];
+			resources->irqs->interrupt[3] = irqs.interrupt[3];
+			resources->irqs->valid_INT = irqs.valid_INT;
+		} else if (!behind_bridge) {
+			/* We need to hook up the interrupts here */
+			for (cloop = 0; cloop < 4; cloop++) {
+				if (irqs.valid_INT & (0x01 << cloop)) {
+					rc = shpchp_set_irq(func->bus, func->device,
+							   0x0A + cloop, irqs.interrupt[cloop]);
+					if (rc) {
+						shpchp_destroy_resource_list (&temp_resources);
+						return_resource(&(resources->bus_head), hold_bus_node);
+						return_resource(&(resources->io_head), hold_IO_node);
+						return_resource(&(resources->mem_head), hold_mem_node);
+						return_resource(&(resources->p_mem_head), hold_p_mem_node);
+						return rc;
+					}
+				}
+			}	/* end of for loop */
+		}
+
+		/* Return unused bus resources
+		 * First use the temporary node to store information for the board
+		 */
+		if (hold_bus_node && bus_node && temp_resources.bus_head) {
+			hold_bus_node->length = bus_node->base - hold_bus_node->base;
+
+			hold_bus_node->next = func->bus_head;
+			func->bus_head = hold_bus_node;
+
+			temp_byte = (u8)(temp_resources.bus_head->base - 1);
+
+			/* set subordinate bus */
+			dbg("re-set subordinate bus = 0x%x\n", temp_byte);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+
+			if (temp_resources.bus_head->length == 0) {
+				kfree(temp_resources.bus_head);
+				temp_resources.bus_head = NULL;
+			} else {
+				dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
+					func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length);
+				return_resource(&(resources->bus_head), temp_resources.bus_head);
+			}
+		}
+
+		/* If we have IO space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_IO_node && temp_resources.io_head) {
+			io_node = do_pre_bridge_resource_split(&(temp_resources.io_head),
+							       &hold_IO_node, 0x1000);
+
+			/* Check if we were able to split something off */
+			if (io_node) {
+				hold_IO_node->base = io_node->base + io_node->length;
+
+				RES_CHECK(hold_IO_node->base, 8);
+				temp_byte = (u8)((hold_IO_node->base) >> 8);
+				rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+				return_resource(&(resources->io_head), io_node);
+			}
+
+			io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000);
+
+			/*  Check if we were able to split something off */
+			if (io_node) {
+				/* First use the temporary node to store information for the board */
+				hold_IO_node->length = io_node->base - hold_IO_node->base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_IO_node->length) {
+					hold_IO_node->next = func->io_head;
+					func->io_head = hold_IO_node;
+
+					RES_CHECK(io_node->base - 1, 8);
+					temp_byte = (u8)((io_node->base - 1) >> 8);
+					rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&(resources->io_head), io_node);
+				} else {
+					/* it doesn't need any IO */
+					temp_byte = 0x00;
+					rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&(resources->io_head), io_node);
+					kfree(hold_IO_node);
+				}
+			} else {
+				/* It used most of the range */
+				hold_IO_node->next = func->io_head;
+				func->io_head = hold_IO_node;
+			}
+		} else if (hold_IO_node) {
+			/* it used the whole range */
+			hold_IO_node->next = func->io_head;
+			func->io_head = hold_IO_node;
+		}
+
+		/* If we have memory space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_mem_node && temp_resources.mem_head) {
+			mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				hold_mem_node->base = mem_node->base + mem_node->length;
+
+				RES_CHECK(hold_mem_node->base, 16);
+				temp_word = (u32)((hold_mem_node->base) >> 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+				return_resource(&(resources->mem_head), mem_node);
+			}
+
+			mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_mem_node->length = mem_node->base - hold_mem_node->base;
+
+				if (hold_mem_node->length) {
+					hold_mem_node->next = func->mem_head;
+					func->mem_head = hold_mem_node;
+
+					/* configure end address */
+					RES_CHECK(mem_node->base - 1, 16);
+					temp_word = (u32)((mem_node->base - 1) >> 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					/* Return unused resources to the pool */
+					return_resource(&(resources->mem_head), mem_node);
+				} else {
+					/* it doesn't need any Mem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->mem_head), mem_node);
+					kfree(hold_mem_node);
+				}
+			} else {
+				/* It used most of the range */
+				hold_mem_node->next = func->mem_head;
+				func->mem_head = hold_mem_node;
+			}
+		} else if (hold_mem_node) {
+			/* It used the whole range */
+			hold_mem_node->next = func->mem_head;
+			func->mem_head = hold_mem_node;
+		}
+
+		/* If we have prefetchable memory space available and there is some 
+		 * left at the end, return the unused portion
+		 */
+		if (hold_p_mem_node && temp_resources.p_mem_head) {
+			p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
+								  &hold_p_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				hold_p_mem_node->base = p_mem_node->base + p_mem_node->length;
+
+				RES_CHECK(hold_p_mem_node->base, 16);
+				temp_word = (u32)((hold_p_mem_node->base) >> 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+				return_resource(&(resources->p_mem_head), p_mem_node);
+			}
+
+			p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_p_mem_node->length) {
+					hold_p_mem_node->next = func->p_mem_head;
+					func->p_mem_head = hold_p_mem_node;
+
+					RES_CHECK(p_mem_node->base - 1, 16);
+					temp_word = (u32)((p_mem_node->base - 1) >> 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->p_mem_head), p_mem_node);
+				} else {
+					/* It doesn't need any PMem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->p_mem_head), p_mem_node);
+					kfree(hold_p_mem_node);
+				}
+			} else {
+				/* It used the most of the range */
+				hold_p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = hold_p_mem_node;
+			}
+		} else if (hold_p_mem_node) {
+			/* It used the whole range */
+			hold_p_mem_node->next = func->p_mem_head;
+			func->p_mem_head = hold_p_mem_node;
+		}
+
+		/* We should be configuring an IRQ and the bridge's base address
+		 * registers if it needs them.  Although we have never seen such
+		 * a device
+		 */
+
+		shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+
+		dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, 
+			func->bus, func->device, func->function);
+	} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+		/* Standard device */
+		u64	base64;
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY)
+			return (DEVICE_TYPE_NOT_SUPPORTED);
+
+		/* Figure out IO and memory needs */
+		for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
+			temp_register = 0xFFFFFFFF;
+
+			rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+			rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register);
+			dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, 
+				func->bus, func->device, func->function);
+
+			if (!temp_register)
+				continue;
+
+			base64 = 0L;
+			if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) {
+				/* Map IO */
+
+				/* Set base = amount of IO space */
+				base = temp_register & 0xFFFFFFFC;
+				base = ~base + 1;
+
+				dbg("NEED IO length(0x%x)\n", base);
+				io_node = get_io_resource(&(resources->io_head),(ulong)base);
+
+				/* Allocate the resource to the board */
+				if (io_node) {
+					dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length);
+					base = (u32)io_node->base;
+					io_node->next = func->io_head;
+					func->io_head = io_node;
+				} else {
+					err("Got NO IO resource(length=0x%x)\n", base);
+					return -ENOMEM;
+				}
+			} else {	/* Map MEM */
+				int prefetchable = 1;
+				struct pci_resource **res_node = &func->p_mem_head;
+				char *res_type_str = "PMEM";
+				u32	temp_register2;
+
+				if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) {
+					prefetchable = 0;
+					res_node = &func->mem_head;
+					res_type_str++;
+				}
+
+				base = temp_register & 0xFFFFFFF0;
+				base = ~base + 1;
+
+				switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+				case PCI_BASE_ADDRESS_MEM_TYPE_32:
+					dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base);
+
+					if (prefetchable && resources->p_mem_head)
+						mem_node=get_resource(&(resources->p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node=get_resource(&(resources->mem_head), (ulong)base);
+					}
+
+					/* Allocate the resource to the board */
+					if (mem_node) {
+						base = (u32)mem_node->base; 
+						mem_node->next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+					} else {
+						err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				case PCI_BASE_ADDRESS_MEM_TYPE_64:
+					rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+					dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, temp_register, base);
+
+					if (prefetchable && resources->p_mem_head)
+						mem_node = get_resource(&(resources->p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node = get_resource(&(resources->mem_head), (ulong)base);
+					}
+
+					/* Allocate the resource to the board */
+					if (mem_node) {
+						base64 = mem_node->base; 
+						mem_node->next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), (u32)base64, mem_node->length);
+					} else {
+						err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				default:
+					dbg("reserved BAR type=0x%x\n", temp_register);
+					break;
+				}
+
+			}
+
+			if (base64) {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+				cloop += 4;
+				base64 >>= 32;
+
+				if (base64) {
+					dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64);
+					base64 = 0x0L;
+				}
+
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+			} else {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base);
+			}
+		}		/* End of base register loop */
+
+#if defined(CONFIG_X86_64)
+		/* Figure out which interrupt pin this function uses */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte);
+
+		/* If this function needs an interrupt and we are behind a bridge
+		   and the pin is tied to something that's alread mapped,
+		   set this one the same
+		 */
+		if (temp_byte && resources->irqs && 
+		    (resources->irqs->valid_INT & 
+		     (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) {
+			/* We have to share with something already set up */
+			IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03];
+		} else {
+			/* Program IRQ based on card type */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+
+			if (class_code == PCI_BASE_CLASS_STORAGE) {
+				IRQ = shpchp_disk_irq;
+			} else {
+				IRQ = shpchp_nic_irq;
+			}
+		}
+
+		/* IRQ Line */
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ);
+
+		if (!behind_bridge) {
+			rc = shpchp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ);
+			if (rc)
+				return(1);
+		} else {
+			/* TBD - this code may also belong in the other clause of this If statement */
+			resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ;
+			resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03;
+		}
+#endif
+		/* Disable ROM base Address */
+		temp_word = 0x00L;
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word);
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+		if (rc)
+			return rc;
+
+		shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+
+		dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function);
+	}			/* End of Not-A-Bridge else */
+	else {
+		/* It's some strange type of PCI adapter (Cardbus?) */
+		return(DEVICE_TYPE_NOT_SUPPORTED);
+	}
+
+	func->configured = 1;
+
+	return 0;
+}
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp_hpc.c linux-2.4.27-pre3/drivers/hotplug/shpchp_hpc.c
--- linux-2.4.26/drivers/hotplug/shpchp_hpc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchp_hpc.c	2004-05-18 16:53:01.000000000 +0000
@@ -0,0 +1,1615 @@
+/*
+ * Standard PCI Hot Plug Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>,<dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include "shpchp.h"
+
+#ifdef DEBUG
+#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
+#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
+#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
+#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
+#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
+#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
+/* Redefine this flagword to set debug level */
+#define DEBUG_LEVEL            DBG_K_STANDARD
+
+#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
+
+#define DBG_PRINT( dbg_flags, args... )              \
+	do {                                             \
+	  if ( DEBUG_LEVEL & ( dbg_flags ) )             \
+	  {                                              \
+	    int len;                                     \
+	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
+		  __FILE__, __LINE__, __FUNCTION__ );    \
+	    sprintf( __dbg_str_buf + len, args );        \
+	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
+	  }                                              \
+	} while (0)
+
+#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
+#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
+#else
+#define DEFINE_DBG_BUFFER
+#define DBG_ENTER_ROUTINE
+#define DBG_LEAVE_ROUTINE
+#endif				/* DEBUG */
+
+/* Slot Available Register I field definition */
+#define SLOT_33MHZ		0x0000001f
+#define SLOT_66MHZ_PCIX		0x00001f00
+#define SLOT_100MHZ_PCIX	0x001f0000
+#define SLOT_133MHZ_PCIX	0x1f000000
+
+/* Slot Available Register II field definition */
+#define SLOT_66MHZ		0x0000001f
+#define SLOT_66MHZ_PCIX_266	0x00000f00
+#define SLOT_100MHZ_PCIX_266	0x0000f000
+#define SLOT_133MHZ_PCIX_266	0x000f0000
+#define SLOT_66MHZ_PCIX_533		0x00f00000
+#define SLOT_100MHZ_PCIX_533	0x0f000000
+#define SLOT_133MHZ_PCIX_533	0xf0000000
+
+/* Secondary Bus Configuration Register */
+/* For PI = 1, Bits 0 to 2 have been encoded as follows to show current bus speed/mode */
+#define PCI_33MHZ	0x0
+#define PCI_66MHZ	0x1
+#define PCIX_66MHZ	0x2
+#define PCIX_100MHZ	0x3
+#define PCIX_133MHZ	0x4
+
+/* For PI = 2, Bits 0 to 3 have been encoded as follows to show current bus speed/mode */
+#define PCI_33MHZ		0x0
+#define PCI_66MHZ		0x1
+#define PCIX_66MHZ		0x2
+#define PCIX_100MHZ		0x3
+#define PCIX_133MHZ		0x4
+#define PCIX_66MHZ_ECC		0x5
+#define PCIX_100MHZ_ECC		0x6
+#define PCIX_133MHZ_ECC		0x7
+#define PCIX_66MHZ_266		0x9
+#define PCIX_100MHZ_266		0x0a
+#define PCIX_133MHZ_266		0x0b
+#define PCIX_66MHZ_533		0x11
+#define PCIX_100MHZ_533		0x12
+#define PCIX_133MHZ_533		0x13
+
+/* Slot Configuration */
+#define SLOT_NUM		0x0000001F
+#define	FIRST_DEV_NUM		0x00001F00
+#define PSN			0x07FF0000
+#define	UPDOWN			0x20000000
+#define	MRLSENSOR		0x40000000
+#define ATTN_BUTTON		0x80000000
+
+/* Slot Status Field Definitions */
+/* Slot State */
+#define PWR_ONLY	0x0001
+#define ENABLED		0x0002
+#define DISABLED	0x0003
+
+/* Power Indicator State */
+#define PWR_LED_ON	0x0004
+#define PWR_LED_BLINK	0x0008
+#define PWR_LED_OFF	0x000c
+
+/* Attention Indicator State */
+#define ATTEN_LED_ON	0x0010
+#define	ATTEN_LED_BLINK	0x0020
+#define ATTEN_LED_OFF	0x0030
+
+/* Power Fault */
+#define pwr_fault	0x0040
+
+/* Attention Button */
+#define ATTEN_BUTTON	0x0080
+
+/* MRL Sensor */
+#define MRL_SENSOR	0x0100
+
+/* 66 MHz Capable */
+#define IS_66MHZ_CAP	0x0200
+
+/* PRSNT1#/PRSNT2# */
+#define SLOT_EMP	0x0c00
+
+/* PCI-X Capability */
+#define NON_PCIX	0x0000
+#define PCIX_66		0x1000
+#define PCIX_133	0x3000
+#define PCIX_266	0x4000  /* For PI = 2 only */
+#define PCIX_533	0x5000	/* For PI = 2 only */
+
+/* SHPC 'write' operations/commands */
+
+/* Slot operation - 0x00h to 0x3Fh */
+
+#define NO_CHANGE	0x00
+
+/* Slot state - Bits 0 & 1 of controller command register */
+#define SET_SLOT_PWR		0x01	
+#define SET_SLOT_ENABLE		0x02	
+#define SET_SLOT_DISABLE	0x03	
+
+/* Power indicator state - Bits 2 & 3 of controller command register*/
+#define SET_PWR_ON		0x04	
+#define SET_PWR_BLINK		0x08	
+#define SET_PWR_OFF		0x0C	
+
+/* Attention indicator state - Bits 4 & 5 of controller command register*/
+#define SET_ATTN_ON		0x010	
+#define SET_ATTN_BLINK		0x020
+#define SET_ATTN_OFF		0x030	
+
+/* Set bus speed/mode A - 0x40h to 0x47h */
+#define SETA_PCI_33MHZ		0x40
+#define SETA_PCI_66MHZ		0x41
+#define SETA_PCIX_66MHZ		0x42
+#define SETA_PCIX_100MHZ	0x43
+#define SETA_PCIX_133MHZ	0x44
+#define RESERV_1		0x45
+#define RESERV_2		0x46
+#define RESERV_3		0x47
+
+/* Set bus speed/mode B - 0x50h to 0x5fh */
+#define	SETB_PCI_33MHZ		0x50
+#define SETB_PCI_66MHZ		0x51
+#define SETB_PCIX_66MHZ_PM	0x52
+#define SETB_PCIX_100MHZ_PM	0x53
+#define SETB_PCIX_133MHZ_PM	0x54
+#define SETB_PCIX_66MHZ_EM	0x55
+#define SETB_PCIX_100MHZ_EM	0x56
+#define SETB_PCIX_133MHZ_EM	0x57
+#define SETB_PCIX_66MHZ_266	0x58
+#define SETB_PCIX_100MHZ_266	0x59
+#define SETB_PCIX_133MHZ_266	0x5a
+#define SETB_PCIX_66MHZ_533	0x5b
+#define SETB_PCIX_100MHZ_533	0x5c
+#define SETB_PCIX_133MHZ_533	0x5d
+
+/* Power-on all slots - 0x48h */
+#define SET_PWR_ON_ALL	0x48
+
+/* Enable all slots	- 0x49h */
+#define SET_ENABLE_ALL	0x49
+
+/*  SHPC controller command error code */
+#define SWITCH_OPEN		0x1
+#define INVALID_CMD		0x2
+#define INVALID_SPEED_MODE	0x4
+
+/* For accessing SHPC Working Register Set */
+#define DWORD_SELECT	0x2
+#define DWORD_DATA		0x4
+#define BASE_OFFSET		0x0
+
+/* Field Offset in Logical Slot Register - byte boundary */
+#define SLOT_EVENT_LATCH	0x2
+#define SLOT_SERR_INT_MASK	0x3
+
+static spinlock_t hpc_event_lock;
+
+DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
+static struct php_ctlr_state_s *php_ctlr_list_head = 0;	/* HPC state linked list */
+static int ctlr_seq_num = 0;	/* Controller sequenc # */
+
+static spinlock_t list_lock;
+
+static void shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);
+
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+
+/* This is the interrupt polling timeout function. */
+static void int_poll_timeout(unsigned long lphp_ctlr)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+
+	DBG_ENTER_ROUTINE
+
+	if ( !php_ctlr ) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+	}
+
+	/* Poll for interrupt events.  regs == NULL => polling */
+	shpc_isr( 0, (void *)php_ctlr, NULL );
+
+	init_timer(&php_ctlr->int_poll_timer);
+	if (!shpchp_poll_time)
+	shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+
+	start_int_poll_timer(php_ctlr, shpchp_poll_time);  
+	
+	return;
+}
+
+/* This function starts the interrupt polling timer. */
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+{
+    if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+	}
+
+    if ( ( seconds <= 0 ) || ( seconds > 60 ) )
+        seconds = 2;            /* Clamp to sane value */
+
+    php_ctlr->int_poll_timer.function = &int_poll_timeout;
+    php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
+    php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
+    add_timer(&php_ctlr->int_poll_timer);
+
+	return;
+}
+
+static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 cmd_status;
+	int retval = 0;
+	u16 temp_word;
+	int i;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	for (i = 0; i < 10; i++) {
+		cmd_status = readw(php_ctlr->creg + CMD_STATUS);
+		
+		if (!(cmd_status & 0x1))
+			break;
+		/*  Check every 0.1 sec for a total of 1 sec*/
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ/10);
+	}
+
+	cmd_status = readw(php_ctlr->creg + CMD_STATUS);
+	
+	if (cmd_status & 0x1) { 
+		/* After 1 sec and and the controller is still busy */
+		err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
+		return -1;
+	}
+
+	++t_slot;
+	temp_word =  (t_slot << 8) | (cmd & 0xFF);
+	dbg("%s :  t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
+	
+	/* To make sure the Controller Busy bit is 0 before we send out the
+	 * command. 
+	 */
+	writew(temp_word, php_ctlr->creg + CMD);
+	dbg("%s : temp_word written %x\n", __FUNCTION__, temp_word);
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_check_cmd_status(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+	u16 cmd_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F;
+	
+	switch (cmd_status >> 1) {
+	case 0:
+		retval = 0;
+		break;
+	case 1:
+		retval = SWITCH_OPEN;
+		err("%s: Switch opened!\n", __FUNCTION__);
+		break;
+	case 2:
+		retval = INVALID_CMD;
+		err("%s: Invalid HPC command!\n", __FUNCTION__);
+		break;
+	case 4:
+		retval = INVALID_SPEED_MODE;
+		err("%s: Invalid bus speed/mode!\n", __FUNCTION__);
+		break;
+	default:
+		retval = cmd_status;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_attention_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 atten_led_state;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16) slot_reg;
+	atten_led_state = (slot_status & 0x0030) >> 4;
+
+	switch (atten_led_state) {
+	case 0:
+		*status = 0xFF;	/* Reserved */
+		break;
+	case 1:
+		*status = 1;	/* On */
+		break;
+	case 2:
+		*status = 2;	/* Blink */
+		break;
+	case 3:
+		*status = 0;	/* Off */
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_power_status(struct slot * slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 slot_state;
+	int	retval = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16) slot_reg;
+	slot_state = (slot_status & 0x0003);
+
+	switch (slot_state) {
+	case 0:
+		*status = 0xFF;
+		break;
+	case 1:
+		*status = 2;	/* Powered only */
+		break;
+	case 2:
+		*status = 1;	/* Enabled */
+		break;
+	case 3:
+		*status = 0;	/* Disabled */
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_latch_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16)slot_reg;
+
+	*status = ((slot_status & 0x0100) == 0) ? 0 : 1;	/* 0 -> close; 1 -> open */
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_adapter_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 card_state;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16)slot_reg;
+	card_state = (u8)((slot_status & 0x0C00) >> 10);
+	*status = (card_state != 0x3) ? 1 : 0;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	*prog_int = readb(php_ctlr->creg + PROG_INTERFACE);
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status, sec_bus_status;
+	u8 m66_cap, pcix_cap, pi;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	dbg("%s: pi = %d, slot_reg = %x\n", __FUNCTION__, pi, slot_reg);
+	slot_status = (u16) slot_reg;
+	dbg("%s: slot_status = %x\n", __FUNCTION__, slot_status);
+	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
+
+	pcix_cap = (u8) ((slot_status & 0x3000) >> 12);
+	dbg("%s:  pcix_cap = %x\n", __FUNCTION__, pcix_cap);
+	m66_cap = (u8) ((slot_status & 0x0200) >> 9);
+	dbg("%s:  m66_cap = %x\n", __FUNCTION__, m66_cap);
+
+	if (pi == 2) {
+		switch (pcix_cap) {
+		case 0:
+			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
+			break;
+		case 1:
+			*value = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			*value = PCI_SPEED_133MHz_PCIX;
+			break;
+		case 4:
+			*value = PCI_SPEED_133MHz_PCIX_266;	
+			break;
+		case 5:
+			*value = PCI_SPEED_133MHz_PCIX_533;	
+			break;
+		case 2:	/* Reserved */
+		default:
+			*value = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			break;
+		}
+	} else {
+		switch (pcix_cap) {
+		case 0:
+			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
+			break;
+		case 1:
+			*value = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			*value = PCI_SPEED_133MHz_PCIX;	
+			break;
+		case 2:	/* Reserved */
+		default:
+			*value = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			break;
+		}
+	}
+
+	dbg("Adapter speed = %d\n", *value);
+	
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 sec_bus_status;
+	u8 pi;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
+
+	if (pi == 2) {
+		*mode = (sec_bus_status & 0x0100) >> 7;
+	} else {
+		retval = -1;
+	}
+
+	dbg("Mode 1 ECC cap = %d\n", *mode);
+	
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_query_power_fault(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 pwr_fault_state, status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16) slot_reg;
+	pwr_fault_state = (slot_status & 0x0040) >> 7;
+	status = (pwr_fault_state == 1) ? 0 : 1;
+
+	DBG_LEAVE_ROUTINE
+	/* Note: Logic 0 => fault */
+	return status;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd = 0;
+	int rc = 0;
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	switch (value) {
+		case 0 :	
+			slot_cmd = 0x30;	/* OFF */
+			break;
+		case 1:
+			slot_cmd = 0x10;	/* ON */
+			break;
+		case 2:
+			slot_cmd = 0x20;	/* BLINK */
+			break;
+		default:
+			return -1;
+	}
+
+	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+	
+	return rc;
+}
+
+
+static void hpc_set_green_led_on(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	slot_cmd = 0x04;
+
+	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	return;
+}
+
+static void hpc_set_green_led_off(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	slot_cmd = 0x0C;
+
+	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	return;
+}
+
+static void hpc_set_green_led_blink(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	slot_cmd = 0x08;
+
+	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	return;
+}
+
+int shpc_get_ctlr_slot_config(struct controller *ctrl,
+	int *num_ctlr_slots,	/* number of slots in this HPC					*/
+	int *first_device_num,	/* PCI dev num of the first slot in this SHPC	*/
+	int *physical_slot_num,	/* phy slot num of the first slot in this SHPC	*/
+	int *updown,			/* physical_slot_num increament: 1 or -1		*/
+	int *flags)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	*first_device_num = php_ctlr->slot_device_offset;	/* Obtained in shpc_init() */
+	*num_ctlr_slots = php_ctlr->num_slots;				/* Obtained in shpc_init() */
+
+	*physical_slot_num = (readl(php_ctlr->creg + SLOT_CONFIG) & PSN) >> 16;
+	dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);
+	*updown = ((readl(php_ctlr->creg + SLOT_CONFIG) & UPDOWN ) >> 29) ? 1 : -1;	
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static void hpc_release_ctlr(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+	struct php_ctlr_state_s *p, *p_prev;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (shpchp_poll_mode) {
+	    del_timer(&php_ctlr->int_poll_timer);
+	} else {	
+		if (php_ctlr->irq) {
+			free_irq(php_ctlr->irq, ctrl);
+			php_ctlr->irq = 0;
+		}
+	}
+	if (php_ctlr->pci_dev) {
+		dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__);
+		iounmap(php_ctlr->creg);
+		release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0));
+		dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__);
+		php_ctlr->pci_dev = 0;
+	}
+
+	spin_lock(&list_lock);
+	p = php_ctlr_list_head;
+	p_prev = NULL;
+	while (p) {
+		if (p == php_ctlr) {
+			if (p_prev)
+				p_prev->pnext = p->pnext;
+			else
+				php_ctlr_list_head = p->pnext;
+			break;
+		} else {
+			p_prev = p;
+			p = p->pnext;
+		}
+	}
+	spin_unlock(&list_lock);
+
+	kfree(php_ctlr);
+
+	DBG_LEAVE_ROUTINE
+			  
+}
+
+static int hpc_power_on_slot(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	slot_cmd = 0x01;
+
+	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static int hpc_slot_enable(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	/* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
+	slot_cmd = 0x3A;  
+
+	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_slot_disable(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	/* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */
+	slot_cmd = 0x1F;
+
+	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_enable_all_slots( struct slot *slot )
+{
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = shpc_write_cmd(slot, 0, SET_ENABLE_ALL);
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static int hpc_pwr_on_all_slots(struct slot *slot)
+{
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	retval = shpc_write_cmd(slot, 0, SET_PWR_ON_ALL);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
+{
+	u8 slot_cmd;
+	u8 pi;
+	int retval = 0;
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	
+	if (pi == 1) {
+		switch (value) {
+		case 0:
+			slot_cmd = SETA_PCI_33MHZ;
+			break;
+		case 1:
+			slot_cmd = SETA_PCI_66MHZ;
+			break;
+		case 2:
+			slot_cmd = SETA_PCIX_66MHZ;
+			break;
+		case 3:
+			slot_cmd = SETA_PCIX_100MHZ;	
+			break;
+		case 4:
+			slot_cmd = SETA_PCIX_133MHZ;	
+			break;
+		default:
+			slot_cmd = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			return retval;	
+		}
+	} else {
+		switch (value) {
+		case 0:
+			slot_cmd = SETB_PCI_33MHZ;
+			break;
+		case 1:
+			slot_cmd = SETB_PCI_66MHZ;
+			break;
+		case 2:
+			slot_cmd = SETB_PCIX_66MHZ_PM;
+			break;
+		case 3:
+			slot_cmd = SETB_PCIX_100MHZ_PM;	
+			break;
+		case 4:
+			slot_cmd = SETB_PCIX_133MHZ_PM;	
+			break;
+		case 5:
+			slot_cmd = SETB_PCIX_66MHZ_EM;	
+			break;
+		case 6:
+			slot_cmd = SETB_PCIX_100MHZ_EM;	
+			break;
+		case 7:
+			slot_cmd = SETB_PCIX_133MHZ_EM;	
+			break;
+		case 8:
+			slot_cmd = SETB_PCIX_66MHZ_266;	
+			break;
+		case 9:
+			slot_cmd = SETB_PCIX_100MHZ_266;	
+			break;
+		case 0xa:
+			slot_cmd = SETB_PCIX_133MHZ_266;	
+			break;
+		case 0xb:
+			slot_cmd = SETB_PCIX_66MHZ_533;	
+			break;
+		case 0xc:
+			slot_cmd = SETB_PCIX_100MHZ_533;	
+			break;
+		case 0xd:
+			slot_cmd = SETB_PCIX_133MHZ_533;	
+			break;
+		default:
+			slot_cmd = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			return retval;	
+		}
+
+	}
+	retval = shpc_write_cmd(slot, 0, slot_cmd);
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static void shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
+{
+	struct controller *ctrl = NULL;
+	struct php_ctlr_state_s *php_ctlr;
+	u8 schedule_flag = 0;
+	u8 temp_byte;
+	u32 temp_dword, intr_loc, intr_loc2;
+	int hp_slot;
+
+	if (!dev_id)
+		return;
+
+	if (!shpchp_poll_mode) { 
+		ctrl = (struct controller *)dev_id;
+		php_ctlr = ctrl->hpc_ctlr_handle;
+	} else {
+		php_ctlr = (struct php_ctlr_state_s *) dev_id;
+		ctrl = (struct controller *)php_ctlr->callback_instance_id;
+	}
+
+	if (!ctrl)
+		return;
+
+	if (!php_ctlr || !php_ctlr->creg)
+		return;
+
+	/* Check to see if it was our interrupt */
+	intr_loc = readl(php_ctlr->creg + INTR_LOC);  
+
+	if (!intr_loc)
+		return;
+
+	dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); 
+
+	if (!shpchp_poll_mode) {
+		/* Mask Global Interrupt Mask - see implementation note on p. 139 */
+		/* of SHPC spec rev 1.0*/
+		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: Before masking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword |= 0x00000001;
+		dbg("%s: After masking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
+
+		intr_loc2 = readl(php_ctlr->creg + INTR_LOC);  
+		dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
+	}
+
+	if (intr_loc & 0x0001) {
+		/* 
+		 * Command Complete Interrupt Pending 
+		 * RO only - clear by writing 0 to the Command Completion
+		 * Detect bit in Controller SERR-INT register
+		 */
+		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: Before clearing CCIP, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword &= 0xfffeffff;
+		dbg("%s: After clearing CCIP, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
+
+		wake_up_interruptible(&ctrl->queue);
+	}
+
+	if ((intr_loc = (intr_loc >> 1)) == 0) {
+		/* Unmask Global Interrupt Mask */
+		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: 1-Before unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword &= 0xfffffffe;
+		dbg("%s: 1-After unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
+		return;
+	}
+
+	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { 
+	/* To find out which slot has interrupt pending */
+		if ((intr_loc >> hp_slot) & 0x01) {
+			temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot));
+			dbg("%s: Slot %x with intr, temp_dword = %x\n",
+				__FUNCTION__, hp_slot, temp_dword); 
+			temp_byte = (temp_dword >> 16) & 0xFF;
+			dbg("%s: Slot with intr, temp_byte = %x\n",
+				__FUNCTION__, temp_byte); 
+			if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08))
+				schedule_flag += php_ctlr->switch_change_callback(
+					hp_slot, php_ctlr->callback_instance_id);
+			if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04))
+				schedule_flag += php_ctlr->attention_button_callback(
+					hp_slot, php_ctlr->callback_instance_id);
+			if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01))
+				schedule_flag += php_ctlr->presence_change_callback(
+					hp_slot , php_ctlr->callback_instance_id);
+			if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12))
+				schedule_flag += php_ctlr->power_fault_callback(
+					hp_slot, php_ctlr->callback_instance_id);
+			
+			/* Clear all slot events */
+			temp_dword = 0xe01fffff;
+			dbg("%s: Clearing slot events, temp_dword = %x\n",
+				__FUNCTION__, temp_dword); 
+			writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot));
+
+			intr_loc2 = readl(php_ctlr->creg + INTR_LOC);  
+			dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
+		}
+	}
+
+	if (!shpchp_poll_mode) {
+		/* Unmask Global Interrupt Mask */
+		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: 2-Before unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword &= 0xfffffffe;
+		dbg("%s: 2-After unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
+	}
+	
+	return;
+}
+
+static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
+	int retval = 0;
+	u8 pi;
+	u32 slot_avail1, slot_avail2;
+	int slot_num;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1);
+	slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2);
+
+	if (pi == 2) {
+		if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_533) >> 27)  ) != 0 )
+			bus_speed = PCIX_133MHZ_533;
+		else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_533) >> 23)  ) != 0 )
+			bus_speed = PCIX_100MHZ_533;
+		else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_533) >> 19)  ) != 0 )
+			bus_speed = PCIX_66MHZ_533;
+		else if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_266) >> 15)  ) != 0 )
+			bus_speed = PCIX_133MHZ_266;
+		else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_266) >> 11)  ) != 0 )
+			bus_speed = PCIX_100MHZ_266;
+		else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_266) >> 7)  ) != 0 )
+			bus_speed = PCIX_66MHZ_266;
+		else if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23)  ) != 0 )
+			bus_speed = PCIX_133MHZ;
+		else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15)  ) != 0 )
+			bus_speed = PCIX_100MHZ;
+		else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7)  ) != 0 )
+			bus_speed = PCIX_66MHZ;
+		else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 )
+			bus_speed = PCI_66MHZ;
+		else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 )
+			bus_speed = PCI_33MHZ;
+		else bus_speed = PCI_SPEED_UNKNOWN;
+	} else {
+		if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23)  ) != 0 )
+			bus_speed = PCIX_133MHZ;
+		else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15)  ) != 0 )
+			bus_speed = PCIX_100MHZ;
+		else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7)  ) != 0 )
+			bus_speed = PCIX_66MHZ;
+		else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 )
+			bus_speed = PCI_66MHZ;
+		else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 )
+			bus_speed = PCI_33MHZ;
+		else bus_speed = PCI_SPEED_UNKNOWN;
+	}
+
+	*value = bus_speed;
+	dbg("Max bus speed = %d\n", bus_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
+	u16 sec_bus_status;
+	int retval = 0;
+	u8 pi;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
+
+	if (pi == 2) {
+		switch (sec_bus_status & 0x000f) {
+		case 0:
+			bus_speed = PCI_SPEED_33MHz;
+			break;
+		case 1:
+			bus_speed = PCI_SPEED_66MHz;
+			break;
+		case 2:
+			bus_speed = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			bus_speed = PCI_SPEED_100MHz_PCIX;	
+			break;
+		case 4:
+			bus_speed = PCI_SPEED_133MHz_PCIX;	
+			break;
+		case 5:
+			bus_speed = PCI_SPEED_66MHz_PCIX_ECC;
+			break;
+		case 6:
+			bus_speed = PCI_SPEED_100MHz_PCIX_ECC;
+			break;
+		case 7:
+			bus_speed = PCI_SPEED_133MHz_PCIX_ECC;	
+			break;
+		case 8:
+			bus_speed = PCI_SPEED_66MHz_PCIX_266;	
+			break;
+		case 9:
+			bus_speed = PCI_SPEED_100MHz_PCIX_266;	
+			break;
+		case 0xa:
+			bus_speed = PCI_SPEED_133MHz_PCIX_266;	
+			break;
+		case 0xb:
+			bus_speed = PCI_SPEED_66MHz_PCIX_533;	
+			break;
+		case 0xc:
+			bus_speed = PCI_SPEED_100MHz_PCIX_533;	
+			break;
+		case 0xd:
+			bus_speed = PCI_SPEED_133MHz_PCIX_533;	
+			break;
+		case 0xe:
+		case 0xf:
+		default:
+			bus_speed = PCI_SPEED_UNKNOWN;
+			break;
+		}
+	} else {
+		/* In the case where pi is undefined, default it to 1 */ 
+		switch (sec_bus_status & 0x0007) {
+		case 0:
+			bus_speed = PCI_SPEED_33MHz;
+			break;
+		case 1:
+			bus_speed = PCI_SPEED_66MHz;
+			break;
+		case 2:
+			bus_speed = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			bus_speed = PCI_SPEED_100MHz_PCIX;	
+			break;
+		case 4:
+			bus_speed = PCI_SPEED_133MHz_PCIX;	
+			break;
+		case 5:
+			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
+			break;
+		case 6:
+			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
+			break;
+		case 7:
+			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */	
+			break;
+		default:
+			bus_speed = PCI_SPEED_UNKNOWN;
+			break;
+		}
+	}
+	*value = bus_speed;
+	dbg("Current bus speed = %d\n", bus_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+
+}
+
+static struct hpc_ops shpchp_hpc_ops = {
+	.power_on_slot			= hpc_power_on_slot,
+	.slot_enable			= hpc_slot_enable,
+	.slot_disable			= hpc_slot_disable,
+	.enable_all_slots		= hpc_enable_all_slots,
+	.pwr_on_all_slots		= hpc_pwr_on_all_slots,
+	.set_bus_speed_mode		= hpc_set_bus_speed_mode,	  
+	.set_attention_status	= hpc_set_attention_status,
+	.get_power_status		= hpc_get_power_status,
+	.get_attention_status	= hpc_get_attention_status,
+	.get_latch_status		= hpc_get_latch_status,
+	.get_adapter_status		= hpc_get_adapter_status,
+
+	.get_max_bus_speed		= hpc_get_max_bus_speed,
+	.get_cur_bus_speed		= hpc_get_cur_bus_speed,
+	.get_adapter_speed		= hpc_get_adapter_speed,
+	.get_mode1_ECC_cap		= hpc_get_mode1_ECC_cap,
+	.get_prog_int			= hpc_get_prog_int,
+
+	.query_power_fault		= hpc_query_power_fault,
+	.green_led_on			= hpc_set_green_led_on,
+	.green_led_off			= hpc_set_green_led_off,
+	.green_led_blink		= hpc_set_green_led_blink,
+	
+	.release_ctlr			= hpc_release_ctlr,
+	.check_cmd_status		= hpc_check_cmd_status,
+};
+
+int shpc_init(struct controller * ctrl,
+		struct pci_dev * pdev,
+		php_intr_callback_t attention_button_callback,
+		php_intr_callback_t switch_change_callback,
+		php_intr_callback_t presence_change_callback,
+		php_intr_callback_t power_fault_callback)
+{
+	struct php_ctlr_state_s *php_ctlr, *p;
+	void *instance_id = ctrl;
+	int rc;
+	u8 hp_slot;
+	static int first = 1;
+	u32 shpc_cap_offset, shpc_base_offset;
+	u32 tempdword, slot_reg;
+	u16 vendor_id, device_id;
+	u8  i;
+
+	DBG_ENTER_ROUTINE
+
+	spin_lock_init(&list_lock);
+	php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
+
+	if (!php_ctlr) {	/* allocate controller state data */
+		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
+		goto abort;
+	}
+
+	memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
+
+	php_ctlr->pci_dev = pdev;	/* save pci_dev in context */
+
+	rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id);
+	dbg("%s: Vendor ID: %x\n",__FUNCTION__, vendor_id);
+	if (rc) {
+		err("%s: Unable to read PCI COnfiguration data\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	rc = pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
+	dbg("%s: Device ID: %x\n",__FUNCTION__, device_id);
+	if (rc) {
+		err("%s: Unable to read PCI COnfiguration data\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	if ((vendor_id == PCI_VENDOR_ID_AMD) || (device_id == PCI_DEVICE_ID_AMD_GOLAM_7450)) {
+		shpc_base_offset = 0;  /* amd shpc driver doesn't use this; assume 0 */
+	} else {
+		if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) {
+			err("%s : shpc_cap_offset == 0\n", __FUNCTION__);
+			goto abort_free_ctlr;
+		}
+		dbg("%s: shpc_cap_offset = %x\n", __FUNCTION__, shpc_cap_offset);
+
+		rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET);
+		if (rc) {
+			err("%s : pci_word_config_byte failed\n", __FUNCTION__);
+			goto abort_free_ctlr;
+		}
+	
+		rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &shpc_base_offset);
+		if (rc) {
+			err("%s : pci_read_config_dword failed\n", __FUNCTION__);
+			goto abort_free_ctlr;
+		}
+
+		for (i = 0; i <= 14; i++) {
+			rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset +  DWORD_SELECT , i);
+			if (rc) {
+				err("%s : pci_word_config_byte failed\n", __FUNCTION__);
+				goto abort_free_ctlr;
+			}
+	
+			rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &tempdword);
+			if (rc) {
+				err("%s : pci_read_config_dword failed\n", __FUNCTION__);
+				goto abort_free_ctlr;
+			}
+			dbg("%s: offset %d: tempdword %x\n", __FUNCTION__,i, tempdword);
+		}
+	}
+
+	if (first) {
+		spin_lock_init(&hpc_event_lock);
+		first = 0;
+	}
+
+	dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, PCI_SLOT(pdev->devfn), 
+		PCI_FUNC(pdev->devfn), pdev->irq);
+	for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+		if (pci_resource_len(pdev, rc) > 0)
+			dbg("pci resource[%d] start=0x%lx(len=0x%lx), shpc_base_offset %x\n", rc,
+				pci_resource_start(pdev, rc), pci_resource_len(pdev, rc), shpc_base_offset);
+
+	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, 
+		pdev->subsystem_vendor, pdev->subsystem_device);
+
+	if (!request_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0), MY_NAME)) {
+		err("%s: cannot reserve MMIO region\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	php_ctlr->creg = (struct ctrl_reg *)
+		ioremap(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
+	if (!php_ctlr->creg) {
+		err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0), 
+			pci_resource_start(pdev, 0) + shpc_base_offset);
+		release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
+		goto abort_free_ctlr;
+	}
+	dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
+	dbg("%s: physical addr %p\n", __FUNCTION__, (void*)pci_resource_start(pdev, 0));
+
+	init_MUTEX(&ctrl->crit_sect);
+	/* Ssetup wait queue */
+	init_waitqueue_head(&ctrl->queue);
+
+	/* Find the IRQ */
+	php_ctlr->irq = pdev->irq;
+	dbg("HPC interrupt = %d\n", php_ctlr->irq);
+
+	/* Save interrupt callback info */
+	php_ctlr->attention_button_callback = attention_button_callback;
+	php_ctlr->switch_change_callback = switch_change_callback;
+	php_ctlr->presence_change_callback = presence_change_callback;
+	php_ctlr->power_fault_callback = power_fault_callback;
+	php_ctlr->callback_instance_id = instance_id;
+
+	/* Return PCI Controller Info */
+	php_ctlr->slot_device_offset = (readl(php_ctlr->creg + SLOT_CONFIG) & FIRST_DEV_NUM ) >> 8;
+	php_ctlr->num_slots = readl(php_ctlr->creg + SLOT_CONFIG) & SLOT_NUM;
+	dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset);
+	dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots);
+
+	/* Mask Global Interrupt Mask & Command Complete Interrupt Mask */
+	tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
+	tempdword = 0x0003000f;   
+	writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE);
+	tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
+	
+	/* Mask the MRL sensor SERR Mask of individual slot in
+	 * Slot SERR-INT Mask & clear all the existing event if any
+	 */
+	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
+		slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot );
+		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
+			hp_slot, slot_reg);
+		tempdword = 0xffffffff;  
+		writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot));
+	}
+	
+	if (shpchp_poll_mode)  {/* Install interrupt polling code */
+		/* Install and start the interrupt polling timer */
+		init_timer(&php_ctlr->int_poll_timer);
+		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
+	} else {
+		/* Installs the interrupt handler */
+#ifdef CONFIG_PCI_USE_VECTOR 
+		rc = pci_enable_msi(pdev);
+		if (rc) {
+			info("Can't get msi for the hotplug controller\n");
+			info("Use INTx for the hotplug controller\n");
+			dbg("%s: rc = %x\n", __FUNCTION__, rc);
+		} else
+			php_ctlr->irq = pdev->irq;
+#endif		
+		rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, 
+			ctlr_seq_num, rc);
+		if (rc) {
+			err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+			goto abort_free_ctlr;
+		}
+		/* Execute OSHP method here */
+	}
+	dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__);
+
+	/*  Add this HPC instance into the HPC list */
+	spin_lock(&list_lock);
+	if (php_ctlr_list_head == 0) {
+		php_ctlr_list_head = php_ctlr;
+		p = php_ctlr_list_head;
+		p->pnext = 0;
+	} else {
+		p = php_ctlr_list_head;
+
+		while (p->pnext)
+			p = p->pnext;
+
+		p->pnext = php_ctlr;
+	}
+	spin_unlock(&list_lock);
+
+	ctlr_seq_num++;
+	ctrl->hpc_ctlr_handle = php_ctlr;
+	ctrl->hpc_ops = &shpchp_hpc_ops;
+	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
+		slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot );
+		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
+			hp_slot, slot_reg);
+		tempdword = 0xe01fffff;  
+		writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot));
+	}
+	if (!shpchp_poll_mode) {
+		/* Unmask all general input interrupts and SERR */
+		tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		tempdword = 0x0000000a;
+		writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE);
+		tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
+	}
+
+	dbg("%s: Leaving shpc_init\n", __FUNCTION__);
+	DBG_LEAVE_ROUTINE
+	return 0;
+
+	/* We end up here for the many possible ways to fail this API.  */
+abort_free_ctlr:
+	kfree(php_ctlr);
+abort:
+	DBG_LEAVE_ROUTINE
+	return -1;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp_pci.c linux-2.4.27-pre3/drivers/hotplug/shpchp_pci.c
--- linux-2.4.26/drivers/hotplug/shpchp_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchp_pci.c	2004-05-18 16:51:52.000000000 +0000
@@ -0,0 +1,1043 @@
+/*
+ * Standard 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) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/tqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include "shpchp.h"
+#ifndef CONFIG_IA64
+#include "../../arch/i386/kernel/pci-i386.h"    /* horrible hack showing how processor dependant we are... */
+#endif
+
+static int is_pci_dev_in_use(struct pci_dev* dev) 
+{
+	/* 
+	 * dev->driver will be set if the device is in use by a new-style 
+	 * driver -- otherwise, check the device's regions to see if any
+	 * driver has claimed them
+	 */
+
+	int i, inuse=0;
+
+	if (dev->driver) return 1; /* Assume driver feels responsible */
+
+	for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
+		if (!pci_resource_start(dev, i))
+			continue;
+
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO)
+			inuse = check_region(pci_resource_start(dev, i),
+					     pci_resource_len(dev, i));
+		else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+			inuse = check_mem_region(pci_resource_start(dev, i),
+						 pci_resource_len(dev, i));
+	}
+
+	return inuse;
+
+}
+
+
+static int pci_hp_remove_device(struct pci_dev *dev)
+{
+	if (is_pci_dev_in_use(dev)) {
+		err("***Cannot safely power down device -- "
+		       "it appears to be in use***\n");
+		return -EBUSY;
+	}
+	pci_remove_device(dev);
+	return 0;
+}
+
+
+static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) 
+{
+	struct pci_bus* bus = wrapped_bus->bus;
+	struct pci_dev* dev = wrapped_dev->dev;
+	struct pci_func *temp_func;
+	int i=0;
+
+	dbg("%s: Enter\n", __FUNCTION__);
+	/* We need to fix up the hotplug function representation with the linux representation */
+	do {
+		temp_func = shpchp_slot_find(dev->bus->number, dev->devfn >> 3, i++);
+		dbg("%s: i %d temp_func %p, bus %x dev %x\n", __FUNCTION__, i, temp_func, 
+			dev->bus->number, dev->devfn >>3);
+	} while (temp_func && (temp_func->function != (dev->devfn & 0x07)));
+
+	if (temp_func) {
+		temp_func->pci_dev = dev;
+		dbg("%s: dev %p dev->irq %x\n", __FUNCTION__, dev, dev->irq);
+	} else {
+		/* 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("@@@@@@@@@@@ shpchp_slot_create in %s\n", __FUNCTION__);
+		temp_func = shpchp_slot_create(bus->number);
+		if (temp_func == NULL)
+			return -ENOMEM;
+		temp_func->pci_dev = dev;
+	}
+
+	/* Create /proc/bus/pci proc entry for this device and bus device is on */
+	/* Notify the drivers of the change */
+	if (temp_func->pci_dev) {
+		dbg("%s: PCI_ID=%04X:%04X\n", __FUNCTION__, temp_func->pci_dev->vendor,
+			temp_func->pci_dev->device);
+		dbg("%s: PCI BUS %x DEVFN %x\n", __FUNCTION__, temp_func->pci_dev->bus->number,
+			temp_func->pci_dev->devfn);
+		dbg("%s: PCI_SLOT_NAME %s\n", __FUNCTION__, 
+			temp_func->pci_dev->slot_name);
+		pci_enable_device(temp_func->pci_dev);
+		pci_proc_attach_device(temp_func->pci_dev);
+		pci_announce_device_to_drivers(temp_func->pci_dev);
+	}
+
+	return 0;
+}
+
+
+static int unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) 
+{
+	struct pci_dev* dev = wrapped_dev->dev;
+
+	struct pci_func *temp_func;
+	int i=0;
+
+	/* We need to remove the hotplug function representation with the linux representation */
+	do {
+		temp_func = shpchp_slot_find(dev->bus->number, dev->devfn >> 3, i++);
+		if (temp_func) {
+			dbg("temp_func->function = %d\n", temp_func->function);
+		}
+	} while (temp_func && (temp_func->function != (dev->devfn & 0x07)));
+
+	/* Now, remove the Linux Representation */
+	if (dev) {
+		if (pci_hp_remove_device(dev) == 0) {
+			kfree(dev); /* Now, remove */
+		} else {
+			return -1; /* problems while freeing, abort visitation */
+		}
+	}
+
+	if (temp_func) {
+		temp_func->pci_dev = NULL;
+	} else {
+		dbg("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
+	}
+
+	return 0;
+}
+
+
+static int unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev) 
+{
+	struct pci_bus* bus = wrapped_bus->bus;
+
+	/* The cleanup code for proc entries regarding buses should be in the kernel...*/
+	if (bus->procdir)
+		dbg("detach_pci_bus %s\n", bus->procdir->name);
+	pci_proc_detach_bus(bus);
+	/* The cleanup code should live in the kernel... */
+	bus->self->subordinate = NULL;
+	/* Unlink from parent bus */
+	list_del(&bus->node);
+
+	/* Now, remove */
+	if (bus)
+		kfree(bus);
+
+	return 0;
+}
+
+
+static int unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) 
+{
+	struct pci_dev* dev = wrapped_dev->dev;
+	int rc;
+
+	dbg("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	/* Now, remove the Linux Driver Representation */
+	if (dev->driver) {
+		if (dev->driver->remove) {
+			dev->driver->remove(dev);
+			dbg("driver was properly removed\n");
+		}
+		dev->driver = NULL;
+	}
+
+	rc = is_pci_dev_in_use(dev);
+	if (rc)
+		info("%s: device still in use\n", __FUNCTION__);
+	return rc;
+}
+
+
+static struct pci_visit configure_functions = {
+	.visit_pci_dev =	configure_visit_pci_dev,
+};
+
+
+static struct pci_visit unconfigure_functions_phase1 = {
+	.post_visit_pci_dev =	unconfigure_visit_pci_dev_phase1
+};
+
+static struct pci_visit unconfigure_functions_phase2 = {
+	.post_visit_pci_bus =	unconfigure_visit_pci_bus_phase2,               
+	.post_visit_pci_dev =	unconfigure_visit_pci_dev_phase2
+};
+
+
+int shpchp_configure_device (struct controller* ctrl, struct pci_func* func)  
+{
+	unsigned char bus;
+	struct pci_dev dev0;
+	struct pci_bus *child;
+	struct pci_dev* temp;
+	int rc = 0;
+
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	
+	dbg("%s: Enter\n", __FUNCTION__);
+	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+
+	memset(&dev0, 0, sizeof(struct pci_dev));
+
+	dbg("%s: func->pci_dev %p\n", __FUNCTION__, func->pci_dev);
+	if (func->pci_dev != NULL)
+		dbg("%s: func->pci_dev->irq %x\n", __FUNCTION__, func->pci_dev->irq);
+	if (func->pci_dev == NULL)
+		func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7));
+	dbg("%s: after pci_find_slot, func->pci_dev %p\n", __FUNCTION__, func->pci_dev);
+	if (func->pci_dev != NULL)
+		dbg("%s: after pci_find_slot, func->pci_dev->irq %x\n", __FUNCTION__, func->pci_dev->irq);
+
+	/* Still NULL ? Well then scan for it ! */
+	if (func->pci_dev == NULL) {
+		dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__);
+		dev0.bus = ctrl->pci_dev->subordinate;
+		dbg("%s: dev0.bus %p\n", __FUNCTION__, dev0.bus);
+		dev0.bus->number = func->bus;
+		dbg("%s: dev0.bus->number %x\n", __FUNCTION__, func->bus);
+		dev0.devfn = PCI_DEVFN(func->device, func->function);
+		dev0.sysdata = ctrl->pci_dev->sysdata;
+
+		/* this will generate pci_dev structures for all functions, 
+		 * but we will only call this case when lookup fails
+		 */
+		dbg("%s: dev0.irq %x\n", __FUNCTION__, dev0.irq);
+		func->pci_dev = pci_scan_slot(&dev0);
+		dbg("%s: func->pci_dev->irq %x\n", __FUNCTION__, 
+			func->pci_dev->irq);
+		if (func->pci_dev == NULL) {
+			dbg("ERROR: pci_dev still null\n");
+			return 0;
+		}
+	}
+
+	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
+		child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
+		dbg("%s: calling pci_do_scan_bus\n", __FUNCTION__);
+		pci_do_scan_bus(child);
+
+	}
+
+	temp = func->pci_dev;
+	dbg("%s: func->pci_dev->irq %x\n", __FUNCTION__, func->pci_dev->irq);
+
+	if (temp) {
+		wrapped_dev.dev = temp;
+		wrapped_bus.bus = temp->bus;
+		rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
+	}
+		
+	dbg("%s: Exit\n", __FUNCTION__);
+	return rc;
+}
+
+
+int shpchp_unconfigure_device(struct pci_func* func) 
+{
+	int rc = 0;
+	int j;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	
+	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+
+	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);
+		if (temp) {
+			wrapped_dev.dev = temp;
+			wrapped_bus.bus = temp->bus;
+			rc = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus);
+			if (rc)
+				break;
+
+			rc = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus);
+			if (rc)
+				break;
+		}
+	}
+	return rc;
+}
+
+/*
+ * shpchp_set_irq
+ *
+ * @bus_num: bus number of PCI device
+ * @dev_num: device number of PCI device
+ * @slot: pointer to u8 where slot number will be returned
+ */
+int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
+{
+#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
+	int rc;
+	u16 temp_word;
+	struct pci_dev fakedev;
+	struct pci_bus fakebus;
+
+	fakedev.devfn = dev_num << 3;
+	fakedev.bus = &fakebus;
+	fakebus.number = bus_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("%s: rc %d\n", __FUNCTION__, rc);
+	if (!rc)
+		return !rc;
+
+	/* set the Edge Level Control Register (ELCR) */
+	temp_word = inb(0x4d0);
+	temp_word |= inb(0x4d1) << 8;
+
+	temp_word |= 0x01 << irq_num;
+
+	/* This should only be for x86 as it sets the Edge Level Control Register */
+	outb((u8) (temp_word & 0xFF), 0x4d0);
+	outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
+#endif
+	return 0;
+}
+
+/* More PCI configuration routines; this time centered around hotplug controller */
+
+
+/*
+ * shpchp_save_config
+ *
+ * Reads configuration for all slots in a PCI bus and saves info.
+ *
+ * Note:  For non-hot plug busses, the slot # saved is the device #
+ *
+ * returns 0 if success
+ */
+int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	struct pci_func *new_slot;
+	int sub_bus;
+	int FirstSupported;
+	int LastSupported;
+	int max_functions;
+	int function;
+	u8 DevError;
+	int device = 0;
+	int cloop = 0;
+	int stop_it;
+	int index;
+	int is_hot_plug = num_ctlr_slots || first_device_num;
+	struct pci_bus lpci_bus, *pci_bus;
+
+	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, first_device_num);
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+
+	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, first_device_num);
+
+	/*   Decide which slots are supported */
+	if (is_hot_plug) {
+		/*********************************
+		 *  is_hot_plug is the slot mask
+		 *********************************/
+		FirstSupported = first_device_num;
+		LastSupported = FirstSupported + num_ctlr_slots - 1;
+	} else {
+		FirstSupported = 0;
+		LastSupported = 0x1F;
+	}
+
+	dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, LastSupported);
+
+	/*   Save PCI configuration space for all devices in supported slots */
+	pci_bus->number = busnumber;
+	for (device = FirstSupported; device <= LastSupported; device++) {
+		ID = 0xFFFFFFFF;
+		rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
+
+		if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
+			if (rc)
+				return rc;
+
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
+			if (rc)
+				return rc;
+
+			dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+
+			/* If multi-function device, set max_functions to 8 */
+			if (header_type & 0x80)
+				max_functions = 8;
+			else
+				max_functions = 1;
+
+			function = 0;
+
+			do {
+				DevError = 0;
+
+				if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   /* P-P Bridge */
+					/* Recurse the subordinate bus
+					 * get the subordinate bus number
+					 */
+					rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
+					if (rc) {
+						return rc;
+					} else {
+						sub_bus = (int) secondary_bus;
+
+						/* Save secondary bus cfg spc with this recursive call. */
+						rc = shpchp_save_config(ctrl, sub_bus, 0, 0);
+						if (rc)
+							return rc;
+					}
+				}
+
+				index = 0;
+				new_slot = shpchp_slot_find(busnumber, device, index++);
+
+				dbg("new_slot = %p\n", new_slot);
+
+				while (new_slot && (new_slot->function != (u8) function)) {
+					new_slot = shpchp_slot_find(busnumber, device, index++);
+					dbg("new_slot = %p\n", new_slot);
+				}
+				if (!new_slot) {
+					/* Setup slot structure. */
+					new_slot = shpchp_slot_create(busnumber);
+					dbg("new_slot = %p\n", new_slot);
+
+					if (new_slot == NULL)
+						return(1);
+				}
+
+				new_slot->bus = (u8) busnumber;
+				new_slot->device = (u8) device;
+				new_slot->function = (u8) function;
+				new_slot->is_a_board = 1;
+				new_slot->switch_save = 0x10;
+				/* In case of unsupported board */
+				new_slot->status = DevError;
+				new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function);
+				dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev);
+
+				for (cloop = 0; cloop < 0x20; cloop++) {
+					rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop]));
+					dbg("%s: new_slot->config_space[%x] = %x\n", __FUNCTION__, cloop, new_slot->config_space[cloop]); 
+					if (rc)
+						return rc;
+				}
+
+				function++;
+
+				stop_it = 0;
+
+				/*  This loop skips to the next present function
+				 *  reading in Class Code and Header type.
+				 */
+
+				while ((function < max_functions)&&(!stop_it)) {
+					rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
+
+					if (ID == 0xFFFFFFFF) {  /* nothing there. */
+						function++;
+						dbg("Nothing there\n");
+					} else {  /* Something there */
+						rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
+						if (rc)
+							return rc;
+
+						rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
+						if (rc)
+							return rc;
+
+						dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+						stop_it++;
+					}
+				}
+
+			} while (function < max_functions);
+		}		/* End of IF (device in slot?) */
+		else if (is_hot_plug) {
+			/* Setup slot structure with entry for empty slot */
+			new_slot = shpchp_slot_create(busnumber);
+
+			if (new_slot == NULL) {
+				return(1);
+			}
+			dbg("new_slot = %p\n", new_slot);
+
+			new_slot->bus = (u8) busnumber;
+			new_slot->device = (u8) device;
+			new_slot->function = 0;
+			new_slot->is_a_board = 0;
+			new_slot->presence_save = 0;
+			new_slot->switch_save = 0;
+		}
+	}			/* End of FOR loop */
+
+	return(0);
+}
+
+
+/*
+ * shpchp_save_slot_config
+ *
+ * Saves configuration info for all PCI devices in a given slot
+ * including subordinate busses.
+ *
+ * returns 0 if success
+ */
+int shpchp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	int sub_bus;
+	int max_functions;
+	int function;
+	int cloop = 0;
+	int stop_it;
+	struct pci_bus lpci_bus, *pci_bus;
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = new_slot->bus;
+
+	ID = 0xFFFFFFFF;
+
+	pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
+
+	if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
+
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
+
+		if (header_type & 0x80)	/* Multi-function device */
+			max_functions = 8;
+		else
+			max_functions = 1;
+
+		function = 0;
+
+		do {
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  /* PCI-PCI Bridge */
+				/*  Recurse the subordinate bus */
+				pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
+
+				sub_bus = (int) secondary_bus;
+
+				/* Save the config headers for the secondary bus. */
+				rc = shpchp_save_config(ctrl, sub_bus, 0, 0);
+
+				if (rc)
+					return(rc);
+
+			}	/* End of IF */
+
+			new_slot->status = 0;
+
+			for (cloop = 0; cloop < 0x20; cloop++) {
+				pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop]));
+				dbg("%s: new_slot->config_space[%x] = %x\n", __FUNCTION__,cloop, new_slot->config_space[cloop]); 
+			}
+
+			function++;
+
+			stop_it = 0;
+
+			/*  this loop skips to the next present function
+			 *  reading in the Class Code and the Header type.
+			 */
+
+			while ((function < max_functions) && (!stop_it)) {
+				pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
+
+				if (ID == 0xFFFFFFFF) {	 /* nothing there. */
+					function++;
+				} else {  /* Something there */
+					pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
+
+					pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
+
+					stop_it++;
+				}
+			}
+
+		} while (function < max_functions);
+	}			/* End of IF (device in slot?) */
+	else {
+		return(2);
+	}
+
+	return(0);
+}
+
+
+/*
+ * shpchp_save_used_resources
+ *
+ * Stores used resource information for existing boards.  this is
+ * for boards that were in the system when this driver was loaded.
+ * this function is for hot plug ADD
+ *
+ * returns 0 if success
+ * if disable  == 1(DISABLE_CARD),
+ *  it loops for all functions of the slot and disables them.
+ * else, it just get resources of the function and return.
+ */
+int shpchp_save_used_resources (struct controller *ctrl, struct pci_func *func, int disable)
+{
+	u8 cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	u8 temp_byte;
+	u16 command;
+	u16 save_command;
+	u16 w_base, w_length;
+	u32 temp_register;
+	u32 save_base;
+	u32 base, length;
+	u64 base64 = 0;
+	int index = 0;
+	unsigned int devfn;
+	struct pci_resource *mem_node = NULL;
+	struct pci_resource *p_mem_node = NULL;
+	struct pci_resource *t_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_bus lpci_bus, *pci_bus;
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+
+	if (disable)
+		func = shpchp_slot_find(func->bus, func->device, index++);
+
+	while ((func != NULL) && func->is_a_board) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		/* Save the command register */
+		pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command);
+
+		if (disable) {
+			/* disable card */
+			command = 0x00;
+			pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+		}
+
+		/* Check for Bridge */
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+
+		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {     /* PCI-PCI Bridge */
+			dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command);
+			if (disable) {
+				/* Clear Bridge Control Register */
+				command = 0x00;
+				pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+			}
+
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
+
+			bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node->base = (ulong)secondary_bus;
+			bus_node->length = (ulong)(temp_byte - secondary_bus + 1);
+
+			bus_node->next = func->bus_head;
+			func->bus_head = bus_node;
+
+			/* Save IO base and Limit registers */
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &temp_byte);
+			base = temp_byte;
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &temp_byte);
+			length = temp_byte;
+
+			if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) {
+				io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!io_node)
+					return -ENOMEM;
+
+				io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8;
+				io_node->length = (ulong)(length - base + 0x10) << 8;
+
+				io_node->next = func->io_head;
+				func->io_head = io_node;
+			}
+
+			/* Save memory base and Limit registers */
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+				mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!mem_node)
+					return -ENOMEM;
+
+				mem_node->base = (ulong)w_base << 16;
+				mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
+
+				mem_node->next = func->mem_head;
+				func->mem_head = mem_node;
+			}
+			/* Save prefetchable memory base and Limit registers */
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+				p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!p_mem_node)
+					return -ENOMEM;
+
+				p_mem_node->base = (ulong)w_base << 16;
+				p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
+
+				p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = p_mem_node;
+			}
+		} else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+			dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command);
+
+			/* Figure out IO and memory base lengths */
+			for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);
+
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register);
+
+				if (!disable) {
+					pci_bus_write_config_dword (pci_bus, devfn, cloop, save_base);
+				}
+
+				if (!temp_register)
+					continue;
+
+				base = temp_register;
+
+				if ((base & PCI_BASE_ADDRESS_SPACE_IO) && (!disable || (save_command & PCI_COMMAND_IO))) {
+					/* IO base */
+					/* set temp_register = amount of IO space requested */
+					base = base & 0xFFFFFFFCL;
+					base = (~base) + 1;
+
+					io_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+					if (!io_node)
+						return -ENOMEM;
+
+					io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK;
+					io_node->length = (ulong)base;
+					dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", io_node->base, io_node->length);
+
+					io_node->next = func->io_head;
+					func->io_head = io_node;
+				} else {  /* map Memory */
+					int prefetchable = 1;
+					/* struct pci_resources **res_node; */
+					char *res_type_str = "PMEM";
+					u32 temp_register2;
+
+					t_mem_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+					if (!t_mem_node)
+						return -ENOMEM;
+
+					if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+						prefetchable = 0;
+						mem_node = t_mem_node;
+						res_type_str++;
+					} else
+						p_mem_node = t_mem_node;
+
+					base = base & 0xFFFFFFF0L;
+					base = (~base) + 1;
+
+					switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+					case PCI_BASE_ADDRESS_MEM_TYPE_32:
+						if (prefetchable) {
+							p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node->length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length);
+
+							p_mem_node->next = func->p_mem_head;
+							func->p_mem_head = p_mem_node;
+						} else {
+							mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node->length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+
+							mem_node->next = func->mem_head;
+							func->mem_head = mem_node;
+						}
+						break;
+					case PCI_BASE_ADDRESS_MEM_TYPE_64:
+						pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+						base64 = temp_register2;
+						base64 = (base64 << 32) | save_base;
+
+						if (temp_register2) {
+							dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", res_type_str, temp_register2, (u32)base64);
+							base64 &= 0x00000000FFFFFFFFL;
+						}
+
+						if (prefetchable) {
+							p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node->length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length);
+
+							p_mem_node->next = func->p_mem_head;
+							func->p_mem_head = p_mem_node;
+						} else {
+							mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node->length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+
+							mem_node->next = func->mem_head;
+							func->mem_head = mem_node;
+						}
+						cloop += 4;
+						break;
+					default:
+						dbg("asur: reserved BAR type=0x%x\n", temp_register);
+						break;
+					}
+				} 
+			}	/* End of base register loop */
+		} else {	/* Some other unknown header type */
+			dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", func->bus, func->device);
+		}
+
+		/* find the next device in this slot */
+		if (!disable)
+			break;
+		func = shpchp_slot_find(func->bus, func->device, index++);
+	}
+
+	return(0);
+}
+
+
+/*
+ * shpchp_return_board_resources
+ *
+ * this routine returns all resources allocated to a board to
+ * the available pool.
+ *
+ * returns 0 if success
+ */
+int shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources)
+{
+	int rc = 0;
+	struct pci_resource *node;
+	struct pci_resource *t_node;
+	dbg("%s\n", __FUNCTION__);
+
+	if (!func)
+		return(1);
+
+	node = func->io_head;
+	func->io_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->io_head), node);
+		node = t_node;
+	}
+
+	node = func->mem_head;
+	func->mem_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->mem_head), node);
+		node = t_node;
+	}
+
+	node = func->p_mem_head;
+	func->p_mem_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->p_mem_head), node);
+		node = t_node;
+	}
+
+	node = func->bus_head;
+	func->bus_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->bus_head), node);
+		node = t_node;
+	}
+
+	rc |= shpchp_resource_sort_and_combine(&(resources->mem_head));
+	rc |= shpchp_resource_sort_and_combine(&(resources->p_mem_head));
+	rc |= shpchp_resource_sort_and_combine(&(resources->io_head));
+	rc |= shpchp_resource_sort_and_combine(&(resources->bus_head));
+
+	return(rc);
+}
+
+
+/*
+ * shpchp_destroy_resource_list
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void shpchp_destroy_resource_list (struct resource_lists * resources)
+{
+	struct pci_resource *res, *tres;
+
+	res = resources->io_head;
+	resources->io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = resources->mem_head;
+	resources->mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = resources->p_mem_head;
+	resources->p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = resources->bus_head;
+	resources->bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
+
+/*
+ * shpchp_destroy_board_resources
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void shpchp_destroy_board_resources (struct pci_func * func)
+{
+	struct pci_resource *res, *tres;
+
+	dbg("%s: \n", __FUNCTION__);
+
+	res = func->io_head;
+	func->io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = func->mem_head;
+	func->mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = func->p_mem_head;
+	func->p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = func->bus_head;
+	func->bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm.h linux-2.4.27-pre3/drivers/hotplug/shpchprm.h
--- linux-2.4.26/drivers/hotplug/shpchprm.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchprm.h	2004-05-18 16:51:29.000000000 +0000
@@ -0,0 +1,57 @@
+/*
+ * SHPCHPRM : SHPCHP Resource Manager for ACPI/non-ACPI platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _SHPCHPRM_H_
+#define _SHPCHPRM_H_
+
+#ifdef	CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY
+#include "shpchprm_legacy.h"
+#else
+#include "shpchprm_nonacpi.h"
+#endif
+
+int shpchprm_init(enum php_ctlr_type ct);
+void shpchprm_cleanup(void);
+int shpchprm_print_pirt(void);
+void *shpchprm_get_slot(struct slot *slot);
+int shpchprm_find_available_resources(struct controller *ctrl);
+int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type);
+void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type);
+int shpchprm_get_interrupt(int seg, int bus, int device, int pin, int *irq);
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum);
+
+#ifdef	DEBUG
+#define RES_CHECK(this, bits)	\
+	{ if (((this) & (bits - 1))) \
+		printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); }
+#else
+#define RES_CHECK(this, bits)
+#endif
+
+#endif				/* _SHPCHPRM_H_ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_acpi.c linux-2.4.27-pre3/drivers/hotplug/shpchprm_acpi.c
--- linux-2.4.26/drivers/hotplug/shpchprm_acpi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchprm_acpi.c	2004-05-18 16:55:39.000000000 +0000
@@ -0,0 +1,1696 @@
+/*
+ * SHPCHPRM ACPI: PHP Resource Manager for ACPI platform
+ *
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/efi.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#ifdef	CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/actypes.h>
+#include "shpchp.h"
+#include "shpchprm.h"
+
+#define	PCI_MAX_BUS		0x100
+#define	ACPI_STA_DEVICE_PRESENT	0x01
+
+#define	METHOD_NAME__SUN	"_SUN"
+#define	METHOD_NAME__HPP	"_HPP"
+#define	METHOD_NAME_OSHP	"OSHP"
+
+#define	PHP_RES_BUS		0xA0
+#define	PHP_RES_IO		0xA1
+#define	PHP_RES_MEM		0xA2
+#define	PHP_RES_PMEM		0xA3
+
+#define	BRIDGE_TYPE_P2P		0x00
+#define	BRIDGE_TYPE_HOST	0x01
+
+/* This should go to drivers/acpi/include/ */
+struct acpi__hpp {
+	u8	cache_line_size;
+	u8	latency_timer;
+	u8	enable_serr;
+	u8	enable_perr;
+};
+
+struct acpi_php_slot {
+	struct acpi_php_slot	*next;
+	struct acpi_bridge	*bridge;
+	acpi_handle	handle;
+	int	seg;
+	int	bus;
+	int	dev;
+	int	fun;
+	u32	sun;
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	void	*slot_ops;	/* _STA, _EJx, etc */
+	struct slot *slot;
+};		/* per func */
+
+struct acpi_bridge {
+	struct acpi_bridge	*parent;
+	struct acpi_bridge	*next;
+	struct acpi_bridge	*child;
+	acpi_handle	handle;
+	int seg;
+	int pbus;				/* pdev->bus->number		*/
+	int pdevice;				/* PCI_SLOT(pdev->devfn)	*/
+	int pfunction;				/* PCI_DEVFN(pdev->devfn)	*/
+	int bus;				/* pdev->subordinate->number	*/
+	struct acpi__hpp		*_hpp;
+	struct acpi_php_slot	*slots;
+	struct pci_resource 	*tmem_head;	/* total from crs	*/
+	struct pci_resource 	*tp_mem_head;	/* total from crs	*/
+	struct pci_resource 	*tio_head;	/* total from crs	*/
+	struct pci_resource 	*tbus_head;	/* total from crs	*/
+	struct pci_resource 	*mem_head;	/* available	*/
+	struct pci_resource 	*p_mem_head;	/* available	*/
+	struct pci_resource 	*io_head;	/* available	*/
+	struct pci_resource 	*bus_head;	/* available	*/
+	int scanned;
+	int type;
+};
+
+static struct acpi_bridge *acpi_bridges_head;
+
+static u8 * acpi_path_name( acpi_handle	handle)
+{
+	acpi_status		status;
+	static u8	path_name[ACPI_PATHNAME_MAX];
+	struct acpi_buffer		ret_buf = { ACPI_PATHNAME_MAX, path_name };
+
+	memset(path_name, 0, sizeof (path_name));
+	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);
+
+	if (ACPI_FAILURE(status))
+		return NULL;
+	else
+		return path_name;	
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab);
+static void acpi_run_oshp ( struct acpi_bridge	*ab);
+
+static int acpi_add_slot_to_php_slots(
+	struct acpi_bridge	*ab,
+	int				bus_num,
+	acpi_handle		handle,
+	u32				adr,
+	u32				sun
+	)
+{
+	struct acpi_php_slot	*aps;
+	static long	samesun = -1;
+
+	aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);
+	if (!aps) {
+		err ("acpi_shpchprm: alloc for aps fail\n");
+		return -1;
+	}
+	memset(aps, 0, sizeof(struct acpi_php_slot));
+
+	aps->handle = handle;
+	aps->bus = bus_num;
+	aps->dev = (adr >> 16) & 0xffff;
+	aps->fun = adr & 0xffff;
+	aps->sun = sun;
+
+	aps->next = ab->slots;	/* cling to the bridge */
+	aps->bridge = ab;
+	ab->slots = aps;
+
+	ab->scanned += 1;
+	if (!ab->_hpp)
+		acpi_get__hpp(ab);
+
+	acpi_run_oshp(ab);
+	if (sun != samesun) {
+		info("acpi_shpchprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", 
+			aps->sun, ab->seg, aps->bus, aps->dev, aps->fun);
+		samesun = sun;
+	}
+	return 0;
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			nui[4];
+	struct acpi_buffer	ret_buf = { 0, NULL};
+	union acpi_object	*ext_obj, *package;
+	u8			*path_name = acpi_path_name(ab->handle);
+	int			i, len = 0;
+
+	/* get _hpp */
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
+		if (!ret_buf.pointer) {
+			err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name);
+			return;
+		}
+		status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+		if (ACPI_SUCCESS(status))
+			break;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status);
+			return;
+		}
+	}
+
+	ext_obj = (union acpi_object *) ret_buf.pointer;
+	if (ext_obj->type != ACPI_TYPE_PACKAGE) {
+		err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name);
+		goto free_and_return;
+	}
+
+	len = ext_obj->package.count;
+	package = (union acpi_object *) ret_buf.pointer;
+	for ( i = 0; (i < len) || (i < 4); i++) {
+		ext_obj = (union acpi_object *) &package->package.elements[i];
+		switch (ext_obj->type) {
+		case ACPI_TYPE_INTEGER:
+			nui[i] = (u8)ext_obj->integer.value;
+			break;
+		default:
+			err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name);
+			goto free_and_return;
+		}
+	}
+
+	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
+
+	ab->_hpp->cache_line_size	= nui[0];
+	ab->_hpp->latency_timer		= nui[1];
+	ab->_hpp->enable_serr		= nui[2];
+	ab->_hpp->enable_perr		= nui[3];
+
+	dbg("  _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
+	dbg("  _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
+	dbg("  _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
+	dbg("  _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+
+free_and_return:
+	kfree(ret_buf.pointer);
+}
+
+static void acpi_run_oshp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(ab->handle);
+	struct acpi_buffer		ret_buf = { 0, NULL};
+
+	/* run OSHP */
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, &ret_buf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
+	} else
+		dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);
+	return;
+}
+
+static acpi_status acpi_evaluate_crs(
+	acpi_handle		handle,
+	struct acpi_resource	**retbuf
+	)
+{
+	acpi_status		status;
+	struct acpi_buffer		crsbuf;
+	u8			*path_name = acpi_path_name(handle);
+
+	crsbuf.length  = 0;
+	crsbuf.pointer = NULL;
+
+	status = acpi_get_current_resources (handle, &crsbuf);
+
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		break;		/* found */
+	case AE_NOT_FOUND:
+		dbg("acpi_shpchprm:%s _CRS not found\n", path_name);
+		return status;
+	default:
+		err ("acpi_shpchprm:%s _CRS fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL);
+	if (!crsbuf.pointer) {
+		err ("acpi_shpchprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name);
+		return AE_NO_MEMORY;
+	}
+
+	status = acpi_get_current_resources (handle, &crsbuf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm: %s _CRS fail=0x%x.\n", path_name, status);
+		kfree(crsbuf.pointer);
+		return status;
+	}
+
+	*retbuf = crsbuf.pointer;
+
+	return status;
+}
+
+static void free_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res, *next;
+
+	for (res = aprh; res; res = next) {
+		next = res->next;
+		kfree(res);
+	}
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res->next)
+		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
+}
+
+static void print_slot_resources( struct acpi_php_slot	*aps)
+{
+	if (aps->bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (aps->bus_head);
+	}
+
+	if (aps->io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (aps->io_head);
+	}
+
+	if (aps->mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (aps->mem_head);
+	}
+
+	if (aps->p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (aps->p_mem_head);
+	}
+}
+
+static void print_pci_resources( struct acpi_bridge	*ab)
+{
+	if (ab->tbus_head) {
+		dbg("    Total BUS Resources:\n");
+		print_pci_resource (ab->tbus_head);
+	}
+	if (ab->bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (ab->bus_head);
+	}
+
+	if (ab->tio_head) {
+		dbg("    Total IO Resources:\n");
+		print_pci_resource (ab->tio_head);
+	}
+	if (ab->io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (ab->io_head);
+	}
+
+	if (ab->tmem_head) {
+		dbg("    Total MEM Resources:\n");
+		print_pci_resource (ab->tmem_head);
+	}
+	if (ab->mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (ab->mem_head);
+	}
+
+	if (ab->tp_mem_head) {
+		dbg("    Total PMEM Resources:\n");
+		print_pci_resource (ab->tp_mem_head);
+	}
+	if (ab->p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (ab->p_mem_head);
+	}
+	if (ab->_hpp) {
+		dbg("    _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
+		dbg("    _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
+		dbg("    _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
+		dbg("    _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+	}
+}
+
+static int shpchprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	shpchp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+static int shpchprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res->next)
+		shpchprm_delete_resource(aprh, res->base, res->length);
+
+	return 0;
+}
+
+static int shpchprm_add_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+
+	for (res = *aprh; res; res = res->next) {
+		if ((res->base + res->length) == base) {
+			res->length += size;
+			size = 0L;
+			break;
+		}
+		if (res->next == *aprh)
+			break;
+	}
+
+	if (size) {
+		res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		if (!res) {
+			err ("acpi_shpchprm: alloc for res fail\n");
+			return -ENOMEM;
+		}
+		memset(res, 0, sizeof (struct pci_resource));
+
+		res->base = base;
+		res->length = size;
+		res->next = *aprh;
+		*aprh = res;
+	}
+
+	return 0;
+}
+
+static int shpchprm_add_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+	int	rc = 0;
+
+	for (res = this; res && !rc; res = res->next)
+		rc = shpchprm_add_resource(aprh, res->base, res->length);
+
+	return rc;
+}
+
+static void acpi_parse_io (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_io	*dataio;
+	dataio = (struct acpi_resource_io *) data;
+
+	dbg("Io Resource\n");
+	dbg("  %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10);
+	dbg("  Range minimum base: %08X\n", dataio->min_base_address);
+	dbg("  Range maximum base: %08X\n", dataio->max_base_address);
+	dbg("  Alignment: %08X\n", dataio->alignment);
+	dbg("  Range Length: %08X\n", dataio->range_length);
+}
+
+static void acpi_parse_fixed_io (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_fixed_io  *datafio;
+	datafio = (struct acpi_resource_fixed_io *) data;
+
+	dbg("Fixed Io Resource\n");
+	dbg("  Range base address: %08X", datafio->base_address);
+	dbg("  Range length: %08X", datafio->range_length);
+}
+
+static void acpi_parse_address16_32 (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data,
+	acpi_resource_type		id
+	)
+{
+	/* 
+	 * acpi_resource_address16 == acpi_resource_address32
+	 * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data;
+	 */
+	struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data;
+	struct pci_resource **aprh, **tprh;
+
+	if (id == ACPI_RSTYPE_ADDRESS16)
+		dbg("acpi_shpchprm:16-Bit Address Space Resource\n");
+	else
+		dbg("acpi_shpchprm:32-Bit Address Space Resource\n");
+
+	switch (data32->resource_type) {
+	case ACPI_MEMORY_RANGE: 
+		dbg("  Resource Type: Memory Range\n");
+		aprh = &ab->mem_head;
+		tprh = &ab->tmem_head;
+
+		switch (data32->attribute.memory.cache_attribute) {
+		case ACPI_NON_CACHEABLE_MEMORY:
+			dbg("  Type Specific: Noncacheable memory\n");
+			break; 
+		case ACPI_CACHABLE_MEMORY:
+			dbg("  Type Specific: Cacheable memory\n");
+			break; 
+		case ACPI_WRITE_COMBINING_MEMORY:
+			dbg("  Type Specific: Write-combining memory\n");
+			break; 
+		case ACPI_PREFETCHABLE_MEMORY:
+			aprh = &ab->p_mem_head;
+			dbg("  Type Specific: Prefetchable memory\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid cache attribute\n");
+			break;
+		}
+
+		dbg("  Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only");
+		break;
+
+	case ACPI_IO_RANGE: 
+		dbg("  Resource Type: I/O Range\n");
+		aprh = &ab->io_head;
+		tprh = &ab->tio_head;
+
+		switch (data32->attribute.io.range_attribute) {
+		case ACPI_NON_ISA_ONLY_RANGES:
+			dbg("  Type Specific: Non-ISA Io Addresses\n");
+			break; 
+		case ACPI_ISA_ONLY_RANGES:
+			dbg("  Type Specific: ISA Io Addresses\n");
+			break; 
+		case ACPI_ENTIRE_RANGE:
+			dbg("  Type Specific: ISA and non-ISA Io Addresses\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid range attribute\n");
+			break;
+		}
+		break;
+
+	case ACPI_BUS_NUMBER_RANGE: 
+		dbg("  Resource Type: Bus Number Range(fixed)\n");
+		/* Fixup to be compatible with the rest of php driver */
+		data32->min_address_range++;
+		data32->address_length--;
+		aprh = &ab->bus_head;
+		tprh = &ab->tbus_head;
+		break; 
+	default: 
+		dbg("  Resource Type: Invalid resource type. Exiting.\n");
+		return;
+	}
+
+	dbg("  Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer");
+	dbg("  %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive");
+	dbg("  Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not");
+	dbg("  Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not");
+	dbg("  Granularity: %08X\n", data32->granularity);
+	dbg("  Address range min: %08X\n", data32->min_address_range);
+	dbg("  Address range max: %08X\n", data32->max_address_range);
+	dbg("  Address translation offset: %08X\n", data32->address_translation_offset);
+	dbg("  Address Length: %08X\n", data32->address_length);
+
+	if (0xFF != data32->resource_source.index) {
+		dbg("  Resource Source Index: %X\n", data32->resource_source.index);
+		/* dbg("  Resource Source: %s\n", data32->resource_source.string_ptr); */
+	}
+
+	shpchprm_add_resource(aprh, data32->min_address_range, data32->address_length);
+}
+
+static acpi_status acpi_parse_crs(
+	struct acpi_bridge	*ab,
+	struct acpi_resource	*crsbuf
+	)
+{
+	acpi_status		status = AE_OK;
+	struct acpi_resource	*resource = crsbuf;
+	u8				count = 0;
+	u8				done = 0;
+
+	while (!done) {
+		dbg("acpi_shpchprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++);
+		switch (resource->id) {
+		case ACPI_RSTYPE_IRQ:
+			dbg("Irq -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_DMA:
+			dbg("DMA -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_START_DPF:
+			dbg("Start DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_DPF:
+			dbg("End DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_IO:
+			acpi_parse_io (ab, &resource->data);
+			break; 
+		case ACPI_RSTYPE_FIXED_IO:
+			acpi_parse_fixed_io (ab, &resource->data);
+			break; 
+		case ACPI_RSTYPE_VENDOR:
+			dbg("Vendor -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_TAG:
+			dbg("End_tag -------- Resource\n");
+			done = 1;
+			break; 
+		case ACPI_RSTYPE_MEM24:
+			dbg("Mem24 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_MEM32:
+			dbg("Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_FIXED_MEM32:
+			dbg("Fixed Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_ADDRESS16:
+			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16);
+			break; 
+		case ACPI_RSTYPE_ADDRESS32:
+			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32);
+			break; 
+		case ACPI_RSTYPE_ADDRESS64:
+			info("Address64 -------- Resource unparsed\n");
+			break; 
+		case ACPI_RSTYPE_EXT_IRQ:
+			dbg("Ext Irq -------- Resource\n");
+			break; 
+		default:
+			dbg("Invalid -------- resource type 0x%x\n", resource->id);
+			break;
+		}
+
+		resource = (struct acpi_resource *) ((char *)resource + resource->length);
+	}
+
+	return status;
+}
+
+static acpi_status acpi_get_crs( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	struct acpi_resource	*crsbuf;
+
+	status = acpi_evaluate_crs(ab->handle, &crsbuf);
+	if (ACPI_SUCCESS(status)) {
+		status = acpi_parse_crs(ab, crsbuf);
+		kfree(crsbuf);
+
+		shpchp_resource_sort_and_combine(&ab->bus_head);
+		shpchp_resource_sort_and_combine(&ab->io_head);
+		shpchp_resource_sort_and_combine(&ab->mem_head);
+		shpchp_resource_sort_and_combine(&ab->p_mem_head);
+
+		shpchprm_add_resources (&ab->tbus_head, ab->bus_head);
+		shpchprm_add_resources (&ab->tio_head, ab->io_head);
+		shpchprm_add_resources (&ab->tmem_head, ab->mem_head);
+		shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
+	}
+
+	return status;
+}
+
+/* Find acpi_bridge downword from ab.  */
+static struct acpi_bridge *
+find_acpi_bridge_by_bus(
+	struct acpi_bridge *ab,
+	int seg,
+	int bus		/* pdev->subordinate->number */
+	)
+{
+	struct acpi_bridge	*lab = NULL;
+
+	if (!ab)
+		return NULL;
+
+	if ((ab->bus == bus) && (ab->seg == seg))
+		return ab;
+
+	if (ab->child)
+		lab = find_acpi_bridge_by_bus(ab->child, seg, bus);
+
+	if (!lab)
+	if (ab->next)
+		lab = find_acpi_bridge_by_bus(ab->next, seg, bus);
+
+	return lab;
+}
+
+/*
+ * Build a device tree of ACPI PCI Bridges
+ */
+static void shpchprm_acpi_register_a_bridge (
+	struct acpi_bridge	**head,
+	struct acpi_bridge	*pab,	/* parent bridge to which child bridge is added */
+	struct acpi_bridge	*cab	/* child bridge to add */
+	)
+{
+	struct acpi_bridge	*lpab;
+	struct acpi_bridge	*lcab;
+
+	lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus);
+	if (!lpab) {
+		if (!(pab->type & BRIDGE_TYPE_HOST))
+			warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus);
+		pab->next = *head;
+		*head = pab;
+		lpab = pab;
+	}
+
+	if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab))
+		return;
+
+	lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus);
+	if (lcab) {
+		if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus))
+			err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus);
+		return;
+	} else
+		lcab = cab;
+
+	lcab->parent = lpab;
+	lcab->next = lpab->child;
+	lpab->child = lcab;
+}
+
+static acpi_status shpchprm_acpi_build_php_slots_callback(
+	acpi_handle	handle,
+	u32		Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		bus_num;
+	ulong		seg_num;
+	ulong		sun, adr;
+	ulong		padr = 0;
+	acpi_handle		phandle = NULL;
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*lab;
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* Get _SUN */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun);
+	switch(status) {
+	case AE_NOT_FOUND:
+		return AE_OK;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status);
+			return status;
+		}
+	}
+
+	/* Get _ADR. _ADR must exist if _SUN exists */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr);
+
+	status = acpi_get_parent(handle, &phandle);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	bus_num = pab->bus;
+	seg_num = pab->seg;
+
+	if (pab->bus == bus_num) {
+		lab = pab;
+	} else {
+		dbg("WARN: pab is not parent\n");
+		lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num);
+		if (!lab) {
+			dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+			lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL);
+			if (!lab) {
+				err("acpi_shpchprm: alloc for ab fail\n");
+				return AE_NO_MEMORY;
+			}
+			memset(lab, 0, sizeof(struct acpi_bridge));
+
+			lab->handle = phandle;
+			lab->pbus = pab->bus;
+			lab->pdevice = (int)(padr >> 16) & 0xffff;
+			lab->pfunction = (int)(padr & 0xffff);
+			lab->bus = (int)bus_num;
+			lab->scanned = 0;
+			lab->type = BRIDGE_TYPE_P2P;
+
+			shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab);
+		} else
+			dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+	}
+
+	acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun);
+	return (status);
+}
+
+static int shpchprm_acpi_build_php_slots(
+	struct acpi_bridge	*ab,
+	u32			depth
+	)
+{
+	acpi_status	status;
+	u8		*path_name = acpi_path_name(ab->handle);
+
+	/* Walk down this pci bridge to get _SUNs if any behind P2P */
+	status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+				ab->handle,
+				depth,
+				shpchprm_acpi_build_php_slots_callback,
+				ab,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void build_a_bridge(
+	struct acpi_bridge	*pab,
+	struct acpi_bridge	*ab
+	)
+{
+	u8		*path_name = acpi_path_name(ab->handle);
+
+	shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab);
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x)    on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("acpi_shpchprm: Registered PCI  P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
+		break;
+	};
+
+	/* any immediate PHP slots under this pci bridge */
+	shpchprm_acpi_build_php_slots(ab, 1);
+}
+
+static struct acpi_bridge * add_p2p_bridge(
+	acpi_handle 		handle,
+	struct acpi_bridge	*pab,	/* parent */
+	ulong	adr
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_dev	*pdev;
+	ulong		devnum, funcnum;
+	u8			*path_name = acpi_path_name(handle);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_shpchprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	devnum = (adr >> 16) & 0xffff;
+	funcnum = adr & 0xffff;
+
+	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev || !pdev->subordinate) {
+		err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name);
+		kfree(ab);
+		return NULL;
+	}
+
+	ab->handle = handle;
+	ab->seg = pab->seg;
+	ab->pbus = pab->bus;		/* or pdev->bus->number */
+	ab->pdevice = devnum;		/* or PCI_SLOT(pdev->devfn) */
+	ab->pfunction = funcnum;	/* or PCI_FUNC(pdev->devfn) */
+	ab->bus = pdev->subordinate->number;
+	ab->scanned = 0;
+	ab->type = BRIDGE_TYPE_P2P;
+
+	dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n",
+		pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+		pab->bus, (u32)devnum, (u32)funcnum, path_name);
+
+	build_a_bridge(pab, ab);
+
+	return ab;
+}
+
+static acpi_status scan_p2p_bridge(
+	acpi_handle		handle,
+	u32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*ab;
+	acpi_status		status;
+	ulong		adr = 0;
+	u8			*path_name = acpi_path_name(handle);
+	ulong		devnum, funcnum;
+	struct pci_dev	*pdev;
+
+	/* Get device, function */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND)
+			err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
+		return AE_OK;
+	}
+
+	devnum = (adr >> 16) & 0xffff;
+	funcnum = adr & 0xffff;
+
+	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev)
+		return AE_OK;
+	if (!pdev->subordinate)
+		return AE_OK;
+
+	ab = add_p2p_bridge(handle, pab, adr);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					(u32)1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static struct acpi_bridge * add_host_bridge(
+	acpi_handle handle,
+	ulong	segnum,
+	ulong	busnum
+	)
+{
+	ulong		adr = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* Get device, function: host br adr is always 0000 though.  */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
+		return NULL;
+	}
+	dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_shpchprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	ab->handle = handle;
+	ab->seg = (int)segnum;
+	ab->bus = ab->pbus = (int)busnum;
+	ab->pdevice = (int)(adr >> 16) & 0xffff;
+	ab->pfunction = (int)(adr & 0xffff);
+	ab->scanned = 0;
+	ab->type = BRIDGE_TYPE_HOST;
+
+	/* Get root pci bridge's current resources */
+	status = acpi_get_crs(ab);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s evaluate _CRS fail=0x%x\n", path_name, status);
+		kfree(ab);
+		return NULL;
+	}
+	build_a_bridge(ab, ab);
+
+	return ab;
+}
+
+static acpi_status acpi_scan_from_root_pci_callback (
+	acpi_handle	handle,
+	u32			Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		segnum = 0;
+	ulong		busnum = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* Get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status);
+			return status;
+		}
+		segnum = 0;
+	}
+
+	/* Get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	ab = add_host_bridge(handle, segnum, busnum);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static int shpchprm_acpi_scan_pci (void)
+{
+	acpi_status	status;
+
+	/*
+	 * TBD: traverse LDM device tree with the help of
+	 *  unified ACPI augmented for php device population.
+	 */
+	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
+				acpi_scan_from_root_pci_callback,
+				NULL,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status);
+		return -1;
+	}
+
+	return 0;
+}
+
+int shpchprm_init(enum php_ctlr_type ctlr_type)
+{
+	int	rc;
+
+	if (ctlr_type != PCI)
+		return -ENODEV;
+
+	dbg("shpchprm ACPI init <enter>\n");
+	acpi_bridges_head = NULL;
+
+	/* construct PCI bus:device tree of acpi_handles */
+	rc = shpchprm_acpi_scan_pci();
+	if (rc)
+		return rc;
+
+	dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success");
+	return rc;
+}
+
+static void free_a_slot(struct acpi_php_slot *aps)
+{
+	dbg("        free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun);
+
+	free_pci_resource (aps->io_head);
+	free_pci_resource (aps->bus_head);
+	free_pci_resource (aps->mem_head);
+	free_pci_resource (aps->p_mem_head);
+
+	kfree(aps);
+}
+
+static void free_a_bridge( struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot	*aps, *next;
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
+		break;
+	};
+
+	/* free slots first */
+	for (aps = ab->slots; aps; aps = next) {
+		next = aps->next;
+		free_a_slot(aps);
+	}
+
+	free_pci_resource (ab->io_head);
+	free_pci_resource (ab->tio_head);
+	free_pci_resource (ab->bus_head);
+	free_pci_resource (ab->tbus_head);
+	free_pci_resource (ab->mem_head);
+	free_pci_resource (ab->tmem_head);
+	free_pci_resource (ab->p_mem_head);
+	free_pci_resource (ab->tp_mem_head);
+
+	kfree(ab);
+}
+
+static void shpchprm_free_bridges ( struct acpi_bridge	*ab)
+{
+	if (!ab)
+		return;
+
+	if (ab->child)
+		shpchprm_free_bridges (ab->child);
+
+	if (ab->next)
+		shpchprm_free_bridges (ab->next);
+
+	free_a_bridge(ab);
+}
+
+void shpchprm_cleanup(void)
+{
+	shpchprm_free_bridges (acpi_bridges_head);
+}
+
+static int get_number_of_slots (
+	struct acpi_bridge	*ab,
+	int			selfonly
+	)
+{
+	struct acpi_php_slot	*aps;
+	int	prev_slot = -1;
+	int	slot_num = 0;
+
+	for ( aps = ab->slots; aps; aps = aps->next)
+		if (aps->dev != prev_slot) {
+			prev_slot = aps->dev;
+			slot_num++;
+		}
+
+	if (ab->child)
+		slot_num += get_number_of_slots (ab->child, 0);
+
+	if (selfonly)
+		return slot_num;
+
+	if (ab->next)
+		slot_num += get_number_of_slots (ab->next, 0);
+
+	return slot_num;
+}
+
+static int print_acpi_resources (struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot		*aps;
+	int	i;
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle));
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle));
+		break;
+	};
+
+	print_pci_resources (ab);
+
+	for ( i = -1, aps = ab->slots; aps; aps = aps->next) {
+		if (aps->dev == i)
+			continue;
+		dbg("  Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun);
+		print_slot_resources(aps);
+		i = aps->dev;
+	}
+
+	if (ab->child)
+		print_acpi_resources (ab->child);
+
+	if (ab->next)
+		print_acpi_resources (ab->next);
+
+	return 0;
+}
+
+int shpchprm_print_pirt(void)
+{
+	dbg("SHPCHPRM ACPI Slots\n");
+	if (acpi_bridges_head)
+		print_acpi_resources (acpi_bridges_head);
+	return 0;
+}
+
+static struct acpi_php_slot * get_acpi_slot (
+	struct acpi_bridge *ab,
+	u32 sun
+	)
+{
+	struct acpi_php_slot	*aps = NULL;
+
+	for ( aps = ab->slots; aps; aps = aps->next)
+		if (aps->sun == sun)
+			return aps;
+
+	if (!aps && ab->child) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun);
+		if (aps)
+			return aps;
+	}
+
+	if (!aps && ab->next) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun);
+		if (aps)
+			return aps;
+	}
+
+	return aps;
+
+}
+
+void * shpchprm_get_slot(struct slot *slot)
+{
+	struct acpi_bridge	*ab = acpi_bridges_head;
+	struct acpi_php_slot	*aps = get_acpi_slot (ab, slot->number);
+
+	aps->slot = slot;
+
+	dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun);
+
+	return (void *)aps;
+}
+
+static void shpchprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func->bus_head);
+	}
+	if (func->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func->io_head);
+	}
+	if (func->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func->mem_head);
+	}
+	if (func->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func->p_mem_head);
+	}
+}
+
+static void shpchprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl->bus_head);
+	}
+	if (ctrl->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl->io_head);
+	}
+	if (ctrl->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl->mem_head);
+	}
+	if (ctrl->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl->p_mem_head);
+	}
+}
+
+static int shpchprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = shpchprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = shpchprm_delete_resources (&ctrl->bus_head, func->bus_head);
+		rc |= shpchprm_delete_resources (&ctrl->io_head, func->io_head);
+		rc |= shpchprm_delete_resources (&ctrl->mem_head, func->mem_head);
+		rc |= shpchprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func;
+	int busn = ctrl->bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn < 32; devn++) {
+		for (funn = 0; funn < 8; funn++) {
+			if (devn == ctrl->device && funn == ctrl->function)
+				continue;
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+			pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid);
+
+			if (vid != 0xFFFFFFFF) {
+				func = shpchp_slot_find(busn, devn, funn);
+				if (!func)
+					continue;
+				configure_existing_function(ctrl, func);
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
+				shpchprm_dump_func_res(func);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int bind_pci_resources(
+	struct controller *ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int		status = 0;
+
+	if (ab->bus_head) {
+		dbg("bapr:  BUS Resources add on PCI 0x%x\n", ab->bus);
+		status = shpchprm_add_resources (&ctrl->bus_head, ab->bus_head);
+		if (shpchprm_delete_resources (&ab->bus_head, ctrl->bus_head))
+			warn("bapr:  cannot sub BUS Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No BUS Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->io_head) {
+		dbg("bapr:  IO Resources add on PCI 0x%x\n", ab->bus);
+		status = shpchprm_add_resources (&ctrl->io_head, ab->io_head);
+		if (shpchprm_delete_resources (&ab->io_head, ctrl->io_head))
+			warn("bapr:  cannot sub IO Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No  IO Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->mem_head) {
+		dbg("bapr:  MEM Resources add on PCI 0x%x\n", ab->bus);
+		status = shpchprm_add_resources (&ctrl->mem_head, ab->mem_head);
+		if (shpchprm_delete_resources (&ab->mem_head, ctrl->mem_head))
+			warn("bapr:  cannot sub MEM Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No MEM Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->p_mem_head) {
+		dbg("bapr:  PMEM Resources add on PCI 0x%x\n", ab->bus);
+		status = shpchprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head);
+		if (shpchprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head))
+			warn("bapr:  cannot sub PMEM Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No PMEM Resource on PCI 0x%x.\n", ab->bus);
+
+	return status;
+}
+
+static int no_pci_resources( struct acpi_bridge *ab)
+{
+	return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head);
+}
+
+static int find_pci_bridge_resources (
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+	struct pci_func func;
+
+	memset(&func, 0, sizeof(struct pci_func));
+
+	func.bus = ab->pbus;
+	func.device = ab->pdevice;
+	func.function = ab->pfunction;
+	func.is_a_board = 1;
+
+	/* Get used resources for this PCI bridge */
+	rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD);
+
+	ab->io_head = func.io_head;
+	ab->mem_head = func.mem_head;
+	ab->p_mem_head = func.p_mem_head;
+	ab->bus_head = func.bus_head;
+	if (ab->bus_head)
+		shpchprm_delete_resource(&ab->bus_head, ctrl->bus, 1);
+
+	return rc;
+}
+
+static int get_pci_resources_from_bridge(
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+
+	dbg("grfb:  Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus);
+
+	rc = find_pci_bridge_resources (ctrl, ab);
+
+	shpchp_resource_sort_and_combine(&ab->bus_head);
+	shpchp_resource_sort_and_combine(&ab->io_head);
+	shpchp_resource_sort_and_combine(&ab->mem_head);
+	shpchp_resource_sort_and_combine(&ab->p_mem_head);
+
+	shpchprm_add_resources (&ab->tbus_head, ab->bus_head);
+	shpchprm_add_resources (&ab->tio_head, ab->io_head);
+	shpchprm_add_resources (&ab->tmem_head, ab->mem_head);
+	shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
+
+	return rc;
+}
+
+static int get_pci_resources(
+	struct controller	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int	rc = 0;
+
+	if (no_pci_resources(ab)) {
+		dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus);
+		rc = get_pci_resources_from_bridge(ctrl, ab);
+	}
+
+	return rc;
+}
+
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+	int offset = devnum - ctrl->slot_device_offset;
+
+	dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl->slot_num_inc, offset);
+	*sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc *offset);
+	return 0;
+}
+
+/*
+ * Get resources for this ctrl.
+ *  1. get total resources from ACPI _CRS or bridge (this ctrl)
+ *  2. find used resources of existing adapters
+ *	3. subtract used resources from total resources
+ */
+int shpchprm_find_available_resources( struct controller *ctrl)
+{
+	int rc = 0;
+	struct acpi_bridge	*ab;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number);
+	if (!ab) {
+		err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number);
+		return -1;
+	}
+	if (no_pci_resources(ab)) {
+		rc = get_pci_resources(ctrl, ab);
+		if (rc) {
+			err("pfar:cannot get pci resources of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number);
+			return -1;
+		}
+	}
+
+	rc = bind_pci_resources(ctrl, ab);
+	dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
+	shpchprm_dump_ctrl_res(ctrl);
+
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
+	shpchprm_dump_ctrl_res(ctrl);
+
+	return rc;
+}
+
+int shpchprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_bus lpci_bus, *pci_bus;
+	int			rc = 0;
+	unsigned int		devfn;
+	u8			cls= 0x08;	/* default cache line size	*/
+	u8			lt = 0x40;	/* default latency timer	*/
+	u8			ep = 0;
+	u8			es = 0;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+
+	if (ab) {
+		if (ab->_hpp) {
+			lt  = (u8)ab->_hpp->latency_timer;
+			cls = (u8)ab->_hpp->cache_line_size;
+			ep  = (u8)ab->_hpp->enable_perr;
+			es  = (u8)ab->_hpp->enable_serr;
+		} else
+			dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
+	} else
+		dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
+
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* Set subordinate Latency Timer */
+		rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt);
+	}
+
+	/* set base Latency Timer */
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt);
+	dbg("  set latency timer  =0x%02x: %x\n", lt, rc);
+
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls);
+	dbg("  set cache_line_size=0x%02x: %x\n", cls, rc);
+
+	return rc;
+}
+
+void shpchprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, cmd, bcommand, bcmd;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct acpi_bridge	*ab;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+	}
+
+	cmd = command  = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	bcmd = bcommand  = bcommand | PCI_BRIDGE_CTL_NO_ISA;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+	if (ab) {
+		if (ab->_hpp) {
+			if (ab->_hpp->enable_perr) {
+				command |= PCI_COMMAND_PARITY;
+				bcommand |= PCI_BRIDGE_CTL_PARITY;
+			} else {
+				command &= ~PCI_COMMAND_PARITY;
+				bcommand &= ~PCI_BRIDGE_CTL_PARITY;
+			}
+			if (ab->_hpp->enable_serr) {
+				command |= PCI_COMMAND_SERR;
+				bcommand |= PCI_BRIDGE_CTL_SERR;
+			} else {
+				command &= ~PCI_COMMAND_SERR;
+				bcommand &= ~PCI_BRIDGE_CTL_SERR;
+			}
+		} else
+			dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
+	} else
+		dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
+
+	if (command != cmd) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+	}
+	if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_legacy.c linux-2.4.27-pre3/drivers/hotplug/shpchprm_legacy.c
--- linux-2.4.26/drivers/hotplug/shpchprm_legacy.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchprm_legacy.c	2004-05-18 16:54:41.000000000 +0000
@@ -0,0 +1,444 @@
+/*
+ * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include "shpchp.h"
+#include "shpchprm.h"
+#include "shpchprm_legacy.h"
+
+static void *shpchp_rom_start;
+static u16 unused_IRQ;
+
+void shpchprm_cleanup()
+{
+	if (shpchp_rom_start)
+		iounmap(shpchp_rom_start);
+}
+
+
+int shpchprm_print_pirt()
+{
+	return 0;
+}
+
+void * shpchprm_get_slot(struct slot *slot)
+{
+	return NULL;
+}
+
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+	int	offset = devnum - ctrl->slot_device_offset;
+
+	*sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc * offset);
+	return 0;
+}
+
+/* find the Hot Plug Resource Table in the specified region of memory */
+static void *detect_HRT_floating_pointer(void *begin, void *end)
+{
+	void *fp;
+	void *endp;
+	u8 temp1, temp2, temp3, temp4;
+	int status = 0;
+
+	endp = (end - sizeof(struct hrt) + 1);
+
+	for (fp = begin; fp <= endp; fp += 16) {
+		temp1 = readb(fp + SIG0);
+		temp2 = readb(fp + SIG1);
+		temp3 = readb(fp + SIG2);
+		temp4 = readb(fp + SIG3);
+		if (temp1 == '$' && temp2 == 'H' && temp3 == 'R' && temp4 == 'T') {
+			status = 1;
+			break;
+		}
+	}
+
+	if (!status)
+		fp = NULL;
+
+	dbg("Discovered Hotplug Resource Table at %p\n", fp);
+	return fp;
+}
+
+/*
+ * shpchprm_find_available_resources
+ *
+ *  Finds available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *  this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */
+int shpchprm_find_available_resources(struct controller *ctrl)
+{
+	u8 populated_slot;
+	u8 bridged_slot;
+	void *one_slot;
+	struct pci_func *func = NULL;
+	int i = 10, index = 0;
+	u32 temp_dword, rc;
+	ulong temp_ulong;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	void *rom_resource_table;
+	struct pci_bus lpci_bus, *pci_bus;
+	u8 cfgspc_irq, temp;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	rom_resource_table = detect_HRT_floating_pointer(shpchp_rom_start, shpchp_rom_start + 0xffff);
+	dbg("rom_resource_table = %p\n", rom_resource_table);
+	if (rom_resource_table == NULL)
+		return -ENODEV;
+
+	/* Sum all resources and setup resource maps */
+	unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
+	dbg("unused_IRQ = %x\n", unused_IRQ);
+
+	temp = 0;
+	while (unused_IRQ) {
+		if (unused_IRQ & 1) {
+			shpchp_disk_irq = temp;
+			break;
+		}
+		unused_IRQ = unused_IRQ >> 1;
+		temp++;
+	}
+
+	dbg("shpchp_disk_irq= %d\n", shpchp_disk_irq);
+	unused_IRQ = unused_IRQ >> 1;
+	temp++;
+
+	while (unused_IRQ) {
+		if (unused_IRQ & 1) {
+			shpchp_nic_irq = temp;
+			break;
+		}
+		unused_IRQ = unused_IRQ >> 1;
+		temp++;
+	}
+
+	dbg("shpchp_nic_irq= %d\n", shpchp_nic_irq);
+	unused_IRQ = readl(rom_resource_table + PCIIRQ);
+
+	temp = 0;
+
+	pci_read_config_byte(ctrl->pci_dev, PCI_INTERRUPT_LINE, &cfgspc_irq);
+
+	if (!shpchp_nic_irq) {
+		shpchp_nic_irq = cfgspc_irq;
+	}
+
+	if (!shpchp_disk_irq) {
+		shpchp_disk_irq = cfgspc_irq;
+	}
+
+	dbg("shpchp_disk_irq, shpchp_nic_irq= %d, %d\n", shpchp_disk_irq, shpchp_nic_irq);
+
+	one_slot = rom_resource_table + sizeof(struct hrt);
+
+	i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
+	dbg("number_of_entries = %d\n", i);
+
+	if (!readb(one_slot + SECONDARY_BUS))
+		return (1);
+
+	dbg("dev|IO base|length|MEMbase|length|PM base|length|PB SB MB\n");
+
+	while (i && readb(one_slot + SECONDARY_BUS)) {
+		u8 dev_func = readb(one_slot + DEV_FUNC);
+		u8 primary_bus = readb(one_slot + PRIMARY_BUS);
+		u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
+		u8 max_bus = readb(one_slot + MAX_BUS);
+		u16 io_base = readw(one_slot + IO_BASE);
+		u16 io_length = readw(one_slot + IO_LENGTH);
+		u16 mem_base = readw(one_slot + MEM_BASE);
+		u16 mem_length = readw(one_slot + MEM_LENGTH);
+		u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
+		u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
+
+		dbg("%2.2x |  %4.4x | %4.4x |  %4.4x | %4.4x |  %4.4x | %4.4x |%2.2x %2.2x %2.2x\n",
+				dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
+				primary_bus, secondary_bus, max_bus);
+
+		/* If this entry isn't for our controller's bus, ignore it */
+		if (primary_bus != ctrl->slot_bus) {
+			i--;
+			one_slot += sizeof(struct slot_rt);
+			continue;
+		}
+		/* Find out if this entry is for an occupied slot */
+		temp_dword = 0xFFFFFFFF;
+		pci_bus->number = primary_bus;
+		pci_bus_read_config_dword(pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
+
+		dbg("temp_D_word = %x\n", temp_dword);
+
+		if (temp_dword != 0xFFFFFFFF) {
+			index = 0;
+			func = shpchp_slot_find(primary_bus, dev_func >> 3, 0);
+
+			while (func && (func->function != (dev_func & 0x07))) {
+				dbg("func = %p b:d:f(%x:%x:%x)\n", func, primary_bus, dev_func >> 3, index);
+				func = shpchp_slot_find(primary_bus, dev_func >> 3, index++);
+			}
+
+			/* If we can't find a match, skip this table entry */
+			if (!func) {
+				i--;
+				one_slot += sizeof(struct slot_rt);
+				continue;
+			}
+			/* This may not work and shouldn't be used */
+			if (secondary_bus != primary_bus)
+				bridged_slot = 1;
+			else
+				bridged_slot = 0;
+
+			populated_slot = 1;
+		} else {
+			populated_slot = 0;
+			bridged_slot = 0;
+		}
+		dbg("slot populated =%s \n", populated_slot?"yes":"no");
+
+		/* If we've got a valid IO base, use it */
+
+		temp_ulong = io_base + io_length;
+
+		if ((io_base) && (temp_ulong <= 0x10000)) {
+			io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!io_node)
+				return -ENOMEM;
+
+			io_node->base = (ulong)io_base;
+			io_node->length = (ulong)io_length;
+			dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length);
+
+			if (!populated_slot) {
+				io_node->next = ctrl->io_head;
+				ctrl->io_head = io_node;
+			} else {
+				io_node->next = func->io_head;
+				func->io_head = io_node;
+			}
+		}
+
+		/* If we've got a valid memory base, use it */
+		temp_ulong = mem_base + mem_length;
+		if ((mem_base) && (temp_ulong <= 0x10000)) {
+			mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!mem_node)
+				return -ENOMEM;
+
+			mem_node->base = (ulong)mem_base << 16;
+			mem_node->length = (ulong)(mem_length << 16);
+			dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length);
+
+			if (!populated_slot) {
+				mem_node->next = ctrl->mem_head;
+				ctrl->mem_head = mem_node;
+			} else {
+				mem_node->next = func->mem_head;
+				func->mem_head = mem_node;
+			}
+		}
+
+		/*
+		 * If we've got a valid prefetchable memory base, and
+		 * the base + length isn't greater than 0xFFFF
+		 */
+		temp_ulong = pre_mem_base + pre_mem_length;
+		if ((pre_mem_base) && (temp_ulong <= 0x10000)) {
+			p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!p_mem_node)
+				return -ENOMEM;
+
+			p_mem_node->base = (ulong)pre_mem_base << 16;
+			p_mem_node->length = (ulong)pre_mem_length << 16;
+			dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length);
+
+			if (!populated_slot) {
+				p_mem_node->next = ctrl->p_mem_head;
+				ctrl->p_mem_head = p_mem_node;
+			} else {
+				p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = p_mem_node;
+			}
+		}
+
+		/*
+		 * If we've got a valid bus number, use it
+		 * The second condition is to ignore bus numbers on
+		 * populated slots that don't have PCI-PCI bridges
+		 */
+		if (secondary_bus && (secondary_bus != primary_bus)) {
+			bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node->base = (ulong)secondary_bus;
+			bus_node->length = (ulong)(max_bus - secondary_bus + 1);
+			dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length);
+
+			if (!populated_slot) {
+				bus_node->next = ctrl->bus_head;
+				ctrl->bus_head = bus_node;
+			} else {
+				bus_node->next = func->bus_head;
+				func->bus_head = bus_node;
+			}
+		}
+
+		i--;
+		one_slot += sizeof(struct slot_rt);
+	}
+
+	/* If all of the following fail, we don't have any resources for hot plug add */
+	rc = 1;
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head));
+
+	return (rc);
+}
+
+int shpchprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type)
+{
+	u32 rc;
+	u8 temp_byte;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int	devfn;
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	temp_byte = 0x40;	/* Hard coded value for LT */
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* Set subordinate Latency Timer */
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+		if (rc) {
+			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+			return rc;
+		}
+	}
+
+	/* Set base Latency Timer */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+	if (rc) {
+		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+		return rc;
+	}
+
+	/* Set Cache Line size */
+	temp_byte = 0x08;	/* hard coded value for CLS */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+	if (rc) {
+		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+	}
+
+	/* Set enable_perr */
+	/* Set enable_serr */
+
+	return rc;
+}
+
+void shpchprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, bcommand;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
+		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
+			| PCI_BRIDGE_CTL_NO_ISA;
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
+static int legacy_shpchprm_init_pci(void)
+{
+	shpchp_rom_start = (u8 *) ioremap(ROM_PHY_ADDR, ROM_PHY_LEN);
+	if (!shpchp_rom_start) {
+		err("Could not ioremap memory region for ROM\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int shpchprm_init(enum php_ctlr_type ctrl_type)
+{
+	int retval;
+
+	switch (ctrl_type) {
+	case PCI:
+		retval = legacy_shpchprm_init_pci();
+		break;
+	default:
+		retval = -ENODEV;
+		break;
+	}
+
+	return retval;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_legacy.h linux-2.4.27-pre3/drivers/hotplug/shpchprm_legacy.h
--- linux-2.4.26/drivers/hotplug/shpchprm_legacy.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchprm_legacy.h	2004-05-18 16:51:51.000000000 +0000
@@ -0,0 +1,113 @@
+/*
+ * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform using HRT
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _SHPCHPRM_LEGACY_H_
+#define _SHPCHPRM_LEGACY_H_
+
+#define ROM_PHY_ADDR	0x0F0000
+#define ROM_PHY_LEN	0x00FFFF
+
+struct slot_rt {
+	u8 dev_func;
+	u8 primary_bus;
+	u8 secondary_bus;
+	u8 max_bus;
+	u16 io_base;
+	u16 io_length;
+	u16 mem_base;
+	u16 mem_length;
+	u16 pre_mem_base;
+	u16 pre_mem_length;
+} __attribute__ ((packed));
+
+/* offsets to the hotplug slot resource table registers based on the above structure layout */
+enum slot_rt_offsets {
+	DEV_FUNC = offsetof(struct slot_rt, dev_func),
+	PRIMARY_BUS = offsetof(struct slot_rt, primary_bus),
+	SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus),
+	MAX_BUS = offsetof(struct slot_rt, max_bus),
+	IO_BASE = offsetof(struct slot_rt, io_base),
+	IO_LENGTH = offsetof(struct slot_rt, io_length),
+	MEM_BASE = offsetof(struct slot_rt, mem_base),
+	MEM_LENGTH = offsetof(struct slot_rt, mem_length),
+	PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base),
+	PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length),
+};
+
+struct hrt {
+	char sig0;
+	char sig1;
+	char sig2;
+	char sig3;
+	u16 unused_IRQ;
+	u16 PCIIRQ;
+	u8 number_of_entries;
+	u8 revision;
+	u16 reserved1;
+	u32 reserved2;
+} __attribute__ ((packed));
+
+/* offsets to the hotplug resource table registers based on the above structure layout */
+enum hrt_offsets {
+	SIG0 = offsetof(struct hrt, sig0),
+	SIG1 = offsetof(struct hrt, sig1),
+	SIG2 = offsetof(struct hrt, sig2),
+	SIG3 = offsetof(struct hrt, sig3),
+	UNUSED_IRQ = offsetof(struct hrt, unused_IRQ),
+	PCIIRQ = offsetof(struct hrt, PCIIRQ),
+	NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries),
+	REVISION = offsetof(struct hrt, revision),
+	HRT_RESERVED1 = offsetof(struct hrt, reserved1),
+	HRT_RESERVED2 = offsetof(struct hrt, reserved2),
+};
+
+struct irq_info {
+	u8 bus, devfn;		/* bus, device and function */
+	struct {
+		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;	/* Available IRQs */
+	} __attribute__ ((packed)) irq[4];
+	u8 slot;		/* slot number, 0=onboard */
+	u8 rfu;
+} __attribute__ ((packed));
+
+struct irq_routing_table {
+	u32 signature;		/* PIRQ_SIGNATURE should be here */
+	u16 version;		/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
+	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;	/* Crap */
+	u8 rfu[11];
+	u8 checksum;		/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__ ((packed));
+
+#endif				/* _SHPCHPRM_LEGACY_H_ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_nonacpi.c linux-2.4.27-pre3/drivers/hotplug/shpchprm_nonacpi.c
--- linux-2.4.26/drivers/hotplug/shpchprm_nonacpi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchprm_nonacpi.c	2004-05-18 16:53:25.000000000 +0000
@@ -0,0 +1,430 @@
+/*
+ * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include "shpchp.h"
+#include "shpchprm.h"
+#include "shpchprm_nonacpi.h"
+
+void shpchprm_cleanup(void)
+{
+	return;
+}
+
+int shpchprm_print_pirt(void)
+{
+	return 0;
+}
+
+void * shpchprm_get_slot(struct slot *slot)
+{
+	return NULL;
+}
+
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+	int	offset = devnum - ctrl->slot_device_offset;
+	
+	dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl->slot_num_inc, offset);
+	*sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc * offset);
+	return 0;
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res->next)
+		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
+}
+
+
+static void phprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func->bus_head);
+	}
+	if (func->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func->io_head);
+	}
+	if (func->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func->mem_head);
+	}
+	if (func->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func->p_mem_head);
+	}
+}
+
+static int phprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int phprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	shpchp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int phprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res->next)
+		phprm_delete_resource(aprh, res->base, res->length);
+
+	return 0;
+}
+
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = phprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = phprm_delete_resources (&ctrl->bus_head, func->bus_head);
+		rc |= phprm_delete_resources (&ctrl->io_head, func->io_head);
+		rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head);
+		rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func;
+	int busn = ctrl->slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn < 32; devn++) {
+		for (funn = 0; funn < 8; funn++) {
+			/* if (devn == ctrl->device && funn == ctrl->function)
+				continue;
+			 */
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+
+			pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid);
+
+			if (vid != 0xFFFFFFFF) {
+				func = shpchp_slot_find(busn, devn, funn);
+				if (!func)
+					continue;
+				configure_existing_function(ctrl, func);
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
+				phprm_dump_func_res(func);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void phprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl->bus_head);
+	}
+	if (ctrl->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl->io_head);
+	}
+	if (ctrl->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl->mem_head);
+	}
+	if (ctrl->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl->p_mem_head);
+	}
+}
+
+/*
+ * phprm_find_available_resources
+ *
+ *  Finds available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *  this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */
+int shpchprm_find_available_resources(struct controller *ctrl)
+{
+	struct pci_func func;
+	u32 rc;
+
+	memset(&func, 0, sizeof(struct pci_func));
+
+	func.bus = ctrl->bus;
+	func.device = ctrl->device;
+	func.function = ctrl->function;
+	func.is_a_board = 1;
+
+	/* Get resources for this PCI bridge */
+	rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD);
+	dbg("%s: shpchp_save_used_resources rc = %d\n", __FUNCTION__, rc);
+
+	if (func.mem_head)
+		func.mem_head->next = ctrl->mem_head;
+	ctrl->mem_head = func.mem_head;
+
+	if (func.p_mem_head)
+		func.p_mem_head->next = ctrl->p_mem_head;
+	ctrl->p_mem_head = func.p_mem_head;
+
+	if (func.io_head)
+		func.io_head->next = ctrl->io_head;
+	ctrl->io_head = func.io_head;
+
+	if(func.bus_head)
+		func.bus_head->next = ctrl->bus_head;
+	ctrl->bus_head = func.bus_head;
+	if (ctrl->bus_head)
+		phprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1);
+
+	dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
+	phprm_dump_ctrl_res(ctrl);
+	
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
+	phprm_dump_ctrl_res(ctrl);
+
+
+	/* If all of the following fail, we don't have any resources for hot plug add */
+	rc = 1;
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head));
+
+	return (rc);
+}
+
+int shpchprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type)
+{
+	u32 rc;
+	u8 temp_byte;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int	devfn;
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	temp_byte = 0x40;	/* hard coded value for LT */
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+
+		if (rc) {
+			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+			return rc;
+		}
+	}
+
+	/* set base Latency Timer */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+
+	if (rc) {
+		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+		return rc;
+	}
+
+	/* set Cache Line size */
+	temp_byte = 0x08;	/* hard coded value for CLS */
+
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+
+	if (rc) {
+		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+	}
+
+	/* set enable_perr */
+	/* set enable_serr */
+
+	return rc;
+}
+
+void shpchprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, bcommand;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+
+	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
+		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+
+	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+
+		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
+			| PCI_BRIDGE_CTL_NO_ISA;
+
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
+static int legacy_shpchprm_init_pci(void)
+{
+	return 0;
+}
+
+int shpchprm_init(enum php_ctlr_type ctrl_type)
+{
+	int retval;
+
+	switch (ctrl_type) {
+	case PCI:
+		retval = legacy_shpchprm_init_pci();
+		break;
+	default:
+		retval = -ENODEV;
+		break;
+	}
+
+	return retval;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_nonacpi.h linux-2.4.27-pre3/drivers/hotplug/shpchprm_nonacpi.h
--- linux-2.4.26/drivers/hotplug/shpchprm_nonacpi.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/hotplug/shpchprm_nonacpi.h	2004-05-18 16:55:24.000000000 +0000
@@ -0,0 +1,56 @@
+/*
+ * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _SHPCHPRM_NONACPI_H_
+#define _SHPCHPRM_NONACPI_H_
+
+struct irq_info {
+	u8 bus, devfn;		/* bus, device and function */
+	struct {
+		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;	/* Available IRQs */
+	} __attribute__ ((packed)) irq[4];
+	u8 slot;		/* slot number, 0=onboard */
+	u8 rfu;
+} __attribute__ ((packed));
+
+struct irq_routing_table {
+	u32 signature;		/* PIRQ_SIGNATURE should be here */
+	u16 version;		/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
+	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;	/* Crap */
+	u8 rfu[11];
+	u8 checksum;		/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__ ((packed));
+
+#endif				/* _SHPCHPRM_NONACPI_H_ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/ide-disk.c linux-2.4.27-pre3/drivers/ide/ide-disk.c
--- linux-2.4.26/drivers/ide/ide-disk.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/ide-disk.c	2004-05-18 16:50:49.000000000 +0000
@@ -1161,15 +1161,15 @@ static void init_idedisk_capacity (ide_d
 {
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity = drive->cyl * drive->head * drive->sect;
-	unsigned long set_max = idedisk_read_native_max_address(drive);
+	int have_setmax = idedisk_supports_host_protected_area(drive);
+	unsigned long set_max =
+		(have_setmax ? idedisk_read_native_max_address(drive) : 0);
 	unsigned long long capacity_2 = capacity;
 	unsigned long long set_max_ext;
 
 	drive->capacity48 = 0;
 	drive->select.b.lba = 0;
 
-	(void) idedisk_supports_host_protected_area(drive);
-
 	if (id->cfs_enable_2 & 0x0400) {
 		capacity_2 = id->lba_capacity_2;
 		drive->head		= drive->bios_head = 255;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/aec62xx.c linux-2.4.27-pre3/drivers/ide/pci/aec62xx.c
--- linux-2.4.26/drivers/ide/pci/aec62xx.c	2003-06-13 14:51:33.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/aec62xx.c	2004-05-18 16:55:01.000000000 +0000
@@ -356,13 +356,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		aec62xx_tune_drive(drive, 5);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 static int aec62xx_irq_timeout (ide_drive_t *drive)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/cmd64x.c linux-2.4.27-pre3/drivers/ide/pci/cmd64x.c
--- linux-2.4.26/drivers/ide/pci/cmd64x.c	2003-06-13 14:51:33.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/cmd64x.c	2004-05-18 16:55:03.000000000 +0000
@@ -485,13 +485,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		config_chipset_for_pio(drive, 1);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 static int cmd64x_alt_dma_status (struct pci_dev *dev)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/generic.c linux-2.4.27-pre3/drivers/ide/pci/generic.c
--- linux-2.4.26/drivers/ide/pci/generic.c	2003-08-25 11:44:41.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/generic.c	2004-05-18 16:54:48.000000000 +0000
@@ -141,6 +141,8 @@ static struct pci_device_id generic_pci_
 	{ PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
 	{ PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
 	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO,	   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_1,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
+	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_2,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
 	{ 0, },
 };
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/generic.h linux-2.4.27-pre3/drivers/ide/pci/generic.h
--- linux-2.4.26/drivers/ide/pci/generic.h	2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/generic.h	2004-05-18 16:51:37.000000000 +0000
@@ -130,16 +130,33 @@ static ide_pci_device_t generic_chipsets
 	},{	/* 9 */
 		.vendor		= PCI_VENDOR_ID_TOSHIBA,
 		.device		= PCI_DEVICE_ID_TOSHIBA_PICCOLO,
-		.name		= "Piccolo",
+		.name		= "Piccolo0102",
+		.init_chipset	= init_chipset_generic,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.bootable	= ON_BOARD,
+	},{	/* 10 */
+		.vendor		= PCI_VENDOR_ID_TOSHIBA,
+		.device		= PCI_DEVICE_ID_TOSHIBA_PICCOLO_1,
+		.name		= "Piccolo0103",
+		.init_chipset	= init_chipset_generic,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.bootable	= ON_BOARD,
+	},{	/* 11 */
+		.vendor		= PCI_VENDOR_ID_TOSHIBA,
+		.device		= PCI_DEVICE_ID_TOSHIBA_PICCOLO_2,
+		.name		= "Piccolo0105",
 		.init_chipset	= init_chipset_generic,
-		.init_iops	= NULL,
 		.init_hwif	= init_hwif_generic,
 		.init_dma	= init_dma_generic,
 		.channels	= 2,
 		.autodma	= NOAUTODMA,
-		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
 		.bootable	= ON_BOARD,
-		.extra		= 0,
 	},{
 		.vendor		= 0,
 		.device		= 0,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/hpt34x.c linux-2.4.27-pre3/drivers/ide/pci/hpt34x.c
--- linux-2.4.26/drivers/ide/pci/hpt34x.c	2003-06-13 14:51:33.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/hpt34x.c	2004-05-18 16:51:20.000000000 +0000
@@ -216,17 +216,19 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+#ifndef CONFIG_HPT34X_AUTODMA
+		return hwif->ide_dma_off_quietly(drive);
+#else
+		return hwif->ide_dma_on(drive);
+#endif
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		hpt34x_tune_drive(drive, 255);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-
-#ifndef CONFIG_HPT34X_AUTODMA
-	return hwif->ide_dma_off_quietly(drive);
-#endif /* CONFIG_HPT34X_AUTODMA */
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 /*
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/hpt366.c linux-2.4.27-pre3/drivers/ide/pci/hpt366.c
--- linux-2.4.26/drivers/ide/pci/hpt366.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/hpt366.c	2004-05-18 16:51:30.000000000 +0000
@@ -567,13 +567,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		hpt3xx_tune_drive(drive, 5);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 /*
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/it8172.c linux-2.4.27-pre3/drivers/ide/pci/it8172.c
--- linux-2.4.26/drivers/ide/pci/it8172.c	2003-06-13 14:51:33.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/it8172.c	2004-05-18 16:53:52.000000000 +0000
@@ -228,13 +228,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		it8172_tune_drive(drive, 5);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/pdc202xx_new.c linux-2.4.27-pre3/drivers/ide/pci/pdc202xx_new.c
--- linux-2.4.26/drivers/ide/pci/pdc202xx_new.c	2003-06-13 14:51:33.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/pdc202xx_new.c	2004-05-18 16:51:19.000000000 +0000
@@ -415,13 +415,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		hwif->tuneproc(drive, 5);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 static int pdcnew_quirkproc (ide_drive_t *drive)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/pdc202xx_old.c linux-2.4.27-pre3/drivers/ide/pci/pdc202xx_old.c
--- linux-2.4.26/drivers/ide/pci/pdc202xx_old.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/pdc202xx_old.c	2004-05-18 16:53:25.000000000 +0000
@@ -516,13 +516,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		hwif->tuneproc(drive, 5);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 static int pdc202xx_quirkproc (ide_drive_t *drive)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/piix.c linux-2.4.27-pre3/drivers/ide/pci/piix.c
--- linux-2.4.26/drivers/ide/pci/piix.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/piix.c	2004-05-18 16:55:08.000000000 +0000
@@ -593,13 +593,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		hwif->tuneproc(drive, 255);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 /**
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/serverworks.c linux-2.4.27-pre3/drivers/ide/pci/serverworks.c
--- linux-2.4.26/drivers/ide/pci/serverworks.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/serverworks.c	2004-05-18 16:53:35.000000000 +0000
@@ -473,7 +473,9 @@ static int svwks_config_drive_xfer_rate 
 				int dma = config_chipset_for_dma(drive);
 				if ((id->field_valid & 2) && !dma)
 					goto try_dma_modes;
-			}
+			} else
+				/* UDMA disabled by mask, try other DMA modes */
+				goto try_dma_modes;
 		} else if (id->field_valid & 2) {
 try_dma_modes:
 			if ((id->dma_mword & hwif->mwdma_mask) ||
@@ -490,6 +492,7 @@ try_dma_modes:
 		} else {
 			goto no_dma_set;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
@@ -497,7 +500,8 @@ no_dma_set:
 		//	hwif->tuneproc(drive, 5);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 /* This can go soon */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/siimage.c linux-2.4.27-pre3/drivers/ide/pci/siimage.c
--- linux-2.4.26/drivers/ide/pci/siimage.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/siimage.c	2004-05-18 16:54:41.000000000 +0000
@@ -516,13 +516,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		config_chipset_for_pio(drive, 1);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 /* returns 1 if dma irq issued, 0 otherwise */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/sis5513.c linux-2.4.27-pre3/drivers/ide/pci/sis5513.c
--- linux-2.4.26/drivers/ide/pci/sis5513.c	2003-08-25 11:44:41.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/sis5513.c	2004-05-18 16:52:38.000000000 +0000
@@ -697,13 +697,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		sis5513_tune_drive(drive, 5);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 
 /* initiates/aborts (U)DMA read/write operations on a drive. */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/slc90e66.c linux-2.4.27-pre3/drivers/ide/pci/slc90e66.c
--- linux-2.4.26/drivers/ide/pci/slc90e66.c	2003-06-13 14:51:33.000000000 +0000
+++ linux-2.4.27-pre3/drivers/ide/pci/slc90e66.c	2004-05-18 16:51:00.000000000 +0000
@@ -302,13 +302,15 @@ try_dma_modes:
 		} else {
 			goto fast_ata_pio;
 		}
+		return hwif->ide_dma_on(drive);
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
 no_dma_set:
 		hwif->tuneproc(drive, 5);
 		return hwif->ide_dma_off_quietly(drive);
 	}
-	return hwif->ide_dma_on(drive);
+	/* IORDY not supported */
+	return 0;
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/media/video/videodev.c linux-2.4.27-pre3/drivers/media/video/videodev.c
--- linux-2.4.26/drivers/media/video/videodev.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/media/video/videodev.c	2004-05-18 16:51:26.000000000 +0000
@@ -553,7 +553,14 @@ int video_register_device(struct video_d
 
 	/* pick a minor number */
 	down(&videodev_lock);
-	if (-1 == nr) {
+	if (nr >= 0  &&  nr < end-base) {
+		/* use the one the driver asked for */
+		i = base+nr;
+		if (NULL != video_device[i]) {
+			up(&videodev_lock);
+			return -ENFILE;
+		}
+	} else {
 		/* use first free */
 		for(i=base;i<end;i++)
 			if (NULL == video_device[i])
@@ -562,13 +569,6 @@ int video_register_device(struct video_d
 			up(&videodev_lock);
 			return -ENFILE;
 		}
-	} else {
-		/* use the one the driver asked for */
-		i = base+nr;
-		if (NULL != video_device[i]) {
-			up(&videodev_lock);
-			return -ENFILE;
-		}
 	}
 	video_device[i]=vfd;
 	vfd->minor=i;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/8139cp.c linux-2.4.27-pre3/drivers/net/8139cp.c
--- linux-2.4.26/drivers/net/8139cp.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/8139cp.c	2004-05-18 16:53:09.000000000 +0000
@@ -1,6 +1,6 @@
 /* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */
 /*
-	Copyright 2001,2002 Jeff Garzik <jgarzik@pobox.com>
+	Copyright 2001-2004 Jeff Garzik <jgarzik@pobox.com>
 
 	Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) [tg3.c]
 	Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
@@ -48,8 +48,8 @@
  */
 
 #define DRV_NAME		"8139cp"
-#define DRV_VERSION		"1.1"
-#define DRV_RELDATE		"Aug 30, 2003"
+#define DRV_VERSION		"1.2"
+#define DRV_RELDATE		"Mar 22, 2004"
 
 
 #include <linux/config.h>
@@ -69,6 +69,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#include <linux/cache.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -334,36 +335,36 @@ struct cp_extra_stats {
 };
 
 struct cp_private {
-	unsigned		tx_head;
-	unsigned		tx_tail;
-	unsigned		rx_tail;
-
 	void			*regs;
 	struct net_device	*dev;
 	spinlock_t		lock;
+	u32			msg_enable;
+
+	struct pci_dev		*pdev;
+	u32			rx_config;
+	u16			cpcmd;
+
+	struct net_device_stats net_stats;
+	struct cp_extra_stats	cp_stats;
+	struct cp_dma_stats	*nic_stats;
+	dma_addr_t		nic_stats_dma;
 
+	unsigned		rx_tail		____cacheline_aligned;
 	struct cp_desc		*rx_ring;
-	struct cp_desc		*tx_ring;
-	struct ring_info	tx_skb[CP_TX_RING_SIZE];
 	struct ring_info	rx_skb[CP_RX_RING_SIZE];
 	unsigned		rx_buf_sz;
+
+	unsigned		tx_head		____cacheline_aligned;
+	unsigned		tx_tail;
+
+	struct cp_desc		*tx_ring;
+	struct ring_info	tx_skb[CP_TX_RING_SIZE];
 	dma_addr_t		ring_dma;
 
 #if CP_VLAN_TAG_USED
 	struct vlan_group	*vlgrp;
 #endif
 
-	u32			msg_enable;
-
-	struct net_device_stats net_stats;
-	struct cp_extra_stats	cp_stats;
-	struct cp_dma_stats	*nic_stats;
-	dma_addr_t		nic_stats_dma;
-
-	struct pci_dev		*pdev;
-	u32			rx_config;
-	u16			cpcmd;
-
 	unsigned int		wol_enabled : 1; /* Is Wake-on-LAN enabled? */
 	u32			power_state[16];
 
@@ -424,25 +425,27 @@ static struct {
 #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;
+	struct cp_private *cp = netdev_priv(dev);
+	unsigned long flags;
 
-	spin_lock_irq(&cp->lock);
+	spin_lock_irqsave(&cp->lock, flags);
 	cp->vlgrp = grp;
 	cp->cpcmd |= RxVlanOn;
 	cpw16(CpCmd, cp->cpcmd);
-	spin_unlock_irq(&cp->lock);
+	spin_unlock_irqrestore(&cp->lock, flags);
 }
 
 static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
+	unsigned long flags;
 
-	spin_lock_irq(&cp->lock);
+	spin_lock_irqsave(&cp->lock, flags);
 	cp->cpcmd &= ~RxVlanOn;
 	cpw16(CpCmd, cp->cpcmd);
 	if (cp->vlgrp)
 		cp->vlgrp->vlan_devices[vid] = NULL;
-	spin_unlock_irq(&cp->lock);
+	spin_unlock_irqrestore(&cp->lock, flags);
 }
 #endif /* CP_VLAN_TAG_USED */
 
@@ -510,7 +513,7 @@ static inline unsigned int cp_rx_csum_ok
 
 static int cp_rx_poll (struct net_device *dev, int *budget)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	unsigned rx_tail = cp->rx_tail;
 	unsigned rx_work = dev->quota;
 	unsigned rx;
@@ -630,9 +633,13 @@ 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;
+	struct cp_private *cp;
 	u16 status;
 
+	if (unlikely(dev == NULL))
+		return IRQ_NONE;
+	cp = netdev_priv(dev);
+
 	status = cpr16(IntrStatus);
 	if (!status || (status == 0xFFFF))
 		return IRQ_NONE;
@@ -648,20 +655,23 @@ cp_interrupt (int irq, void *dev_instanc
 	/* close possible race's with dev_close */
 	if (unlikely(!netif_running(dev))) {
 		cpw16(IntrMask, 0);
-		goto out;
+		spin_unlock(&cp->lock);
+		return IRQ_HANDLED;
 	}
 
-	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) {
+	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)
 		mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE);
 
+	spin_unlock(&cp->lock);
+
 	if (status & PciErr) {
 		u16 pci_status;
 
@@ -672,8 +682,7 @@ cp_interrupt (int irq, void *dev_instanc
 
 		/* TODO: reset hardware */
 	}
-out:
-	spin_unlock(&cp->lock);
+
 	return IRQ_HANDLED;
 }
 
@@ -736,7 +745,7 @@ static void cp_tx (struct cp_private *cp
 
 static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	unsigned entry;
 	u32 eor;
 #if CP_VLAN_TAG_USED
@@ -894,7 +903,7 @@ static int cp_start_xmit (struct sk_buff
 
 static void __cp_set_rx_mode (struct net_device *dev)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int i, rx_mode;
 	u32 tmp;
@@ -939,7 +948,7 @@ static void __cp_set_rx_mode (struct net
 static void cp_set_rx_mode (struct net_device *dev)
 {
 	unsigned long flags;
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 
 	spin_lock_irqsave (&cp->lock, flags);
 	__cp_set_rx_mode(dev);
@@ -955,35 +964,28 @@ static void __cp_get_stats(struct cp_pri
 
 static struct net_device_stats *cp_get_stats(struct net_device *dev)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
+	unsigned long flags;
 
 	/* The chip only need report frame silently dropped. */
-	spin_lock_irq(&cp->lock);
+	spin_lock_irqsave(&cp->lock, flags);
  	if (netif_running(dev) && netif_device_present(dev))
  		__cp_get_stats(cp);
-	spin_unlock_irq(&cp->lock);
+	spin_unlock_irqrestore(&cp->lock, flags);
 
 	return &cp->net_stats;
 }
 
 static void cp_stop_hw (struct cp_private *cp)
 {
-	struct net_device *dev = cp->dev;
-
 	cpw16(IntrStatus, ~(cpr16(IntrStatus)));
 	cpw16_f(IntrMask, 0);
 	cpw8(Cmd, 0);
 	cpw16_f(CpCmd, 0);
-	cpw16(IntrStatus, ~(cpr16(IntrStatus)));
-	synchronize_irq();
-	udelay(10);
+	cpw16_f(IntrStatus, ~(cpr16(IntrStatus)));
 
 	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)
@@ -1012,6 +1014,7 @@ static inline void cp_start_hw (struct c
 static void cp_init_hw (struct cp_private *cp)
 {
 	struct net_device *dev = cp->dev;
+	dma_addr_t ring_dma;
 
 	cp_reset_hw(cp);
 
@@ -1037,10 +1040,13 @@ static void cp_init_hw (struct cp_privat
 	cpw32_f(HiTxRingAddr, 0);
 	cpw32_f(HiTxRingAddr + 4, 0);
 
-	cpw32_f(RxRingAddr, cp->ring_dma);
-	cpw32_f(RxRingAddr + 4, 0);		/* FIXME: 64-bit PCI */
-	cpw32_f(TxRingAddr, cp->ring_dma + (sizeof(struct cp_desc) * CP_RX_RING_SIZE));
-	cpw32_f(TxRingAddr + 4, 0);		/* FIXME: 64-bit PCI */
+	ring_dma = cp->ring_dma;
+	cpw32_f(RxRingAddr, ring_dma & 0xffffffff);
+	cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16);
+
+	ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE;
+	cpw32_f(TxRingAddr, ring_dma & 0xffffffff);
+	cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16);
 
 	cpw16(MultiIntr, 0);
 
@@ -1154,7 +1160,7 @@ static void cp_free_rings (struct cp_pri
 
 static int cp_open (struct net_device *dev)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	int rc;
 
 	if (netif_msg_ifup(cp))
@@ -1184,19 +1190,24 @@ err_out_hw:
 
 static int cp_close (struct net_device *dev)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
+	unsigned long flags;
 
 	if (netif_msg_ifdown(cp))
 		printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
 
+	spin_lock_irqsave(&cp->lock, flags);
+
 	netif_stop_queue(dev);
 	netif_carrier_off(dev);
 
-	spin_lock_irq(&cp->lock);
 	cp_stop_hw(cp);
-	spin_unlock_irq(&cp->lock);
 
+	spin_unlock_irqrestore(&cp->lock, flags);
+
+	synchronize_irq();
 	free_irq(dev->irq, dev);
+
 	cp_free_rings(cp);
 	return 0;
 }
@@ -1204,8 +1215,9 @@ static int cp_close (struct net_device *
 #ifdef BROKEN
 static int cp_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	int rc;
+	unsigned long flags;
 
 	/* check for invalid MTU, according to hardware limits */
 	if (new_mtu < CP_MIN_MTU || new_mtu > CP_MAX_MTU)
@@ -1218,7 +1230,7 @@ static int cp_change_mtu(struct net_devi
 		return 0;
 	}
 
-	spin_lock_irq(&cp->lock);
+	spin_lock_irqsave(&cp->lock, flags);
 
 	cp_stop_hw(cp);			/* stop h/w and free rings */
 	cp_clean_rings(cp);
@@ -1229,7 +1241,7 @@ static int cp_change_mtu(struct net_devi
 	rc = cp_init_rings(cp);		/* realloc and restart h/w */
 	cp_start_hw(cp);
 
-	spin_unlock_irq(&cp->lock);
+	spin_unlock_irqrestore(&cp->lock, flags);
 
 	return rc;
 }
@@ -1248,7 +1260,7 @@ static char mii_2_8139_map[8] = {
 
 static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 
 	return location < 8 && mii_2_8139_map[location] ?
 	       readw(cp->regs + mii_2_8139_map[location]) : 0;
@@ -1258,7 +1270,7 @@ static int mdio_read(struct net_device *
 static void mdio_write(struct net_device *dev, int phy_id, int location,
 		       int value)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 
 	if (location == 0) {
 		cpw8(Cfg9346, Cfg9346_Unlock);
@@ -1326,7 +1338,7 @@ static void netdev_get_wol (struct cp_pr
 
 static void cp_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 
 	strcpy (info->driver, DRV_NAME);
 	strcpy (info->version, DRV_VERSION);
@@ -1345,55 +1357,57 @@ static int cp_get_stats_count (struct ne
 
 static int cp_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	int rc;
+	unsigned long flags;
 
-	spin_lock_irq(&cp->lock);
+	spin_lock_irqsave(&cp->lock, flags);
 	rc = mii_ethtool_gset(&cp->mii_if, cmd);
-	spin_unlock_irq(&cp->lock);
+	spin_unlock_irqrestore(&cp->lock, flags);
 
 	return rc;
 }
 
 static int cp_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	int rc;
+	unsigned long flags;
 
-	spin_lock_irq(&cp->lock);
+	spin_lock_irqsave(&cp->lock, flags);
 	rc = mii_ethtool_sset(&cp->mii_if, cmd);
-	spin_unlock_irq(&cp->lock);
+	spin_unlock_irqrestore(&cp->lock, flags);
 
 	return rc;
 }
 
 static int cp_nway_reset(struct net_device *dev)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	return mii_nway_restart(&cp->mii_if);
 }
 
 static u32 cp_get_msglevel(struct net_device *dev)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	return cp->msg_enable;
 }
 
 static void cp_set_msglevel(struct net_device *dev, u32 value)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	cp->msg_enable = value;
 }
 
 static u32 cp_get_rx_csum(struct net_device *dev)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	return (cpr16(CpCmd) & RxChkSum) ? 1 : 0;
 }
 
 static int cp_set_rx_csum(struct net_device *dev, u32 data)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	u16 cmd = cp->cpcmd, newcmd;
 
 	newcmd = cmd;
@@ -1404,10 +1418,12 @@ static int cp_set_rx_csum(struct net_dev
 		newcmd &= ~RxChkSum;
 
 	if (newcmd != cmd) {
-		spin_lock_irq(&cp->lock);
+		unsigned long flags;
+
+		spin_lock_irqsave(&cp->lock, flags);
 		cp->cpcmd = newcmd;
 		cpw16_f(CpCmd, newcmd);
-		spin_unlock_irq(&cp->lock);
+		spin_unlock_irqrestore(&cp->lock, flags);
 	}
 
 	return 0;
@@ -1416,35 +1432,38 @@ static int cp_set_rx_csum(struct net_dev
 static void cp_get_regs(struct net_device *dev, struct ethtool_regs *regs,
 		        void *p)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
+	unsigned long flags;
 
 	if (regs->len < CP_REGS_SIZE)
 		return /* -EINVAL */;
 
 	regs->version = CP_REGS_VER;
 
-	spin_lock_irq(&cp->lock);
+	spin_lock_irqsave(&cp->lock, flags);
 	memcpy_fromio(p, cp->regs, CP_REGS_SIZE);
-	spin_unlock_irq(&cp->lock);
+	spin_unlock_irqrestore(&cp->lock, flags);
 }
 
 static void cp_get_wol (struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
+	unsigned long flags;
 
-	spin_lock_irq (&cp->lock);
+	spin_lock_irqsave (&cp->lock, flags);
 	netdev_get_wol (cp, wol);
-	spin_unlock_irq (&cp->lock);
+	spin_unlock_irqrestore (&cp->lock, flags);
 }
 
 static int cp_set_wol (struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
+	unsigned long flags;
 	int rc;
 
-	spin_lock_irq (&cp->lock);
+	spin_lock_irqsave (&cp->lock, flags);
 	rc = netdev_set_wol (cp, wol);
-	spin_unlock_irq (&cp->lock);
+	spin_unlock_irqrestore (&cp->lock, flags);
 
 	return rc;
 }
@@ -1464,13 +1483,13 @@ static void cp_get_strings (struct net_d
 static void cp_get_ethtool_stats (struct net_device *dev,
 				  struct ethtool_stats *estats, u64 *tmp_stats)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	unsigned int work = 100;
 	int i;
 
 	/* begin NIC statistics dump */
-	cpw32(StatsAddr + 4, 0); /* FIXME: 64-bit PCI */
-	cpw32(StatsAddr, cp->nic_stats_dma | DumpStats);
+	cpw32(StatsAddr + 4, (cp->nic_stats_dma >> 16) >> 16);
+	cpw32(StatsAddr, (cp->nic_stats_dma & 0xffffffff) | DumpStats);
 	cpr32(StatsAddr);
 
 	while (work-- > 0) {
@@ -1526,16 +1545,17 @@ static struct ethtool_ops cp_ethtool_ops
 
 static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 	struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &rq->ifr_data;
 	int rc;
+	unsigned long flags;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	spin_lock_irq(&cp->lock);
+	spin_lock_irqsave(&cp->lock, flags);
 	rc = generic_mii_ioctl(&cp->mii_if, mii, cmd, NULL);
-	spin_unlock_irq(&cp->lock);
+	spin_unlock_irqrestore(&cp->lock, flags);
 	return rc;
 }
 
@@ -1637,7 +1657,9 @@ static int cp_init_one (struct pci_dev *
 	if (!dev)
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
-	cp = dev->priv;
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	cp = netdev_priv(dev);
 	cp->pdev = pdev;
 	cp->dev = dev;
 	cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug);
@@ -1662,12 +1684,6 @@ static int cp_init_one (struct pci_dev *
 	if (rc)
 		goto err_out_mwi;
 
-	if (pdev->irq < 2) {
-		rc = -EIO;
-		printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n",
-		       pdev->irq, pci_name(pdev));
-		goto err_out_res;
-	}
 	pciaddr = pci_resource_start(pdev, 1);
 	if (!pciaddr) {
 		rc = -EIO;
@@ -1687,19 +1703,20 @@ static int cp_init_one (struct pci_dev *
 	    !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
 		pci_using_dac = 1;
 	} else {
+		pci_using_dac = 0;
+
 		rc = pci_set_dma_mask(pdev, 0xffffffffULL);
 		if (rc) {
 			printk(KERN_ERR PFX "No usable DMA configuration, "
 			       "aborting.\n");
 			goto err_out_res;
 		}
-		pci_using_dac = 0;
 	}
 
 	cp->cpcmd = (pci_using_dac ? PCIDAC : 0) |
 		    PCIMulRW | RxChkSum | CpRxOn | CpTxOn;
 
-	regs = ioremap_nocache(pciaddr, CP_REGS_SIZE);
+	regs = ioremap(pciaddr, CP_REGS_SIZE);
 	if (!regs) {
 		rc = -EIO;
 		printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
@@ -1740,6 +1757,9 @@ static int cp_init_one (struct pci_dev *
 	dev->vlan_rx_kill_vid = cp_vlan_rx_kill_vid;
 #endif
 
+	if (pci_using_dac)
+		dev->features |= NETIF_F_HIGHDMA;
+
 	dev->irq = pdev->irq;
 
 	rc = register_netdev(dev);
@@ -1774,14 +1794,14 @@ err_out_mwi:
 err_out_disable:
 	pci_disable_device(pdev);
 err_out_free:
-	kfree(dev);
+	free_netdev(dev);
 	return rc;
 }
 
 static void cp_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct cp_private *cp = dev->priv;
+	struct cp_private *cp = netdev_priv(dev);
 
 	if (!dev)
 		BUG();
@@ -1792,7 +1812,7 @@ static void cp_remove_one (struct pci_de
 	pci_clear_mwi(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
-	kfree(dev);
+	free_netdev(dev);
 }
 
 #ifdef CONFIG_PM
@@ -1803,7 +1823,7 @@ static int cp_suspend (struct pci_dev *p
 	unsigned long flags;
 
 	dev = pci_get_drvdata (pdev);
-	cp  = dev->priv;
+	cp  = netdev_priv(dev);
 
 	if (!dev || !netif_running (dev)) return 0;
 
@@ -1832,7 +1852,7 @@ static int cp_resume (struct pci_dev *pd
 	struct cp_private *cp;
 
 	dev = pci_get_drvdata (pdev);
-	cp  = dev->priv;
+	cp  = netdev_priv(dev);
 
 	netif_device_attach (dev);
 	
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/8390.c linux-2.4.27-pre3/drivers/net/8390.c
--- linux-2.4.26/drivers/net/8390.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/8390.c	2004-05-18 16:51:24.000000000 +0000
@@ -1109,7 +1109,7 @@ void NS8390_init(struct net_device *dev,
 	for(i = 0; i < 6; i++) 
 	{
 		outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
-		if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
+		if (ei_debug > 1 && inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
 			printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
 	}
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/Config.in linux-2.4.27-pre3/drivers/net/Config.in
--- linux-2.4.26/drivers/net/Config.in	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/Config.in	2004-05-18 16:53:52.000000000 +0000
@@ -311,6 +311,10 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; the
    fi
 fi
 
+if [ "$CONFIG_PPC_PSERIES" = "y" ]; then
+   dep_tristate 'IBM PowerPC Virtual Ethernet driver support' CONFIG_IBMVETH $CONFIG_PPC_PSERIES
+fi 
+
 dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
 
 tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/Makefile linux-2.4.27-pre3/drivers/net/Makefile
--- linux-2.4.26/drivers/net/Makefile	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/Makefile	2004-05-18 16:52:12.000000000 +0000
@@ -245,6 +245,8 @@ obj-$(CONFIG_AMD8111_ETH) += amd8111e.o 
 obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o
 obj-$(CONFIG_USB_USBNET) += mii.o
 
+obj-$(CONFIG_IBMVETH) += ibmveth.o
+
 ifeq ($(CONFIG_ARCH_ACORN),y)
 mod-subdirs	+= ../acorn/net
 subdir-y	+= ../acorn/net
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/a2065.c linux-2.4.27-pre3/drivers/net/a2065.c
--- linux-2.4.26/drivers/net/a2065.c	2003-06-13 14:51:34.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/a2065.c	2004-05-18 16:53:39.000000000 +0000
@@ -284,6 +284,7 @@ static int lance_rx (struct net_device *
 	struct sk_buff *skb = 0;	/* XXX shut up gcc warnings */
 
 #ifdef TEST_HITS
+	int i;
 	printk ("[");
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		if (i == lp->rx_new)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/amd8111e.c linux-2.4.27-pre3/drivers/net/amd8111e.c
--- linux-2.4.26/drivers/net/amd8111e.c	2003-08-25 11:44:42.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/amd8111e.c	2004-05-18 16:51:18.000000000 +0000
@@ -1,6 +1,6 @@
 
 /* Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
- * Copyright (C) 2003 Advanced Micro Devices 
+ * Copyright (C) 2004 Advanced Micro Devices 
  *
  * 
  * Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> [ 8139cp.c,tg3.c ]
@@ -55,6 +55,14 @@ Revision History:
 	 4. Dynamic IPG support is disabled by default.
 	3.0.3 06/05/2003
 	 1. Bug fix: Fixed failure to close the interface if SMP is enabled.
+	3.0.4 12/09/2003
+	 1. Added set_mac_address routine for bonding driver support.
+	 2. Tested the driver for bonding support
+	 3. Bug fix: Fixed mismach in actual receive buffer lenth and lenth 
+	    indicated to the h/w.
+	 4. Modified amd8111e_rx() routine to receive all the received packets 
+	    in the first interrupt.
+	 5. Bug fix: Corrected  rx_errors  reported in get_stats() function.  
 
 */
 
@@ -91,9 +99,9 @@ Revision History:
 
 #include "amd8111e.h"
 #define MODULE_NAME	"amd8111e"
-#define MODULE_VERSION	"3.0.3"
+#define MODULE_VERSION	"3.0.4"
 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
-MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.3");
+MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.4");
 MODULE_LICENSE("GPL");
 MODULE_PARM(speed_duplex, "1-" __MODULE_STRING (MAX_UNITS) "i");
 MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex");
@@ -276,8 +284,10 @@ static inline void amd8111e_set_rx_buff_
 	unsigned int mtu = dev->mtu;
 	
 	if (mtu > ETH_DATA_LEN){
-		/* MTU + ethernet header + FCS + optional VLAN tag */
-		lp->rx_buff_len = mtu + ETH_HLEN + 8;
+		/* MTU + ethernet header + FCS
+		+ optional VLAN tag + skb reserve space 2 */
+
+		lp->rx_buff_len = mtu + ETH_HLEN + 10;
 		lp->options |= OPTION_JUMBO_ENABLE;
 	} else{
 		lp->rx_buff_len = PKT_BUFF_SZ;
@@ -337,7 +347,7 @@ static int amd8111e_init_ring(struct net
 			lp->rx_skbuff[i]->data,lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
 
 		lp->rx_ring[i].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[i]);
-		lp->rx_ring[i].buff_count = cpu_to_le16(lp->rx_buff_len);
+		lp->rx_ring[i].buff_count = cpu_to_le16(lp->rx_buff_len-2);
 		lp->rx_ring[i].rx_flags = cpu_to_le16(OWN_BIT);
 	}
 
@@ -513,6 +523,9 @@ static void amd8111e_init_hw_default( st
 	void * mmio = lp->mmio;
 
 
+        /* stop the chip */
+	writel(RUN, mmio + CMD0);
+
 	/* AUTOPOLL0 Register *//*TBD default value is 8100 in FPS */
 	writew( 0x8101, mmio + AUTOPOLL0);
 
@@ -710,7 +723,7 @@ static int amd8111e_rx(struct net_device
 	int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;
 	int min_pkt_len, status;
 	int num_rx_pkt = 0;
-	int max_rx_pkt = NUM_RX_BUFFERS/2;
+	int max_rx_pkt = NUM_RX_BUFFERS;
 	short pkt_len;
 #if AMD8111E_VLAN_TAG_USED		
 	short vtag;
@@ -752,14 +765,14 @@ static int amd8111e_rx(struct net_device
 
 		if (pkt_len < min_pkt_len) {
 			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
-			lp->stats.rx_errors++;
+			lp->drv_rx_errors++;
 			goto err_next_pkt;
 		}
 		if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
 			/* if allocation fail, 
 				ignore that pkt and go to next one */
 			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
-			lp->stats.rx_errors++;
+			lp->drv_rx_errors++;
 			goto err_next_pkt;
 		}
 		
@@ -896,12 +909,14 @@ static struct net_device_stats *amd8111e
 	new_stats->tx_bytes = amd8111e_read_mib(mmio, xmt_octets);
 
 	/* stats.rx_errors */
+	/* hw errors + errors driver reported */
 	new_stats->rx_errors = amd8111e_read_mib(mmio, rcv_undersize_pkts)+
 				amd8111e_read_mib(mmio, rcv_fragments)+
 				amd8111e_read_mib(mmio, rcv_jabbers)+
 				amd8111e_read_mib(mmio, rcv_alignment_errors)+
 				amd8111e_read_mib(mmio, rcv_fcs_errors)+
-				amd8111e_read_mib(mmio, rcv_miss_pkts);
+				amd8111e_read_mib(mmio, rcv_miss_pkts)+
+				lp->drv_rx_errors;
 
 	/* stats.tx_errors */
 	new_stats->tx_errors = amd8111e_read_mib(mmio, xmt_underrun_pkts);
@@ -1171,7 +1186,7 @@ static int amd8111e_close(struct net_dev
 
 	spin_unlock_irq(&lp->lock);
 	free_irq(dev->irq, dev);
-
+	
 	/* Update the statistics before closing */
 	amd8111e_get_stats(dev);
 	lp->opened = 0;
@@ -1545,6 +1560,23 @@ static int amd8111e_ioctl(struct net_dev
 	}
 	return -EOPNOTSUPP;
 }
+static int amd8111e_set_mac_address(struct net_device *dev, void *p)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	int i;
+	struct sockaddr *addr = p;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	spin_lock_irq(&lp->lock);
+	/* Setting the MAC address to the device */
+	for(i = 0; i < ETH_ADDR_LEN; i++)
+		writeb( dev->dev_addr[i], lp->mmio + PADR + i ); 
+		
+	spin_unlock_irq(&lp->lock);
+
+	return 0;
+}
+
 /* 
 This function changes the mtu of the device. It restarts the device  to initialize the descriptor with new receive buffers.
 */  
@@ -1875,6 +1907,7 @@ static int __devinit amd8111e_probe_one(
 	dev->stop = amd8111e_close;
 	dev->get_stats = amd8111e_get_stats;
 	dev->set_multicast_list = amd8111e_set_multicast_list;
+	dev->set_mac_address = amd8111e_set_mac_address;
 	dev->do_ioctl = amd8111e_ioctl;
 	dev->change_mtu = amd8111e_change_mtu;
 	dev->irq =pdev->irq;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/amd8111e.h linux-2.4.27-pre3/drivers/net/amd8111e.h
--- linux-2.4.26/drivers/net/amd8111e.h	2003-08-25 11:44:42.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/amd8111e.h	2004-05-18 16:54:28.000000000 +0000
@@ -1,6 +1,6 @@
 /*
  * Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
- * Copyright (C) 2003 Advanced Micro Devices 
+ * Copyright (C) 2004 Advanced Micro Devices 
  *
  * 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
@@ -790,6 +790,7 @@ struct amd8111e_priv{
 #endif	
 	char opened;
 	struct net_device_stats stats;
+	unsigned int drv_rx_errors;
 	struct dev_mc_list* mc_list;
 	struct amd8111e_coalesce_conf coal_conf;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/b44.c linux-2.4.27-pre3/drivers/net/b44.c
--- linux-2.4.26/drivers/net/b44.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/b44.c	2004-05-18 16:53:00.000000000 +0000
@@ -2,6 +2,8 @@
  *
  * Copyright (C) 2002 David S. Miller (davem@redhat.com)
  * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ *
+ * Distribute under GPL.
  */
 
 #include <linux/kernel.h>
@@ -25,8 +27,8 @@
 
 #define DRV_MODULE_NAME		"b44"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"0.92"
-#define DRV_MODULE_RELDATE	"Nov 4, 2003"
+#define DRV_MODULE_VERSION	"0.93"
+#define DRV_MODULE_RELDATE	"Mar, 2004"
 
 #define B44_DEF_MSG_ENABLE	  \
 	(NETIF_MSG_DRV		| \
@@ -83,6 +85,10 @@ static int b44_debug = -1;	/* -1 == use 
 static struct pci_device_id b44_pci_tbl[] = {
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ }	/* terminate list with empty entry */
 };
 
@@ -90,7 +96,7 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
 
 static void b44_halt(struct b44 *);
 static void b44_init_rings(struct b44 *);
-static int b44_init_hw(struct b44 *);
+static void b44_init_hw(struct b44 *);
 
 static int b44_wait_bit(struct b44 *bp, unsigned long reg,
 			u32 bit, unsigned long timeout, const int clear)
@@ -1170,11 +1176,10 @@ static int b44_set_mac_addr(struct net_d
  * packet processing.  Invoked with bp->lock held.
  */
 static void __b44_set_rx_mode(struct net_device *);
-static int b44_init_hw(struct b44 *bp)
+static void b44_init_hw(struct b44 *bp)
 {
 	u32 val;
 
-	b44_disable_ints(bp);
 	b44_chip_reset(bp);
 	b44_phy_reset(bp);
 	b44_setup_phy(bp);
@@ -1203,8 +1208,6 @@ static int b44_init_hw(struct b44 *bp)
 
 	val = br32(B44_ENET_CTRL);
 	bw32(B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
-
-	return 0;
 }
 
 static int b44_open(struct net_device *dev)
@@ -1223,9 +1226,7 @@ static int b44_open(struct net_device *d
 	spin_lock_irq(&bp->lock);
 
 	b44_init_rings(bp);
-	err = b44_init_hw(bp);
-	if (err)
-		goto err_out_noinit;
+	b44_init_hw(bp);
 	bp->flags |= B44_FLAG_INIT_COMPLETE;
 
 	spin_unlock_irq(&bp->lock);
@@ -1240,11 +1241,6 @@ static int b44_open(struct net_device *d
 
 	return 0;
 
-err_out_noinit:
-	b44_halt(bp);
-	b44_free_rings(bp);
-	spin_unlock_irq(&bp->lock);
-	free_irq(dev->irq, dev);
 err_out_free:
 	b44_free_consistent(bp);
 	return err;
@@ -1373,7 +1369,7 @@ static void b44_set_rx_mode(struct net_d
 	spin_unlock_irq(&bp->lock);
 }
 
-static int b44_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static int b44_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
 {
 	struct b44 *bp = dev->priv;
 	struct pci_dev *pci_dev = bp->pdev;
@@ -1383,7 +1379,7 @@ static int b44_ethtool_ioctl (struct net
 		return -EFAULT;
 
 	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO:{
+	case ETHTOOL_GDRVINFO: {
 		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
 		strcpy (info.driver, DRV_MODULE_NAME);
 		strcpy (info.version, DRV_MODULE_VERSION);
@@ -1616,13 +1612,13 @@ static int b44_ethtool_ioctl (struct net
 
 static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+	struct mii_ioctl_data __user *data = (struct mii_ioctl_data __user *)&ifr->ifr_data;
 	struct b44 *bp = dev->priv;
 	int err;
 
 	switch (cmd) {
 	case SIOCETHTOOL:
-		return b44_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+		return b44_ethtool_ioctl(dev, (void __user*) ifr->ifr_data);
 
 	case SIOCGMIIPHY:
 		data->phy_id = bp->phy_addr;
@@ -1758,6 +1754,7 @@ static int __devinit b44_init_one(struct
 	}
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev,&pdev->dev);
 
 	/* No interesting netdevice features in this card... */
 	dev->features |= 0;
@@ -1887,6 +1884,8 @@ static int b44_resume(struct pci_dev *pd
 	if (!netif_running(dev))
 		return 0;
 
+	pci_restore_state(pdev, bp->pci_cfg_state);
+
 	spin_lock_irq(&bp->lock);
 
 	b44_init_rings(bp);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e100/e100.h linux-2.4.27-pre3/drivers/net/e100/e100.h
--- linux-2.4.26/drivers/net/e100/e100.h	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e100/e100.h	2004-05-18 16:52:57.000000000 +0000
@@ -434,6 +434,7 @@ struct driver_stats {
 #define D102_REV_ID      12
 #define D102C_REV_ID     13	/* 82550 step C */
 #define D102E_REV_ID     15
+#define D102E_A1_REV_ID  16
 
 /* ############Start of 82555 specific defines################## */
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e100/e100_main.c linux-2.4.27-pre3/drivers/net/e100/e100_main.c
--- linux-2.4.26/drivers/net/e100/e100_main.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e100/e100_main.c	2004-05-18 16:51:21.000000000 +0000
@@ -46,7 +46,16 @@
 
 /* Change Log
  * 
- * 2.3.38       12/14/03
+ * 2.3.40       2/13/04
+ * o Updated microcode for D102 rev 15 and rev 16 to include fix
+ *   for TCO issue.  NFS packets would be misinterpreted as TCO packets
+ *   and incorrectly routed to the BMC over SMBus.  The microcode fix
+ *   checks the fragmented IP bit in the NFS/UDP header to distinguish
+ *   between NFS and TCO.
+ * o Bug fix: don't strip MAC header count from Rx byte count.
+ *   Ben Greear (greear@candeltech.com).
+ *
+ * 2.3.38	12/14/03
  * o Added netpoll support.
  * o Added ICH6 device ID support
  * o Moved to 2.6 APIs: pci_name() and free_netdev().
@@ -54,12 +63,6 @@
  *   as such (Anton Blanchard [anton@samba.org]).
  * 
  * 2.3.33       10/21/03
- * o Bug fix (Bugzilla 97908): Loading e100 was causing crash on Itanium2
- *   with HP chipset
- * o Bug fix (Bugzilla 101583): e100 can't pass traffic with ipv6
- * o Bug fix (Bugzilla 101360): PRO/10+ can't pass traffic
- * 
- * 2.3.27       08/08/03
  */
  
 #include <linux/config.h>
@@ -132,7 +135,7 @@ static void e100_non_tx_background(unsig
 static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb);
 /* Global Data structures and variables */
 char e100_copyright[] __devinitdata = "Copyright (c) 2004 Intel Corporation";
-char e100_driver_version[]="2.3.38-k1";
+char e100_driver_version[]="2.3.40-k1";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
@@ -582,6 +585,7 @@ e100_found1(struct pci_dev *pcid, const 
 	bdp->device = dev;
 
 	pci_set_drvdata(pcid, dev);
+	SET_NETDEV_DEV(dev, &pcid->dev);
 
 	bdp->flags = 0;
 	bdp->ifs_state = 0;
@@ -2062,6 +2066,8 @@ e100_rx_srv(struct e100_private *bdp)
 		else
 			skb_put(skb, (int) data_sz);
 
+		bdp->drv_stats.net_stats.rx_bytes += skb->len;
+
 		/* set the protocol */
 		skb->protocol = eth_type_trans(skb, dev);
 
@@ -2076,8 +2082,6 @@ e100_rx_srv(struct e100_private *bdp)
 			skb->ip_summed = CHECKSUM_NONE;
 		}
 
-		bdp->drv_stats.net_stats.rx_bytes += skb->len;
-
 		if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) {
 			vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid));
 		} else {
@@ -2835,6 +2839,11 @@ e100_load_microcode(struct e100_private 
 		  D102_E_CPUSAVER_TIMER_DWORD,
 		  D102_E_CPUSAVER_BUNDLE_DWORD,
 		  D102_E_CPUSAVER_MIN_SIZE_DWORD },
+		{ D102E_A1_REV_ID,
+		  D102_E_RCVBUNDLE_UCODE,
+		  D102_E_CPUSAVER_TIMER_DWORD,
+		  D102_E_CPUSAVER_BUNDLE_DWORD,
+		  D102_E_CPUSAVER_MIN_SIZE_DWORD },
 		{ 0, {0}, 0, 0, 0}
 	}, *opts;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e100/e100_ucode.h linux-2.4.27-pre3/drivers/net/e100/e100_ucode.h
--- linux-2.4.26/drivers/net/e100/e100_ucode.h	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e100/e100_ucode.h	2004-05-18 16:54:01.000000000 +0000
@@ -346,7 +346,7 @@ below), and they each have their own ver
 
 #define     D102_E_RCVBUNDLE_UCODE \
 {\
-0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x1FFF1FFF, 0x1FFF1FFF, \
+0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \
 0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
 0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
 0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
@@ -359,7 +359,26 @@ below), and they each have their own ver
 0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
 0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
 0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
-0x00300006, 0x00E014FB, 0x00000000, 0x00000000  \
+0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \
+0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
 }
 
 #endif /* _E100_UCODE_H_ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e1000/e1000.h linux-2.4.27-pre3/drivers/net/e1000/e1000.h
--- linux-2.4.26/drivers/net/e1000/e1000.h	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e1000/e1000.h	2004-05-18 16:52:37.000000000 +0000
@@ -113,7 +113,7 @@ struct e1000_adapter;
 #define E1000_SMARTSPEED_MAX       15
 
 /* Packet Buffer allocations */
-#define E1000_TX_FIFO_SIZE_SHIFT 0xA
+#define E1000_PBA_BYTES_SHIFT 0xA
 #define E1000_TX_HEAD_ADDR_SHIFT 7
 #define E1000_PBA_TX_MASK 0xFFFF0000
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e1000/e1000_ethtool.c linux-2.4.27-pre3/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.26/drivers/net/e1000/e1000_ethtool.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e1000/e1000_ethtool.c	2004-05-18 16:54:06.000000000 +0000
@@ -353,6 +353,7 @@ e1000_ethtool_geeprom(struct e1000_adapt
 	struct e1000_hw *hw = &adapter->hw;
 	int first_word, last_word;
 	int ret_val = 0;
+	uint16_t i;
 
 	if(eeprom->len == 0) {
 		ret_val = -EINVAL;
@@ -377,12 +378,16 @@ e1000_ethtool_geeprom(struct e1000_adapt
 					    last_word - first_word + 1,
 					    eeprom_buff);
 	else {
-		uint16_t i;
 		for (i = 0; i < last_word - first_word + 1; i++)
 			if((ret_val = e1000_read_eeprom(hw, first_word + i, 1,
 							&eeprom_buff[i])))
 				break;
 	}
+
+	/* Device's eeprom is always little-endian, word addressable */
+	for (i = 0; i < last_word - first_word + 1; i++)
+		le16_to_cpus(&eeprom_buff[i]);
+
 geeprom_error:
 	return ret_val;
 }
@@ -395,6 +400,7 @@ e1000_ethtool_seeprom(struct e1000_adapt
 	uint16_t *eeprom_buff;
 	void *ptr;
 	int max_len, first_word, last_word, ret_val = 0;
+	uint16_t i;
 
 	if(eeprom->len == 0)
 		return -EOPNOTSUPP;
@@ -428,11 +434,19 @@ e1000_ethtool_seeprom(struct e1000_adapt
 		ret_val = e1000_read_eeprom(hw, last_word, 1,
 		                  &eeprom_buff[last_word - first_word]);
 	}
+
+	/* Device's eeprom is always little-endian, word addressable */
+	for (i = 0; i < last_word - first_word + 1; i++)
+		le16_to_cpus(&eeprom_buff[i]);
+
 	if((ret_val != 0) || copy_from_user(ptr, user_data, eeprom->len)) {
 		ret_val = -EFAULT;
 		goto seeprom_error;
 	}
 
+	for (i = 0; i < last_word - first_word + 1; i++)
+		eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+
 	ret_val = e1000_write_eeprom(hw, first_word,
 				     last_word - first_word + 1, eeprom_buff);
 
@@ -445,6 +459,85 @@ seeprom_error:
 	return ret_val;
 }
 
+static int
+e1000_ethtool_gring(struct e1000_adapter *adapter,
+                    struct ethtool_ringparam *ring)
+{
+	e1000_mac_type mac_type = adapter->hw.mac_type;
+	struct e1000_desc_ring *txdr = &adapter->tx_ring;
+	struct e1000_desc_ring *rxdr = &adapter->rx_ring;
+
+	ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD :
+		E1000_MAX_82544_RXD;
+	ring->tx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_TXD :
+		E1000_MAX_82544_TXD;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = rxdr->count;
+	ring->tx_pending = txdr->count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+
+	return 0;
+}
+static int 
+e1000_ethtool_sring(struct e1000_adapter *adapter,
+                    struct ethtool_ringparam *ring)
+{
+	int err;
+	e1000_mac_type mac_type = adapter->hw.mac_type;
+	struct e1000_desc_ring *txdr = &adapter->tx_ring;
+	struct e1000_desc_ring *rxdr = &adapter->rx_ring;
+	struct e1000_desc_ring tx_old, tx_new;
+	struct e1000_desc_ring rx_old, rx_new;
+
+	tx_old = adapter->tx_ring;
+	rx_old = adapter->rx_ring;
+	
+	if(netif_running(adapter->netdev))
+		e1000_down(adapter);
+
+	rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD);
+	rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ?
+		E1000_MAX_RXD : E1000_MAX_82544_RXD));
+	E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); 
+
+	txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD);
+	txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ?
+		E1000_MAX_TXD : E1000_MAX_82544_TXD));
+	E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); 
+
+	if(netif_running(adapter->netdev)) {
+		/* try to get new resources before deleting old */
+		if((err = e1000_setup_rx_resources(adapter)))
+			goto err_setup_rx;
+		if((err = e1000_setup_tx_resources(adapter)))
+			goto err_setup_tx;
+
+		/* save the new, restore the old in order to free it,
+		 * then restore the new back again */	
+	
+		rx_new = adapter->rx_ring;
+		tx_new = adapter->tx_ring;
+		adapter->rx_ring = rx_old;
+		adapter->tx_ring = tx_old;
+		e1000_free_rx_resources(adapter);
+		e1000_free_tx_resources(adapter);
+		adapter->rx_ring = rx_new;
+		adapter->tx_ring = tx_new;
+		if((err = e1000_up(adapter)))
+			return err;
+	}
+	return 0;
+err_setup_tx:
+	e1000_free_rx_resources(adapter);
+err_setup_rx:
+	adapter->rx_ring = rx_old;
+	adapter->tx_ring = tx_old;
+	e1000_up(adapter);
+	return err;
+}
+
 #define REG_PATTERN_TEST(R, M, W)                                              \
 {                                                                              \
 	uint32_t pat, value;                                                   \
@@ -1421,6 +1514,9 @@ e1000_ethtool_ioctl(struct net_device *n
 
 		if(copy_from_user(&regs, addr, sizeof(regs)))
 			return -EFAULT;
+		memset(regs_buff, 0, sizeof(regs_buff));
+		if (regs.len > E1000_REGS_LEN)
+			regs.len = E1000_REGS_LEN;
 		e1000_ethtool_gregs(adapter, &regs, regs_buff);
 		if(copy_to_user(addr, &regs, sizeof(regs)))
 			return -EFAULT;
@@ -1507,6 +1603,19 @@ err_geeprom_ioctl:
 		addr += offsetof(struct ethtool_eeprom, data);
 		return e1000_ethtool_seeprom(adapter, &eeprom, addr);
 	}
+	case ETHTOOL_GRINGPARAM: {
+		struct ethtool_ringparam ering = {ETHTOOL_GRINGPARAM};
+		e1000_ethtool_gring(adapter, &ering);
+		if(copy_to_user(addr, &ering, sizeof(ering)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SRINGPARAM: {
+		struct ethtool_ringparam ering;
+		if(copy_from_user(&ering, addr, sizeof(ering)))
+			return -EFAULT;
+		return e1000_ethtool_sring(adapter, &ering);
+	}
 	case ETHTOOL_GPAUSEPARAM: {
 		struct ethtool_pauseparam epause = {ETHTOOL_GPAUSEPARAM};
 		e1000_ethtool_gpause(adapter, &epause);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e1000/e1000_hw.c linux-2.4.27-pre3/drivers/net/e1000/e1000_hw.c
--- linux-2.4.26/drivers/net/e1000/e1000_hw.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e1000/e1000_hw.c	2004-05-18 16:54:12.000000000 +0000
@@ -65,6 +65,7 @@ static void e1000_release_eeprom(struct 
 static void e1000_standby_eeprom(struct e1000_hw *hw);
 static int32_t e1000_id_led_init(struct e1000_hw * hw);
 static int32_t e1000_set_vco_speed(struct e1000_hw *hw);
+static int32_t e1000_set_phy_mode(struct e1000_hw *hw);
 
 /* IGP cable length table */
 static const
@@ -469,11 +470,11 @@ e1000_init_hw(struct e1000_hw *hw)
     uint16_t pcix_stat_hi_word;
     uint16_t cmd_mmrbc;
     uint16_t stat_mmrbc;
-
     DEBUGFUNC("e1000_init_hw");
 
     /* Initialize Identification LED */
-    if((ret_val = e1000_id_led_init(hw))) {
+    ret_val = e1000_id_led_init(hw);
+    if(ret_val) {
         DEBUGOUT("Error Initializing Identification LED\n");
         return ret_val;
     }
@@ -594,16 +595,16 @@ e1000_adjust_serdes_amplitude(struct e10
         return E1000_SUCCESS;
     }
 
-    if ((ret_val = e1000_read_eeprom(hw, EEPROM_SERDES_AMPLITUDE, 1,
-                                     &eeprom_data))) {
+    ret_val = e1000_read_eeprom(hw, EEPROM_SERDES_AMPLITUDE, 1, &eeprom_data);
+    if (ret_val) {
         return ret_val;
     }
 
     if(eeprom_data != EEPROM_RESERVED_WORD) {
         /* Adjust SERDES output amplitude only. */
         eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK; 
-        if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL,
-                                          eeprom_data)))
+        ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL, eeprom_data);
+        if(ret_val)
             return ret_val;
     }
 
@@ -752,14 +753,16 @@ e1000_setup_fiber_serdes_link(struct e10
     if(hw->media_type == e1000_media_type_fiber)
         signal = (hw->mac_type > e1000_82544) ? E1000_CTRL_SWDPIN1 : 0;
 
-    if((ret_val = e1000_adjust_serdes_amplitude(hw)))
+    ret_val = e1000_adjust_serdes_amplitude(hw);
+    if(ret_val)
         return ret_val;
 
     /* Take the link out of reset */
     ctrl &= ~(E1000_CTRL_LRST);
 
     /* Adjust VCO speed to improve BER performance */
-    if((ret_val = e1000_set_vco_speed(hw)))
+    ret_val = e1000_set_vco_speed(hw);
+    if(ret_val)
         return ret_val;
 
     e1000_config_collision_dist(hw);
@@ -846,7 +849,8 @@ e1000_setup_fiber_serdes_link(struct e10
              * we detect a signal. This will allow us to communicate with
              * non-autonegotiating link partners.
              */
-            if((ret_val = e1000_check_for_link(hw))) {
+            ret_val = e1000_check_for_link(hw);
+            if(ret_val) {
                 DEBUGOUT("Error while checking for link\n");
                 return ret_val;
             }
@@ -893,12 +897,18 @@ e1000_setup_copper_link(struct e1000_hw 
     }
 
     /* Make sure we have a valid PHY */
-    if((ret_val = e1000_detect_gig_phy(hw))) {
+    ret_val = e1000_detect_gig_phy(hw);
+    if(ret_val) {
         DEBUGOUT("Error, did not detect valid phy.\n");
         return ret_val;
     }
     DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
 
+    /* Set PHY to class A mode (if necessary) */
+    ret_val = e1000_set_phy_mode(hw);
+    if(ret_val)
+        return ret_val;
+
     if(hw->mac_type <= e1000_82543 ||
        hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
        hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2)
@@ -907,7 +917,8 @@ e1000_setup_copper_link(struct e1000_hw 
     if(!hw->phy_reset_disable) {
         if (hw->phy_type == e1000_phy_igp) {
 
-            if((ret_val = e1000_phy_reset(hw))) {
+            ret_val = e1000_phy_reset(hw);
+            if(ret_val) {
                 DEBUGOUT("Error Resetting the PHY\n");
                 return ret_val;
             }
@@ -922,14 +933,16 @@ e1000_setup_copper_link(struct e1000_hw 
             E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
 
             /* disable lplu d3 during driver init */
-            if((ret_val = e1000_set_d3_lplu_state(hw, FALSE))) {
+            ret_val = e1000_set_d3_lplu_state(hw, FALSE);
+            if(ret_val) {
                 DEBUGOUT("Error Disabling LPLU D3\n");
                 return ret_val;
             }
 
             /* Configure mdi-mdix settings */
-            if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                             &phy_data)))
+            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+                                         &phy_data);
+            if(ret_val)
                 return ret_val;
 
             if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
@@ -956,8 +969,9 @@ e1000_setup_copper_link(struct e1000_hw 
                     break;
                 }
             }
-            if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                              phy_data)))
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+                                          phy_data);
+            if(ret_val)
                 return ret_val;
 
             /* set auto-master slave resolution settings */
@@ -975,27 +989,28 @@ e1000_setup_copper_link(struct e1000_hw 
                  * resolution as hardware default. */
                 if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
                     /* Disable SmartSpeed */
-                    if((ret_val = e1000_read_phy_reg(hw,
-                                                    IGP01E1000_PHY_PORT_CONFIG,
-                                                    &phy_data)))
+                    ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                                 &phy_data);
+                    if(ret_val)
                         return ret_val;
                     phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-                    if((ret_val = e1000_write_phy_reg(hw,
-                                                     IGP01E1000_PHY_PORT_CONFIG,
-                                                     phy_data)))
+                    ret_val = e1000_write_phy_reg(hw,
+                                                  IGP01E1000_PHY_PORT_CONFIG,
+                                                  phy_data);
+                    if(ret_val)
                         return ret_val;
                     /* Set auto Master/Slave resolution process */
-                    if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
-                                                     &phy_data)))
+                    ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+                    if(ret_val)
                         return ret_val;
                     phy_data &= ~CR_1000T_MS_ENABLE;
-                    if((ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
-                                                      phy_data)))
+                    ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+                    if(ret_val)
                         return ret_val;
                 }
 
-                if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL,
-                                                 &phy_data)))
+                ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
+                if(ret_val)
                     return ret_val;
 
                 /* load defaults for future use */
@@ -1018,14 +1033,15 @@ e1000_setup_copper_link(struct e1000_hw 
                 default:
                     break;
                 }
-                if((ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL,
-                                                  phy_data)))
+                ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
+                if(ret_val)
                     return ret_val;
             }
         } else {
             /* Enable CRS on TX. This must be set for half-duplex operation. */
-            if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                             &phy_data)))
+            ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                         &phy_data);
+            if(ret_val)
                 return ret_val;
 
             phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
@@ -1064,15 +1080,17 @@ e1000_setup_copper_link(struct e1000_hw 
             phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
             if(hw->disable_polarity_correction == 1)
                 phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-            if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                              phy_data)))
+            ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+                                          phy_data);
+            if(ret_val)
                 return ret_val;
 
             /* Force TX_CLK in the Extended PHY Specific Control Register
              * to 25MHz clock.
              */
-            if((ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-                                             &phy_data)))
+            ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                         &phy_data);
+            if(ret_val)
                 return ret_val;
 
             phy_data |= M88E1000_EPSCR_TX_CLK_25;
@@ -1083,14 +1101,15 @@ e1000_setup_copper_link(struct e1000_hw 
                               M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
                 phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
                              M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-                if((ret_val = e1000_write_phy_reg(hw,
-                                                  M88E1000_EXT_PHY_SPEC_CTRL,
-                                                  phy_data)))
+                ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                              phy_data);
+                if(ret_val)
                     return ret_val;
             }
 
             /* SW Reset the PHY so all changes take effect */
-            if((ret_val = e1000_phy_reset(hw))) {
+            ret_val = e1000_phy_reset(hw);
+            if(ret_val) {
                 DEBUGOUT("Error Resetting the PHY\n");
                 return ret_val;
             }
@@ -1124,7 +1143,8 @@ e1000_setup_copper_link(struct e1000_hw 
                 hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
 
             DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
-            if((ret_val = e1000_phy_setup_autoneg(hw))) {
+            ret_val = e1000_phy_setup_autoneg(hw);
+            if(ret_val) {
                 DEBUGOUT("Error Setting up Auto-Negotiation\n");
                 return ret_val;
             }
@@ -1133,18 +1153,21 @@ e1000_setup_copper_link(struct e1000_hw 
             /* Restart auto-negotiation by setting the Auto Neg Enable bit and
              * the Auto Neg Restart bit in the PHY control register.
              */
-            if((ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data)))
+            ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+            if(ret_val)
                 return ret_val;
 
             phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-            if((ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data)))
+            ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+            if(ret_val)
                 return ret_val;
 
             /* Does the user want to wait for Auto-Neg to complete here, or
              * check at a later time (for example, callback routine).
              */
             if(hw->wait_autoneg_complete) {
-                if((ret_val = e1000_wait_autoneg(hw))) {
+                ret_val = e1000_wait_autoneg(hw);
+                if(ret_val) {
                     DEBUGOUT("Error while waiting for autoneg to complete\n");
                     return ret_val;
                 }
@@ -1152,7 +1175,8 @@ e1000_setup_copper_link(struct e1000_hw 
             hw->get_link_status = TRUE;
         } else {
             DEBUGOUT("Forcing speed and duplex\n");
-            if((ret_val = e1000_phy_force_speed_duplex(hw))) {
+            ret_val = e1000_phy_force_speed_duplex(hw);
+            if(ret_val) {
                 DEBUGOUT("Error Forcing Speed and Duplex\n");
                 return ret_val;
             }
@@ -1163,9 +1187,11 @@ e1000_setup_copper_link(struct e1000_hw 
      * valid.
      */
     for(i = 0; i < 10; i++) {
-        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
-        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
 
         if(phy_data & MII_SR_LINK_STATUS) {
@@ -1180,19 +1206,22 @@ e1000_setup_copper_link(struct e1000_hw 
             if(hw->mac_type >= e1000_82544) {
                 e1000_config_collision_dist(hw);
             } else {
-                if((ret_val = e1000_config_mac_to_phy(hw))) {
+                ret_val = e1000_config_mac_to_phy(hw);
+                if(ret_val) {
                     DEBUGOUT("Error configuring MAC to PHY settings\n");
                     return ret_val;
                 }
             }
-            if((ret_val = e1000_config_fc_after_link_up(hw))) {
+            ret_val = e1000_config_fc_after_link_up(hw);
+            if(ret_val) {
                 DEBUGOUT("Error Configuring Flow Control\n");
                 return ret_val;
             }
             DEBUGOUT("Valid link established!!!\n");
 
             if(hw->phy_type == e1000_phy_igp) {
-                if((ret_val = e1000_config_dsp_after_link_change(hw, TRUE))) {
+                ret_val = e1000_config_dsp_after_link_change(hw, TRUE);
+                if(ret_val) {
                     DEBUGOUT("Error Configuring DSP after link up\n");
                     return ret_val;
                 }
@@ -1222,12 +1251,13 @@ e1000_phy_setup_autoneg(struct e1000_hw 
     DEBUGFUNC("e1000_phy_setup_autoneg");
 
     /* Read the MII Auto-Neg Advertisement Register (Address 4). */
-    if((ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV,
-                                     &mii_autoneg_adv_reg)))
+    ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+    if(ret_val)
         return ret_val;
 
     /* Read the MII 1000Base-T Control Register (Address 9). */
-    if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg)))
+    ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+    if(ret_val)
         return ret_val;
 
     /* Need to parse both autoneg_advertised and fc and set up
@@ -1334,13 +1364,14 @@ e1000_phy_setup_autoneg(struct e1000_hw 
         return -E1000_ERR_CONFIG;
     }
 
-    if((ret_val = e1000_write_phy_reg(hw, PHY_AUTONEG_ADV,
-                                      mii_autoneg_adv_reg)))
+    ret_val = e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+    if(ret_val)
         return ret_val;
 
     DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
 
-    if((ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg)))
+    ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+    if(ret_val)
         return ret_val;
 
     return E1000_SUCCESS;
@@ -1379,7 +1410,8 @@ e1000_phy_force_speed_duplex(struct e100
     ctrl &= ~E1000_CTRL_ASDE;
 
     /* Read the MII Control Register. */
-    if((ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg)))
+    ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg);
+    if(ret_val)
         return ret_val;
 
     /* We need to disable autoneg in order to force link and duplex. */
@@ -1426,16 +1458,16 @@ e1000_phy_force_speed_duplex(struct e100
     E1000_WRITE_REG(hw, CTRL, ctrl);
 
     if (hw->phy_type == e1000_phy_m88) {
-        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+        if(ret_val)
             return ret_val;
 
         /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
          * forced whenever speed are duplex are forced.
          */
         phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-        if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                          phy_data)))
+        ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
             return ret_val;
 
         DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
@@ -1446,20 +1478,21 @@ e1000_phy_force_speed_duplex(struct e100
         /* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
          * forced whenever speed or duplex are forced.
          */
-        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
         phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
 
-        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
-                                          phy_data)))
+        ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+        if(ret_val)
             return ret_val;
     }
 
     /* Write back the modified PHY MII control register. */
-    if((ret_val = e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg)))
+    ret_val = e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg);
+    if(ret_val)
         return ret_val;
 
     udelay(1);
@@ -1481,10 +1514,12 @@ e1000_phy_force_speed_duplex(struct e100
             /* Read the MII Status Register and wait for Auto-Neg Complete bit
              * to be set.
              */
-            if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
                 return ret_val;
 
-            if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
                 return ret_val;
 
             if(mii_status_reg & MII_SR_LINK_STATUS) break;
@@ -1492,7 +1527,8 @@ e1000_phy_force_speed_duplex(struct e100
         }
         if((i == 0) && (hw->phy_type == e1000_phy_m88)) {
             /* We didn't get link.  Reset the DSP and wait again for link. */
-            if((ret_val = e1000_phy_reset_dsp(hw))) {
+            ret_val = e1000_phy_reset_dsp(hw);
+            if(ret_val) {
                 DEBUGOUT("Error Resetting PHY DSP\n");
                 return ret_val;
             }
@@ -1504,10 +1540,12 @@ e1000_phy_force_speed_duplex(struct e100
             /* Read the MII Status Register and wait for Auto-Neg Complete bit
              * to be set.
              */
-            if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
                 return ret_val;
 
-            if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+            ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+            if(ret_val)
                 return ret_val;
         }
     }
@@ -1517,46 +1555,26 @@ e1000_phy_force_speed_duplex(struct e100
          * Extended PHY Specific Control Register to 25MHz clock.  This value
          * defaults back to a 2.5MHz clock when the PHY is reset.
          */
-        if((ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data |= M88E1000_EPSCR_TX_CLK_25;
-        if((ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-                                          phy_data)))
+        ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
             return ret_val;
 
         /* In addition, because of the s/w reset above, we need to enable CRS on
          * TX.  This must be set for both full and half duplex operation.
          */
-        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-        if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
-                                          phy_data)))
+        ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+        if(ret_val)
             return ret_val;
-
-        /* Polarity reversal workaround for forced 10F/10H links. */
-        if(hw->mac_type <= e1000_82544 &&
-           (hw->forced_speed_duplex == e1000_10_full ||
-            hw->forced_speed_duplex == e1000_10_half)) {
-            if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT,
-                                              0x0019)))
-                return ret_val;
-            if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL,
-                                              0x8F0F)))
-                return ret_val;
-            /* IEEE requirement is 150ms */
-            msec_delay(200);
-            if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT,
-                                              0x0019)))
-                return ret_val;
-            if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL,
-                                              0x8F00)))
-                return ret_val;
-        }
     }
     return E1000_SUCCESS;
 }
@@ -1614,8 +1632,9 @@ e1000_config_mac_to_phy(struct e1000_hw 
      * registers depending on negotiated values.
      */
     if (hw->phy_type == e1000_phy_igp) {
-        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
 
         if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD;
@@ -1633,8 +1652,9 @@ e1000_config_mac_to_phy(struct e1000_hw 
                 IGP01E1000_PSSR_SPEED_100MBPS)
             ctrl |= E1000_CTRL_SPD_100;
     } else {
-        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
 
         if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
@@ -1752,7 +1772,8 @@ e1000_config_fc_after_link_up(struct e10
     if(((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
        ((hw->media_type == e1000_media_type_internal_serdes) && (hw->autoneg_failed)) ||
        ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
-        if((ret_val = e1000_force_mac_fc(hw))) {
+        ret_val = e1000_force_mac_fc(hw);
+        if(ret_val) {
             DEBUGOUT("Error forcing flow control settings\n");
             return ret_val;
         }
@@ -1768,9 +1789,11 @@ e1000_config_fc_after_link_up(struct e10
          * has completed.  We read this twice because this reg has
          * some "sticky" (latched) bits.
          */
-        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
             return ret_val;
-        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg)))
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
             return ret_val;
 
         if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
@@ -1780,11 +1803,13 @@ e1000_config_fc_after_link_up(struct e10
              * Register (Address 5) to determine how flow control was
              * negotiated.
              */
-            if((ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV,
-                                             &mii_nway_adv_reg)))
+            ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV,
+                                         &mii_nway_adv_reg);
+            if(ret_val)
                 return ret_val;
-            if((ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY,
-                                             &mii_nway_lp_ability_reg)))
+            ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY,
+                                         &mii_nway_lp_ability_reg);
+            if(ret_val)
                 return ret_val;
 
             /* Two bits in the Auto Negotiation Advertisement Register
@@ -1901,7 +1926,8 @@ e1000_config_fc_after_link_up(struct e10
              * negotiated to HALF DUPLEX, flow control should not be
              * enabled per IEEE 802.3 spec.
              */
-            if((ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex))) {
+            ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
+            if(ret_val) {
                 DEBUGOUT("Error getting link speed and duplex\n");
                 return ret_val;
             }
@@ -1912,7 +1938,8 @@ e1000_config_fc_after_link_up(struct e10
             /* Now we call a subroutine to actually force the MAC
              * controller to use the correct flow control settings.
              */
-            if((ret_val = e1000_force_mac_fc(hw))) {
+            ret_val = e1000_force_mac_fc(hw);
+            if(ret_val) {
                 DEBUGOUT("Error forcing flow control settings\n");
                 return ret_val;
             }
@@ -1966,9 +1993,11 @@ e1000_check_for_link(struct e1000_hw *hw
          * of the PHY.
          * Read the register twice since the link bit is sticky.
          */
-        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
-        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
 
         if(phy_data & MII_SR_LINK_STATUS) {
@@ -2002,7 +2031,8 @@ e1000_check_for_link(struct e1000_hw *hw
         if(hw->mac_type >= e1000_82544)
             e1000_config_collision_dist(hw);
         else {
-            if((ret_val = e1000_config_mac_to_phy(hw))) {
+            ret_val = e1000_config_mac_to_phy(hw);
+            if(ret_val) {
                 DEBUGOUT("Error configuring MAC to PHY settings\n");
                 return ret_val;
             }
@@ -2012,7 +2042,8 @@ e1000_check_for_link(struct e1000_hw *hw
          * need to restore the desired flow control settings because we may
          * have had to re-autoneg with a different link partner.
          */
-        if((ret_val = e1000_config_fc_after_link_up(hw))) {
+        ret_val = e1000_config_fc_after_link_up(hw);
+        if(ret_val) {
             DEBUGOUT("Error configuring flow control\n");
             return ret_val;
         }
@@ -2080,7 +2111,8 @@ e1000_check_for_link(struct e1000_hw *hw
         E1000_WRITE_REG(hw, CTRL, ctrl);
 
         /* Configure Flow Control after forcing link up. */
-        if((ret_val = e1000_config_fc_after_link_up(hw))) {
+        ret_val = e1000_config_fc_after_link_up(hw);
+        if(ret_val) {
             DEBUGOUT("Error configuring flow control\n");
             return ret_val;
         }
@@ -2173,13 +2205,15 @@ e1000_get_speed_and_duplex(struct e1000_
      * match the duplex in the link partner's capabilities.
      */
     if(hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
-        if((ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
+        if(ret_val)
             return ret_val;
 
         if(!(phy_data & NWAY_ER_LP_NWAY_CAPS))
             *duplex = HALF_DUPLEX;
         else {
-            if((ret_val == e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data)))
+            ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data);
+            if(ret_val)
                 return ret_val;
             if((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
                (*speed == SPEED_10 && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
@@ -2210,9 +2244,11 @@ e1000_wait_autoneg(struct e1000_hw *hw)
         /* Read the MII Status Register and wait for Auto-Neg
          * Complete bit to be set.
          */
-        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
-        if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
         if(phy_data & MII_SR_AUTONEG_COMPLETE) {
             return E1000_SUCCESS;
@@ -2377,8 +2413,9 @@ e1000_read_phy_reg(struct e1000_hw *hw,
 
     if(hw->phy_type == e1000_phy_igp &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
-        if((ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
-                                             (uint16_t)reg_addr)))
+        ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                         (uint16_t)reg_addr);
+        if(ret_val)
             return ret_val;
     }
 
@@ -2480,8 +2517,9 @@ e1000_write_phy_reg(struct e1000_hw *hw,
 
     if(hw->phy_type == e1000_phy_igp &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
-        if((ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
-                                             (uint16_t)reg_addr)))
+        ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                         (uint16_t)reg_addr);
+        if(ret_val)
             return ret_val;
     }
 
@@ -2620,11 +2658,13 @@ e1000_phy_reset(struct e1000_hw *hw)
     DEBUGFUNC("e1000_phy_reset");
 
     if(hw->mac_type != e1000_82541_rev_2) {
-        if((ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data |= MII_CR_RESET;
-        if((ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data)))
+        ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+        if(ret_val)
             return ret_val;
 
         udelay(1);
@@ -2651,12 +2691,14 @@ e1000_detect_gig_phy(struct e1000_hw *hw
     DEBUGFUNC("e1000_detect_gig_phy");
 
     /* Read the PHY ID Registers to identify which PHY is onboard. */
-    if((ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high)))
+    ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
+    if(ret_val)
         return ret_val;
 
     hw->phy_id = (uint32_t) (phy_id_high << 16);
     udelay(20);
-    if((ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low)))
+    ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low);
+    if(ret_val)
         return ret_val;
 
     hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
@@ -2708,9 +2750,12 @@ e1000_phy_reset_dsp(struct e1000_hw *hw)
     DEBUGFUNC("e1000_phy_reset_dsp");
 
     do {
-        if((ret_val = e1000_write_phy_reg(hw, 29, 0x001d))) break;
-        if((ret_val = e1000_write_phy_reg(hw, 30, 0x00c1))) break;
-        if((ret_val = e1000_write_phy_reg(hw, 30, 0x0000))) break;
+        ret_val = e1000_write_phy_reg(hw, 29, 0x001d);
+        if(ret_val) break;
+        ret_val = e1000_write_phy_reg(hw, 30, 0x00c1);
+        if(ret_val) break;
+        ret_val = e1000_write_phy_reg(hw, 30, 0x0000);
+        if(ret_val) break;
         ret_val = E1000_SUCCESS;
     } while(0);
 
@@ -2743,13 +2788,14 @@ e1000_phy_igp_get_info(struct e1000_hw *
     phy_info->polarity_correction = e1000_polarity_reversal_enabled;
 
     /* Check polarity status */
-    if((ret_val = e1000_check_polarity(hw, &polarity)))
+    ret_val = e1000_check_polarity(hw, &polarity);
+    if(ret_val)
         return ret_val;
 
     phy_info->cable_polarity = polarity;
 
-    if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
-                                     &phy_data)))
+    ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
@@ -2758,7 +2804,8 @@ e1000_phy_igp_get_info(struct e1000_hw *
     if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
        IGP01E1000_PSSR_SPEED_1000MBPS) {
         /* Local/Remote Receiver Information are only valid at 1000 Mbps */
-        if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
@@ -2767,7 +2814,8 @@ e1000_phy_igp_get_info(struct e1000_hw *
                               SR_1000T_REMOTE_RX_STATUS_SHIFT;
 
         /* Get cable length */
-        if((ret_val = e1000_get_cable_length(hw, &min_length, &max_length)))
+        ret_val = e1000_get_cable_length(hw, &min_length, &max_length);
+        if(ret_val)
             return ret_val;
 
         /* transalte to old method */
@@ -2807,7 +2855,8 @@ e1000_phy_m88_get_info(struct e1000_hw *
      * and it stored in the hw->speed_downgraded parameter. */
     phy_info->downshift = hw->speed_downgraded;
 
-    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data)))
+    ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_info->extended_10bt_distance =
@@ -2818,12 +2867,14 @@ e1000_phy_m88_get_info(struct e1000_hw *
         M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
 
     /* Check polarity status */
-    if((ret_val = e1000_check_polarity(hw, &polarity)))
+    ret_val = e1000_check_polarity(hw, &polarity);
+    if(ret_val)
         return ret_val;
 
     phy_info->cable_polarity = polarity;
 
-    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data)))
+    ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
@@ -2836,7 +2887,8 @@ e1000_phy_m88_get_info(struct e1000_hw *
         phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
                                   M88E1000_PSSR_CABLE_LENGTH_SHIFT);
 
-        if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
@@ -2878,10 +2930,12 @@ e1000_phy_get_info(struct e1000_hw *hw,
         return -E1000_ERR_CONFIG;
     }
 
-    if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+    ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data)))
+    ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+    if(ret_val)
         return ret_val;
 
     if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
@@ -3344,6 +3398,7 @@ e1000_spi_eeprom_ready(struct e1000_hw *
         udelay(5);
         retry_count += 5;
 
+        e1000_standby_eeprom(hw);
     } while(retry_count < EEPROM_MAX_RETRY_SPI);
 
     /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
@@ -4112,12 +4167,14 @@ e1000_setup_led(struct e1000_hw *hw)
     case e1000_82541_rev_2:
     case e1000_82547_rev_2:
         /* Turn off PHY Smart Power Down (if enabled) */
-        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
-                                         &hw->phy_spd_default)))
-            return ret_val;
-        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
-                                          (uint16_t)(hw->phy_spd_default &
-                                          ~IGP01E1000_GMII_SPD))))
+        ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                     &hw->phy_spd_default);
+        if(ret_val)
+            return ret_val;
+        ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                      (uint16_t)(hw->phy_spd_default &
+                                      ~IGP01E1000_GMII_SPD));
+        if(ret_val)
             return ret_val;
         /* Fall Through */
     default:
@@ -4164,8 +4221,9 @@ e1000_cleanup_led(struct e1000_hw *hw)
     case e1000_82541_rev_2:
     case e1000_82547_rev_2:
         /* Turn on PHY Smart Power Down (if previously enabled) */
-        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
-                                          hw->phy_spd_default)))
+        ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
+                                      hw->phy_spd_default);
+        if(ret_val)
             return ret_val;
         /* Fall Through */
     default:
@@ -4612,8 +4670,9 @@ e1000_get_cable_length(struct e1000_hw *
 
     /* Use old method for Phy older than IGP */
     if(hw->phy_type == e1000_phy_m88) {
-        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
 
         /* Convert the enum value to ranged values */
@@ -4652,7 +4711,8 @@ e1000_get_cable_length(struct e1000_hw *
         /* Read the AGC registers for all channels */
         for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
 
-            if((ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data)))
+            ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data);
+            if(ret_val)
                 return ret_val;
 
             cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
@@ -4719,15 +4779,17 @@ e1000_check_polarity(struct e1000_hw *hw
 
     if(hw->phy_type == e1000_phy_m88) {
         /* return the Polarity bit in the Status register. */
-        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
         *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
                     M88E1000_PSSR_REV_POLARITY_SHIFT;
     } else if(hw->phy_type == e1000_phy_igp) {
         /* Read the Status register to check the speed */
-        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
 
         /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
@@ -4736,8 +4798,9 @@ e1000_check_polarity(struct e1000_hw *hw
            IGP01E1000_PSSR_SPEED_1000MBPS) {
 
             /* Read the GIG initialization PCS register (0x00B4) */
-            if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
-                                             &phy_data)))
+            ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
+                                         &phy_data);
+            if(ret_val)
                 return ret_val;
 
             /* Check the polarity bits */
@@ -4775,15 +4838,17 @@ e1000_check_downshift(struct e1000_hw *h
     DEBUGFUNC("e1000_check_downshift");
 
     if(hw->phy_type == e1000_phy_igp) {
-        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
 
         hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
     }
     else if(hw->phy_type == e1000_phy_m88) {
-        if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                     &phy_data);
+        if(ret_val)
             return ret_val;
 
         hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
@@ -4823,7 +4888,8 @@ e1000_config_dsp_after_link_change(struc
         return E1000_SUCCESS;
 
     if(link_up) {
-        if((ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex))) {
+        ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
+        if(ret_val) {
             DEBUGOUT("Error getting link speed and duplex\n");
             return ret_val;
         }
@@ -4836,14 +4902,16 @@ e1000_config_dsp_after_link_change(struc
                 min_length >= e1000_igp_cable_length_50) {
 
                 for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
-                    if((ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i],
-                                                     &phy_data)))
+                    ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i],
+                                                 &phy_data);
+                    if(ret_val)
                         return ret_val;
 
                     phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
 
-                    if((ret_val = e1000_write_phy_reg(hw, dsp_reg_array[i],
-                                                      phy_data)))
+                    ret_val = e1000_write_phy_reg(hw, dsp_reg_array[i],
+                                                  phy_data);
+                    if(ret_val)
                         return ret_val;
                 }
                 hw->dsp_config_state = e1000_dsp_config_activated;
@@ -4856,23 +4924,26 @@ e1000_config_dsp_after_link_change(struc
                 uint32_t idle_errs = 0;
 
                 /* clear previous idle error counts */
-                if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
-                                                 &phy_data)))
+                ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
+                                             &phy_data);
+                if(ret_val)
                     return ret_val;
 
                 for(i = 0; i < ffe_idle_err_timeout; i++) {
                     udelay(1000);
-                    if((ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
-                                                     &phy_data)))
+                    ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
+                                                 &phy_data);
+                    if(ret_val)
                         return ret_val;
 
                     idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
                     if(idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
                         hw->ffe_config_state = e1000_ffe_config_active;
 
-                        if((ret_val = e1000_write_phy_reg(hw,
+                        ret_val = e1000_write_phy_reg(hw,
                                     IGP01E1000_PHY_DSP_FFE,
-                                    IGP01E1000_PHY_DSP_FFE_CM_CP)))
+                                    IGP01E1000_PHY_DSP_FFE_CM_CP);
+                        if(ret_val)
                             return ret_val;
                         break;
                     }
@@ -4884,47 +4955,91 @@ e1000_config_dsp_after_link_change(struc
         }
     } else {
         if(hw->dsp_config_state == e1000_dsp_config_activated) {
-            if((ret_val = e1000_write_phy_reg(hw, 0x0000,
-                IGP01E1000_IEEE_FORCE_GIGA)))
+            ret_val = e1000_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_FORCE_GIGA);
+            if(ret_val)
                 return ret_val;
             for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
-                if((ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i],
-                                                 &phy_data)))
+                ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i], &phy_data);
+                if(ret_val)
                     return ret_val;
 
                 phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
                 phy_data |=  IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
 
-                if((ret_val = e1000_write_phy_reg(hw,dsp_reg_array[i],
-                                                  phy_data)))
+                ret_val = e1000_write_phy_reg(hw,dsp_reg_array[i], phy_data);
+                if(ret_val)
                     return ret_val;
             }
 
-            if((ret_val = e1000_write_phy_reg(hw, 0x0000,
-                                              IGP01E1000_IEEE_RESTART_AUTONEG)))
+            ret_val = e1000_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_RESTART_AUTONEG);
+            if(ret_val)
                 return ret_val;
 
             hw->dsp_config_state = e1000_dsp_config_enabled;
         }
 
         if(hw->ffe_config_state == e1000_ffe_config_active) {
-            if((ret_val = e1000_write_phy_reg(hw, 0x0000,
-                                              IGP01E1000_IEEE_FORCE_GIGA)))
+            ret_val = e1000_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_FORCE_GIGA);
+            if(ret_val)
                 return ret_val;
-            if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE,
-                                              IGP01E1000_PHY_DSP_FFE_DEFAULT)))
+            ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE,
+                                          IGP01E1000_PHY_DSP_FFE_DEFAULT);
+            if(ret_val)
                 return ret_val;
 
-            if((ret_val = e1000_write_phy_reg(hw, 0x0000,
-                                              IGP01E1000_IEEE_RESTART_AUTONEG)))
+            ret_val = e1000_write_phy_reg(hw, 0x0000,
+                                          IGP01E1000_IEEE_RESTART_AUTONEG);
+            if(ret_val)
                 return ret_val;
-        hw->ffe_config_state = e1000_ffe_config_enabled;
+            hw->ffe_config_state = e1000_ffe_config_enabled;
         }
     }
     return E1000_SUCCESS;
 }
 
 /*****************************************************************************
+ * Set PHY to class A mode
+ * Assumes the following operations will follow to enable the new class mode.
+ *  1. Do a PHY soft reset
+ *  2. Restart auto-negotiation or force link.
+ *
+ * hw - Struct containing variables accessed by shared code
+ ****************************************************************************/
+static int32_t
+e1000_set_phy_mode(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("e1000_set_phy_mode");
+
+    if((hw->mac_type == e1000_82545_rev_3) &&
+       (hw->media_type == e1000_media_type_copper)) {
+        ret_val = e1000_read_eeprom(hw, EEPROM_PHY_CLASS_WORD, 1, &eeprom_data);
+        if(ret_val) {
+            return ret_val;
+        }
+
+        if((eeprom_data != EEPROM_RESERVED_WORD) &&
+           (eeprom_data & EEPROM_PHY_CLASS_A)) {
+            ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x000B);
+            if(ret_val)
+                return ret_val;
+            ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x8104);
+            if(ret_val)
+                return ret_val;
+
+            hw->phy_reset_disable = FALSE;
+        }
+    }
+
+    return E1000_SUCCESS;
+}
+
+/*****************************************************************************
  *
  * This function sets the lplu state according to the active flag.  When
  * activating lplu this function also disables smart speed and vise versa.
@@ -4953,25 +5068,27 @@ e1000_set_d3_lplu_state(struct e1000_hw 
     /* During driver activity LPLU should not be used or it will attain link
      * from the lowest speeds starting from 10Mbps. The capability is used for
      * Dx transitions and states */
-    if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data)))
+    ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
+    if(ret_val)
         return ret_val;
 
     if(!active) {
         phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
-        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data)))
+        ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+        if(ret_val)
             return ret_val;
 
         /* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
          * Dx states where the power conservation is most important.  During
          * driver activity we should enable SmartSpeed, so performance is
          * maintained. */
-        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
-        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                          phy_data)))
+        ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+        if(ret_val)
             return ret_val;
 
     } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
@@ -4979,17 +5096,18 @@ e1000_set_d3_lplu_state(struct e1000_hw 
               (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
 
         phy_data |= IGP01E1000_GMII_FLEX_SPD;
-        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data)))
+        ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
+        if(ret_val)
             return ret_val;
 
         /* When LPLU is enabled we should disable SmartSpeed */
-        if((ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                         &phy_data)))
+        ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
+        if(ret_val)
             return ret_val;
 
         phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-        if((ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-                                          phy_data)))
+        ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
+        if(ret_val)
             return ret_val;
 
     }
@@ -5020,34 +5138,40 @@ e1000_set_vco_speed(struct e1000_hw *hw)
 
     /* Set PHY register 30, page 5, bit 8 to 0 */
 
-    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT,
-                                     &default_page)))
+    ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, &default_page);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005)))
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data)))
+    ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
-    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data)))
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+    if(ret_val)
         return ret_val;
 
     /* Set PHY register 30, page 4, bit 11 to 1 */
 
-    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004)))
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data)))
+    ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
+    if(ret_val)
         return ret_val;
 
     phy_data |= M88E1000_PHY_VCO_REG_BIT11;
-    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data)))
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
+    if(ret_val)
         return ret_val;
 
-    if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT,
-                                      default_page)))
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, default_page);
+    if(ret_val)
         return ret_val;
 
     return E1000_SUCCESS;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e1000/e1000_hw.h linux-2.4.27-pre3/drivers/net/e1000/e1000_hw.h
--- linux-2.4.26/drivers/net/e1000/e1000_hw.h	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e1000/e1000_hw.h	2004-05-18 16:51:37.000000000 +0000
@@ -369,6 +369,9 @@ int32_t e1000_set_d3_lplu_state(struct e
 
 #define E1000_82542_2_0_REV_ID 2
 #define E1000_82542_2_1_REV_ID 3
+#define E1000_REVISION_0       0
+#define E1000_REVISION_1       1
+#define E1000_REVISION_2       2
 
 #define SPEED_10    10
 #define SPEED_100   100
@@ -763,6 +766,7 @@ struct e1000_ffvt_entry {
 #define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
 #define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
 #define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
 #define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
 #define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
 
@@ -899,6 +903,7 @@ struct e1000_ffvt_entry {
 #define E1000_82542_TDFT     0x08018
 #define E1000_82542_FFMT     E1000_FFMT
 #define E1000_82542_FFVT     E1000_FFVT
+#define E1000_82542_HOST_IF  E1000_HOST_IF
 
 /* Statistics counters collected by the MAC */
 struct e1000_hw_stats {
@@ -1434,6 +1439,10 @@ struct e1000_hw {
 #define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
 #define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
 #define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
+                                                    * filtering */
+#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
+                                             * memory */
 #define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
 #define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
 #define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
@@ -1480,6 +1489,7 @@ struct e1000_hw {
 #define EEPROM_COMPAT                 0x0003
 #define EEPROM_ID_LED_SETTINGS        0x0004
 #define EEPROM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
+#define EEPROM_PHY_CLASS_WORD         0x0007
 #define EEPROM_INIT_CONTROL1_REG      0x000A
 #define EEPROM_INIT_CONTROL2_REG      0x000F
 #define EEPROM_INIT_CONTROL3_PORT_B   0x0014
@@ -1513,6 +1523,9 @@ struct e1000_hw {
 /* Mask bits for SERDES amplitude adjustment in Word 6 of the EEPROM */
 #define EEPROM_SERDES_AMPLITUDE_MASK  0x000F
 
+/* Mask bit for PHY class in Word 7 of the EEPROM */
+#define EEPROM_PHY_CLASS_A   0x8000
+
 /* Mask bits for fields in Word 0x0a of the EEPROM */
 #define EEPROM_WORD0A_ILOS   0x0010
 #define EEPROM_WORD0A_SWDPIO 0x01E0
@@ -1540,7 +1553,7 @@ struct e1000_hw {
 #define PBA_SIZE 4
 
 /* Collision related configuration parameters */
-#define E1000_COLLISION_THRESHOLD       16
+#define E1000_COLLISION_THRESHOLD       15
 #define E1000_CT_SHIFT                  4
 #define E1000_COLLISION_DISTANCE        64
 #define E1000_FDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e1000/e1000_main.c linux-2.4.27-pre3/drivers/net/e1000/e1000_main.c
--- linux-2.4.26/drivers/net/e1000/e1000_main.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e1000/e1000_main.c	2004-05-18 16:52:51.000000000 +0000
@@ -30,7 +30,33 @@
 
 /* Change Log
  *
- * 5.2.30.1	1/29/03
+ * 5.2.39	3/12/04
+ *   o Added support to read/write eeprom data in proper order.
+ *     By default device eeprom is always little-endian, word
+ *     addressable 
+ *   o Disable TSO as the default for the driver until hangs
+ *     reported against non-IA acrhs can be root-caused.
+ *   o Back out the CSA fix for 82547 as it continues to cause
+ *     systems lock-ups with production systems.
+ *   o Fixed FC high/low water mark values to actually be in the
+ *     range of the Rx FIFO area.  It was a math error.
+ *     [Dainis Jonitis (dainis_jonitis@exigengroup.lv)]
+ *   o Handle failure to get new resources when doing ethtool
+ *     ring paramater changes.  Previously, driver would free old,
+ *     but fails to allocate new, causing problems.  Now, driver 
+ *     allocates new, and if sucessful, frees old.
+ *   o Changed collision threshold from 16 to 15 to comply with IEEE
+ *     spec.
+ *   o Toggle chip-select when checking ready status on SPI eeproms.
+ *   o Put PHY into class A mode to pass IEEE tests on some designs.
+ *     Designs with EEPROM word 0x7, bit 15 set will have their PHYs
+ *     set to class A mode, rather than the default class AB.
+ *   o Handle failures of register_netdev.  Stephen Hemminger
+ *     [shemminger@osdl.org].
+ *   o updated README & MAN pages, number of Transmit/Receive
+ *     descriptors may be denied depending on system resources.
+ *
+ * 5.2.30	1/14/03
  *   o Set VLAN filtering to IEEE 802.1Q after reset so we don't break
  *     SoL connections that use VLANs.
  *   o Allow 1000/Full setting for AutoNeg param for Fiber connections
@@ -42,32 +68,14 @@
  *   o Report driver message on user override of InterruptThrottleRate
  *     module parameter.
  *   o Change I/O address storage from uint32_t to unsigned long.
+ *   o Added ethtool RINGPARAM support.
  *
  * 5.2.22	10/15/03
- *   o Bug fix: SERDES devices might be connected to a back-plane
- *     switch that doesn't support auto-neg, so add the capability
- *     to force 1000/Full.  Also, since forcing 1000/Full, sample
- *     RxSynchronize bit to detect link state.
- *   o Bug fix: Flow control settings for hi/lo watermark didn't
- *     consider changes in the Rx FIFO size, which could occur with
- *     Jumbo Frames or with the reduced FIFO in 82547.
- *   o Better propagation of error codes. [Janice Girouard 
- *     (janiceg@us.ibm.com)].
- *   o Bug fix: hang under heavy Tx stress when running out of Tx
- *     descriptors; wasn't clearing context descriptor when backing
- *     out of send because of no-resource condition.
- *   o Bug fix: check netif_running in dev->poll so we don't have to
- *     hang in dev->close until all polls are finished.  [Robert
- *     Ollson (robert.olsson@data.slu.se)].
- *   o Revert TxDescriptor ring size back to 256 since change to 1024
- *     wasn't accepted into the kernel.
- *
- * 5.2.16	8/8/03
  */
 
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.2.30.1-k1";
+char e1000_driver_version[] = "5.2.39-k1";
 char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -327,14 +335,16 @@ e1000_reset(struct e1000_adapter *adapte
 		adapter->tx_fifo_head = 0;
 		adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT;
 		adapter->tx_fifo_size =
-			(E1000_PBA_40K - pba) << E1000_TX_FIFO_SIZE_SHIFT;
+			(E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT;
 		atomic_set(&adapter->tx_fifo_stall, 0);
 	}
 	E1000_WRITE_REG(&adapter->hw, PBA, pba);
 
 	/* flow control settings */
-	adapter->hw.fc_high_water = pba - E1000_FC_HIGH_DIFF;
-	adapter->hw.fc_low_water = pba - E1000_FC_LOW_DIFF;
+	adapter->hw.fc_high_water =
+		(pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_HIGH_DIFF;
+	adapter->hw.fc_low_water =
+		(pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_LOW_DIFF;
 	adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME;
 	adapter->hw.fc_send_xon = 1;
 	adapter->hw.fc = adapter->hw.original_fc;
@@ -402,6 +412,7 @@ e1000_probe(struct pci_dev *pdev,
 	}
 
 	SET_MODULE_OWNER(netdev);
+	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	pci_set_drvdata(pdev, netdev);
 	adapter = netdev->priv;
@@ -470,10 +481,15 @@ e1000_probe(struct pci_dev *pdev,
 	}
 
 #ifdef NETIF_F_TSO
+#ifdef BROKEN_ON_NON_IA_ARCHS
+	/* Disbaled for now until root-cause is found for
+	 * hangs reported against non-IA archs.  TSO can be
+	 * enabled using ethtool -K eth<x> tso on */
 	if((adapter->hw.mac_type >= e1000_82544) &&
 	   (adapter->hw.mac_type != e1000_82547))
 		netdev->features |= NETIF_F_TSO;
 #endif
+#endif
 
 	if(pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
@@ -520,7 +536,8 @@ e1000_probe(struct pci_dev *pdev,
 	INIT_TQUEUE(&adapter->tx_timeout_task,
 		(void (*)(void *))e1000_tx_timeout_task, netdev);
 
-	register_netdev(netdev);
+	if((err = register_netdev(netdev)))
+		goto err_register;
 
 	/* we're going to reset, so assume we have no link for now */
 
@@ -565,6 +582,7 @@ e1000_probe(struct pci_dev *pdev,
 	cards_found++;
 	return 0;
 
+err_register:
 err_sw_init:
 err_eeprom:
 	iounmap(adapter->hw.hw_addr);
@@ -1650,7 +1668,7 @@ e1000_tx_map(struct e1000_adapter *adapt
 		 * we mapped the skb, but because of all the workarounds
 		 * (above), it's too difficult to predict how many we're
 		 * going to need.*/
-		i = adapter->tx_ring.next_to_use;
+		i = tx_ring->next_to_use;
 
 		if(i == first) {
 			/* Cleanup after e1000_tx_[csum|tso] scribbling
@@ -1675,7 +1693,7 @@ e1000_tx_map(struct e1000_adapter *adapt
 			if(++i == tx_ring->count) i = 0;
 		}
 
-		adapter->tx_ring.next_to_use = first;
+		tx_ring->next_to_use = first;
 
 		return 0;
 	}
@@ -2122,26 +2140,10 @@ e1000_intr(int irq, void *data, struct p
 		__netif_rx_schedule(netdev);
 	}
 #else
-        /* Writing IMC and IMS is needed for 82547.
-	   Due to Hub Link bus being occupied, an interrupt 
-	   de-assertion message is not able to be sent. 
-	   When an interrupt assertion message is generated later,
-	   two messages are re-ordered and sent out.
-	   That causes APIC to think 82547 is in de-assertion
-	   state, while 82547 is in assertion state, resulting 
-	   in dead lock. Writing IMC forces 82547 into 
-	   de-assertion state.
-        */
-	if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2)
-		e1000_irq_disable(adapter);
-
 	for(i = 0; i < E1000_MAX_INTR; i++)
 		if(!e1000_clean_rx_irq(adapter) &
 		   !e1000_clean_tx_irq(adapter))
 			break;
-
-	if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2)
-		e1000_irq_enable(adapter);
 #endif
 
 	return IRQ_HANDLED;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e1000/e1000_osdep.h linux-2.4.27-pre3/drivers/net/e1000/e1000_osdep.h
--- linux-2.4.26/drivers/net/e1000/e1000_osdep.h	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e1000/e1000_osdep.h	2004-05-18 16:52:09.000000000 +0000
@@ -47,7 +47,7 @@
 	                	BUG(); \
 			} else { \
 				set_current_state(TASK_UNINTERRUPTIBLE); \
-				schedule_timeout((x * HZ)/1000); \
+				schedule_timeout((x * HZ)/1000 + 2); \
 			} } while(0)
 #endif
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/e1000/e1000_param.c linux-2.4.27-pre3/drivers/net/e1000/e1000_param.c
--- linux-2.4.26/drivers/net/e1000/e1000_param.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/e1000/e1000_param.c	2004-05-18 16:51:29.000000000 +0000
@@ -107,7 +107,7 @@ E1000_PARAM(Duplex, "Duplex setting");
 
 /* Auto-negotiation Advertisement Override
  *
- * Valid Range: 0x01-0x0F, 0x20-0x2F
+ * Valid Range: 0x01-0x0F, 0x20-0x2F (copper); 0x20 (fiber)
  *
  * The AutoNeg value is a bit mask describing which speed and duplex
  * combinations should be advertised during auto-negotiation.
@@ -117,7 +117,7 @@ E1000_PARAM(Duplex, "Duplex setting");
  * Speed (Mbps)  N/A   N/A   1000   N/A    100   100   10     10
  * Duplex                    Full          Full  Half  Full   Half
  *
- * Default Value: 0x2F
+ * Default Value: 0x2F (copper); 0x20 (fiber)
  */
 
 E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/ibmveth.c linux-2.4.27-pre3/drivers/net/ibmveth.c
--- linux-2.4.26/drivers/net/ibmveth.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/ibmveth.c	2004-05-18 16:54:29.000000000 +0000
@@ -0,0 +1,1121 @@
+/**************************************************************************/
+/*                                                                        */
+/* IBM eServer i/pSeries Virtual Ethernet Device Driver                   */
+/* Copyright (C) 2003 Dave Larson (larson1@us.ibm.com), IBM Corp.         */
+/*                                                                        */
+/*  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  */
+/*                                                                        */
+/* This module contains the implementation of a virtual ethernet device   */
+/* for use with IBM i/pSeries LPAR Linux.  It utilizes the logical LAN    */
+/* option of the RS/6000 Platform Architechture to interface with virtual */
+/* ethernet NICs that are presented to the partition by the hypervisor.   */
+/*                                                                        */ 
+/**************************************************************************/
+/*
+  TODO:
+  - remove frag processing code - no longer needed
+  - add support for sysfs
+  - possibly remove procfs support
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/ethtool.h>
+#include <linux/proc_fs.h>
+#include <asm/semaphore.h>
+#include <asm/hvcall.h>
+#include <asm/atomic.h>
+#include <asm/pci_dma.h>
+#include <asm/vio.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include "ibmveth.h"
+
+#define DEBUG 1
+
+#define ibmveth_printk(fmt, args...) \
+  printk(KERN_INFO "%s: " fmt, __FILE__, ## args)
+
+#define ibmveth_error_printk(fmt, args...) \
+  printk(KERN_ERR "(%s:%3.3d ua:%lx) ERROR: " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args)
+
+#ifdef DEBUG
+#define ibmveth_debug_printk_no_adapter(fmt, args...) \
+  printk(KERN_DEBUG "(%s:%3.3d): " fmt, __FILE__, __LINE__ , ## args)
+#define ibmveth_debug_printk(fmt, args...) \
+  printk(KERN_DEBUG "(%s:%3.3d ua:%lx): " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args)
+#define ibmveth_assert(expr) \
+  if(!(expr)) {                                   \
+    printk(KERN_DEBUG "assertion failed (%s:%3.3d ua:%lx): %s\n", __FILE__, __LINE__, adapter->vdev->unit_address, #expr); \
+    BUG(); \
+  }
+#else
+#define ibmveth_debug_printk_no_adapter(fmt, args...)
+#define ibmveth_debug_printk(fmt, args...)
+#define ibmveth_assert(expr) 
+#endif
+
+static int ibmveth_open(struct net_device *dev);
+static int ibmveth_close(struct net_device *dev);
+static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int ibmveth_poll(struct net_device *dev, int *budget);
+static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static struct net_device_stats *ibmveth_get_stats(struct net_device *dev);
+static void ibmveth_set_multicast_list(struct net_device *dev);
+static void ibmveth_proc_register_driver(void);
+static void ibmveth_proc_unregister_driver(void);
+static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter);
+static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter);
+
+#define IBMVETH_PROC_DIR "ibmveth"
+static struct proc_dir_entry *ibmveth_proc_dir;
+
+static const char ibmveth_driver_name[] = "ibmveth";
+static const char ibmveth_driver_string[] = "IBM i/pSeries Virtual Ethernet Driver";
+static const char ibmveth_driver_version[] = "1.0";
+
+MODULE_AUTHOR("Dave Larson <larson1@us.ibm.com>");
+MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver");
+MODULE_LICENSE("GPL");
+
+/* simple methods of getting data from the current rxq entry */
+static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter)
+{
+	return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].toggle == adapter->rx_queue.toggle);
+}
+
+static inline int ibmveth_rxq_buffer_valid(struct ibmveth_adapter *adapter)
+{
+	return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].valid);
+}
+
+static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
+{
+	return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].offset);
+}
+
+static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
+{
+	return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
+}
+
+/* setup the initial settings for a buffer pool */
+static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size)
+{
+	pool->size = pool_size;
+	pool->index = pool_index;
+	pool->buff_size = buff_size;
+	pool->threshold = pool_size / 2;
+}
+
+/* allocate and setup an buffer pool - called during open */
+static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
+{
+	int i;
+
+	pool->free_map = kmalloc(sizeof(u16) * pool->size, GFP_KERNEL); 
+
+	if(!pool->free_map) {
+		return -1;
+	}
+
+	pool->dma_addr = kmalloc(sizeof(dma_addr_t) * pool->size, GFP_KERNEL); 
+	if(!pool->dma_addr) {
+		kfree(pool->free_map);
+		pool->free_map = NULL;
+		return -1;
+	}
+
+	pool->skbuff = kmalloc(sizeof(void*) * pool->size, GFP_KERNEL);
+
+	if(!pool->skbuff) {
+		kfree(pool->dma_addr);
+		pool->dma_addr = NULL;
+
+		kfree(pool->free_map);
+		pool->free_map = NULL;
+		return -1;
+	}
+
+	memset(pool->skbuff, 0, sizeof(void*) * pool->size);
+	memset(pool->dma_addr, 0, sizeof(dma_addr_t) * pool->size);
+
+	for(i = 0; i < pool->size; ++i) {
+		pool->free_map[i] = i;
+	}
+
+	atomic_set(&pool->available, 0);
+	pool->producer_index = 0;
+	pool->consumer_index = 0;
+
+	return 0;
+}
+
+/* replenish the buffers for a pool.  note that we don't need to
+ * skb_reserve these since they are used for incoming...
+ */
+static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struct ibmveth_buff_pool *pool)
+{
+	u32 i;
+	u32 count = pool->size - atomic_read(&pool->available);
+	u32 buffers_added = 0;
+
+	mb();
+
+	for(i = 0; i < count; ++i) {
+		struct sk_buff *skb;
+		unsigned int free_index, index;
+		u64 correlator;
+		union ibmveth_buf_desc desc;
+		unsigned long lpar_rc;
+		dma_addr_t dma_addr;
+
+		skb = alloc_skb(pool->buff_size, GFP_ATOMIC);
+
+		if(!skb) {
+			ibmveth_debug_printk("replenish: unable to allocate skb\n");
+			adapter->replenish_no_mem++;
+			break;
+		}
+
+		free_index = pool->consumer_index++ % pool->size;
+		index = pool->free_map[free_index];
+	
+		ibmveth_assert(index != 0xffff);
+		ibmveth_assert(pool->skbuff[index] == NULL);
+
+		dma_addr = vio_map_single(adapter->vdev, skb->data, pool->buff_size, PCI_DMA_FROMDEVICE);
+
+		pool->dma_addr[index] = dma_addr;
+		pool->skbuff[index] = skb;
+
+		correlator = ((u64)pool->index << 32) | index;
+		*(u64*)skb->data = correlator;
+
+		desc.desc = 0;
+		desc.fields.valid = 1;
+		desc.fields.length = pool->buff_size;
+		desc.fields.address = dma_addr; 
+
+		lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
+		    
+		if(lpar_rc != H_Success) {
+			pool->skbuff[index] = NULL;
+			pool->consumer_index--;
+			vio_unmap_single(adapter->vdev, pool->dma_addr[index], pool->buff_size, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb_any(skb);
+			adapter->replenish_add_buff_failure++;
+			break;
+		} else {
+			pool->free_map[free_index] = 0xffff;
+			buffers_added++;
+			adapter->replenish_add_buff_success++;
+		}
+	}
+    
+	atomic_add(buffers_added, &(pool->available));
+}
+
+/* check if replenishing is needed.  */
+static inline int ibmveth_is_replenishing_needed(struct ibmveth_adapter *adapter)
+{
+	return ((atomic_read(&adapter->rx_buff_pool[0].available) < adapter->rx_buff_pool[0].threshold) ||
+		(atomic_read(&adapter->rx_buff_pool[1].available) < adapter->rx_buff_pool[1].threshold) ||
+		(atomic_read(&adapter->rx_buff_pool[2].available) < adapter->rx_buff_pool[2].threshold));
+}
+
+/* replenish tasklet routine */
+static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) 
+{
+	adapter->replenish_task_cycles++;
+
+	ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[0]);
+	ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[1]);
+	ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[2]);
+
+	adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8);
+}
+
+/* kick the replenish tasklet if we need replenishing and it isn't already running */
+static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter *adapter)
+{
+	if(ibmveth_is_replenishing_needed(adapter)) {	
+		tasklet_schedule(&adapter->replenish_task);
+	}
+}
+
+/* empty and free ana buffer pool - also used to do cleanup in error paths */
+static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibmveth_buff_pool *pool)
+{
+	int i;
+
+	if(pool->free_map) {
+		kfree(pool->free_map);
+		pool->free_map  = NULL;
+	}
+
+	if(pool->skbuff && pool->dma_addr) {
+		for(i = 0; i < pool->size; ++i) {
+			struct sk_buff *skb = pool->skbuff[i];
+			if(skb) {
+				vio_unmap_single(adapter->vdev,
+						 pool->dma_addr[i],
+						 pool->buff_size,
+						 PCI_DMA_FROMDEVICE);
+				dev_kfree_skb_any(skb);
+				pool->skbuff[i] = NULL;
+			}
+		}
+	}
+
+	if(pool->dma_addr) {
+		kfree(pool->dma_addr);
+		pool->dma_addr = NULL;
+	}
+
+	if(pool->skbuff) {
+		kfree(pool->skbuff);
+		pool->skbuff = NULL;
+	}
+}
+
+/* remove a buffer from a pool */
+static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64 correlator)
+{
+	unsigned int pool  = correlator >> 32;
+	unsigned int index = correlator & 0xffffffffUL;
+	unsigned int free_index;
+	struct sk_buff *skb;
+
+	ibmveth_assert(pool < IbmVethNumBufferPools);
+	ibmveth_assert(index < adapter->rx_buff_pool[pool].size);
+
+	skb = adapter->rx_buff_pool[pool].skbuff[index];
+
+	ibmveth_assert(skb != NULL);
+
+	adapter->rx_buff_pool[pool].skbuff[index] = NULL;
+
+	vio_unmap_single(adapter->vdev,
+			 adapter->rx_buff_pool[pool].dma_addr[index],
+			 adapter->rx_buff_pool[pool].buff_size,
+			 PCI_DMA_FROMDEVICE);
+
+	free_index = adapter->rx_buff_pool[pool].producer_index++ % adapter->rx_buff_pool[pool].size;
+	adapter->rx_buff_pool[pool].free_map[free_index] = index;
+
+	mb();
+
+	atomic_dec(&(adapter->rx_buff_pool[pool].available));
+}
+
+/* get the current buffer on the rx queue */
+static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *adapter)
+{
+	u64 correlator = adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator;
+	unsigned int pool = correlator >> 32;
+	unsigned int index = correlator & 0xffffffffUL;
+
+	ibmveth_assert(pool < IbmVethNumBufferPools);
+	ibmveth_assert(index < adapter->rx_buff_pool[pool].size);
+
+	return adapter->rx_buff_pool[pool].skbuff[index];
+}
+
+/* recycle the current buffer on the rx queue */
+static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
+{
+	u32 q_index = adapter->rx_queue.index;
+	u64 correlator = adapter->rx_queue.queue_addr[q_index].correlator;
+	unsigned int pool = correlator >> 32;
+	unsigned int index = correlator & 0xffffffffUL;
+	union ibmveth_buf_desc desc;
+	unsigned long lpar_rc;
+
+	ibmveth_assert(pool < IbmVethNumBufferPools);
+	ibmveth_assert(index < adapter->rx_buff_pool[pool].size);
+
+	desc.desc = 0;
+	desc.fields.valid = 1;
+	desc.fields.length = adapter->rx_buff_pool[pool].buff_size;
+	desc.fields.address = adapter->rx_buff_pool[pool].dma_addr[index];
+
+	lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
+		    
+	if(lpar_rc != H_Success) {
+		ibmveth_debug_printk("h_add_logical_lan_buffer failed during recycle rc=%ld", lpar_rc);
+		ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
+	}
+
+	if(++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
+		adapter->rx_queue.index = 0;
+		adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
+	}
+}
+
+static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
+{
+	ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
+
+	if(++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
+		adapter->rx_queue.index = 0;
+		adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
+	}
+}
+
+static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
+{
+	if(adapter->buffer_list_addr != NULL) {
+		if(adapter->buffer_list_dma != NO_TCE) {
+			vio_unmap_single(adapter->vdev, adapter->buffer_list_dma, 4096, PCI_DMA_BIDIRECTIONAL);
+			adapter->buffer_list_dma = NO_TCE;
+		}
+		free_page((unsigned long)adapter->buffer_list_addr);
+		adapter->buffer_list_addr = NULL;
+	} 
+
+	if(adapter->filter_list_addr != NULL) {
+		if(adapter->filter_list_dma != NO_TCE) {
+			vio_unmap_single(adapter->vdev, adapter->filter_list_dma, 4096, PCI_DMA_BIDIRECTIONAL);
+			adapter->filter_list_dma = NO_TCE;
+		}
+		free_page((unsigned long)adapter->filter_list_addr);
+		adapter->filter_list_addr = NULL;
+	}
+
+	if(adapter->rx_queue.queue_addr != NULL) {
+		if(adapter->rx_queue.queue_dma != NO_TCE) {
+			vio_unmap_single(adapter->vdev, adapter->rx_queue.queue_dma, adapter->rx_queue.queue_len, PCI_DMA_BIDIRECTIONAL);
+			adapter->rx_queue.queue_dma = NO_TCE;
+		}
+		kfree(adapter->rx_queue.queue_addr);
+		adapter->rx_queue.queue_addr = NULL;
+	}
+
+	ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[0]);
+	ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[1]);
+	ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[2]);
+}
+
+static int ibmveth_open(struct net_device *netdev)
+{
+	struct ibmveth_adapter *adapter = netdev->priv;
+	u64 mac_address = 0;
+	int rxq_entries;
+	unsigned long lpar_rc;
+	int rc;
+	union ibmveth_buf_desc rxq_desc;
+
+	ibmveth_debug_printk("open starting\n");
+
+	rxq_entries =
+		adapter->rx_buff_pool[0].size +
+		adapter->rx_buff_pool[1].size +
+		adapter->rx_buff_pool[2].size + 1;
+    
+	adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
+	adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
+ 
+	if(!adapter->buffer_list_addr || !adapter->filter_list_addr) {
+		ibmveth_error_printk("unable to allocate filter or buffer list pages\n");
+		ibmveth_cleanup(adapter);
+		return -ENOMEM;
+	}
+
+	adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) * rxq_entries;
+	adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len, GFP_KERNEL);
+
+	if(!adapter->rx_queue.queue_addr) {
+		ibmveth_error_printk("unable to allocate rx queue pages\n");
+		ibmveth_cleanup(adapter);
+		return -ENOMEM;
+	}
+
+	adapter->buffer_list_dma = vio_map_single(adapter->vdev, adapter->buffer_list_addr, 4096, PCI_DMA_BIDIRECTIONAL);
+	adapter->filter_list_dma = vio_map_single(adapter->vdev, adapter->filter_list_addr, 4096, PCI_DMA_BIDIRECTIONAL);
+	adapter->rx_queue.queue_dma = vio_map_single(adapter->vdev, adapter->rx_queue.queue_addr, adapter->rx_queue.queue_len, PCI_DMA_BIDIRECTIONAL);
+
+	if((adapter->buffer_list_dma == NO_TCE) || 
+	   (adapter->filter_list_dma == NO_TCE) || 
+	   (adapter->rx_queue.queue_dma == NO_TCE)) {
+		ibmveth_error_printk("unable to map filter or buffer list pages\n");
+		ibmveth_cleanup(adapter);
+		return -ENOMEM;
+	}
+
+	adapter->rx_queue.index = 0;
+	adapter->rx_queue.num_slots = rxq_entries;
+	adapter->rx_queue.toggle = 1;
+
+	if(ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[0]) ||
+	   ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[1]) ||
+	   ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[2]))
+	{
+		ibmveth_error_printk("unable to allocate buffer pools\n");
+		ibmveth_cleanup(adapter);
+		return -ENOMEM;
+	}
+
+	memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
+	mac_address = mac_address >> 16;
+
+	rxq_desc.desc = 0;
+	rxq_desc.fields.valid = 1;
+	rxq_desc.fields.length = adapter->rx_queue.queue_len;
+	rxq_desc.fields.address = adapter->rx_queue.queue_dma;
+
+	ibmveth_debug_printk("buffer list @ 0x%p\n", adapter->buffer_list_addr);
+	ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr);
+	ibmveth_debug_printk("receive q   @ 0x%p\n", adapter->rx_queue.queue_addr);
+
+    
+	lpar_rc = h_register_logical_lan(adapter->vdev->unit_address,
+					 adapter->buffer_list_dma,
+					 rxq_desc.desc,
+					 adapter->filter_list_dma,
+					 mac_address);
+
+	if(lpar_rc != H_Success) {
+		ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc);
+		ibmveth_error_printk("buffer TCE:0x%x filter TCE:0x%x rxq desc:0x%lx MAC:0x%lx\n",
+				     adapter->buffer_list_dma,
+				     adapter->filter_list_dma,
+				     rxq_desc.desc,
+				     mac_address);
+		ibmveth_cleanup(adapter);
+		return -ENONET; 
+	}
+
+	ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq);
+	if((rc = request_irq(netdev->irq, &ibmveth_interrupt, 0, netdev->name, netdev)) != 0) {
+		ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc);
+		h_free_logical_lan(adapter->vdev->unit_address);
+		ibmveth_cleanup(adapter);
+		return rc;
+	}
+
+	netif_start_queue(netdev);
+
+	ibmveth_debug_printk("scheduling initial replenish cycle\n");
+	ibmveth_schedule_replenishing(adapter);
+
+	ibmveth_debug_printk("open complete\n");
+
+	return 0;
+}
+
+static int ibmveth_close(struct net_device *netdev)
+{
+	struct ibmveth_adapter *adapter = netdev->priv;
+	long lpar_rc;
+    
+	ibmveth_debug_printk("close starting\n");
+
+	netif_stop_queue(netdev);
+
+	free_irq(netdev->irq, netdev);
+
+	tasklet_kill(&adapter->replenish_task);
+
+	lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+
+	if(lpar_rc != H_Success)
+	{
+		ibmveth_error_printk("h_free_logical_lan failed with %lx, continuing with close\n",
+				     lpar_rc);
+	}
+
+	adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8);
+
+	ibmveth_cleanup(adapter);
+
+	ibmveth_debug_printk("close complete\n");
+
+	return 0;
+}
+
+static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) {
+	cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
+	cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | ADVERTISED_FIBRE);
+	cmd->speed = SPEED_1000;
+	cmd->duplex = DUPLEX_FULL;
+	cmd->port = PORT_FIBRE;
+	cmd->phy_address = 0;
+	cmd->transceiver = XCVR_INTERNAL;
+	cmd->autoneg = AUTONEG_ENABLE;
+	cmd->maxtxpkt = 0;
+	cmd->maxrxpkt = 1;
+	return 0;
+}
+
+static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) {
+	strncpy(info->driver, ibmveth_driver_name, sizeof(info->driver) - 1);
+	strncpy(info->version, ibmveth_driver_version, sizeof(info->version) - 1);
+}
+
+static u32 netdev_get_link(struct net_device *dev) {
+	return 0;
+}
+
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+	.get_settings		= netdev_get_settings,
+	.get_link		= netdev_get_link,
+	.get_sg			= ethtool_op_get_sg,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+};
+
+static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+#define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1))
+
+static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct ibmveth_adapter *adapter = netdev->priv;
+	union ibmveth_buf_desc desc[IbmVethMaxSendFrags];
+	unsigned long lpar_rc;
+	int nfrags = 0, curfrag;
+
+	if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) {
+		adapter->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	memset(&desc, 0, sizeof(desc));
+
+	/* nfrags = number of frags after the initial fragment */
+	nfrags = skb_shinfo(skb)->nr_frags;
+
+	if(nfrags)
+		adapter->tx_multidesc_send++;
+
+	/* map the initial fragment */
+	desc[0].fields.length  = nfrags ? skb->len - skb->data_len : skb->len;
+	desc[0].fields.address = vio_map_single(adapter->vdev, skb->data, desc[0].fields.length, PCI_DMA_TODEVICE);
+	desc[0].fields.valid   = 1;
+
+	if(desc[0].fields.address == NO_TCE) {
+		ibmveth_error_printk("tx: unable to map initial fragment\n");
+		adapter->tx_map_failed++;
+		adapter->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	curfrag = nfrags;
+
+	/* map fragments past the initial portion if there are any */
+	while(curfrag--) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[curfrag];
+		desc[curfrag+1].fields.address = vio_map_single(adapter->vdev,
+								page_address(frag->page) + frag->page_offset,
+								frag->size, PCI_DMA_TODEVICE);
+		desc[curfrag+1].fields.length = frag->size;
+		desc[curfrag+1].fields.valid  = 1;
+
+		if(desc[curfrag+1].fields.address == NO_TCE) {
+			ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag);
+			adapter->tx_map_failed++;
+			adapter->stats.tx_dropped++;
+			/* Free all the mappings we just created */
+			while(curfrag < nfrags) {
+				vio_unmap_single(adapter->vdev,
+						 desc[curfrag+1].fields.address,
+						 desc[curfrag+1].fields.length,
+						 PCI_DMA_TODEVICE);
+				curfrag++;
+			}
+			dev_kfree_skb(skb);
+			return 0;
+		}
+	}
+
+	/* send the frame. Arbitrarily set retrycount to 1024 */
+	unsigned long correlator = 0;
+	unsigned int retry_count = 1024;
+	do {
+		lpar_rc = h_send_logical_lan(adapter->vdev->unit_address,
+					     desc[0].desc,
+					     desc[1].desc,
+					     desc[2].desc,
+					     desc[3].desc,
+					     desc[4].desc,
+					     desc[5].desc,
+					     correlator);
+	} while ((lpar_rc == H_Busy) && (retry_count--));
+    
+	if(lpar_rc != H_Success && lpar_rc != H_Dropped) {
+		int i;
+		ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc);
+		for(i = 0; i < 6; i++) {
+			ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i,
+					     desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address);
+		}
+		adapter->tx_send_failed++;
+		adapter->stats.tx_dropped++;
+	} else {
+		adapter->stats.tx_packets++;
+		adapter->stats.tx_bytes += skb->len;
+	}
+
+	do {
+		vio_unmap_single(adapter->vdev, desc[nfrags].fields.address, desc[nfrags].fields.length, PCI_DMA_TODEVICE);
+	} while(--nfrags >= 0);
+
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+static int ibmveth_poll(struct net_device *netdev, int *budget)
+{
+	struct ibmveth_adapter *adapter = netdev->priv;
+	int max_frames_to_process = netdev->quota;
+	int frames_processed = 0;
+	int more_work = 1;
+	unsigned long lpar_rc;
+
+ restart_poll:
+	do {
+		struct net_device *netdev = adapter->netdev;
+
+		if(ibmveth_rxq_pending_buffer(adapter)) {
+			struct sk_buff *skb;
+
+			if(!ibmveth_rxq_buffer_valid(adapter)) {
+				wmb(); /* suggested by larson1 */
+				adapter->rx_invalid_buffer++;
+				ibmveth_debug_printk("recycling invalid buffer\n");
+				ibmveth_rxq_recycle_buffer(adapter);
+			} else {
+				int length = ibmveth_rxq_frame_length(adapter);
+				int offset = ibmveth_rxq_frame_offset(adapter);
+				skb = ibmveth_rxq_get_buffer(adapter);
+
+				ibmveth_rxq_harvest_buffer(adapter);
+
+				skb_reserve(skb, offset);
+				skb_put(skb, length);
+				skb->dev = netdev;
+				skb->protocol = eth_type_trans(skb, netdev);
+
+				netif_receive_skb(skb);	/* send it up */
+
+				adapter->stats.rx_packets++;
+				adapter->stats.rx_bytes += length;
+				frames_processed++;
+			}
+		} else {
+			more_work = 0;
+		}
+	} while(more_work && (frames_processed < max_frames_to_process));
+
+	ibmveth_schedule_replenishing(adapter);
+
+	if(more_work) {
+		/* more work to do - return that we are not done yet */
+		netdev->quota -= frames_processed;
+		*budget -= frames_processed;
+		return 1; 
+	}
+
+	/* we think we are done - reenable interrupts, then check once more to make sure we are done */
+	lpar_rc = h_vio_signal(adapter->vdev->unit_address, IbmVethIntsEnabled);
+	ibmveth_assert(lpar_rc == H_Success);
+
+	netif_rx_complete(netdev);
+
+	if(ibmveth_rxq_pending_buffer(adapter) && netif_rx_reschedule(netdev, frames_processed))
+	{
+		lpar_rc = h_vio_signal(adapter->vdev->unit_address, IbmVethIntsDisabled);
+		ibmveth_assert(lpar_rc == H_Success);
+		more_work = 1;
+		goto restart_poll;
+	}
+
+	netdev->quota -= frames_processed;
+	*budget -= frames_processed;
+
+	/* we really are done */
+	return 0;
+}
+
+static void ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{   
+	struct net_device *netdev = dev_instance;
+	struct ibmveth_adapter *adapter = netdev->priv;
+	unsigned long lpar_rc;
+
+	if(netif_rx_schedule_prep(netdev)) {
+		lpar_rc = h_vio_signal(adapter->vdev->unit_address, IbmVethIntsDisabled);
+		ibmveth_assert(lpar_rc == H_Success);
+		__netif_rx_schedule(netdev);
+	}
+}
+
+static struct net_device_stats *ibmveth_get_stats(struct net_device *dev)
+{
+	struct ibmveth_adapter *adapter = dev->priv;
+	return &adapter->stats;
+}
+
+static void ibmveth_set_multicast_list(struct net_device *netdev)
+{
+	struct ibmveth_adapter *adapter = netdev->priv;
+	unsigned long lpar_rc;
+
+	if((netdev->flags & IFF_PROMISC) || (netdev->mc_count > adapter->mcastFilterSize)) {
+		lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
+					   IbmVethMcastEnableRecv |
+					   IbmVethMcastDisableFiltering,
+					   0);
+		if(lpar_rc != H_Success) {
+			ibmveth_error_printk("h_multicast_ctrl rc=%ld when entering promisc mode\n", lpar_rc);
+		}
+	} else {
+		struct dev_mc_list *mclist = netdev->mc_list;
+		int i;
+		/* clear the filter table & disable filtering */
+		lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
+					   IbmVethMcastEnableRecv |
+					   IbmVethMcastDisableFiltering |
+					   IbmVethMcastClearFilterTable,
+					   0);
+		if(lpar_rc != H_Success) {
+			ibmveth_error_printk("h_multicast_ctrl rc=%ld when attempting to clear filter table\n", lpar_rc);
+		}
+		/* add the addresses to the filter table */
+		for(i = 0; i < netdev->mc_count; ++i, mclist = mclist->next) {
+			// add the multicast address to the filter table
+			unsigned long mcast_addr = 0;
+			memcpy(((char *)&mcast_addr)+2, mclist->dmi_addr, 6);
+			lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
+						   IbmVethMcastAddFilter,
+						   mcast_addr);
+			if(lpar_rc != H_Success) {
+				ibmveth_error_printk("h_multicast_ctrl rc=%ld when adding an entry to the filter table\n", lpar_rc);
+			}
+		}
+	
+		/* re-enable filtering */
+		lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
+					   IbmVethMcastEnableFiltering,
+					   0);
+		if(lpar_rc != H_Success) {
+			ibmveth_error_printk("h_multicast_ctrl rc=%ld when enabling filtering\n", lpar_rc);
+		}
+	}
+}
+
+static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
+{
+	int rc;
+	struct net_device *netdev;
+	struct ibmveth_adapter *adapter;
+
+	unsigned int *mac_addr_p;
+	unsigned int *mcastFilterSize_p;
+
+
+	ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%lx\n", 
+					dev->unit_address);
+
+	mac_addr_p = (unsigned int *) vio_get_attribute(dev, VETH_MAC_ADDR, 0);
+	if(!mac_addr_p) {
+		ibmveth_error_printk("Can't find VETH_MAC_ADDR attribute\n");
+		return 0;
+	}
+	
+	mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0);
+	if(!mcastFilterSize_p) {
+		ibmveth_error_printk("Can't find VETH_MCAST_FILTER_SIZE attribute\n");
+		return 0;
+	}
+	
+	netdev = alloc_etherdev(sizeof(struct ibmveth_adapter));
+
+	if(!netdev)
+		return -ENOMEM;
+
+	SET_MODULE_OWNER(netdev);
+
+	adapter = netdev->priv;
+	memset(adapter, 0, sizeof(adapter));
+	dev->driver_data = netdev;
+
+	adapter->vdev = dev;
+	adapter->netdev = netdev;
+	adapter->mcastFilterSize= *mcastFilterSize_p;
+	
+	/* 	Some older boxes running PHYP non-natively have an OF that
+		returns a 8-byte local-mac-address field (and the first 
+		2 bytes have to be ignored) while newer boxes' OF return
+		a 6-byte field. Note that IEEE 1275 specifies that 
+		local-mac-address must be a 6-byte field.
+		The RPA doc specifies that the first byte must be 10b, so 
+		we'll just look for it to solve this 8 vs. 6 byte field issue */
+
+	while (*((char*)mac_addr_p) != (char)(0x02))
+		((char*)mac_addr_p)++;
+
+	adapter->mac_addr = 0;
+	memcpy(&adapter->mac_addr, mac_addr_p, 6);
+
+	adapter->liobn = dev->tce_table->index;
+	
+	netdev->irq = dev->irq;
+	netdev->open               = ibmveth_open;
+	netdev->poll               = ibmveth_poll;
+	netdev->weight             = 16;
+	netdev->stop               = ibmveth_close;
+	netdev->hard_start_xmit    = ibmveth_start_xmit;
+	netdev->get_stats          = ibmveth_get_stats;
+	netdev->set_multicast_list = ibmveth_set_multicast_list;
+	netdev->do_ioctl           = ibmveth_ioctl;
+	netdev->ethtool_ops           = &netdev_ethtool_ops;
+
+	memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
+
+	ibmveth_init_buffer_pool(&adapter->rx_buff_pool[0], 0, IbmVethPool0DftCnt, IbmVethPool0DftSize);
+	ibmveth_init_buffer_pool(&adapter->rx_buff_pool[1], 1, IbmVethPool1DftCnt, IbmVethPool1DftSize);
+	ibmveth_init_buffer_pool(&adapter->rx_buff_pool[2], 2, IbmVethPool2DftCnt, IbmVethPool2DftSize);
+
+	ibmveth_debug_printk("adapter @ 0x%p\n", adapter);
+
+	tasklet_init(&adapter->replenish_task, (void*)ibmveth_replenish_task, (unsigned long)adapter);
+
+	adapter->buffer_list_dma = NO_TCE;
+	adapter->filter_list_dma = NO_TCE;
+	adapter->rx_queue.queue_dma = NO_TCE;
+
+	ibmveth_debug_printk("registering netdev...\n");
+
+	rc = register_netdev(netdev);
+
+	if(rc) {
+		ibmveth_debug_printk("failed to register netdev rc=%d\n", rc);
+		free_netdev(netdev);
+		return rc;
+	}
+
+	ibmveth_debug_printk("registered\n");
+
+	ibmveth_proc_register_adapter(adapter);
+
+	return 0;
+}
+
+static void __devexit ibmveth_remove(struct vio_dev *dev)
+{
+	struct net_device *netdev = dev->driver_data;
+	struct ibmveth_adapter *adapter = netdev->priv;
+
+	unregister_netdev(netdev);
+
+	ibmveth_proc_unregister_adapter(adapter);
+
+	free_netdev(netdev);
+	return;
+}
+
+#ifdef CONFIG_PROC_FS
+static void ibmveth_proc_register_driver(void)
+{
+	ibmveth_proc_dir = create_proc_entry(IBMVETH_PROC_DIR, S_IFDIR, proc_net);
+	if (ibmveth_proc_dir) {
+		SET_MODULE_OWNER(ibmveth_proc_dir);
+	}
+}
+
+static void ibmveth_proc_unregister_driver(void)
+{
+	remove_proc_entry(IBMVETH_PROC_DIR, proc_net);
+}
+
+static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos) 
+{
+	if (*pos == 0) {
+		return (void *)1;
+	} else {
+		return NULL;
+	}
+}
+
+static void *ibmveth_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	++*pos;
+	return NULL;
+}
+
+static void ibmveth_seq_stop(struct seq_file *seq, void *v) 
+{
+}
+
+static int ibmveth_seq_show(struct seq_file *seq, void *v) 
+{
+	struct ibmveth_adapter *adapter = seq->private;
+	char *current_mac = ((char*) &adapter->netdev->dev_addr);
+	char *firmware_mac = ((char*) &adapter->mac_addr) ;
+
+	seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
+	
+	seq_printf(seq, "Unit Address:    0x%lx\n", adapter->vdev->unit_address);
+	seq_printf(seq, "LIOBN:           0x%lx\n", adapter->liobn);
+	seq_printf(seq, "Current MAC:     %02X:%02X:%02X:%02X:%02X:%02X\n",
+		   current_mac[0], current_mac[1], current_mac[2],
+		   current_mac[3], current_mac[4], current_mac[5]);
+	seq_printf(seq, "Firmware MAC:    %02X:%02X:%02X:%02X:%02X:%02X\n",
+		   firmware_mac[0], firmware_mac[1], firmware_mac[2],
+		   firmware_mac[3], firmware_mac[4], firmware_mac[5]);
+	
+	seq_printf(seq, "\nAdapter Statistics:\n");
+	seq_printf(seq, "  TX:  skbuffs linearized:          %ld\n", adapter->tx_linearized);
+	seq_printf(seq, "       multi-descriptor sends:      %ld\n", adapter->tx_multidesc_send);
+	seq_printf(seq, "       skb_linearize failures:      %ld\n", adapter->tx_linearize_failed);
+	seq_printf(seq, "       vio_map_single failres:      %ld\n", adapter->tx_map_failed);
+	seq_printf(seq, "       send failures:               %ld\n", adapter->tx_send_failed);
+	seq_printf(seq, "  RX:  replenish task cycles:       %ld\n", adapter->replenish_task_cycles);
+	seq_printf(seq, "       alloc_skb_failures:          %ld\n", adapter->replenish_no_mem);
+	seq_printf(seq, "       add buffer failures:         %ld\n", adapter->replenish_add_buff_failure);
+	seq_printf(seq, "       invalid buffers:             %ld\n", adapter->rx_invalid_buffer);
+	seq_printf(seq, "       no buffers:                  %ld\n", adapter->rx_no_buffer);
+	
+	return 0;
+}
+static struct seq_operations ibmveth_seq_ops = {
+	.start = ibmveth_seq_start,
+	.next  = ibmveth_seq_next,
+	.stop  = ibmveth_seq_stop,
+	.show  = ibmveth_seq_show,
+};
+
+static int ibmveth_proc_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	struct proc_dir_entry *proc;
+	int rc;
+
+	rc = seq_open(file, &ibmveth_seq_ops);
+	if (!rc) {
+		/* recover the pointer buried in proc_dir_entry data */
+		seq = file->private_data;
+		proc = PDE(inode);
+		seq->private = proc->data;
+	}
+	return rc;
+}
+
+static struct file_operations ibmveth_proc_fops = {
+	.owner	 = THIS_MODULE,
+	.open    = ibmveth_proc_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
+{
+	struct proc_dir_entry *entry;
+	if (ibmveth_proc_dir) {
+		entry = create_proc_entry(adapter->netdev->name, S_IFREG, ibmveth_proc_dir);
+		if (!entry) {
+			ibmveth_error_printk("Cannot create adapter proc entry");
+		} else {
+			entry->data = (void *) adapter;
+			entry->proc_fops = &ibmveth_proc_fops;
+			SET_MODULE_OWNER(entry);
+		}
+	}
+	return;
+}
+
+static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
+{
+	if (ibmveth_proc_dir) {
+		remove_proc_entry(adapter->netdev->name, ibmveth_proc_dir);
+	}
+}
+
+#else /* CONFIG_PROC_FS */
+static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) 
+{
+}
+
+static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter) 
+{
+}
+static void ibmveth_proc_register_driver(void)
+{
+}
+
+static void ibmveth_proc_unregister_driver(void)
+{
+}
+#endif /* CONFIG_PROC_FS */
+
+static struct vio_device_id ibmveth_device_table[] __devinitdata= {
+	{ "network", "IBM,l-lan"},
+	{ 0,}
+};
+
+MODULE_DEVICE_TABLE(vio, ibmveth_device_table);
+
+static struct vio_driver ibmveth_driver = {
+	.name        = (char *)ibmveth_driver_name,
+	.id_table    = ibmveth_device_table,
+	.probe       = ibmveth_probe,
+	.remove      = ibmveth_remove
+};
+
+static int __init ibmveth_module_init(void)
+{
+	int rc;
+
+	ibmveth_printk("%s: %s %s\n", ibmveth_driver_name, ibmveth_driver_string, ibmveth_driver_version);
+
+	ibmveth_proc_register_driver();
+
+	rc = vio_module_init(&ibmveth_driver);
+
+	return rc;
+}
+
+static void __exit ibmveth_module_exit(void)
+{
+	vio_unregister_driver(&ibmveth_driver);
+	ibmveth_proc_unregister_driver();
+}	
+
+module_init(ibmveth_module_init);
+module_exit(ibmveth_module_exit);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/ibmveth.h linux-2.4.27-pre3/drivers/net/ibmveth.h
--- linux-2.4.26/drivers/net/ibmveth.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/ibmveth.h	2004-05-18 16:50:48.000000000 +0000
@@ -0,0 +1,158 @@
+/**************************************************************************/
+/*                                                                        */
+/* IBM eServer i/[Series Virtual Ethernet Device Driver                   */
+/* Copyright (C) 2003 Dave Larson (larson1@us.ibm.com), IBM Corp.         */
+/*                                                                        */
+/*  This program is free software; you can redistribute it and/or modify  */
+/*  it under the terms of the GNU General Public License as published by  */
+/*  the Free Software Foundation; either version 2 of the License, or     */
+/*  (at your option) any later version.                                   */
+/*                                                                        */
+/*  This program is distributed in the hope that it will be useful,       */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*  GNU General Public License for more details.                          */
+/*                                                                        */
+/*  You should have received a copy of the GNU General Public License     */
+/*  along with this program; if not, write to the Free Software           */
+/*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  */
+/*                                                                   USA  */
+/*                                                                        */
+/**************************************************************************/
+
+#ifndef _IBMVETH_H
+#define _IBMVETH_H
+
+#define IbmVethMaxSendFrags 6
+
+/* constants for H_MULTICAST_CTRL */
+#define IbmVethMcastReceptionModifyBit     0x80000UL
+#define IbmVethMcastReceptionEnableBit     0x20000UL
+#define IbmVethMcastFilterModifyBit        0x40000UL
+#define IbmVethMcastFilterEnableBit        0x10000UL
+
+#define IbmVethMcastEnableRecv       (IbmVethMcastReceptionModifyBit | IbmVethMcastReceptionEnableBit)
+#define IbmVethMcastDisableRecv      (IbmVethMcastReceptionModifyBit)
+#define IbmVethMcastEnableFiltering  (IbmVethMcastFilterModifyBit | IbmVethMcastFilterEnableBit)
+#define IbmVethMcastDisableFiltering (IbmVethMcastFilterModifyBit)
+#define IbmVethMcastAddFilter        0x1UL
+#define IbmVethMcastRemoveFilter     0x2UL
+#define IbmVethMcastClearFilterTable 0x3UL
+
+/* constants for H_VIO_SIGNAL */
+#define IbmVethIntsDisabled          0x0UL
+#define IbmVethIntsEnabled           0x1UL
+
+/* hcall numbers */
+#define H_VIO_SIGNAL             0x104
+#define H_REGISTER_LOGICAL_LAN   0x114
+#define H_FREE_LOGICAL_LAN       0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN       0x120
+#define H_MULTICAST_CTRL         0x130
+#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
+
+/* hcall macros */
+#define h_vio_signal(ua, mode) \
+  plpar_hcall_norets(H_VIO_SIGNAL, ua, mode)
+
+#define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
+  plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
+
+#define h_free_logical_lan(ua) \
+  plpar_hcall_norets(H_FREE_LOGICAL_LAN, ua)
+
+#define h_add_logical_lan_buffer(ua, buf) \
+  plpar_hcall_norets(H_ADD_LOGICAL_LAN_BUFFER, ua, buf)
+
+#define h_send_logical_lan(ua, buf1, buf2, buf3, buf4, buf5, buf6, correlator) \
+  plpar_hcall_8arg_2ret(H_SEND_LOGICAL_LAN, ua, buf1, buf2, buf3, buf4, buf5, buf6, correlator, &correlator)
+
+#define h_multicast_ctrl(ua, cmd, mac) \
+  plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
+
+#define h_change_logical_lan_mac(ua, mac) \
+  plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac)
+
+#define IbmVethNumBufferPools 3
+#define IbmVethPool0DftSize (1024 * 2)
+#define IbmVethPool1DftSize (1024 * 4)
+#define IbmVethPool2DftSize (1024 * 10)
+#define IbmVethPool0DftCnt  256
+#define IbmVethPool1DftCnt  256
+#define IbmVethPool2DftCnt  256
+
+struct ibmveth_buff_pool {
+    u32 size;
+    u32 index;
+    u32 buff_size;
+    u32 threshold;
+    atomic_t available;
+    u32 consumer_index;
+    u32 producer_index;
+    u16 *free_map;
+    dma_addr_t *dma_addr;
+    struct sk_buff **skbuff;
+};
+
+struct ibmveth_rx_q {
+    u64        index;
+    u64        num_slots;
+    u64        toggle;
+    dma_addr_t queue_dma;
+    u32        queue_len;
+    struct ibmveth_rx_q_entry *queue_addr;
+};
+
+struct ibmveth_adapter {
+    struct vio_dev *vdev;
+    struct net_device *netdev;
+    struct net_device_stats stats;
+    unsigned int mcastFilterSize;
+    unsigned long mac_addr;
+    unsigned long liobn;
+    void * buffer_list_addr;
+    void * filter_list_addr;
+    dma_addr_t buffer_list_dma;
+    dma_addr_t filter_list_dma;
+    struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools];
+    struct ibmveth_rx_q rx_queue;
+    /* helper tasks */
+    struct tasklet_struct replenish_task;
+    /* adapter specific stats */
+    u64 replenish_task_cycles;
+    u64 replenish_no_mem;
+    u64 replenish_add_buff_failure;
+    u64 replenish_add_buff_success;
+    u64 rx_invalid_buffer;
+    u64 rx_no_buffer;
+    u64 tx_multidesc_send;
+    u64 tx_linearized;
+    u64 tx_linearize_failed;
+    u64 tx_map_failed;
+    u64 tx_send_failed;
+};
+
+struct ibmveth_buf_desc_fields {	
+    u32 valid : 1;
+    u32 toggle : 1;
+    u32 reserved : 6;
+    u32 length : 24;
+    u32 address;
+};
+
+union ibmveth_buf_desc {
+    u64 desc;	
+    struct ibmveth_buf_desc_fields fields;
+};
+
+struct ibmveth_rx_q_entry {
+    u16 toggle : 1;
+    u16 valid : 1;
+    u16 reserved : 14;
+    u16 offset;
+    u32 length;
+    u64 correlator;
+};
+
+#endif /* _IBMVETH_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/natsemi.c linux-2.4.27-pre3/drivers/net/natsemi.c
--- linux-2.4.26/drivers/net/natsemi.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/natsemi.c	2004-05-18 16:51:05.000000000 +0000
@@ -387,7 +387,7 @@ enum register_offsets {
 	IntrStatus		= 0x10,
 	IntrMask		= 0x14,
 	IntrEnable		= 0x18,
-	IntrHoldoff		= 0x16, /* DP83816 only */
+	IntrHoldoff		= 0x1C, /* DP83816 only */
 	TxRingPtr		= 0x20,
 	TxConfig		= 0x24,
 	RxRingPtr		= 0x30,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/pcnet32.c linux-2.4.27-pre3/drivers/net/pcnet32.c
--- linux-2.4.26/drivers/net/pcnet32.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/pcnet32.c	2004-05-18 16:52:09.000000000 +0000
@@ -1,12 +1,12 @@
 /* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
 /*
  *	Copyright 1996-1999 Thomas Bogendoerfer
- * 
+ *
  *	Derived from the lance driver written 1993,1994,1995 by Donald Becker.
- * 
+ *
  *	Copyright 1993 United States Government as represented by the
  *	Director, National Security Agency.
- * 
+ *
  *	This software may be used and distributed according to the terms
  *	of the GNU General Public License, incorporated herein by reference.
  *
@@ -22,19 +22,16 @@
  *************************************************************************/
 
 #define DRV_NAME	"pcnet32"
-#define DRV_VERSION	"1.28"
-#define DRV_RELDATE	"02.20.2004"
+#define DRV_VERSION	"1.29"
+#define DRV_RELDATE	"04.06.2004"
 #define PFX		DRV_NAME ": "
 
 static const char *version =
 DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n";
 
 #include <linux/module.h>
-
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
@@ -45,16 +42,17 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELD
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/crc32.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 
+#include <asm/bitops.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+
 /*
  * PCI device identifiers for "new style" Linux PCI Device Drivers
  */
@@ -74,10 +72,10 @@ MODULE_DEVICE_TABLE (pci, pcnet32_pci_tb
 
 static int cards_found __devinitdata;
 
-/* 
- * VLB I/O addresses 
+/*
+ * VLB I/O addresses
  */
-static unsigned int pcnet32_portlist[] __initdata = 
+static unsigned int pcnet32_portlist[] __initdata =
 	{ 0x300, 0x320, 0x340, 0x360, 0 };
 
 
@@ -103,6 +101,9 @@ static int rx_copybreak = 200;
 
 #define PCNET32_DMA_MASK 0xffffffff
 
+#define PCNET32_WATCHDOG_TIMEOUT (jiffies + (2 * HZ))
+#define PCNET32_BLINK_TIMEOUT	(jiffies + (HZ/4))
+
 /*
  * table to translate option values from tulip
  * to internal options
@@ -110,7 +111,7 @@ static int rx_copybreak = 200;
 static unsigned char options_mapping[] = {
     PCNET32_PORT_ASEL,			   /*  0 Auto-select	  */
     PCNET32_PORT_AUI,			   /*  1 BNC/AUI	  */
-    PCNET32_PORT_AUI,			   /*  2 AUI/BNC	  */ 
+    PCNET32_PORT_AUI,			   /*  2 AUI/BNC	  */
     PCNET32_PORT_ASEL,			   /*  3 not supported	  */
     PCNET32_PORT_10BT | PCNET32_PORT_FD,   /*  4 10baseT-FD	  */
     PCNET32_PORT_ASEL,			   /*  5 not supported	  */
@@ -131,20 +132,22 @@ static const char pcnet32_gstrings_test[
 };
 #define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN)
 
+#define PCNET32_NUM_REGS 146
+
 #define MAX_UNITS 8	/* More are supported, limit only on options */
 static int options[MAX_UNITS];
 static int full_duplex[MAX_UNITS];
 
 /*
  *				Theory of Operation
- * 
+ *
  * This driver uses the same software structure as the normal lance
  * driver. So look for a verbose description in lance.c. The differences
  * to the normal lance driver is the use of the 32bit mode of PCnet32
  * and PCnetPCI chips. Because these chips are 32bit chips, there is no
  * 16MB limitation and we don't need bounce buffers.
  */
- 
+
 /*
  * History:
  * v0.01:  Initial version
@@ -198,7 +201,7 @@ static int full_duplex[MAX_UNITS];
  * v1.22:  changed pci scanning code to make PPC people happy
  *	   fixed switching to 32bit mode in pcnet32_open() (thanks
  *	   to Michael Richard <mcr@solidum.com> for noticing this one)
- *	   added sub vendor/device id matching (thanks again to 
+ *	   added sub vendor/device id matching (thanks again to
  *	   Michael Richard <mcr@solidum.com>)
  *	   added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
  * v1.23   fixed small bug, when manual selecting MII speed/duplex
@@ -216,13 +219,15 @@ static int full_duplex[MAX_UNITS];
  * v1.26p  Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker
  * v1.27   improved CSR/PROM address detection, lots of cleanups,
  * 	   new pcnet32vlb module option, HP-PARISC support,
- * 	   added module parameter descriptions, 
+ * 	   added module parameter descriptions,
  * 	   initial ethtool support - Helge Deller <deller@gmx.de>
  * v1.27a  Sun Feb 10 2002 Go Taniguchi <go@turbolinux.co.jp>
  *	   use alloc_etherdev and register_netdev
  *	   fix pci probe not increment cards_found
  *	   FD auto negotiate error workaround for xSeries250
  *	   clean up and using new mii module
+ * v1.27b  Sep 30 2002 Kent Yoder <yoder1@us.ibm.com>
+ * 	   Added timer for cable connection state changes.
  * v1.28   20 Feb 2004 Don Fry <brazilnut@us.ibm.com>
  *	   Jon Mason <jonmason@us.ibm.com>, Chinmay Albal <albal@in.ibm.com>
  *	   Now uses ethtool_ops, netif_msg_* and generic_mii_ioctl.
@@ -230,6 +235,10 @@ static int full_duplex[MAX_UNITS];
  *	   length errors, and transmit hangs.  Cleans up after errors in open.
  *	   Jim Lewis <jklewis@us.ibm.com> added ethernet loopback test.
  *	   Thomas Munck Steenholdt <tmus@tmus.dk> non-mii ioctl corrections.
+ * v1.29   6 Apr 2004 Jim Lewis <jklewis@us.ibm.com> added physical
+ *	   identification code (blink led's) and register dump.
+ *	   Don Fry added timer for 971/972 so skbufs don't remain on tx ring
+ *	   forever.
  */
 
 
@@ -270,11 +279,11 @@ static int full_duplex[MAX_UNITS];
 struct pcnet32_rx_head {
     u32 base;
     s16 buf_length;
-    s16 status;	   
+    s16 status;
     u32 msg_length;
     u32 reserved;
 };
-	
+
 struct pcnet32_tx_head {
     u32 base;
     s16 length;
@@ -290,7 +299,7 @@ struct pcnet32_init_block {
     u8	phys_addr[6];
     u16 reserved;
     u32 filter[2];
-    /* Receive and transmit ring base, along with extra bits. */    
+    /* Receive and transmit ring base, along with extra bits. */
     u32 rx_ring;
     u32 tx_ring;
 };
@@ -307,7 +316,7 @@ struct pcnet32_access {
 };
 
 /*
- * The first three fields of pcnet32_private are read by the ethernet device 
+ * The first three fields of pcnet32_private are read by the ethernet device
  * so we allocate the structure should be allocated by pci_alloc_consistent().
  */
 struct pcnet32_private {
@@ -315,16 +324,18 @@ struct pcnet32_private {
     struct pcnet32_rx_head    rx_ring[RX_RING_SIZE];
     struct pcnet32_tx_head    tx_ring[TX_RING_SIZE];
     struct pcnet32_init_block init_block;
-    dma_addr_t 		dma_addr;	/* DMA address of beginning of this object, 
-					   returned by pci_alloc_consistent */
-    struct pci_dev	*pci_dev;	/* Pointer to the associated pci device structure */
+    dma_addr_t		dma_addr;	/* DMA address of beginning of this
+					   object, returned by
+					   pci_alloc_consistent */
+    struct pci_dev	*pci_dev;	/* Pointer to the associated pci device
+					   structure */
     const char		*name;
     /* The saved address of a sent-in-place packet/buffer, for skfree(). */
     struct sk_buff	*tx_skbuff[TX_RING_SIZE];
     struct sk_buff	*rx_skbuff[RX_RING_SIZE];
     dma_addr_t		tx_dma_addr[TX_RING_SIZE];
     dma_addr_t		rx_dma_addr[RX_RING_SIZE];
-    struct pcnet32_access a;
+    struct pcnet32_access	a;
     spinlock_t		lock;		/* Guard lock */
     unsigned int	cur_rx, cur_tx;	/* The next free ring entry */
     unsigned int	dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
@@ -336,7 +347,9 @@ struct pcnet32_private {
 	dxsuflo:1,			/* disable transmit stop on uflo */
 	mii:1;				/* mii port available */
     struct net_device	*next;
-    struct mii_if_info mii_if;
+    struct mii_if_info	mii_if;
+    struct timer_list	watchdog_timer;
+    struct timer_list	blink_timer;
     u32			msg_enable;	/* debug message level */
 };
 
@@ -351,14 +364,21 @@ static void pcnet32_tx_timeout (struct n
 static void pcnet32_interrupt(int, void *, struct pt_regs *);
 static int  pcnet32_close(struct net_device *);
 static struct net_device_stats *pcnet32_get_stats(struct net_device *);
+static void pcnet32_load_multicast(struct net_device *dev);
 static void pcnet32_set_multicast_list(struct net_device *);
 static int  pcnet32_ioctl(struct net_device *, struct ifreq *, int);
+static void pcnet32_watchdog(struct net_device *);
 static int mdio_read(struct net_device *dev, int phy_id, int reg_num);
 static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val);
 static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits);
 static void pcnet32_ethtool_test(struct net_device *dev,
 	struct ethtool_test *eth_test, u64 *data);
 static int pcnet32_loopback_test(struct net_device *dev, uint64_t *data1);
+static int pcnet32_phys_id(struct net_device *dev, u32 data);
+static void pcnet32_led_blink_callback(struct net_device *dev);
+static int pcnet32_get_regs_len(struct net_device *dev);
+static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+	void *ptr);
 
 enum pci_flags_bit {
     PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
@@ -476,6 +496,14 @@ static struct pcnet32_access pcnet32_dwi
     .reset	= pcnet32_dwio_reset
 };
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void pcnet32_poll_controller(struct net_device *dev)
+{
+    disable_irq(dev->irq);
+    pcnet32_interrupt(0, dev, NULL);
+    enable_irq(dev->irq);
+}
+#endif
 
 
 static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -509,14 +537,14 @@ static int pcnet32_set_settings(struct n
 
 static void pcnet32_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct pcnet32_private *lp = dev->priv;
-  
-	strcpy (info->driver, DRV_NAME);
-	strcpy (info->version, DRV_VERSION);
-	if (lp->pci_dev)
-		strcpy (info->bus_info, pci_name(lp->pci_dev));
-	else
-		sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr);
+    struct pcnet32_private *lp = dev->priv;
+
+    strcpy (info->driver, DRV_NAME);
+    strcpy (info->version, DRV_VERSION);
+    if (lp->pci_dev)
+	strcpy (info->bus_info, pci_name(lp->pci_dev));
+    else
+	sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr);
 }
 
 static u32 pcnet32_get_link(struct net_device *dev)
@@ -539,16 +567,16 @@ static u32 pcnet32_get_link(struct net_d
 
 static u32 pcnet32_get_msglevel(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
-	return lp->msg_enable;
+    struct pcnet32_private *lp = dev->priv;
+    return lp->msg_enable;
 }
-  
+
 static void pcnet32_set_msglevel(struct net_device *dev, u32 value)
 {
-	struct pcnet32_private *lp = dev->priv;
-	lp->msg_enable = value;
+    struct pcnet32_private *lp = dev->priv;
+    lp->msg_enable = value;
 }
-  
+
 static int pcnet32_nway_reset(struct net_device *dev)
 {
     struct pcnet32_private *lp = dev->priv;
@@ -565,12 +593,12 @@ static int pcnet32_nway_reset(struct net
 
 static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
-	struct pcnet32_private *lp = dev->priv;
+    struct pcnet32_private *lp = dev->priv;
 
-	ering->tx_max_pending = TX_RING_SIZE - 1;
-	ering->tx_pending = lp->cur_tx - lp->dirty_tx;
-	ering->rx_max_pending = RX_RING_SIZE - 1;
-	ering->rx_pending = lp->cur_rx & RX_RING_MOD_MASK;
+    ering->tx_max_pending = TX_RING_SIZE - 1;
+    ering->tx_pending = lp->cur_tx - lp->dirty_tx;
+    ering->rx_max_pending = RX_RING_SIZE - 1;
+    ering->rx_pending = lp->cur_rx & RX_RING_MOD_MASK;
 }
 
 static void pcnet32_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -597,7 +625,7 @@ static void pcnet32_ethtool_test(struct 
 	    test->flags |= ETH_TEST_FL_FAILED;
 	} else if (netif_msg_hw(lp))
 	    printk(KERN_DEBUG "%s: Loopback test passed.\n", dev->name);
-    } else
+    } else if (netif_msg_hw(lp))
 	printk(KERN_DEBUG "%s: No tests to run (specify 'Offline' on ethtool).",	    dev->name);
 } /* end pcnet32_ethtool_test */
 
@@ -607,32 +635,40 @@ static int pcnet32_loopback_test(struct 
     struct pcnet32_access *a = &lp->a;	/* access to registers */
     ulong ioaddr = dev->base_addr;	/* card base I/O address */
     struct sk_buff *skb;		/* sk buff */
-    int x, y, i;			/* counters */
+    int x, i;				/* counters */
     int numbuffs = 4;			/* number of TX/RX buffers and descs */
     u16 status = 0x8300;		/* TX ring status */
+    u16 teststatus;			/* test of ring status */
     int rc;				/* return code */
     int size;				/* size of packets */
     unsigned char *packet;		/* source packet data */
     static int data_len = 60;		/* length of source packets */
     unsigned long flags;
+    unsigned long ticks;
 
     *data1 = 1;			/* status of test, default to fail */
     rc = 1;			/* default to fail */
 
+    if (netif_running(dev))
+	pcnet32_close(dev);
+
     spin_lock_irqsave(&lp->lock, flags);
-    lp->a.write_csr(ioaddr, 0, 0x7904);
 
-    netif_stop_queue(dev);
+    /* Reset the PCNET32 */
+    lp->a.reset (ioaddr);
+
+    /* switch pcnet32 to 32bit mode */
+    lp->a.write_bcr (ioaddr, 20, 2);
+
+    lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+    lp->init_block.filter[0] = 0;
+    lp->init_block.filter[1] = 0;
 
     /* purge & init rings but don't actually restart */
     pcnet32_restart(dev, 0x0000);
 
     lp->a.write_csr(ioaddr, 0, 0x0004);	/* Set STOP bit */
 
-    x = a->read_bcr(ioaddr, 32);	/* set internal loopback in BSR32 */
-    x = x | 0x00000002;
-    a->write_bcr(ioaddr, 32, x);
-
     /* Initialize Transmit buffers. */
     size = data_len + 15;
     for (x=0; x<numbuffs; x++) {
@@ -646,19 +682,21 @@ static int pcnet32_loopback_test(struct 
 	    skb_put(skb, size);		/* create space for data */
 	    lp->tx_skbuff[x] = skb;
 	    lp->tx_ring[x].length = le16_to_cpu(-skb->len);
-	    lp->tx_ring[x].misc = 0x00000000;
+	    lp->tx_ring[x].misc = 0;
 
-	    /* put DA and SA into the skb */
-	    for (i=0; i<12; i++)
-		*packet++ = 0xff;
+            /* put DA and SA into the skb */
+	    for (i=0; i<6; i++)
+		*packet++ = dev->dev_addr[i];
+	    for (i=0; i<6; i++)
+		*packet++ = dev->dev_addr[i];
 	    /* type */
 	    *packet++ = 0x08;
 	    *packet++ = 0x06;
 	    /* packet number */
 	    *packet++ = x;
 	    /* fill packet with data */
-	    for (y=0; y<data_len; y++)
-		*packet++ = y;
+	    for (i=0; i<data_len; i++)
+		*packet++ = i;
 
 	    lp->tx_dma_addr[x] = pci_map_single(lp->pci_dev, skb->data,
 		    skb->len, PCI_DMA_TODEVICE);
@@ -668,20 +706,41 @@ static int pcnet32_loopback_test(struct 
 	}
     }
 
-    lp->a.write_csr(ioaddr, 0, 0x0002);	/* Set STRT bit */
-    spin_unlock_irqrestore(&lp->lock, flags);
+    x = a->read_bcr(ioaddr, 32);	/* set internal loopback in BSR32 */
+    x = x | 0x0002;
+    a->write_bcr(ioaddr, 32, x);
 
-    mdelay(50);				/* wait a bit */
+    lp->a.write_csr (ioaddr, 15, 0x0044);	/* set int loopback in CSR15 */
 
-    spin_lock_irqsave(&lp->lock, flags);
-    lp->a.write_csr(ioaddr, 0, 0x0004);	/* Set STOP bit */
+    teststatus = le16_to_cpu(0x8000);
+    lp->a.write_csr(ioaddr, 0, 0x0002);		/* Set STRT bit */
+
+    /* Check status of descriptors */
+    for (x=0; x<numbuffs; x++) {
+	ticks = 0;
+	rmb();
+	while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
+	    spin_unlock_irqrestore(&lp->lock, flags);
+	    mdelay(1);
+	    spin_lock_irqsave(&lp->lock, flags);
+	    rmb();
+	    ticks++;
+	}
+	if (ticks == 200) {
+	    if (netif_msg_hw(lp))
+		printk("%s: Desc %d failed to reset!\n",dev->name,x);
+	    break;
+	}
+    }
 
+    lp->a.write_csr(ioaddr, 0, 0x0004);		/* Set STOP bit */
+    wmb();
     if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
 	printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
 
 	for (x=0; x<numbuffs; x++) {
 	    printk(KERN_DEBUG "%s: Packet %d:\n", dev->name, x);
-	    skb=lp->rx_skbuff[x];
+	    skb = lp->rx_skbuff[x];
 	    for (i=0; i<size; i++) {
 		printk("%02x ", *(skb->data+i));
 	    }
@@ -714,20 +773,143 @@ clean_up:
     a->write_csr(ioaddr, 15, (x & ~0x0044));	/* reset bits 6 and 2 */
 
     x = a->read_bcr(ioaddr, 32);		/* reset internal loopback */
-    x = x & ~0x00000002;
+    x = x & ~0x0002;
     a->write_bcr(ioaddr, 32, x);
 
-    pcnet32_restart(dev, 0x0042);		/* resume normal operation */
-
-    netif_wake_queue(dev);
-
-    /* Clear interrupts, and set interrupt enable. */
-    lp->a.write_csr(ioaddr, 0, 0x7940);
     spin_unlock_irqrestore(&lp->lock, flags);
 
+    if (netif_running(dev)) {
+	pcnet32_open(dev);
+    } else {
+	lp->a.write_bcr (ioaddr, 20, 4);	/* return to 16bit mode */
+    }
+
     return(rc);
 } /* end pcnet32_loopback_test  */
 
+static void pcnet32_led_blink_callback(struct net_device *dev)
+{
+    struct pcnet32_private *lp = dev->priv;
+    struct pcnet32_access *a = &lp->a;
+    ulong ioaddr = dev->base_addr;
+    unsigned long flags;
+    int i;
+
+    spin_lock_irqsave(&lp->lock, flags);
+    for (i=4; i<8; i++) {
+	a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000);
+    }
+    spin_unlock_irqrestore(&lp->lock, flags);
+
+    mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT);
+}
+
+static int pcnet32_phys_id(struct net_device *dev, u32 data)
+{
+    struct pcnet32_private *lp = dev->priv;
+    struct pcnet32_access *a = &lp->a;
+    ulong ioaddr = dev->base_addr;
+    unsigned long flags;
+    int i, regs[4];
+
+    if (!lp->blink_timer.function) {
+	init_timer(&lp->blink_timer);
+	lp->blink_timer.function = (void *) pcnet32_led_blink_callback;
+	lp->blink_timer.data = (unsigned long) dev;
+    }
+
+    /* Save the current value of the bcrs */
+    spin_lock_irqsave(&lp->lock, flags);
+    for (i=4; i<8; i++) {
+	regs[i-4] = a->read_bcr(ioaddr, i);
+    }
+    spin_unlock_irqrestore(&lp->lock, flags);
+
+    mod_timer(&lp->blink_timer, jiffies);
+    set_current_state(TASK_INTERRUPTIBLE);
+
+    if ((!data) || (data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))
+    data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+    schedule_timeout(data * HZ);
+    del_timer_sync(&lp->blink_timer);
+
+    /* Restore the original value of the bcrs */
+    spin_lock_irqsave(&lp->lock, flags);
+    for (i=4; i<8; i++) {
+	a->write_bcr(ioaddr, i, regs[i-4]);
+    }
+    spin_unlock_irqrestore(&lp->lock, flags);
+
+    return 0;
+}
+
+int pcnet32_get_regs_len(struct net_device *dev)
+{
+    return(PCNET32_NUM_REGS * sizeof(u16));
+}
+
+void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+	void *ptr)
+{
+    int i, csr0;
+    u16 *buff = ptr;
+    struct pcnet32_private *lp = dev->priv;
+    struct pcnet32_access *a = &lp->a;
+    ulong ioaddr = dev->base_addr;
+    int ticks;
+    unsigned long flags;
+
+    spin_lock_irqsave(&lp->lock, flags);
+
+    csr0 = a->read_csr(ioaddr, 0);
+    if (!(csr0 & 0x0004)) {	/* If not stopped */
+	/* set SUSPEND (SPND) - CSR5 bit 0 */
+	a->write_csr(ioaddr, 5, 0x0001);
+
+	/* poll waiting for bit to be set */
+	ticks = 0;
+	while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
+	    spin_unlock_irqrestore(&lp->lock, flags);
+	    mdelay(1);
+	    spin_lock_irqsave(&lp->lock, flags);
+	    ticks++;
+	    if (ticks > 200) {
+		if (netif_msg_hw(lp))
+		    printk(KERN_DEBUG "%s: Error getting into suspend!\n",
+			    dev->name);
+		break;
+	    }
+	}
+    }
+
+    /* read address PROM */
+    for (i=0; i<16; i += 2)
+	*buff++ = inw(ioaddr + i);
+
+    for (i = 0; i <= 89; i++) {
+	*buff++ = a->read_csr(ioaddr, i);
+    }
+
+    *buff++ = a->read_csr(ioaddr, 112);
+    *buff++ = a->read_csr(ioaddr, 114);
+
+    for (i = 0; i <= 35; i++) {
+	*buff++ = a->read_bcr(ioaddr, i);
+    }
+
+    if (!(csr0 & 0x0004)) {	/* If not stopped */
+	/* clear SUSPEND (SPND) - CSR5 bit 0 */
+	a->write_csr(ioaddr, 5, 0x0000);
+    }
+
+    i = buff - (u16 *)ptr;
+    for (; i < PCNET32_NUM_REGS; i++)
+	*buff++ = 0;
+
+    spin_unlock_irqrestore(&lp->lock, flags);
+}
+
 static struct ethtool_ops pcnet32_ethtool_ops = {
     .get_settings	= pcnet32_get_settings,
     .set_settings	= pcnet32_set_settings,
@@ -742,22 +924,28 @@ static struct ethtool_ops pcnet32_ethtoo
     .get_strings	= pcnet32_get_strings,
     .self_test_count	= pcnet32_self_test_count,
     .self_test		= pcnet32_ethtool_test,
+    .phys_id		= pcnet32_phys_id,
+    .get_regs_len	= pcnet32_get_regs_len,
+    .get_regs		= pcnet32_get_regs,
 };
 
-/* only probes for non-PCI devices, the rest are handled by 
+/* only probes for non-PCI devices, the rest are handled by
  * pci_register_driver via pcnet32_probe_pci */
 
 static void __devinit
 pcnet32_probe_vlbus(void)
 {
     unsigned int *port, ioaddr;
-    
+
     /* search for PCnet32 VLB cards at known addresses */
     for (port = pcnet32_portlist; (ioaddr = *port); port++) {
-	if (!check_region(ioaddr, PCNET32_TOTAL_SIZE)) {
+	if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) {
 	    /* check if there is really a pcnet chip on that ioaddr */
-	    if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57))
+	    if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) {
 		pcnet32_probe1(ioaddr, 0, 0, NULL);
+	    } else {
+		release_region(ioaddr, PCNET32_TOTAL_SIZE);
+	    }
 	}
     }
 }
@@ -771,28 +959,36 @@ pcnet32_probe_pci(struct pci_dev *pdev, 
 
     err = pci_enable_device(pdev);
     if (err < 0) {
-	printk(KERN_ERR PFX "failed to enable device -- err=%d\n", err);
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(KERN_ERR PFX "failed to enable device -- err=%d\n", err);
 	return err;
     }
     pci_set_master(pdev);
 
     ioaddr = pci_resource_start (pdev, 0);
     if (!ioaddr) {
-        printk (KERN_ERR PFX "card has no PCI IO resources, aborting\n");
-        return -ENODEV;
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk (KERN_ERR PFX "card has no PCI IO resources, aborting\n");
+	return -ENODEV;
     }
-    
+
     if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) {
-	printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n");
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n");
 	return -ENODEV;
     }
+    if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci") == NULL) {
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(KERN_ERR PFX "io address range already allocated\n");
+	return -EBUSY;
+    }
 
     return pcnet32_probe1(ioaddr, pdev->irq, 1, pdev);
 }
 
 
-/* pcnet32_probe1 
- *  Called from both pcnet32_probe_vlbus and pcnet_probe_pci.  
+/* pcnet32_probe1
+ *  Called from both pcnet32_probe_vlbus and pcnet_probe_pci.
  *  pdev will be NULL when called from pcnet32_probe_vlbus.
  */
 static int __devinit
@@ -808,6 +1004,7 @@ pcnet32_probe1(unsigned long ioaddr, uns
     struct net_device *dev;
     struct pcnet32_access *a = NULL;
     u8 promaddr[6];
+    int ret = -ENODEV;
 
     /* reset the chip */
     pcnet32_wio_reset(ioaddr);
@@ -820,17 +1017,18 @@ pcnet32_probe1(unsigned long ioaddr, uns
 	if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
 	    a = &pcnet32_dwio;
 	} else
-	    return -ENODEV;
+	    goto err_release_region;
     }
 
     chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16);
-    if (pcnet32_debug & NETIF_MSG_PROBE)
+    if ((pcnet32_debug & NETIF_MSG_PROBE) && (pcnet32_debug & NETIF_MSG_HW))
 	printk(KERN_INFO "  PCnet chip version is %#x.\n", chip_version);
     if ((chip_version & 0xfff) != 0x003) {
-	printk(KERN_INFO PFX "Unsupported chip version.\n");
-	return -ENODEV;
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(KERN_INFO PFX "Unsupported chip version.\n");
+	goto err_release_region;
     }
-    
+
     /* initialize variables */
     fdx = mii = fset = dxsuflo = ltint = 0;
     chip_version = (chip_version >> 12) & 0xffff;
@@ -865,7 +1063,7 @@ pcnet32_probe1(unsigned long ioaddr, uns
     case 0x2626:
 	chipname = "PCnet/Home 79C978"; /* PCI */
 	fdx = 1;
-	/* 
+	/*
 	 * This is based on specs published at www.amd.com.  This section
 	 * assumes that a card with a 79C978 wants to go into 1Mb HomePNA
 	 * mode.  The 79C978 can also go into standard ethernet, and there
@@ -874,12 +1072,6 @@ pcnet32_probe1(unsigned long ioaddr, uns
 	 */
 	/* switch to home wiring mode */
 	media = a->read_bcr(ioaddr, 49);
-#if 0
-	if (pcnet32_debug > 2)
-	    printk(KERN_DEBUG PFX "media value %#x.\n",  media);
-	media &= ~3;
-	media |= 1;
-#endif
 	if (pcnet32_debug & NETIF_MSG_PROBE)
 	    printk(KERN_DEBUG PFX "media reset to %#x.\n",  media);
 	a->write_bcr(ioaddr, 49, media);
@@ -888,34 +1080,50 @@ pcnet32_probe1(unsigned long ioaddr, uns
 	chipname = "PCnet/FAST III 79C975"; /* PCI */
 	fdx = 1; mii = 1;
 	break;
+    case 0x2628:
+	chipname = "PCnet/FAST III 79C976";
+	fdx = 1; mii = 1;
+	break;
     default:
-	printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n",
-			chip_version);
-	return -ENODEV;
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n",
+		    chip_version);
+	goto err_release_region;
     }
 
     /*
      *	On selected chips turn on the BCR18:NOUFLO bit. This stops transmit
      *	starting until the packet is loaded. Strike one for reliability, lose
-     *	one for latency - although on PCI this isnt a big loss. Older chips 
+     *	one for latency - although on PCI this isnt a big loss. Older chips
      *	have FIFO's smaller than a packet, so you can't do this.
+     *	Turn on BCR18:BurstRdEn and BCR18:BurstWrEn.
      */
-	 
-    if(fset)
-    {
-	a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
+
+    if (fset) {
+	a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0860));
 	a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00);
 	dxsuflo = 1;
 	ltint = 1;
     }
-    
+
+    if (ltint) {
+	/* Enable timer to prevent skbuffs from remaining on the tx ring
+	 * forever if no other tx being done.  Set timer period to about
+	 * 122 ms */
+	a->write_bcr(ioaddr, 31, 0x253b);
+    }
+
     dev = alloc_etherdev(0);
     if (!dev) {
-	printk(KERN_ERR PFX "Memory allocation failed.\n");
-	return -ENOMEM;
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(KERN_ERR PFX "Memory allocation failed.\n");
+	ret = -ENOMEM;
+	goto err_release_region;
     }
+    SET_NETDEV_DEV(dev, &pdev->dev);
 
-    printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);
+    if (pcnet32_debug & NETIF_MSG_PROBE)
+	printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);
 
     /* In most chips, after a chip reset, the ethernet address is read from the
      * station address PROM at the base address and programmed into the
@@ -935,60 +1143,63 @@ pcnet32_probe1(unsigned long ioaddr, uns
     /* read PROM address and compare with CSR address */
     for (i = 0; i < 6; i++)
 	promaddr[i] = inb(ioaddr + i);
-    
-    if( memcmp( promaddr, dev->dev_addr, 6)
-	|| !is_valid_ether_addr(dev->dev_addr) ) {
+
+    if (memcmp(promaddr, dev->dev_addr, 6)
+	|| !is_valid_ether_addr(dev->dev_addr)) {
 #ifndef __powerpc__
-	if( is_valid_ether_addr(promaddr) ){
+	if (is_valid_ether_addr(promaddr)) {
 #else
-	if( !is_valid_ether_addr(dev->dev_addr)
+	if (!is_valid_ether_addr(dev->dev_addr)
 	    && is_valid_ether_addr(promaddr)) {
 #endif
-	    printk(" warning: CSR address invalid,\n");
-	    printk(KERN_INFO "    using instead PROM address of");
+	    if (pcnet32_debug & NETIF_MSG_PROBE) {
+		printk(" warning: CSR address invalid,\n");
+		printk(KERN_INFO "    using instead PROM address of");
+	    }
 	    memcpy(dev->dev_addr, promaddr, 6);
 	}
     }
 
     /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
-    if( !is_valid_ether_addr(dev->dev_addr) )
+    if (!is_valid_ether_addr(dev->dev_addr))
 	memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
 
-    for (i = 0; i < 6; i++)
-	printk(" %2.2x", dev->dev_addr[i] );
-
-    if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */
-	i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
-	printk("\n" KERN_INFO "    tx_start_pt(0x%04x):",i);
-	switch(i>>10) {
-	    case 0: printk("  20 bytes,"); break;
-	    case 1: printk("  64 bytes,"); break;
-	    case 2: printk(" 128 bytes,"); break;
-	    case 3: printk("~220 bytes,"); break;
-	}
-	i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
-	printk(" BCR18(%x):",i&0xffff);
-	if (i & (1<<5)) printk("BurstWrEn ");
-	if (i & (1<<6)) printk("BurstRdEn ");
-	if (i & (1<<7)) printk("DWordIO ");
-	if (i & (1<<11)) printk("NoUFlow ");
-	i = a->read_bcr(ioaddr, 25);
-	printk("\n" KERN_INFO "    SRAMSIZE=0x%04x,",i<<8);
-	i = a->read_bcr(ioaddr, 26);
-	printk(" SRAM_BND=0x%04x,",i<<8);
-	i = a->read_bcr(ioaddr, 27);
-	if (i & (1<<14)) printk("LowLatRx");
+    if (pcnet32_debug & NETIF_MSG_PROBE) {
+	for (i = 0; i < 6; i++)
+	    printk(" %2.2x", dev->dev_addr[i]);
+
+	/* Version 0x2623 - 0x2624 */
+	if (((chip_version + 1) & 0xfffe) == 0x2624) {
+	    i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
+	    printk("\n" KERN_INFO "    tx_start_pt(0x%04x):",i);
+	    switch(i>>10) {
+		case 0: printk("  20 bytes,"); break;
+		case 1: printk("  64 bytes,"); break;
+		case 2: printk(" 128 bytes,"); break;
+		case 3: printk("~220 bytes,"); break;
+	    }
+	    i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
+	    printk(" BCR18(%x):",i&0xffff);
+	    if (i & (1<<5)) printk("BurstWrEn ");
+	    if (i & (1<<6)) printk("BurstRdEn ");
+	    if (i & (1<<7)) printk("DWordIO ");
+	    if (i & (1<<11)) printk("NoUFlow ");
+	    i = a->read_bcr(ioaddr, 25);
+	    printk("\n" KERN_INFO "    SRAMSIZE=0x%04x,",i<<8);
+	    i = a->read_bcr(ioaddr, 26);
+	    printk(" SRAM_BND=0x%04x,",i<<8);
+	    i = a->read_bcr(ioaddr, 27);
+	    if (i & (1<<14)) printk("LowLatRx");
+	}
     }
 
     dev->base_addr = ioaddr;
-    if (request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname) == NULL)
-	return -EBUSY;
-    
     /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
     if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
-	printk(KERN_ERR PFX "Consistent memory allocation failed.\n");
-	release_region(ioaddr, PCNET32_TOTAL_SIZE);
-	return -ENOMEM;
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(KERN_ERR PFX "Consistent memory allocation failed.\n");
+	ret = -ENOMEM;
+	goto err_free_netdev;
     }
 
     memset(lp, 0, sizeof(*lp));
@@ -996,7 +1207,9 @@ pcnet32_probe1(unsigned long ioaddr, uns
     lp->pci_dev = pdev;
 
     spin_lock_init(&lp->lock);
-    
+
+    SET_MODULE_OWNER(dev);
+    SET_NETDEV_DEV(dev, &pdev->dev);
     dev->priv = lp;
     lp->name = chipname;
     lp->shared_irq = shared;
@@ -1014,47 +1227,53 @@ pcnet32_probe1(unsigned long ioaddr, uns
     lp->mii_if.dev = dev;
     lp->mii_if.mdio_read = mdio_read;
     lp->mii_if.mdio_write = mdio_write;
-    
-    if (fdx && !(lp->options & PCNET32_PORT_ASEL) && 
+
+    if (fdx && !(lp->options & PCNET32_PORT_ASEL) &&
 		((cards_found>=MAX_UNITS) || full_duplex[cards_found]))
 	lp->options |= PCNET32_PORT_FD;
-    
+
     if (!a) {
-      printk(KERN_ERR PFX "No access methods\n");
-      pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
-      release_region(ioaddr, PCNET32_TOTAL_SIZE);
-      return -ENODEV;
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(KERN_ERR PFX "No access methods\n");
+	ret = -ENODEV;
+	goto err_free_consistent;
     }
     lp->a = *a;
-    
+
     /* detect special T1/E1 WAN card by checking for MAC address */
-    if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75)
+    if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0
+	    && dev->dev_addr[2] == 0x75)
 	lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
 
     lp->init_block.mode = le16_to_cpu(0x0003);	/* Disable Rx and Tx. */
-    lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); 
+    lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
     for (i = 0; i < 6; i++)
 	lp->init_block.phys_addr[i] = dev->dev_addr[i];
     lp->init_block.filter[0] = 0x00000000;
     lp->init_block.filter[1] = 0x00000000;
-    lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, rx_ring));
-    lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, tx_ring));
-    
+    lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr +
+	    offsetof(struct pcnet32_private, rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr +
+	    offsetof(struct pcnet32_private, tx_ring));
+
     /* switch pcnet32 to 32bit mode */
-    a->write_bcr (ioaddr, 20, 2);
+    a->write_bcr(ioaddr, 20, 2);
+
+    a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private,
+		    init_block)) & 0xffff);
+    a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private,
+		    init_block)) >> 16);
 
-    a->write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) & 0xffff);
-    a->write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16);
-    
     if (irq_line) {
 	dev->irq = irq_line;
     }
-    
-    if (dev->irq >= 2)
-	printk(" assigned IRQ %d.\n", dev->irq);
-    else {
+
+    if (dev->irq >= 2) {
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(" assigned IRQ %d.\n", dev->irq);
+    } else {
 	unsigned long irq_mask = probe_irq_on();
-	
+
 	/*
 	 * To auto-IRQ we enable the initialization-done and DMA error
 	 * interrupts. For ISA boards we get a DMA error, but VLB and PCI
@@ -1063,22 +1282,26 @@ pcnet32_probe1(unsigned long ioaddr, uns
 	/* Trigger an initialization just for the interrupt. */
 	a->write_csr (ioaddr, 0, 0x41);
 	mdelay (1);
-	
+
 	dev->irq = probe_irq_off (irq_mask);
-	if (dev->irq)
-	    printk(", probed IRQ %d.\n", dev->irq);
-	else {
-	    printk(", failed to detect IRQ line.\n");
-	    pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
-	    release_region(ioaddr, PCNET32_TOTAL_SIZE);
-	    return -ENODEV;
+	if (!dev->irq) {
+	    if (pcnet32_debug & NETIF_MSG_PROBE)
+		printk(", failed to detect IRQ line.\n");
+	    ret = -ENODEV;
+	    goto err_free_consistent;
 	}
+	if (pcnet32_debug & NETIF_MSG_PROBE)
+	    printk(", probed IRQ %d.\n", dev->irq);
     }
 
     /* Set the mii phy_id so that we can query the link state */
     if (lp->mii)
 	lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f;
-    
+
+    init_timer (&lp->watchdog_timer);
+    lp->watchdog_timer.data = (unsigned long) dev;
+    lp->watchdog_timer.function = (void *) &pcnet32_watchdog;
+
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
     dev->hard_start_xmit = &pcnet32_start_xmit;
@@ -1090,6 +1313,14 @@ pcnet32_probe1(unsigned long ioaddr, uns
     dev->tx_timeout = pcnet32_tx_timeout;
     dev->watchdog_timeo = (5*HZ);
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = pcnet32_poll_controller;
+#endif
+
+    /* Fill in the generic fields of the device structure. */
+    if (register_netdev(dev))
+	goto err_free_consistent;
+
     if (pdev) {
 	pci_set_drvdata(pdev, dev);
     } else {
@@ -1097,11 +1328,21 @@ pcnet32_probe1(unsigned long ioaddr, uns
 	pcnet32_dev = dev;
     }
 
-    /* Fill in the generic fields of the device structure. */
-    register_netdev(dev);
-    printk(KERN_INFO "%s: registered as %s\n",dev->name, lp->name);
+    if (pcnet32_debug & NETIF_MSG_PROBE)
+	printk(KERN_INFO "%s: registered as %s\n", dev->name, lp->name);
     cards_found++;
+
+    a->write_bcr(ioaddr, 2, 0x1002);	/* enable LED writes */
+
     return 0;
+
+err_free_consistent:
+    pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+err_free_netdev:
+    free_netdev(dev);
+err_release_region:
+    release_region(ioaddr, PCNET32_TOTAL_SIZE);
+    return ret;
 }
 
 
@@ -1113,13 +1354,15 @@ pcnet32_open(struct net_device *dev)
     u16 val;
     int i;
     int rc;
+    unsigned long flags;
 
     if (dev->irq == 0 ||
 	request_irq(dev->irq, &pcnet32_interrupt,
-		    lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) {
+		    lp->shared_irq ? SA_SHIRQ : 0, dev->name, (void *)dev)) {
 	return -EAGAIN;
     }
 
+    spin_lock_irqsave(&lp->lock, flags);
     /* Check for a valid station address */
     if (!is_valid_ether_addr(dev->dev_addr)) {
 	rc = -EINVAL;
@@ -1138,13 +1381,13 @@ pcnet32_open(struct net_device *dev)
 	       (u32) (lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)),
 	       (u32) (lp->dma_addr + offsetof(struct pcnet32_private, rx_ring)),
 	       (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)));
-    
+
     /* set/reset autoselect bit */
     val = lp->a.read_bcr (ioaddr, 2) & ~2;
     if (lp->options & PCNET32_PORT_ASEL)
 	val |= 2;
     lp->a.write_bcr (ioaddr, 2, val);
-    
+
     /* handle full duplex setting */
     if (lp->mii_if.full_duplex) {
 	val = lp->a.read_bcr (ioaddr, 9) & ~3;
@@ -1154,34 +1397,38 @@ pcnet32_open(struct net_device *dev)
 		val |= 2;
 	} else if (lp->options & PCNET32_PORT_ASEL) {
 	/* workaround of xSeries250, turn on for 79C975 only */
-	    i = ((lp->a.read_csr(ioaddr, 88) | (lp->a.read_csr(ioaddr,89) << 16)) >> 12) & 0xffff;
-	    if (i == 0x2627) val |= 3;
+	    i = ((lp->a.read_csr(ioaddr, 88) |
+			(lp->a.read_csr(ioaddr,89) << 16)) >> 12) & 0xffff;
+	    if (i == 0x2627)
+		val |= 3;
 	}
 	lp->a.write_bcr (ioaddr, 9, val);
     }
-    
+
     /* set/reset GPSI bit in test register */
     val = lp->a.read_csr (ioaddr, 124) & ~0x10;
     if ((lp->options & PCNET32_PORT_PORTSEL) == PCNET32_PORT_GPSI)
 	val |= 0x10;
     lp->a.write_csr (ioaddr, 124, val);
-    
+
     if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) {
-	val = lp->a.read_bcr (ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */
+	/* disable Auto Negotiation, set 10Mpbs, HD */
+	val = lp->a.read_bcr (ioaddr, 32) & ~0x38;
 	if (lp->options & PCNET32_PORT_FD)
 	    val |= 0x10;
 	if (lp->options & PCNET32_PORT_100)
 	    val |= 0x08;
 	lp->a.write_bcr (ioaddr, 32, val);
     } else {
-	if (lp->options & PCNET32_PORT_ASEL) {  /* enable auto negotiate, setup, disable fd */
-		val = lp->a.read_bcr(ioaddr, 32) & ~0x98;
-		val |= 0x20;
-		lp->a.write_bcr(ioaddr, 32, val);
+	if (lp->options & PCNET32_PORT_ASEL) {
+	    /* enable auto negotiate, setup, disable fd */
+	    val = lp->a.read_bcr(ioaddr, 32) & ~0x98;
+	    val |= 0x20;
+	    lp->a.write_bcr(ioaddr, 32, val);
 	}
     }
 
-#ifdef DO_DXSUFLO 
+#ifdef DO_DXSUFLO
     if (lp->dxsuflo) { /* Disable transmit stop on underflow */
 	val = lp->a.read_csr (ioaddr, 3);
 	val |= 0x40;
@@ -1194,29 +1441,42 @@ pcnet32_open(struct net_device *dev)
 	val |= (1<<14);
 	lp->a.write_csr (ioaddr, 5, val);
     }
-   
+
     lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
-    lp->init_block.filter[0] = 0x00000000;
-    lp->init_block.filter[1] = 0x00000000;
+    pcnet32_load_multicast(dev);
+
     if (pcnet32_init_ring(dev)) {
 	rc = -ENOMEM;
 	goto err_free_ring;
     }
-    
+
     /* Re-initialize the PCNET32, and start it when done. */
-    lp->a.write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) &0xffff);
-    lp->a.write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16);
+    lp->a.write_csr (ioaddr, 1, (lp->dma_addr +
+		offsetof(struct pcnet32_private, init_block)) &0xffff);
+    lp->a.write_csr (ioaddr, 2, (lp->dma_addr +
+		offsetof(struct pcnet32_private, init_block)) >> 16);
 
     lp->a.write_csr (ioaddr, 4, 0x0915);
     lp->a.write_csr (ioaddr, 0, 0x0001);
 
+    if (lp->ltint) {
+	/* start the software timer */
+	lp->a.write_csr(ioaddr, 7, 0x0400);	/* set STINTE */
+    }
+
     netif_start_queue(dev);
 
+    /* If we have mii, print the link status and start the watchdog */
+    if (lp->mii) {
+	mii_check_media (&lp->mii_if, netif_msg_link(lp), 1);
+	mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+    }
+
     i = 0;
     while (i++ < 100)
 	if (lp->a.read_csr (ioaddr, 0) & 0x0100)
 	    break;
-    /* 
+    /*
      * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
      * reports that doing so triggers a bug in the '974.
      */
@@ -1224,33 +1484,34 @@ pcnet32_open(struct net_device *dev)
 
     if (netif_msg_ifup(lp))
 	printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
-	       dev->name, i, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)),
-	       lp->a.read_csr(ioaddr, 0));
+		dev->name, i, (u32) (lp->dma_addr +
+		    offsetof(struct pcnet32_private, init_block)),
+		lp->a.read_csr(ioaddr, 0));
 
+    spin_unlock_irqrestore(&lp->lock, flags);
 
-    MOD_INC_USE_COUNT;
-    
     return 0;	/* Always succeed */
 
 err_free_ring:
     /* free any allocated skbuffs */
     for (i = 0; i < RX_RING_SIZE; i++) {
-	lp->rx_ring[i].status = 0;			    
+	lp->rx_ring[i].status = 0;
 	if (lp->rx_skbuff[i]) {
-            pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2,
+	    pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2,
 		    PCI_DMA_FROMDEVICE);
 	    dev_kfree_skb(lp->rx_skbuff[i]);
-        }
+	}
 	lp->rx_skbuff[i] = NULL;
-        lp->rx_dma_addr[i] = 0;
+	lp->rx_dma_addr[i] = 0;
     }
     /*
-     * Switch back to 16bit mode to avoid problems with dumb 
+     * Switch back to 16bit mode to avoid problems with dumb
      * DOS packet driver after a warm reboot
      */
     lp->a.write_bcr (ioaddr, 20, 4);
 
 err_free_irq:
+    spin_unlock_irqrestore(&lp->lock, flags);
     free_irq(dev->irq, dev);
     return rc;
 }
@@ -1268,7 +1529,7 @@ err_free_irq:
  * restarting the chip, but I'm too lazy to do so right now.  dplatt@3do.com
  */
 
-static void 
+static void
 pcnet32_purge_tx_ring(struct net_device *dev)
 {
     struct pcnet32_private *lp = dev->priv;
@@ -1276,10 +1537,11 @@ pcnet32_purge_tx_ring(struct net_device 
 
     for (i = 0; i < TX_RING_SIZE; i++) {
 	if (lp->tx_skbuff[i]) {
-            pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
-	    dev_kfree_skb_any(lp->tx_skbuff[i]); 
+	    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
+		    lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
+	    dev_kfree_skb_any(lp->tx_skbuff[i]);
 	    lp->tx_skbuff[i] = NULL;
-            lp->tx_dma_addr[i] = 0;
+	    lp->tx_dma_addr[i] = 0;
 	}
     }
 }
@@ -1297,37 +1559,41 @@ pcnet32_init_ring(struct net_device *dev
     lp->dirty_rx = lp->dirty_tx = 0;
 
     for (i = 0; i < RX_RING_SIZE; i++) {
-        struct sk_buff *rx_skbuff = lp->rx_skbuff[i];
+	struct sk_buff *rx_skbuff = lp->rx_skbuff[i];
 	if (rx_skbuff == NULL) {
 	    if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
 		/* there is not much, we can do at this point */
-		printk(KERN_ERR "%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
+		if (pcnet32_debug & NETIF_MSG_DRV)
+		    printk(KERN_ERR "%s: pcnet32_init_ring dev_alloc_skb failed.\n",
+			    dev->name);
 		return -1;
 	    }
 	    skb_reserve (rx_skbuff, 2);
 	}
 
-	if (lp->rx_dma_addr[i] == 0) 
-		lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev,
-			rx_skbuff->tail, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
+	if (lp->rx_dma_addr[i] == 0)
+	    lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail,
+		    PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
 	lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]);
 	lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
 	lp->rx_ring[i].status = le16_to_cpu(0x8000);
     }
     /* The Tx buffer address is filled in as needed, but we do need to clear
-       the upper ownership bit. */
+     * the upper ownership bit. */
     for (i = 0; i < TX_RING_SIZE; i++) {
 	lp->tx_ring[i].base = 0;
 	lp->tx_ring[i].status = 0;
-        lp->tx_dma_addr[i] = 0;
+	lp->tx_dma_addr[i] = 0;
     }
     wmb(); /* Make sure all changes are visible */
 
     lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
     for (i = 0; i < 6; i++)
 	lp->init_block.phys_addr[i] = dev->dev_addr[i];
-    lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, rx_ring));
-    lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr + offsetof(struct pcnet32_private, tx_ring));
+    lp->init_block.rx_ring = (u32)le32_to_cpu(lp->dma_addr +
+	    offsetof(struct pcnet32_private, rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr +
+	    offsetof(struct pcnet32_private, tx_ring));
     return 0;
 }
 
@@ -1337,11 +1603,11 @@ pcnet32_restart(struct net_device *dev, 
     struct pcnet32_private *lp = dev->priv;
     unsigned long ioaddr = dev->base_addr;
     int i;
-    
+
     pcnet32_purge_tx_ring(dev);
     if (pcnet32_init_ring(dev))
 	return;
-    
+
     /* ReInit Ring */
     lp->a.write_csr (ioaddr, 0, 1);
     i = 0;
@@ -1361,31 +1627,32 @@ pcnet32_tx_timeout (struct net_device *d
 
     spin_lock_irqsave(&lp->lock, flags);
     /* Transmitter timeout, serious problems. */
+    if (pcnet32_debug & NETIF_MSG_DRV)
 	printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n",
-	       dev->name, lp->a.read_csr(ioaddr, 0));
-	lp->a.write_csr (ioaddr, 0, 0x0004);
-	lp->stats.tx_errors++;
-	if (netif_msg_tx_err(lp)) {
-	    int i;
-	    printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
-	       lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
-	       lp->cur_rx);
-	    for (i = 0 ; i < RX_RING_SIZE; i++)
-	    printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-		   lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
-		   lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
-	    for (i = 0 ; i < TX_RING_SIZE; i++)
-	    printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-		   lp->tx_ring[i].base, -lp->tx_ring[i].length,
-		   lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
-	    printk("\n");
-	}
-	pcnet32_restart(dev, 0x0042);
+		dev->name, lp->a.read_csr(ioaddr, 0));
+    lp->a.write_csr (ioaddr, 0, 0x0004);
+    lp->stats.tx_errors++;
+    if (netif_msg_tx_err(lp)) {
+	int i;
+	printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+	   lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+	   lp->cur_rx);
+	for (i = 0 ; i < RX_RING_SIZE; i++)
+	printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+	       lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+	       lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
+	for (i = 0 ; i < TX_RING_SIZE; i++)
+	printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+	       lp->tx_ring[i].base, -lp->tx_ring[i].length,
+	       lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
+	printk("\n");
+    }
+    pcnet32_restart(dev, 0x0042);
 
-	dev->trans_start = jiffies;
-	netif_wake_queue(dev);
+    dev->trans_start = jiffies;
+    netif_wake_queue(dev);
 
-	spin_unlock_irqrestore(&lp->lock, flags);
+    spin_unlock_irqrestore(&lp->lock, flags);
 }
 
 
@@ -1398,13 +1665,13 @@ pcnet32_start_xmit(struct sk_buff *skb, 
     int entry;
     unsigned long flags;
 
+    spin_lock_irqsave(&lp->lock, flags);
+
     if (netif_msg_tx_queued(lp)) {
 	printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
 	       dev->name, lp->a.read_csr(ioaddr, 0));
     }
 
-    spin_lock_irqsave(&lp->lock, flags);
-
     /* Default status -- will not enable Successful-TxDone
      * interrupt when that option is available to us.
      */
@@ -1422,21 +1689,22 @@ pcnet32_start_xmit(struct sk_buff *skb, 
 	 */
 	status = 0x9300;
     }
-  
+
     /* Fill in a Tx ring entry */
-  
+
     /* Mask to ring buffer boundary. */
     entry = lp->cur_tx & TX_RING_MOD_MASK;
-  
+
     /* Caution: the write order is important here, set the status
-       with the "ownership" bits last. */
+     * with the "ownership" bits last. */
 
     lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
 
     lp->tx_ring[entry].misc = 0x00000000;
 
     lp->tx_skbuff[entry] = skb;
-    lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+    lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len,
+	    PCI_DMA_TODEVICE);
     lp->tx_ring[entry].base = (u32)le32_to_cpu(lp->tx_dma_addr[entry]);
     wmb(); /* Make sure owner changes after all others are visible */
     lp->tx_ring[entry].status = le16_to_cpu(status);
@@ -1464,29 +1732,36 @@ pcnet32_interrupt(int irq, void *dev_id,
     struct net_device *dev = dev_id;
     struct pcnet32_private *lp;
     unsigned long ioaddr;
-    u16 csr0,rap;
+    u16 csr0, csr7, rap;
     int boguscnt =  max_interrupt_work;
     int must_restart;
 
     if (!dev) {
-	printk (KERN_DEBUG "%s(): irq %d for unknown device\n",
+	if (pcnet32_debug & NETIF_MSG_INTR)
+	    printk (KERN_DEBUG "%s(): irq %d for unknown device\n",
 		__FUNCTION__, irq);
 	return;
     }
 
     ioaddr = dev->base_addr;
     lp = dev->priv;
-    
+
     spin_lock(&lp->lock);
-    
+
     rap = lp->a.read_rap(ioaddr);
-    while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) {
+    csr0 = lp->a.read_csr (ioaddr, 0);
+    csr7 = lp->ltint ? lp->a.read_csr(ioaddr, 7) : 0;
+
+    while ((csr0 & 0x8600 || csr7 & 0x0800) && --boguscnt >= 0) {
 	if (csr0 == 0xffff) {
 	    break;			/* PCMCIA remove happened */
 	}
 	/* Acknowledge all of the current interrupt sources ASAP. */
 	lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f);
 
+	if (csr7 & 0x0800)
+	    lp->a.write_csr(ioaddr, 7, csr7);
+
 	must_restart = 0;
 
 	if (netif_msg_intr(lp))
@@ -1496,14 +1771,14 @@ pcnet32_interrupt(int irq, void *dev_id,
 	if (csr0 & 0x0400)		/* Rx interrupt */
 	    pcnet32_rx(dev);
 
-	if (csr0 & 0x0200) {		/* Tx-done interrupt */
+	if (csr0 & 0x0200 || csr7 & 0x0800) {	/* Tx-done or Timer interrupt */
 	    unsigned int dirty_tx = lp->dirty_tx;
 	    int delta;
 
 	    while (dirty_tx != lp->cur_tx) {
 		int entry = dirty_tx & TX_RING_MOD_MASK;
 		int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
-			
+
 		if (status < 0)
 		    break;		/* It still hasn't been Txed */
 
@@ -1521,8 +1796,9 @@ pcnet32_interrupt(int irq, void *dev_id,
 			lp->stats.tx_fifo_errors++;
 			/* Ackk!  On FIFO errors the Tx unit is turned off! */
 			/* Remove this verbosity later! */
-			printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
-			       dev->name, csr0);
+			if (netif_msg_tx_err(lp))
+			    printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
+				    dev->name, csr0);
 			must_restart = 1;
 		    }
 #else
@@ -1531,8 +1807,9 @@ pcnet32_interrupt(int irq, void *dev_id,
 			if (! lp->dxsuflo) {  /* If controller doesn't recover ... */
 			    /* Ackk!  On FIFO errors the Tx unit is turned off! */
 			    /* Remove this verbosity later! */
-			    printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
-				   dev->name, csr0);
+			    if (netif_msg_tx_err(lp))
+				printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
+					dev->name, csr0);
 			    must_restart = 1;
 			}
 		    }
@@ -1545,19 +1822,20 @@ pcnet32_interrupt(int irq, void *dev_id,
 
 		/* We must free the original skb */
 		if (lp->tx_skbuff[entry]) {
-                    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry],
+		    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry],
 			lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
 		    dev_kfree_skb_irq(lp->tx_skbuff[entry]);
 		    lp->tx_skbuff[entry] = 0;
-                    lp->tx_dma_addr[entry] = 0;
+		    lp->tx_dma_addr[entry] = 0;
 		}
 		dirty_tx++;
 	    }
 
 	    delta = (lp->cur_tx - dirty_tx) & (TX_RING_MOD_MASK + TX_RING_SIZE);
 	    if (delta >= TX_RING_SIZE) {
-		printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-			dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
+		if (netif_msg_drv(lp))
+		    printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+			    dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
 		dirty_tx += TX_RING_SIZE;
 		delta -= TX_RING_SIZE;
 	    }
@@ -1578,18 +1856,20 @@ pcnet32_interrupt(int irq, void *dev_id,
 	    /*
 	     * this happens when our receive ring is full. This shouldn't
 	     * be a problem as we will see normal rx interrupts for the frames
-	     * in the receive ring. But there are some PCI chipsets (I can reproduce
-	     * this on SP3G with Intel saturn chipset) which have sometimes problems
-	     * and will fill up the receive ring with error descriptors. In this
-	     * situation we don't get a rx interrupt, but a missed frame interrupt sooner
-	     * or later. So we try to clean up our receive ring here.
+	     * in the receive ring. But there are some PCI chipsets (I can
+	     * reproduce this on SP3G with Intel saturn chipset) which have
+	     * sometimes problems and will fill up the receive ring with
+	     * error descriptors. In this situation we don't get a rx
+	     * interrupt, but a missed frame interrupt sooner or later.
+	     * So we try to clean up our receive ring here.
 	     */
 	    pcnet32_rx(dev);
 	    lp->stats.rx_errors++; /* Missed a Rx frame. */
 	}
 	if (csr0 & 0x0800) {
-	    printk(KERN_ERR "%s: Bus master arbitration failure, status %4.4x.\n",
-		   dev->name, csr0);
+	    if (netif_msg_drv(lp))
+		printk(KERN_ERR "%s: Bus master arbitration failure, status %4.4x.\n",
+			dev->name, csr0);
 	    /* unlike for the lance, there is no restart needed */
 	}
 
@@ -1598,15 +1878,18 @@ pcnet32_interrupt(int irq, void *dev_id,
 	    lp->a.write_csr (ioaddr, 0, 0x0004);
 	    pcnet32_restart(dev, 0x0002);
 	}
+
+	csr0 = lp->a.read_csr (ioaddr, 0);
+	csr7 = lp->ltint ? lp->a.read_csr(ioaddr, 7) : 0;
     }
 
     /* Clear any other interrupt, and set interrupt enable. */
     lp->a.write_csr (ioaddr, 0, 0x7940);
     lp->a.write_rap (ioaddr,rap);
-    
+
     if (netif_msg_intr(lp))
 	printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
-	       dev->name, lp->a.read_csr (ioaddr, 0));
+		dev->name, lp->a.read_csr (ioaddr, 0));
 
     spin_unlock(&lp->lock);
 }
@@ -1622,7 +1905,7 @@ pcnet32_rx(struct net_device *dev)
 	int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
 
 	if (status != 0x03) {			/* There was an error. */
-	    /* 
+	    /*
 	     * There is a tricky error noted by John Murphy,
 	     * <murf@perftech.com> to Russ Nelson: Even with full-sized
 	     * buffers it's possible for a jabber packet to use two
@@ -1639,17 +1922,18 @@ pcnet32_rx(struct net_device *dev)
 	    /* Malloc up new buffer, compatible with net-2e. */
 	    short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
 	    struct sk_buff *skb;
-			
-	    if(pkt_len < 60) {
-		printk(KERN_ERR "%s: Runt packet!\n",dev->name);
+
+	    if (pkt_len < 60) {
+		if (netif_msg_rx_err(lp))
+		    printk(KERN_ERR "%s: Runt packet!\n", dev->name);
 		lp->stats.rx_errors++;
 	    } else {
 		int rx_in_place = 0;
 
 		if (pkt_len > rx_copybreak) {
 		    struct sk_buff *newskb;
-				
-		    if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {
+
+		    if ((newskb = dev_alloc_skb(PKT_BUF_SZ))) {
 			skb_reserve (newskb, 2);
 			skb = lp->rx_skbuff[entry];
 			pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry],
@@ -1657,27 +1941,31 @@ pcnet32_rx(struct net_device *dev)
 			skb_put (skb, pkt_len);
 			lp->rx_skbuff[entry] = newskb;
 			newskb->dev = dev;
-                        lp->rx_dma_addr[entry] = 
-				pci_map_single(lp->pci_dev, newskb->tail,
-					PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
+			lp->rx_dma_addr[entry] =
+			    pci_map_single(lp->pci_dev, newskb->tail,
+				    PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
 			lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
 			rx_in_place = 1;
 		    } else
 			skb = NULL;
 		} else {
 		    skb = dev_alloc_skb(pkt_len+2);
-                }
-			    
+		}
+
 		if (skb == NULL) {
-                    int i;
-		    printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
+		    int i;
+		    if (netif_msg_drv(lp))
+			printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n",
+				dev->name);
 		    for (i = 0; i < RX_RING_SIZE; i++)
-			if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
+			if ((short)le16_to_cpu(lp->rx_ring[(entry+i)
+				    & RX_RING_MOD_MASK].status) < 0)
 			    break;
 
 		    if (i > RX_RING_SIZE -2) {
 			lp->stats.rx_dropped++;
 			lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+			wmb();	/* Make sure adapter sees owner change */
 			lp->cur_rx++;
 		    }
 		    break;
@@ -1691,8 +1979,8 @@ pcnet32_rx(struct net_device *dev)
 		                        PKT_BUF_SZ-2,
 		                        PCI_DMA_FROMDEVICE);
 		    eth_copy_and_sum(skb,
-				     (unsigned char *)(lp->rx_skbuff[entry]->tail),
-				     pkt_len,0);
+			    (unsigned char *)(lp->rx_skbuff[entry]->tail),
+			    pkt_len,0);
 		}
 		lp->stats.rx_bytes += skb->len;
 		skb->protocol=eth_type_trans(skb,dev);
@@ -1720,9 +2008,14 @@ pcnet32_close(struct net_device *dev)
     unsigned long ioaddr = dev->base_addr;
     struct pcnet32_private *lp = dev->priv;
     int i;
+    unsigned long flags;
+
+    del_timer_sync(&lp->watchdog_timer);
 
     netif_stop_queue(dev);
 
+    spin_lock_irqsave(&lp->lock, flags);
+
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
 
     if (netif_msg_ifdown(lp))
@@ -1732,36 +2025,48 @@ pcnet32_close(struct net_device *dev)
     /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
     lp->a.write_csr (ioaddr, 0, 0x0004);
 
+    if (lp->ltint) {	/* Disable timer interrupts */
+	lp->a.write_csr(ioaddr, 7, 0x0000);
+    }
+
     /*
-     * Switch back to 16bit mode to avoid problems with dumb 
+     * Switch back to 16bit mode to avoid problems with dumb
      * DOS packet driver after a warm reboot
      */
     lp->a.write_bcr (ioaddr, 20, 4);
 
+    spin_unlock_irqrestore(&lp->lock, flags);
+
     free_irq(dev->irq, dev);
-    
+
+    spin_lock_irqsave(&lp->lock, flags);
+
     /* free all allocated skbuffs */
     for (i = 0; i < RX_RING_SIZE; i++) {
-	lp->rx_ring[i].status = 0;			    
+	lp->rx_ring[i].status = 0;
+	wmb();		/* Make sure adapter sees owner change */
 	if (lp->rx_skbuff[i]) {
-            pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2,
+	    pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2,
 		    PCI_DMA_FROMDEVICE);
 	    dev_kfree_skb(lp->rx_skbuff[i]);
         }
 	lp->rx_skbuff[i] = NULL;
-        lp->rx_dma_addr[i] = 0;
+	lp->rx_dma_addr[i] = 0;
     }
-    
+
     for (i = 0; i < TX_RING_SIZE; i++) {
+	lp->tx_ring[i].status = 0;	/* CPU owns buffer */
+	wmb();		/* Make sure adapter sees owner change */
 	if (lp->tx_skbuff[i]) {
-            pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
+	    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
+		    lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
 	    dev_kfree_skb(lp->tx_skbuff[i]);
-        }
+	}
 	lp->tx_skbuff[i] = NULL;
-        lp->tx_dma_addr[i] = 0;
+	lp->tx_dma_addr[i] = 0;
     }
-    
-    MOD_DEC_USE_COUNT;
+
+    spin_unlock_irqrestore(&lp->lock, flags);
 
     return 0;
 }
@@ -1793,9 +2098,9 @@ static void pcnet32_load_multicast (stru
     char *addrs;
     int i;
     u32 crc;
-	
+
     /* set all multicast bits */
-    if (dev->flags & IFF_ALLMULTI){ 
+    if (dev->flags & IFF_ALLMULTI) {
 	ib->filter[0] = 0xffffffff;
 	ib->filter[1] = 0xffffffff;
 	return;
@@ -1805,19 +2110,18 @@ static void pcnet32_load_multicast (stru
     ib->filter[1] = 0;
 
     /* Add addresses */
-    for (i = 0; i < dev->mc_count; i++){
+    for (i = 0; i < dev->mc_count; i++) {
 	addrs = dmi->dmi_addr;
 	dmi   = dmi->next;
-	
+
 	/* multicast address? */
 	if (!(*addrs & 1))
 	    continue;
-	
+
 	crc = ether_crc_le(6, addrs);
 	crc = crc >> 26;
 	mcast_table [crc >> 4] = le16_to_cpu(
-		le16_to_cpu(mcast_table [crc >> 4]) | (1 << (crc & 0xf))
-	);
+		le16_to_cpu(mcast_table [crc >> 4]) | (1 << (crc & 0xf)));
     }
     return;
 }
@@ -1829,18 +2133,19 @@ static void pcnet32_load_multicast (stru
 static void pcnet32_set_multicast_list(struct net_device *dev)
 {
     unsigned long ioaddr = dev->base_addr, flags;
-    struct pcnet32_private *lp = dev->priv;	 
+    struct pcnet32_private *lp = dev->priv;
 
     spin_lock_irqsave(&lp->lock, flags);
     if (dev->flags&IFF_PROMISC) {
 	/* Log any net taps. */
-	printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+	if (netif_msg_hw(lp))
+	    printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
 	lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << 7);
     } else {
 	lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
 	pcnet32_load_multicast (dev);
     }
-    
+
     lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
 
     pcnet32_restart(dev, 0x0042); /*  Resume normal operation */
@@ -1849,42 +2154,42 @@ static void pcnet32_set_multicast_list(s
 
 static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
 {
-	struct pcnet32_private *lp = dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	u16 val_out;
-	int phyaddr;
-
-	if (!lp->mii)
-		return 0;
-		
-	phyaddr = lp->a.read_bcr(ioaddr, 33);
-
-	lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
-	val_out = lp->a.read_bcr(ioaddr, 34);
-	lp->a.write_bcr(ioaddr, 33, phyaddr);
-	
-	return val_out;
+    struct pcnet32_private *lp = dev->priv;
+    unsigned long ioaddr = dev->base_addr;
+    u16 val_out;
+    int phyaddr;
+
+    if (!lp->mii)
+	return 0;
+
+    phyaddr = lp->a.read_bcr(ioaddr, 33);
+
+    lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
+    val_out = lp->a.read_bcr(ioaddr, 34);
+    lp->a.write_bcr(ioaddr, 33, phyaddr);
+
+    return val_out;
 }
 
 static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
 {
-	struct pcnet32_private *lp = dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	int phyaddr;
+    struct pcnet32_private *lp = dev->priv;
+    unsigned long ioaddr = dev->base_addr;
+    int phyaddr;
 
-	if (!lp->mii)
-		return;
-		
-	phyaddr = lp->a.read_bcr(ioaddr, 33);
-
-	lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
-	lp->a.write_bcr(ioaddr, 34, val);
-	lp->a.write_bcr(ioaddr, 33, phyaddr);
+    if (!lp->mii)
+	return;
+
+    phyaddr = lp->a.read_bcr(ioaddr, 33);
+
+    lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));
+    lp->a.write_bcr(ioaddr, 34, val);
+    lp->a.write_bcr(ioaddr, 33, phyaddr);
 }
 
 static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-    struct pcnet32_private *lp = dev->priv;	 
+    struct pcnet32_private *lp = dev->priv;
     struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
     int rc;
     unsigned long flags;
@@ -1901,6 +2206,21 @@ static int pcnet32_ioctl(struct net_devi
     return rc;
 }
 
+static void pcnet32_watchdog(struct net_device *dev)
+{
+    struct pcnet32_private *lp = dev->priv;
+    unsigned long flags;
+
+    /* Print the link status if it has changed */
+    if (lp->mii) {
+	spin_lock_irqsave(&lp->lock, flags);
+	mii_check_media (&lp->mii_if, netif_msg_link(lp), 0);
+	spin_unlock_irqrestore(&lp->lock, flags);
+    }
+
+    mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+}
+
 static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
 {
     struct net_device *dev = pci_get_drvdata(pdev);
@@ -1926,15 +2246,15 @@ static struct pci_driver pcnet32_driver 
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, DRV_NAME " debug level");
 MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per interrupt");  
+MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per interrupt");
 MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM_DESC(rx_copybreak, DRV_NAME " copy breakpoint for copy-only-tiny-frames"); 
+MODULE_PARM_DESC(rx_copybreak, DRV_NAME " copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM(tx_start_pt, "i");
-MODULE_PARM_DESC(tx_start_pt, DRV_NAME " transmit start point (0-3)"); 
+MODULE_PARM_DESC(tx_start_pt, DRV_NAME " transmit start point (0-3)");
 MODULE_PARM(pcnet32vlb, "i");
-MODULE_PARM_DESC(pcnet32vlb, DRV_NAME " Vesa local bus (VLB) support (0/1)"); 
+MODULE_PARM_DESC(pcnet32vlb, DRV_NAME " Vesa local bus (VLB) support (0/1)");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(options, DRV_NAME " initial option setting(s) (0-15)"); 
+MODULE_PARM_DESC(options, DRV_NAME " initial option setting(s) (0-15)");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM_DESC(full_duplex, DRV_NAME " full duplex setting(s) (1)");
 
@@ -1942,6 +2262,8 @@ MODULE_AUTHOR("Thomas Bogendoerfer");
 MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards");
 MODULE_LICENSE("GPL");
 
+#define PCNET32_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+
 /* An additional parameter that may be passed in... */
 static int debug = -1;
 static int tx_start_pt = -1;
@@ -1951,8 +2273,7 @@ static int __init pcnet32_init_module(vo
 {
     printk(KERN_INFO "%s", version);
 
-    if (debug >= 0 && debug < (sizeof(int) - 1))
-	pcnet32_debug = 1 << debug;
+    pcnet32_debug = netif_msg_init(debug, PCNET32_MSG_DEFAULT);
 
     if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
 	tx_start = tx_start_pt;
@@ -1965,9 +2286,9 @@ static int __init pcnet32_init_module(vo
     if (pcnet32vlb)
 	pcnet32_probe_vlbus();
 
-    if (cards_found)
+    if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
 	printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
-    
+
     return (pcnet32_have_pci + cards_found) ? 0 : -ENODEV;
 }
 
@@ -1975,7 +2296,6 @@ static void __exit pcnet32_cleanup_modul
 {
     struct net_device *next_dev;
 
-    /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
     while (pcnet32_dev) {
 	struct pcnet32_private *lp = pcnet32_dev->priv;
 	next_dev = lp->next;
@@ -1985,6 +2305,7 @@ static void __exit pcnet32_cleanup_modul
 	free_netdev(pcnet32_dev);
 	pcnet32_dev = next_dev;
     }
+
     if (pcnet32_have_pci)
 	pci_unregister_driver(&pcnet32_driver);
 }
@@ -1994,7 +2315,6 @@ module_exit(pcnet32_cleanup_module);
 
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c pcnet32.c"
  *  c-indent-level: 4
  *  tab-width: 8
  * End:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/tg3.c linux-2.4.27-pre3/drivers/net/tg3.c
--- linux-2.4.26/drivers/net/tg3.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/tg3.c	2004-05-18 16:52:51.000000000 +0000
@@ -55,8 +55,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"2.9"
-#define DRV_MODULE_RELDATE	"March 8, 2004"
+#define DRV_MODULE_VERSION	"3.3"
+#define DRV_MODULE_RELDATE	"April 27, 2004"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -125,6 +125,8 @@
 /* minimum number of free TX descriptors required to wake up TX process */
 #define TG3_TX_WAKEUP_THRESH		(TG3_TX_RING_SIZE / 4)
 
+#define TG3_NUM_STATS		25	/* number of ETHTOOL_GSTATS u64's */
+
 static char version[] __devinitdata =
 	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
@@ -198,6 +200,37 @@ static struct pci_device_id tg3_pci_tbl[
 
 MODULE_DEVICE_TABLE(pci, tg3_pci_tbl);
 
+struct {
+	char string[ETH_GSTRING_LEN];
+} ethtool_stats_keys[TG3_NUM_STATS] = {
+	{ "rx_fragments" },
+	{ "rx_ucast_packets" },
+	{ "rx_bcast_packets" },
+	{ "rx_fcs_errors" },
+	{ "rx_xon_pause_rcvd" },
+	{ "rx_xoff_pause_rcvd" },
+	{ "rx_mac_ctrl_rcvd" },
+	{ "rx_xoff_entered" },
+	{ "rx_frame_too_long_errors" },
+	{ "rx_jabbers" },
+	{ "rx_undersize_packets" },
+	{ "rx_in_length_errors" },
+	{ "rx_out_length_errors" },
+
+	{ "tx_xon_sent" },
+	{ "tx_xoff_sent" },
+	{ "tx_flow_control" },
+	{ "tx_mac_errors" },
+	{ "tx_single_collisions" },
+	{ "tx_mult_collisions" },
+	{ "tx_deferred" },
+	{ "tx_excessive_collisions" },
+	{ "tx_late_collisions" },
+	{ "tx_ucast_packets" },
+	{ "tx_mcast_packets" },
+	{ "tx_bcast_packets" }
+};
+
 static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
 {
 	if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
@@ -642,7 +675,14 @@ static int tg3_phy_reset_5703_4_5(struct
 	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
 	tg3_writephy(tp, 0x16, 0x0000);
 
-	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		/* Set Extended packet length bit for jumbo frames */
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4400);
+	}
+	else {
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
+	}
 
 	tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
 
@@ -656,7 +696,7 @@ static int tg3_phy_reset_5703_4_5(struct
 /* 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 int tg3_phy_reset(struct tg3 *tp)
 {
 	u32 phy_status;
 	int err;
@@ -666,12 +706,6 @@ static int tg3_phy_reset(struct tg3 *tp,
 	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) {
@@ -698,6 +732,30 @@ out:
 		tg3_writephy(tp, 0x1c, 0x8d68);
 		tg3_writephy(tp, 0x1c, 0x8d68);
 	}
+	if (tp->tg3_flags2 & TG3_FLG2_PHY_BER_BUG) {
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
+		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x310b);
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
+		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x9506);
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x401f);
+		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x14e2);
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
+	}
+	/* Set Extended packet length bit (bit 14) on all chips that */
+	/* support jumbo frames */
+	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
+		/* Cannot do read-modify-write on 5401 */
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
+	}
+	else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		u32 phy_reg;
+
+		/* Set bit 14 with read-modify-write to preserve other bits */
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007);
+		tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy_reg);
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, phy_reg | 0x4000);
+	}
 	tg3_phy_set_wirespeed(tp);
 	return 0;
 }
@@ -1189,7 +1247,8 @@ static int tg3_init_5401phy_dsp(struct t
 	int err;
 
 	/* Turn off tap power management. */
-	err  = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c20);
+	/* Set Extended packet length bit */
+	err  = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
 
 	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x0012);
 	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x1804);
@@ -1211,6 +1270,27 @@ static int tg3_init_5401phy_dsp(struct t
 	return err;
 }
 
+static int tg3_copper_is_advertising_all(struct tg3 *tp)
+{
+	u32 adv_reg, all_mask;
+
+	tg3_readphy(tp, MII_ADVERTISE, &adv_reg);
+	all_mask = (ADVERTISE_10HALF | ADVERTISE_10FULL |
+		    ADVERTISE_100HALF | ADVERTISE_100FULL);
+	if ((adv_reg & all_mask) != all_mask)
+		return 0;
+	if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+		u32 tg3_ctrl;
+
+		tg3_readphy(tp, MII_TG3_CTRL, &tg3_ctrl);
+		all_mask = (MII_TG3_CTRL_ADV_1000_HALF |
+			    MII_TG3_CTRL_ADV_1000_FULL);
+		if ((tg3_ctrl & all_mask) != all_mask)
+			return 0;
+	}
+	return 1;
+}
+
 static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
 {
 	int current_link_up;
@@ -1239,7 +1319,7 @@ static int tg3_setup_copper_phy(struct t
 	 */
 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
 	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
-	     tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) &&
+	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
 	    netif_carrier_ok(tp->dev)) {
 		tg3_readphy(tp, MII_BMSR, &bmsr);
 		tg3_readphy(tp, MII_BMSR, &bmsr);
@@ -1247,7 +1327,7 @@ static int tg3_setup_copper_phy(struct t
 			force_reset = 1;
 	}
 	if (force_reset)
-		tg3_phy_reset(tp, 1);
+		tg3_phy_reset(tp);
 
 	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
 		tg3_readphy(tp, MII_BMSR, &bmsr);
@@ -1274,7 +1354,7 @@ static int tg3_setup_copper_phy(struct t
 			if ((tp->phy_id & PHY_ID_REV_MASK) == PHY_REV_BCM5401_B0 &&
 			    !(bmsr & BMSR_LSTATUS) &&
 			    tp->link_config.active_speed == SPEED_1000) {
-				err = tg3_phy_reset(tp, 1);
+				err = tg3_phy_reset(tp);
 				if (!err)
 					err = tg3_init_5401phy_dsp(tp);
 				if (err)
@@ -1309,8 +1389,14 @@ static int tg3_setup_copper_phy(struct t
 	current_speed = SPEED_INVALID;
 	current_duplex = DUPLEX_INVALID;
 
-	tg3_readphy(tp, MII_BMSR, &bmsr);
-	tg3_readphy(tp, MII_BMSR, &bmsr);
+	bmsr = 0;
+	for (i = 0; i < 100; i++) {
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		if (bmsr & BMSR_LSTATUS)
+			break;
+		udelay(40);
+	}
 
 	if (bmsr & BMSR_LSTATUS) {
 		u32 aux_stat, bmcr;
@@ -1326,22 +1412,25 @@ static int tg3_setup_copper_phy(struct t
 		tg3_aux_stat_to_speed_duplex(tp, aux_stat,
 					     &current_speed,
 					     &current_duplex);
-		tg3_readphy(tp, MII_BMCR, &bmcr);
-		tg3_readphy(tp, MII_BMCR, &bmcr);
+
+		bmcr = 0;
+		for (i = 0; i < 200; i++) {
+			tg3_readphy(tp, MII_BMCR, &bmcr);
+			tg3_readphy(tp, MII_BMCR, &bmcr);
+			if (bmcr && bmcr != 0x7fff)
+				break;
+			udelay(10);
+		}
+
 		if (tp->link_config.autoneg == AUTONEG_ENABLE) {
 			if (bmcr & BMCR_ANENABLE) {
-				u32 gig_ctrl;
-
 				current_link_up = 1;
 
 				/* Force autoneg restart if we are exiting
 				 * low power mode.
 				 */
-				tg3_readphy(tp, MII_TG3_CTRL, &gig_ctrl);
-				if (!(gig_ctrl & (MII_TG3_CTRL_ADV_1000_HALF |
-						  MII_TG3_CTRL_ADV_1000_FULL))) {
+				if (!tg3_copper_is_advertising_all(tp))
 					current_link_up = 0;
-				}
 			} else {
 				current_link_up = 0;
 			}
@@ -2003,6 +2092,13 @@ static int tg3_setup_phy(struct tg3 *tp,
 		      (6 << TX_LENGTHS_IPG_SHIFT) |
 		      (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
 
+	if (netif_carrier_ok(tp->dev)) {
+		tw32(HOSTCC_STAT_COAL_TICKS,
+		     DEFAULT_STAT_COAL_TICKS);
+	} else {
+		tw32(HOSTCC_STAT_COAL_TICKS, 0);
+	}
+
 	return err;
 }
 
@@ -3389,10 +3485,11 @@ out:
 }
 
 /* tp->lock is held. */
-static void tg3_chip_reset(struct tg3 *tp)
+static int tg3_chip_reset(struct tg3 *tp)
 {
 	u32 val;
 	u32 flags_save;
+	int i;
 
 	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
 		/* Force NVRAM to settle.
@@ -3460,6 +3557,8 @@ static void tg3_chip_reset(struct tg3 *t
 
 	tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
 
+	tw32(GRC_MODE, tp->grc_mode);
+
 	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 |=
@@ -3467,7 +3566,45 @@ static void tg3_chip_reset(struct tg3 *t
 		tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
 	}
 
-	tw32(TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
+	/* Prevent PXE from restarting.  */
+	tg3_write_mem(tp,
+		      NIC_SRAM_FIRMWARE_MBOX,
+		      NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
+
+	if (tp->phy_id == PHY_ID_SERDES) {
+		tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
+		tw32_f(MAC_MODE, tp->mac_mode);
+	} else
+		tw32_f(MAC_MODE, 0);
+	udelay(40);
+
+	/* Wait for firmware initialization to complete. */
+	for (i = 0; i < 100000; i++) {
+		tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+		if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+			break;
+		udelay(10);
+	}
+	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);
+		return -ENODEV;
+	}
+
+	/* Reprobe ASF enable state.  */
+	tp->tg3_flags &= ~TG3_FLAG_ENABLE_ASF;
+	tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
+	if (val == NIC_SRAM_DATA_SIG_MAGIC) {
+		u32 nic_cfg;
+
+		tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
+		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE)
+			tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
+	}
+
+	return 0;
 }
 
 /* tp->lock is held. */
@@ -3494,40 +3631,17 @@ static void tg3_stop_fw(struct tg3 *tp)
 /* tp->lock is held. */
 static int tg3_halt(struct tg3 *tp)
 {
-	u32 val;
-	int i;
+	int err;
 
 	tg3_stop_fw(tp);
 	tg3_abort_hw(tp);
-	tg3_chip_reset(tp);
-	tg3_write_mem(tp,
-		      NIC_SRAM_FIRMWARE_MBOX,
-		      NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
-	for (i = 0; i < 100000; i++) {
-		tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
-		if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
-			break;
-		udelay(10);
-	}
-
-	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);
-		return -ENODEV;
-	}
+	err = tg3_chip_reset(tp);
+	if (err)
+		return err;
 
-	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
-		if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
-			tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
-				      DRV_STATE_WOL);
-		else
-			tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
-				      DRV_STATE_UNLOAD);
-	} else
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
 		tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
-			      DRV_STATE_SUSPEND);
+			      DRV_STATE_UNLOAD);
 
 	return 0;
 }
@@ -3833,7 +3947,7 @@ static int tg3_load_5701_a0_firmware_fix
 #define TG3_TSO_FW_START_ADDR		0x08000000
 #define TG3_TSO_FW_TEXT_ADDR		0x08000000
 #define TG3_TSO_FW_TEXT_LEN		0x1a90
-#define TG3_TSO_FW_RODATA_ADDR		0x08001a900
+#define TG3_TSO_FW_RODATA_ADDR		0x08001a90
 #define TG3_TSO_FW_RODATA_LEN		0x60
 #define TG3_TSO_FW_DATA_ADDR		0x08001b20
 #define TG3_TSO_FW_DATA_LEN		0x20
@@ -4491,36 +4605,9 @@ static int tg3_reset_hw(struct tg3 *tp)
 			return err;
 	}
 
-	tg3_chip_reset(tp);
-
-	val = tr32(GRC_MODE);
-	val &= GRC_MODE_HOST_STACKUP;
-	tw32(GRC_MODE, val | tp->grc_mode);
-
-	tg3_write_mem(tp,
-		      NIC_SRAM_FIRMWARE_MBOX,
-		      NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
-	if (tp->phy_id == PHY_ID_SERDES) {
-		tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
-		tw32_f(MAC_MODE, tp->mac_mode);
-	} else
-		tw32_f(MAC_MODE, 0);
-	udelay(40);
-
-	/* Wait for firmware initialization to complete. */
-	for (i = 0; i < 100000; i++) {
-		tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
-		if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
-			break;
-		udelay(10);
-	}
-	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);
-		return -ENODEV;
-	}
+	err = tg3_chip_reset(tp);
+	if (err)
+		return err;
 
 	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
 		tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
@@ -4543,6 +4630,13 @@ static int tg3_reset_hw(struct tg3 *tp)
 		tw32(TG3PCI_PCISTATE, val);
 	}
 
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
+		/* Enable some hw fixes.  */
+		val = tr32(TG3PCI_MSI_DATA);
+		val |= (1 << 26) | (1 << 28) | (1 << 29);
+		tw32(TG3PCI_MSI_DATA, 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
@@ -4573,8 +4667,10 @@ static int tg3_reset_hw(struct tg3 *tp)
 	     (GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP));
 
 	/* Setup the timer prescalar register.  Clock is always 66Mhz. */
-	tw32(GRC_MISC_CFG,
-	     (65 << GRC_MISC_CFG_PRESCALAR_SHIFT));
+	val = tr32(GRC_MISC_CFG);
+	val &= ~0xff;
+	val |= (65 << GRC_MISC_CFG_PRESCALAR_SHIFT);
+	tw32(GRC_MISC_CFG, val);
 
 	/* Initialize MBUF/DESC pool. */
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
@@ -4635,19 +4731,6 @@ static int tg3_reset_hw(struct tg3 *tp)
 		return -ENODEV;
 	}
 
-	tw32(FTQ_RESET, 0xffffffff);
-	tw32(FTQ_RESET, 0x00000000);
-	for (i = 0; i < 2000; i++) {
-		if (tr32(FTQ_RESET) == 0x00000000)
-			break;
-		udelay(10);
-	}
-	if (i >= 2000) {
-		printk(KERN_ERR PFX "tg3_reset_hw cannot reset FTQ for %s.\n",
-		       tp->dev->name);
-		return -ENODEV;
-	}
-
 	/* Clear statistics/status block in chip, and status block in ram. */
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
 		for (i = NIC_SRAM_STATS_BLK;
@@ -4979,8 +5062,17 @@ static int tg3_reset_hw(struct tg3 *tp)
 	tw32_f(MAC_RX_MODE, tp->rx_mode);
 	udelay(10);
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
-		tw32(MAC_SERDES_CFG, 0x616000);
+	if (tp->phy_id == PHY_ID_SERDES) {
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+			/* Set drive transmission level to 1.2V  */
+			val = tr32(MAC_SERDES_CFG);
+			val &= 0xfffff000;
+			val |= 0x880;
+			tw32(MAC_SERDES_CFG, val);
+		}
+		if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
+			tw32(MAC_SERDES_CFG, 0x616000);
+	}
 
 	/* Prevent chip from dropping frames when flow control
 	 * is enabled.
@@ -5519,6 +5611,7 @@ static int tg3_open(struct net_device *d
 #endif
 
 static struct net_device_stats *tg3_get_stats(struct net_device *);
+static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *);
 
 static int tg3_close(struct net_device *dev)
 {
@@ -5550,6 +5643,8 @@ static int tg3_close(struct net_device *
 
 	memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev),
 	       sizeof(tp->net_stats_prev));
+	memcpy(&tp->estats_prev, tg3_get_estats(tp),
+	       sizeof(tp->estats_prev));
 
 	tg3_free_consistent(tp);
 
@@ -5592,6 +5687,49 @@ static unsigned long calc_crc_errors(str
 	return get_stat64(&hw_stats->rx_fcs_errors);
 }
 
+#define ESTAT_ADD(member) \
+	estats->member =	old_estats->member + \
+				get_stat64(&hw_stats->member)
+
+static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp)
+{
+	struct tg3_ethtool_stats *estats = &tp->estats;
+	struct tg3_ethtool_stats *old_estats = &tp->estats_prev;
+	struct tg3_hw_stats *hw_stats = tp->hw_stats;
+
+	if (!hw_stats)
+		return old_estats;
+
+	ESTAT_ADD(rx_fragments);
+	ESTAT_ADD(rx_ucast_packets);
+	ESTAT_ADD(rx_bcast_packets);
+	ESTAT_ADD(rx_fcs_errors);
+	ESTAT_ADD(rx_xon_pause_rcvd);
+	ESTAT_ADD(rx_xoff_pause_rcvd);
+	ESTAT_ADD(rx_mac_ctrl_rcvd);
+	ESTAT_ADD(rx_xoff_entered);
+	ESTAT_ADD(rx_frame_too_long_errors);
+	ESTAT_ADD(rx_jabbers);
+	ESTAT_ADD(rx_undersize_packets);
+	ESTAT_ADD(rx_in_length_errors);
+	ESTAT_ADD(rx_out_length_errors);
+
+	ESTAT_ADD(tx_xon_sent);
+	ESTAT_ADD(tx_xoff_sent);
+	ESTAT_ADD(tx_flow_control);
+	ESTAT_ADD(tx_mac_errors);
+	ESTAT_ADD(tx_single_collisions);
+	ESTAT_ADD(tx_mult_collisions);
+	ESTAT_ADD(tx_deferred);
+	ESTAT_ADD(tx_excessive_collisions);
+	ESTAT_ADD(tx_late_collisions);
+	ESTAT_ADD(tx_ucast_packets);
+	ESTAT_ADD(tx_mcast_packets);
+	ESTAT_ADD(tx_bcast_packets);
+
+	return estats;
+}
+
 static struct net_device_stats *tg3_get_stats(struct net_device *dev)
 {
 	struct tg3 *tp = dev->priv;
@@ -5871,6 +6009,16 @@ static int tg3_set_settings(struct net_d
 	    tp->link_config.phy_is_low_power)
 		return -EAGAIN;
 
+	if (tp->phy_id == PHY_ID_SERDES) {
+		/* These are the only valid advertisement bits allowed.  */
+		if (cmd->autoneg == AUTONEG_ENABLE &&
+		    (cmd->advertising & ~(ADVERTISED_1000baseT_Half |
+					  ADVERTISED_1000baseT_Full |
+					  ADVERTISED_Autoneg |
+					  ADVERTISED_FIBRE)))
+			return -EINVAL;
+	}
+
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
 
@@ -5880,6 +6028,7 @@ static int tg3_set_settings(struct net_d
 		tp->link_config.speed = SPEED_INVALID;
 		tp->link_config.duplex = DUPLEX_INVALID;
 	} else {
+		tp->link_config.advertising = 0;
 		tp->link_config.speed = cmd->speed;
 		tp->link_config.duplex = cmd->duplex;
   	}
@@ -6102,7 +6251,31 @@ static int tg3_set_tx_csum(struct net_de
 
 	return 0;
 }
-  
+
+static int tg3_get_stats_count (struct net_device *dev)
+{
+	return TG3_NUM_STATS;
+}
+
+static void tg3_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:
+		WARN_ON(1);	/* we need a WARN() */
+		break;
+	}
+}
+
+static void tg3_get_ethtool_stats (struct net_device *dev,
+				   struct ethtool_stats *estats, u64 *tmp_stats)
+{
+	struct tg3 *tp = dev->priv;
+	memcpy(tmp_stats, &tp->estats, sizeof(tp->estats));
+}
+
 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;
@@ -6199,6 +6372,9 @@ static struct ethtool_ops tg3_ethtool_op
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= tg3_set_tso,
 #endif
+	.get_strings		= tg3_get_strings,
+	.get_stats_count	= tg3_get_stats_count,
+	.get_ethtool_stats	= tg3_get_ethtool_stats,
 };
 
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
@@ -6346,8 +6522,8 @@ static struct subsys_tbl_ent subsys_id_t
 	{ PCI_VENDOR_ID_BROADCOM, 0x0007, PHY_ID_SERDES  }, /* BCM95701A7 */
 	{ PCI_VENDOR_ID_BROADCOM, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */
 	{ PCI_VENDOR_ID_BROADCOM, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */
-	{ PCI_VENDOR_ID_BROADCOM, 0x0009, PHY_ID_BCM5701 }, /* BCM95703Ax1 */
-	{ PCI_VENDOR_ID_BROADCOM, 0x8009, PHY_ID_BCM5701 }, /* BCM95703Ax2 */
+	{ PCI_VENDOR_ID_BROADCOM, 0x0009, PHY_ID_BCM5703 }, /* BCM95703Ax1 */
+	{ PCI_VENDOR_ID_BROADCOM, 0x8009, PHY_ID_BCM5703 }, /* BCM95703Ax2 */
 
 	/* 3com boards. */
 	{ PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */
@@ -6447,19 +6623,27 @@ static int __devinit tg3_phy_probe(struc
 			tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
 	}
 
-	/* Now read the physical PHY_ID from the chip and verify
-	 * that it is sane.  If it doesn't look good, we fall back
-	 * to either the hard-coded table based PHY_ID and failing
-	 * that the value found in the eeprom area.
-	 */
-	err  = tg3_readphy(tp, MII_PHYSID1, &hw_phy_id_1);
-	err |= tg3_readphy(tp, MII_PHYSID2, &hw_phy_id_2);
-
-	hw_phy_id  = (hw_phy_id_1 & 0xffff) << 10;
-	hw_phy_id |= (hw_phy_id_2 & 0xfc00) << 16;
-	hw_phy_id |= (hw_phy_id_2 & 0x03ff) <<  0;
+	/* Reading the PHY ID register can conflict with ASF
+	 * firwmare access to the PHY hardware.
+	 */
+	err = 0;
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+		hw_phy_id = hw_phy_id_masked = PHY_ID_INVALID;
+	} else {
+		/* Now read the physical PHY_ID from the chip and verify
+		 * that it is sane.  If it doesn't look good, we fall back
+		 * to either the hard-coded table based PHY_ID and failing
+		 * that the value found in the eeprom area.
+		 */
+		err |= tg3_readphy(tp, MII_PHYSID1, &hw_phy_id_1);
+		err |= tg3_readphy(tp, MII_PHYSID2, &hw_phy_id_2);
+
+		hw_phy_id  = (hw_phy_id_1 & 0xffff) << 10;
+		hw_phy_id |= (hw_phy_id_2 & 0xfc00) << 16;
+		hw_phy_id |= (hw_phy_id_2 & 0x03ff) <<  0;
 
-	hw_phy_id_masked = hw_phy_id & PHY_ID_MASK;
+		hw_phy_id_masked = hw_phy_id & PHY_ID_MASK;
+	}
 
 	if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) {
 		tp->phy_id = hw_phy_id;
@@ -6476,50 +6660,58 @@ static int __devinit tg3_phy_probe(struc
 		}
 	}
 
-	err = tg3_phy_reset(tp, 1);
-	if (err)
-		return err;
+	if (tp->phy_id != PHY_ID_SERDES &&
+	    !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+		u32 bmsr, adv_reg, tg3_ctrl;
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
-		u32 mii_tg3_ctrl;
-		
-		/* These chips, when reset, only advertise 10Mb
-		 * capabilities.  Fix that.
-		 */
-		err  = tg3_writephy(tp, MII_ADVERTISE,
-				    (ADVERTISE_CSMA |
-				     ADVERTISE_PAUSE_CAP |
-				     ADVERTISE_10HALF |
-				     ADVERTISE_10FULL |
-				     ADVERTISE_100HALF |
-				     ADVERTISE_100FULL));
-		mii_tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
-				MII_TG3_CTRL_ADV_1000_FULL |
-				MII_TG3_CTRL_AS_MASTER |
-				MII_TG3_CTRL_ENABLE_AS_MASTER);
-		if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
-			mii_tg3_ctrl = 0;
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		tg3_readphy(tp, MII_BMSR, &bmsr);
 
-		err |= tg3_writephy(tp, MII_TG3_CTRL, mii_tg3_ctrl);
-		err |= tg3_writephy(tp, MII_BMCR,
-				    (BMCR_ANRESTART | BMCR_ANENABLE));
-	}
+		if ((bmsr & BMSR_LSTATUS) &&
+		    !(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))
+			goto skip_phy_reset;
+		    
+		err = tg3_phy_reset(tp);
+		if (err)
+			return err;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
-	}
+		adv_reg = (ADVERTISE_10HALF | ADVERTISE_10FULL |
+			   ADVERTISE_100HALF | ADVERTISE_100FULL |
+			   ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+		tg3_ctrl = 0;
+		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+			tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
+				    MII_TG3_CTRL_ADV_1000_FULL);
+			if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+			    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
+				tg3_ctrl |= (MII_TG3_CTRL_AS_MASTER |
+					     MII_TG3_CTRL_ENABLE_AS_MASTER);
+		}
 
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
-	    (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)) {
-		tg3_writephy(tp, 0x1c, 0x8d68);
-		tg3_writephy(tp, 0x1c, 0x8d68);
+		if (!tg3_copper_is_advertising_all(tp)) {
+			tg3_writephy(tp, MII_ADVERTISE, adv_reg);
+
+			if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+				tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl);
+
+			tg3_writephy(tp, MII_BMCR,
+				     BMCR_ANENABLE | BMCR_ANRESTART);
+		}
+		tg3_phy_set_wirespeed(tp);
+
+		tg3_writephy(tp, MII_ADVERTISE, adv_reg);
+		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+			tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl);
 	}
 
-	/* Enable Ethernet@WireSpeed */
-	tg3_phy_set_wirespeed(tp);
+skip_phy_reset:
+	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
+		err = tg3_init_5401phy_dsp(tp);
+		if (err)
+			return err;
+	}
 
 	if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) {
 		err = tg3_init_5401phy_dsp(tp);
@@ -6835,6 +7027,10 @@ static int __devinit tg3_get_invariants(
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
 		tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG;
 
+	/* Note: 5750 also needs this flag set to improve bit error rate. */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+		tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
+
 	/* Only 5701 and later support tagged irq status mode.
 	 * Also, 5788 chips cannot use tagged irq status.
 	 *
@@ -7718,6 +7914,19 @@ static int __devinit tg3_init_one(struct
 		printk("%2.2x%c", dev->dev_addr[i],
 		       i == 5 ? '\n' : ':');
 
+	printk(KERN_INFO "%s: HostTXDS[%d] RXcsums[%d] LinkChgREG[%d] "
+	       "MIirq[%d] ASF[%d] Split[%d] WireSpeed[%d] "
+	       "TSOcap[%d] \n",
+	       dev->name,
+	       (tp->tg3_flags & TG3_FLAG_HOST_TXDS) != 0,
+	       (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0,
+	       (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0,
+	       (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0,
+	       (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0,
+	       (tp->tg3_flags & TG3_FLAG_SPLIT_MODE) != 0,
+	       (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0,
+	       (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0);
+
 	return 0;
 
 err_out_iounmap:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/tg3.h linux-2.4.27-pre3/drivers/net/tg3.h
--- linux-2.4.26/drivers/net/tg3.h	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/tg3.h	2004-05-18 16:53:49.000000000 +0000
@@ -1817,6 +1817,37 @@ struct tg3_bufmgr_config {
 	u32		dma_high_water;
 };
 
+struct tg3_ethtool_stats {
+	/* Statistics maintained by Receive MAC. */
+	u64		rx_fragments;
+	u64		rx_ucast_packets;
+	u64		rx_bcast_packets;
+	u64		rx_fcs_errors;
+	u64		rx_xon_pause_rcvd;
+	u64		rx_xoff_pause_rcvd;
+	u64		rx_mac_ctrl_rcvd;
+	u64		rx_xoff_entered;
+	u64		rx_frame_too_long_errors;
+	u64		rx_jabbers;
+	u64		rx_undersize_packets;
+	u64		rx_in_length_errors;
+	u64		rx_out_length_errors;
+
+	/* Statistics maintained by Transmit MAC. */
+	u64		tx_xon_sent;
+	u64		tx_xoff_sent;
+	u64		tx_flow_control;
+	u64		tx_mac_errors;
+	u64		tx_single_collisions;
+	u64		tx_mult_collisions;
+	u64		tx_deferred;
+	u64		tx_excessive_collisions;
+	u64		tx_late_collisions;
+	u64		tx_ucast_packets;
+	u64		tx_mcast_packets;
+	u64		tx_bcast_packets;
+};
+
 struct tg3 {
 	/* begin "general, frequently-used members" cacheline section */
 
@@ -1880,6 +1911,9 @@ struct tg3 {
 	/* begin "everything else" cacheline(s) section */
 	struct net_device_stats		net_stats;
 	struct net_device_stats		net_stats_prev;
+	struct tg3_ethtool_stats	estats;
+	struct tg3_ethtool_stats	estats_prev;
+
 	unsigned long			phy_crc_errors;
 
 	u32				rx_offset;
@@ -1929,6 +1963,7 @@ struct tg3 {
 #define TG3_FLG2_TSO_CAPABLE		0x00000020
 #define TG3_FLG2_PHY_ADC_BUG		0x00000040
 #define TG3_FLG2_PHY_5704_A0_BUG	0x00000080
+#define TG3_FLG2_PHY_BER_BUG		0x00000100
 
 	u32				split_mode_max_reqs;
 #define SPLIT_MODE_5704_MAX_REQ		3
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/tulip/ChangeLog linux-2.4.27-pre3/drivers/net/tulip/ChangeLog
--- linux-2.4.26/drivers/net/tulip/ChangeLog	2003-06-13 14:51:35.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/tulip/ChangeLog	1970-01-01 00:00:00.000000000 +0000
@@ -1,563 +0,0 @@
-2002-09-18  Ryan Bradetich  <rbradetich@uswest.net>
-
-	tulip hppa support:
-	* eeprom.c (tulip_build_fake_mediatable): new function
-	(tulip_parse_eeprom): call it, when no media table
-	* interrupt.c (phy_interrupt): new function
-	(tulip_interrupt): call it, before checking for no-irq-work
-	* tulip.c: add HAS_PHY_IRQ chip feature flag.
-	add csr12_shadow to tulip_private struct, only for hppa currently.
-	* tulip_core (tulip_init_one): support hppa wonky eeproms
-
-2002-05-11  Juan Quintela  <quintela@mandrakesoft.com>
-
-	* 21142.c (t21142_lnk_change): Revert earlier patch
-	to always reset phy; only conditionally do so now.
-
-2002-05-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core (tulip_pci_tbl): Add new "comet"
-	pci id.  Contributed by Ohta Kyuma.
-
-2002-03-07  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core (tulip_mwi_config): Use new PCI API functions
-	for enabling and disabled Memory-Write-Invalidate
-	PCI transaction.
-	Fix bugs in tulip MWI config also.
-
-2002-02-07  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>
-
-	* tulip_core (tulip_pci_tbl[]):
-	Add PCI id for comet tulip clone.
-
-2001-12-19  John Zielinski
-
-	* tulip_core.c (tulip_up, tulip_init_one):
-	More places to revert PHY autoconfiguration bit removal.
-
-2001-12-16  Andrew Lambeth  <wal@vmware.com>
-
-	* tulip_core.c (tulip_start_xmit): Use the more-portable
-	spin_lock_irqsave.
-
-2001-11-13  David S. Miller  <davem@redhat.com>
-
-	* tulip_core.c (tulip_mwi_config): Kill unused label early_out.
-
-2001-11-06  Richard Mortimer  <richm@oldelvet.netscapeonline.co.uk>
-
-	* tulip_core.c:  Correct set of values to mask out of csr0,
-	for DM9102A chips.  Limit burst/alignment of DM9102A chips
-	on Sparcs.
-
-2001-11-06  Jun Sun  <jsun@mvista.com>
-
-	* tulip_core.c:  Support finding MAC address on
-	two MIPS boards, DDB5476 and DDB5477.
-
-2001-11-06  Kevin B. Hendricks  <khendricks@ivey.uwo.ca>
-
-	* Makefile, tulip.h, tulip_core.c, pnic2.c, 21142.c:
-	Fixes for PNIC II support.
-
-2001-11-06  David S. Miller  <davem@redhat.com>
-
-	* tulip_core.c: Support reading MAC address from
-	Sparc OBP property local-mac-address.
-
-2001-07-17  Erik A. Hendriks  <hendriks@lanl.gov>
-
-	* 21142.c: Merge fix from tulip.c 0.92w which prevents the
-	overwriting of csr6 bits we want to preserve.
-
-2001-07-10  Jeff Golds  <jgolds@resilience.com>
-
-	* tulip_core.c: Fix two comments
-
-2001-07-06  Stephen Degler  <sdegler@degler.net>
-
-	* media.c:
-	The media selection process at the end of NWAY is busted
-	because for the case of MII/SYM it needs to be:
-
-        csr13 <- 0
-        csr14 <- 0
-        csr6 <-  the value calculated is okay.
-
-	In the other media cases csr14 is computed by
-	t21142_csr14val[dev->if_port], which seems ok.  The value of
-	zero as opposed to 3FFFFF comes straight from appendix D of the
-	21143 data book, and it makes logical sense because you're
-	bypassing all the SIA interface when you usa MII or SYM (see
-	figure 1-1 in the data book if your're visually oriented)
-
-2001-07-03  Jeff Golds  <jgolds@resilience.com>
-
-	* tulip_core.c (tulip_clean_tx_ring):
-	Clear status for in-progress Tx's, and count
-	Tx errors for all packets being released.
-
-2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip.h, tulip_core.c:
-	Integrate MMIO support from devel branch, but default
-	it to off for stable kernel and driver series.
-
-2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (tulip_init_one):
-	Free descriptor rings on error.
-
-2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (tulip_mwi_config, tulip_init_one):
-	Large update to csr0 bus configuration code.  This is not stable
-	yet, so it is only conditionally enabled, via CONFIG_TULIP_MWI.
-
-2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c:
-	Initialize timer in tulip_init_one and tulip_down,
-	not in tulip_up.
-
-2001-06-14  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c:
-	- Update tulip_suspend, tulip_resume for new PCI PM API.
-	- Surround suspend/resume code with CONFIG_PM.
-
-2001-06-12  Jeff Golds  <jgolds@resilience.com>
-
-	* tulip_core.c:
-	- Reset sw ring ptrs in tulip_up.  Fixes PM resume case.
-	- Clean rx and tx rings on device down.
-
-2001-06-05  David Miller  <davem@redhat.com>
-
-	* tulip_core (set_rx_mode):  Do not use set_bit
-	on an integer variable.  Also fix endianness issue.
-
-2001-06-04  Jeff Garzik  <jgarzik@pobox.com>
-
-	* interrupt.c:
-	Simplify rx processing when CONFIG_NET_HW_FLOWCONTROL is
-	active, and in the process fix a bug where flow control
-	and low load caused rx not to be acknowledged properly.
-
-2001-06-01  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip.h:
-	- Remove tulip_outl_csr helper, redundant.
-	- Add tulip_start_rxtx inline helper.
-	- tulip_stop_rxtx helper: Add synchronization. Always use current
-	  csr6 value, instead of tp->csr6 value or value passed as arg.
-	- tulip_restart_rxtx helper: Add synchronization. Always
-	  use tp->csr6 for desired mode, not value passed as arg.
-	- New RxOn, TxOn, RxTx constants for csr6 modes.
-	- Remove now-redundant constants csr6_st, csr6_sr.
-
-	* 21142.c, interrupt.c, media.c, pnic.c, tulip_core.c:
-	Update for above rxtx helper changes.
-
-	* interrupt.c:
-	- whitespace cleanup around #ifdef CONFIG_NET_HW_FLOWCONTROL,
-	  convert tabs to spaces.
-	- Move tp->stats.rx_missed_errors update outside the ifdef.
-
-2001-05-18  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: Added ethtool support.
-	  ETHTOOL_GDRVINFO ioctl only, for now.
-
-2001-05-14  Robert Olsson <Robert.Olsson@data.slu.se>
-
-	* Restored HW_FLOWCONTROL from Linux 2.1 series tulip (ANK)
-	  plus Jamal's NETIF_RX_* feedback control.
-
-2001-05-14  Robert Olsson <Robert.Olsson@data.slu.se>
-
-	* Added support for 21143's Interrupt Mitigation.
-	  Jamal original instigator.
-
-2001-05-14  Robert Olsson <Robert.Olsson@data.slu.se>
-
-	* tulip_refill_rx prototype added to tulip.h
-
-2001-05-13  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: Remove HAS_PCI_MWI flag from Comet, untested.
-
-2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c, tulip.h: Remove Conexant PCI id, no chip
-	docs are available to fix problems with support.
-
-2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (tulip_init_one): Do not call
-	unregister_netdev in error cleanup.  Remnant of old
-	usage of init_etherdev.
-
-2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
-
-	* media.c (tulip_find_mii): Simple write the updated BMCR
-	twice, as it seems the best thing to do for both broken and
-	sane chips.
-	If the mii_advert value, as read from MII_ADVERTISE, is zero,
-	then generate a value we should advertise from the capability
-	bits in BMSR.
-	Fill in tp->advertising for all cases.
-	Just to be safe, clear all unwanted bits.
-
-2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (private_ioctl):  Fill in tp->advertising
-	when advertising value is changed by the user.
-
-2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: Mark Comet chips as needed the updated MWI
-	csr0 configuration.
-
-2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
-
-	* media.c, tulip_core.c:  Move MII scan into
-	from inlined inside tulip_init_one to new function
-	tulip_find_mii in media.c.
-
-2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
-
-	* media.c (tulip_check_duplex):
-	Only restart Rx/Tx engines if they are active
-	(and csr6 changes)
-
-2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (tulip_mwi_config):
-	Clamp values read from PCI cache line size register to
-	values acceptable to tulip chip.  Done for safety and
-	-almost- certainly unneeded.
-
-2001-05-11  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (tulip_init_one):
-	Instead of unconditionally enabling autonegotiation, disable
-	autonegotiation if not using the default port.  Further,
-	flip the nway bit immediately, and then update the
-	speed/duplex in a separate MII transaction.  We do this
-	because some boards require that nway be disabled separately,
-	before media selection is forced.
-
-	TODO: Investigate if we can simply write the same value
-	to BMCR twice, to avoid setting unnecessarily changing
-	phy settings.
-
-2001-05-11  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip.h, tulip_core.c:  If HAS_PCI_MWI is set for a
-	given chip, adjust the csr0 values not according to
-	provided values but according to system cache line size.
-	Currently cache alignment is matched as closely to cache
-	line size as possible.  Currently programmable burst limit
-	is set (ie. never unlimited), and always equal to cache
-	alignment and system cache size.  Currently MWI bit is set
-	only if the MWI bit is present in the PCI command register.
-
-2001-05-11  Jeff Garzik  <jgarzik@pobox.com>
-
-	* media.c (tulip_select_media):
-	For media types 1 and 3, only use the provided eeprom
-	advertising value if it is non-zero.
-	(tulip_check_duplex):
-	Do not exit ASAP if full_duplex_lock is set.  This
-	ensures that the csr6 value is written if an update
-	is needed.
-
-2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
-
-	Merge PNIC-II-specific stuff from Becker's tulip.c:
-
-	* tulip.h, 21142.c (pnic2_lnk_change): new function
-	* tulip_core.c (tulip_init_one): use it
-
-	* tulip_core.c (tulip_tx_timeout): Add specific
-	debugging for PNIC2.
-
-2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (tulip_init_one): Print out
-	tulip%d instead of PCI device number, for
-	consistency.
-
-2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
-
-	* Merge changes from Becker's tulip.c:
-	Fix bugs in ioctl.
-	Fix several bugs by distinguishing between MII
-	and SYM advertising values.
-	Set CSR14 autonegotiation bit for media types 2 and 4,
-	where the SIA CSR setup values are not provided.
-
-2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
-
-	* media.c (tulip_select_media): Only update MII
-	advertising value if startup arg < 2.
-
-	* tulip.h: Do not enable CSR13/14/15 autoconfiguration
-	for 21041.
-
-	* tulip_core.c:
-	21041: add specific code for reset, and do not set CAC bit
-	When resetting media, for media table type 11 media, pass
-	value 2 as 'startup' arg to select_media, to avoid updating
-	MII advertising value.
-
-2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
-
-	* pnic.c (pnic_check_duplex): remove
-	pnic.c (pnic_lnk_change, pnic_timer): use
-	tulip_check_duplex not pnic_check_duplex.
-
-	* media.c (tulip_check_duplex):
-	Clean up to use symbolic names instead of numeric constants.
-	Set TxThreshold mode as necessary as well as clearing it.
-	Update csr6 if csr6 changes, not simply if duplex changes.
-
-	(found by Manfred Spraul)
-
-2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
-
-	* 21142.c, eeprom.c, tulip.h, tulip_core.c:
-	Remove DPRINTK as another, better method of
-	debug message printing is available.
-
-2001-05-09  Jeff Garzik  <jgarzik@pobox.com>
-
-	* 21142.c (t21142_lnk_change): Pass arg startup==1
-	to tulip_select_media, in order to force csr13 to be
-	zeroed out prior to going to full duplex mode.  Fixes
-	autonegotiation on a quad-port Znyx card.
-	(from Stephen Dengler)
-
-2001-05-09  Russell King  <rmk@arm.linux.org.uk>
-
-	* interrupt.c: Better PCI bus error reporting.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: Now that dev->name is only available late
-	  in the probe, insert a hack to replace a not-evaluated
-	  "eth%d" string with an evaluated "tulip%d" string.
-	  Also, remove obvious comment and an indentation cleanup.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: If we are a module, always print out the
-	  version string.  If we are built into the kernel, only print
-	  the version string if at least one tulip is detected.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	Merged from Becker's tulip.c 0.92t:
-
-	* tulip_core.c: Add support for Conexant LANfinity.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: Only suspend/resume if the interface
-	  is up and running.  Use alloc_etherdev and pci_request_regions.
-	  Spelling fix.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: Remove code that existed when one or more of
-	  the following defines existed.  These defines were never used
-	  by normal users in practice: TULIP_FULL_DUPLEX,
-	  TULIP_DEFAULT_MEDIA, and TULIP_NO_MEDIA_SWITCH.
-
-	* tulip.h, eeprom.c: Move EE_* constants from tulip.h to eeprom.c.
-	* tulip.h, media.c: Move MDIO_* constants from tulip.h to media.c.
-
-	* media.c: Add barrier() to mdio_read/write's PNIC status check
-	  loops.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	Merged from Becker's tulip.c 0.92t:
-
-	* tulip.h: Add MEDIA_MASK constant for bounding medianame[]
-	  array lookups.
-	* eeprom.c, media.c, timer.c, tulip_core.c: Use it.
-
-	* media.c, tulip_core.c: mdio_{read,write} cleanup.  Since this
-	  is called [pretty much] directly from ioctl, we mask
-	  read/write arguments to limit the values passed.
-	  Added mii_lock.  Added comet_miireg2offset and better
-	  Comet-specific mdio_read/write code.	Pay closer attention
-	  to the bits we set in ioctl.	Remove spinlocks from ioctl,
-	  they are in mdio_read/write now.  Use mask to limit
-	  phy number in tulip_init_one's MII scan.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	Merged from Becker's tulip.c 0.92t:
-
-	* 21142.c, tulip_core.c: PNIC2 MAC address and NWay fixes.
-	* tulip.h: Add FullDuplex constant, used in above change.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	* timer.c: Do not call netif_carrier_{on,off}, it is not used in
-	  the main tree.  Leave code in, disabled, as markers for future
-	  carrier notification.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	Merged from Becker's tulip.c 0.92t, except for the tulip.h
-	whitespace cleanup:
-
-	* interrupt.c: If Rx stops, make sure to update the
-	  multicast filter before restarting.
-	* tulip.h: Add COMET_MAC_ADDR feature flag, clean up flags.
-	  Add Accept* Rx mode bit constants.
-	  Add mc_filter[] to driver private struct.
-	* tulip_core.c: Add new Comet PCI id 0x1113:0x9511.
-	  Add COMET_MAC_ADDR feature flag to comet entry in board info array.
-	  Prefer to test COMET_MAC_ADDR flag to testing chip_id for COMET,
-	  when dealing with the Comet's MAC address.
-	  Enable Tx underrun recovery for Comet chips.
-	  Use new Accept* constants in set_rx_mode.
-	  Prefer COMET_MAC_ADDR flag test to chip_id test in set_rx_mode.
-	  Store built mc_filter for later use in intr handler by Comets.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: Use tp->cur_tx when building the
-	  setup frame, instead of assuming that the setup
-	  frame is always built in slot zero.  This case is
-	  hit during PM resume.
-
-2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
-
-	* *.c: Update file headers (copyright, urls, etc.)
-	* Makefile: re-order to that chip-specific modules on own line
-	* eeprom.c: BSS/zero-init cleanup (Andrey Panin)
-	* tulip_core.c: merge medianame[] update from tulip.c.
-	  Additional arch-specific rx_copybreak, csr0 values. (various)
-
-2001-02-20  Jeff Garzik  <jgarzik@pobox.com>
-
-	* media.c (tulip_select_media): No need to initialize
-	new_csr6, all cases initialize it properly.
-
-2001-02-18  Manfred Spraul  <manfred@colorfullife.com>
-
-	* interrupt.c (tulip_refill_rx): Make public.
-	If PNIC chip stops due to lack of Rx buffers, restart it.
-	(tulip_interrupt): PNIC doesn't have a h/w timer, emulate
-	with software timers.
-	* pnic.c (pnic_check_duplex): New function, PNIC-specific
-	version of tulip_check_duplex.
-	(pnic_lnk_change): Call pnic_check_duplex.  If we use an
-	external MII, then we mustn't use the internal negotiation.
-	(pnic_timer): Support Rx refilling on work overflow in
-	interrupt handler, as PNIC doesn't support a h/w timer.
-	* tulip_core.c (tulip_tbl[]): Modify default csr6
-
-2001-02-11  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (tulip_init_one): Call pci_enable_device
-	to ensure wakeup/resource assignment before checking those
-	values.
-	(tulip_init_one): Replace PCI ids with constants from pci_id.h.
-	(tulip_suspend, tulip_resume, tulip_remove_one): Call
-	pci_power_on/off (commented out for now).
-
-2001-02-10  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip.h: Add CFDD_xxx bits for Tulip power management
-	* tulip_core.c (tulip_set_power_state): New function,
-	manipulating Tulip chip power state where supported.
-	(tulip_up, tulip_down, tulip_init_one): Use it.
-
-2001-02-10  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (tulip_tx_timeout): Call netif_wake_queue
-	to ensure the next Tx is always sent to us.
-
-2001-01-27  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (tulip_remove_one): Fix mem leak by freeing
-	tp->media_tbl.  Add check for !dev, reformat code appropriately.
-
-2001-01-27  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_tbl[]: Comment all entries to make order and chip_id
-	relationship more clear.
-	* tulip_pci_tbl[]: Add new Accton PCI id (COMET chipset).
-
-2001-01-16  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: static vars no longer explicitly
-	initialized to zero.
-	* eeprom.c (tulip_read_eeprom): Make sure to delay between
-	EE_ENB and EE_ENB|EE_SHIFT_CLK.  Merged from becker tulip.c.
-
-2001-01-05  Peter De Schrijver  <p2@mind.be>
-
-	* eeprom.c (tulip_parse_eeprom): Interpret a bit more of 21142
-	extended format type 3 info blocks in a tulip SROM.
-
-2001-01-03  Matti Aarnio  <matti.aarnio@zmailer.org>
-
-	* media.c (tulip_select_media): Support media types 5 and 6
-
-2001-??-??  ??
-
-	* tulip_core.c: Add comment about LanMedia needing
-	a different driver.
-	Enable workarounds for early PCI chipsets.
-	Add IA64 csr0 support, update HPPA csr0 support.
-
-2000-12-17  Alan Cox  <alan@redhat.com>
-
-        * eeprom.c, timer.c, tulip.h, tulip_core.c: Merge support
-	for the Davicom's quirks into the main tulip.
-	Patch by Tobias Ringstrom
-
-2000-11-08  Jim Studt  <jim@federated.com>
-
-	* eeprom.c (tulip_parse_eeprom):  Check array bounds for
-	medianame[] and block_name[] arrays to avoid oops due
-	to bad values returned from hardware.
-
-2000-11-02  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c (set_rx_mode): This is synchronized via
-	dev->xmit_lock, so only the queueing of the setup frame needs to
-	be locked, against tulip_interrupt.
-
-2000-11-02  Alexey Kuznetov  <kuznet@ms2.inr.ac.ru>
-
-	* timer.c (tulip_timer): Call netif_carrier_{on,off} to report
-	link state to the rest of the kernel, and userspace.
-	* interrupt.c (tulip_interrupt): Remove tx_full.
-	* tulip.h: Likewise.
-	* tulip_core.c (tulip_init_ring, tulip_start_xmit, set_rx_mode):
-	Likewise.
-
-2000-10-18  Jeff Garzik  <jgarzik@pobox.com>
-
-	* tulip_core.c: (tulip_init_one) Print out ethernet interface
-	on error.  Print out a message when pci_enable_device fails.
-	Handle DMA alloc failure.
-
-2000-10-18  Jeff Garzik  <jgarzik@pobox.com>
-
-	* Makefile: New file.
-	* tulip_core.c (tulip_init_one): Correct error messages
-	on PIO/MMIO region reserve failure.
-	(tulip_init_one) Add new check to ensure that PIO region is
-	sufficient for our needs.
-
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/tulip/timer.c linux-2.4.27-pre3/drivers/net/tulip/timer.c
--- linux-2.4.26/drivers/net/tulip/timer.c	2003-06-13 14:51:35.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/tulip/timer.c	2004-05-18 16:50:45.000000000 +0000
@@ -211,10 +211,16 @@ void comet_timer(unsigned long data)
 	if (tulip_debug > 1)
 		printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
 			   "%4.4x.\n",
-			   dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
+			   dev->name,
+			   tulip_mdio_read(dev, tp->phys[0], 1),
+			   tulip_mdio_read(dev, tp->phys[0], 5));
 	/* mod_timer synchronizes us with potential add_timer calls
 	 * from interrupts.
 	 */
+	if (tulip_check_duplex(dev) < 0)
+		{ netif_carrier_off(dev); }
+	else
+		{ netif_carrier_on(dev); }
 	mod_timer(&tp->timer, RUN_AT(next_tick));
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/tulip/tulip_core.c linux-2.4.27-pre3/drivers/net/tulip/tulip_core.c
--- linux-2.4.26/drivers/net/tulip/tulip_core.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/tulip/tulip_core.c	2004-05-18 16:53:45.000000000 +0000
@@ -176,7 +176,7 @@ struct tulip_chip_table tulip_tbl[] = {
 
   /* COMET */
   { "ADMtek Comet", 256, 0x0001abef,
-	MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer },
+	HAS_MII | MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer },
 
   /* COMPEX9881 */
   { "Compex 9881 PMAC", 128, 0x0001ebef,
@@ -320,8 +320,8 @@ static void tulip_up(struct net_device *
 	tp->dirty_rx = tp->dirty_tx = 0;
 
 	if (tp->flags & MC_HASH_ONLY) {
-		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
-		u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
+		u32 addr_low = le32_to_cpu(get_unaligned((u32 *)dev->dev_addr));
+		u32 addr_high = le16_to_cpu(get_unaligned((u16 *)(dev->dev_addr+4)));
 		if (tp->chip_id == AX88140) {
 			outl(0, ioaddr + CSR13);
 			outl(addr_low,  ioaddr + CSR14);
@@ -1544,8 +1544,8 @@ static int __devinit tulip_init_one (str
 		}
 	} else if (chip_idx == COMET) {
 		/* No need to read the EEPROM. */
-		put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
-		put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
+		put_unaligned(cpu_to_le32(inl(ioaddr + 0xA4)), (u32 *)dev->dev_addr);
+		put_unaligned(cpu_to_le16(inl(ioaddr + 0xA8)), (u16 *)(dev->dev_addr + 4));
 		for (i = 0; i < 6; i ++)
 			sum += dev->dev_addr[i];
 	} else {
@@ -1884,11 +1884,11 @@ static void __devexit tulip_remove_one (
 		return;
 
 	tp = dev->priv;
+	unregister_netdev (dev);
 	pci_free_consistent (pdev,
 			     sizeof (struct tulip_rx_desc) * RX_RING_SIZE +
 			     sizeof (struct tulip_tx_desc) * TX_RING_SIZE,
 			     tp->rx_ring, tp->rx_ring_dma);
-	unregister_netdev (dev);
 	if (tp->mtable)
 		kfree (tp->mtable);
 #ifndef USE_IO_OPS
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/net/via-rhine.c linux-2.4.27-pre3/drivers/net/via-rhine.c
--- linux-2.4.26/drivers/net/via-rhine.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/net/via-rhine.c	2004-05-18 16:53:01.000000000 +0000
@@ -28,10 +28,10 @@
 
 
 	Linux kernel version history:
-	
+
 	LK1.1.0:
 	- Jeff Garzik: softnet 'n stuff
-	
+
 	LK1.1.1:
 	- Justin Guyett: softnet and locking fixes
 	- Jeff Garzik: use PCI interface
@@ -58,7 +58,7 @@
 	LK1.1.6:
 	- Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio)
 	                 set netif_running_on/off on startup, del_timer_sync
-	
+
 	LK1.1.7:
 	- Manfred Spraul: added reset into tx_timeout
 
@@ -83,7 +83,7 @@
 	LK1.1.13 (jgarzik):
 	- Add ethtool support
 	- Replace some MII-related magic numbers with constants
-	
+
 	LK1.1.14 (Ivan G.):
  	- fixes comments for Rhine-III
 	- removes W_MAX_TIMEOUT (unused)
@@ -92,7 +92,7 @@
 	- sends chip_id as a parameter to wait_for_reset since np is not
 	  initialized on first call
 	- changes mmio "else if (chip_id==VT6102)" to "else" so it will work
-	  for Rhine-III's (documentation says same bit is correct)		
+	  for Rhine-III's (documentation says same bit is correct)
 	- transmit frame queue message is off by one - fixed
 	- adds IntrNormalSummary to "Something Wicked" exclusion list
 	  so normal interrupts will not trigger the message (src: Donald Becker)
@@ -316,10 +316,10 @@ IIId. Synchronization
 
 The driver runs as two independent, single-threaded flows of control.  One
 is the send-packet routine, which enforces single-threaded use by the
-dev->priv->lock spinlock. The other thread is the interrupt handler, which 
+dev->priv->lock spinlock. The other thread is the interrupt handler, which
 is single threaded by the hardware and interrupt handling software.
 
-The send packet thread has partial control over the Tx ring. It locks the 
+The send packet thread has partial control over the Tx ring. It locks the
 dev->priv->lock whenever it's queuing a Tx packet. If the next slot in the ring
 is not available it stops the transmit queue by calling netif_stop_queue.
 
@@ -615,6 +615,15 @@ static void __devinit reload_eeprom(long
 			break;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void via_rhine_poll(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	via_rhine_interrupt(dev->irq, (void *)dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
 static int __devinit via_rhine_init_one (struct pci_dev *pdev,
 					 const struct pci_device_id *ent)
 {
@@ -630,7 +639,7 @@ static int __devinit via_rhine_init_one 
 #ifdef USE_MEM
 	long ioaddr0;
 #endif
-	
+
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
 	static int printed_version;
@@ -651,7 +660,7 @@ static int __devinit via_rhine_init_one 
 		printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n");
 		goto err_out;
 	}
-	
+
 	/* sanity check */
 	if ((pci_resource_len (pdev, 0) < io_size) ||
 	    (pci_resource_len (pdev, 1) < io_size)) {
@@ -671,7 +680,8 @@ static int __devinit via_rhine_init_one 
 		goto err_out;
 	}
 	SET_MODULE_OWNER(dev);
-	
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
 	if (pci_request_regions(pdev, shortname))
 		goto err_out_free_netdev;
 
@@ -783,6 +793,9 @@ static int __devinit via_rhine_init_one 
 	dev->ethtool_ops = &netdev_ethtool_ops;
 	dev->tx_timeout = via_rhine_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = via_rhine_poll;
+#endif
 	if (np->drv_flags & ReqTxAlign)
 		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 
@@ -834,6 +847,8 @@ static int __devinit via_rhine_init_one 
 					netif_carrier_on(dev);
 				else
 					netif_carrier_off(dev);
+
+				break;
 			}
 		}
 		np->mii_cnt = phy_idx;
@@ -867,7 +882,7 @@ err_out_free_res:
 #endif
 	pci_release_regions(pdev);
 err_out_free_netdev:
-	kfree (dev);
+	free_netdev (dev);
 err_out:
 	return -ENODEV;
 }
@@ -878,7 +893,7 @@ static int alloc_ring(struct net_device*
 	void *ring;
 	dma_addr_t ring_dma;
 
-	ring = pci_alloc_consistent(np->pdev, 
+	ring = pci_alloc_consistent(np->pdev,
 				    RX_RING_SIZE * sizeof(struct rx_desc) +
 				    TX_RING_SIZE * sizeof(struct tx_desc),
 				    &ring_dma);
@@ -890,7 +905,7 @@ static int alloc_ring(struct net_device*
 		np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
 								   &np->tx_bufs_dma);
 		if (np->tx_bufs == NULL) {
-			pci_free_consistent(np->pdev, 
+			pci_free_consistent(np->pdev,
 				    RX_RING_SIZE * sizeof(struct rx_desc) +
 				    TX_RING_SIZE * sizeof(struct tx_desc),
 				    ring, ring_dma);
@@ -910,7 +925,7 @@ void free_ring(struct net_device* dev)
 {
 	struct netdev_private *np = dev->priv;
 
-	pci_free_consistent(np->pdev, 
+	pci_free_consistent(np->pdev,
 			    RX_RING_SIZE * sizeof(struct rx_desc) +
 			    TX_RING_SIZE * sizeof(struct tx_desc),
 			    np->rx_ring, np->rx_ring_dma);
@@ -935,7 +950,7 @@ static void alloc_rbufs(struct net_devic
 	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
 	np->rx_head_desc = &np->rx_ring[0];
 	next = np->rx_ring_dma;
-	
+
 	/* Init the ring entries */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].rx_status = 0;
@@ -1138,7 +1153,7 @@ static int via_rhine_open(struct net_dev
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n",
 			   dev->name, np->pdev->irq);
-	
+
 	i = alloc_ring(dev);
 	if (i)
 		return i;
@@ -1253,7 +1268,7 @@ static void via_rhine_tx_timeout (struct
 	/* Reinitialize the hardware. */
 	wait_for_reset(dev, np->chip_id, dev->name);
 	init_registers(dev);
-	
+
 	spin_unlock(&np->lock);
 	enable_irq(np->pdev->irq);
 
@@ -1303,7 +1318,7 @@ static int via_rhine_start_tx(struct sk_
 		np->tx_ring[entry].addr = cpu_to_le32(np->tx_skbuff_dma[entry]);
 	}
 
-	np->tx_ring[entry].desc_length = 
+	np->tx_ring[entry].desc_length =
 		cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
 	/* lock eth irq */
@@ -1351,7 +1366,7 @@ static irqreturn_t via_rhine_interrupt(i
 	int handled = 0;
 
 	ioaddr = dev->base_addr;
-	
+
 	while ((intr_status = get_intr_status(dev))) {
 		handled = 1;
 
@@ -1569,7 +1584,7 @@ static void via_rhine_rx(struct net_devi
 				break;			/* Better luck next round. */
 			skb->dev = dev;			/* Mark as being used by this device. */
 			np->rx_skbuff_dma[entry] =
-				pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, 
+				pci_map_single(np->pdev, skb->tail, np->rx_buf_sz,
 							   PCI_DMA_FROMDEVICE);
 			np->rx_ring[entry].addr = cpu_to_le32(np->rx_skbuff_dma[entry]);
 		}
@@ -1877,7 +1892,7 @@ static int via_rhine_close(struct net_de
 static void __devexit via_rhine_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	
+
 	unregister_netdev(dev);
 
 	pci_release_regions(pdev);
@@ -1886,7 +1901,7 @@ static void __devexit via_rhine_remove_o
 	iounmap((char *)(dev->base_addr));
 #endif
 
-	kfree(dev);
+	free_netdev(dev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/pci/pci.c linux-2.4.27-pre3/drivers/pci/pci.c
--- linux-2.4.26/drivers/pci/pci.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/pci/pci.c	2004-05-18 16:52:10.000000000 +0000
@@ -943,7 +943,7 @@ pci_generic_prep_mwi(struct pci_dev *dev
 	if (cacheline_size == pci_cache_line_size)
 		return 0;
 
-	printk(KERN_WARNING "PCI: cache line size of %d is not supported "
+	printk(KERN_DEBUG "PCI: cache line size of %d is not supported "
 	       "by device %s\n", pci_cache_line_size << 2, dev->slot_name);
 
 	return -EINVAL;
@@ -2214,6 +2214,7 @@ EXPORT_SYMBOL(pcibios_find_device);
 
 EXPORT_SYMBOL(isa_dma_bridge_buggy);
 EXPORT_SYMBOL(pci_pci_problems);
+EXPORT_SYMBOL(pciehp_msi_quirk);
 
 /* Pool allocator */
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/pci/pci.ids linux-2.4.27-pre3/drivers/pci/pci.ids
--- linux-2.4.26/drivers/pci/pci.ids	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/pci/pci.ids	2004-05-18 16:53:26.000000000 +0000
@@ -476,6 +476,7 @@
 	700f  PCI Bridge [IGP 320M]
 	7010  PCI Bridge [IGP 340M]
 	cab2  RS200/RS200M AGP Bridge [IGP 340M]
+	cbb2  RS200/RS200M AGP Bridge [IGP 345M]
 1003  ULSI Systems
 	0201  US201
 1004  VLSI Technology Inc
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/pci/quirks.c linux-2.4.27-pre3/drivers/pci/quirks.c
--- linux-2.4.26/drivers/pci/quirks.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/pci/quirks.c	2004-05-18 16:50:57.000000000 +0000
@@ -719,6 +719,13 @@ static void __init asus_hides_smbus_lpc(
 	}
 }
 
+int pciehp_msi_quirk;
+
+static void __devinit quirk_pciehp_msi(struct pci_dev *pdev)
+{
+	pciehp_msi_quirk = 1;
+}
+
 /*
  *  The main table of quirks.
  */
@@ -808,6 +815,8 @@ static struct pci_fixup pci_fixups[] __i
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_0,	asus_hides_smbus_lpc },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801BA_0,	asus_hides_smbus_lpc },
 
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_SMCH,  quirk_pciehp_msi },
+	
 	{ 0 }
 };
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/ChangeLog.ips linux-2.4.27-pre3/drivers/scsi/ChangeLog.ips
--- linux-2.4.26/drivers/scsi/ChangeLog.ips	2003-06-13 14:51:36.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/ChangeLog.ips	2004-05-18 16:55:08.000000000 +0000
@@ -1,6 +1,13 @@
 IBM ServeRAID driver Change Log
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+        7.00.xx  - Linux 2.6 Kernel Changes
+             
+        6.11.07  - Make Logical Drive Info structure safe for DMA     
+                 - Get VersionInfo buffer off the stack !             
+        
+        6.10.24  - Remove 1G Addressing Limitations                   
+        
         6.00.00  - Add 6x Adapters and Battery Flash 
         
         5.30.00  - use __devexit_p()
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/Config.in linux-2.4.27-pre3/drivers/scsi/Config.in
--- linux-2.4.26/drivers/scsi/Config.in	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/Config.in	2004-05-18 16:52:52.000000000 +0000
@@ -68,6 +68,14 @@ dep_tristate 'Always IN2000 SCSI support
 dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI $CONFIG_PCI
 dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI
 dep_tristate 'AMI MegaRAID2 support' CONFIG_SCSI_MEGARAID2 $CONFIG_SCSI
+dep_mbool 'Serial ATA (SATA) support' CONFIG_SCSI_SATA $CONFIG_SCSI
+dep_tristate '  ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SVW $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate '  Promise SATA TX2/TX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_PROMISE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate '  Promise SATA SX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SX4 $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate '  Silicon Image SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIL $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate '  SiS 964/180 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIS $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate '  VIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_VIA $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate '  Vitesse VSC-7174 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_VITESSE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 
 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
 if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/Makefile linux-2.4.27-pre3/drivers/scsi/Makefile
--- linux-2.4.26/drivers/scsi/Makefile	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/Makefile	2004-05-18 16:54:37.000000000 +0000
@@ -21,7 +21,7 @@ CFLAGS_seagate.o =   -DARBITRATE -DPARIT
 
 O_TARGET := scsidrv.o
 
-export-objs	:= scsi_syms.o 53c700.o
+export-objs	:= scsi_syms.o 53c700.o libata-core.o
 mod-subdirs	:= pcmcia ../acorn/scsi
 
 
@@ -130,6 +130,13 @@ obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
 obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
 obj-$(CONFIG_SCSI_LASI700)	+= lasi700.o 53c700.o
 obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
+obj-$(CONFIG_SCSI_SATA_SVW)	+= libata.o sata_svw.o
+obj-$(CONFIG_SCSI_SATA_PROMISE)	+= libata.o sata_promise.o
+obj-$(CONFIG_SCSI_SATA_SIL)	+= libata.o sata_sil.o
+obj-$(CONFIG_SCSI_SATA_VIA)	+= libata.o sata_via.o
+obj-$(CONFIG_SCSI_SATA_VITESSE)	+= libata.o sata_vsc.o
+obj-$(CONFIG_SCSI_SATA_SIS)	+= libata.o sata_sis.o
+obj-$(CONFIG_SCSI_SATA_SX4)	+= libata.o sata_sx4.o
 
 subdir-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi
 obj-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi/acorn-scsi.o
@@ -141,7 +148,7 @@ obj-$(CONFIG_BLK_DEV_SR)	+= sr_mod.o
 obj-$(CONFIG_CHR_DEV_SG)	+= sg.o
 
 list-multi	:= scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o cpqfc.o \
-			zalon7xx_mod.o
+			zalon7xx_mod.o libata.o
 scsi_mod-objs	:= scsi.o hosts.o scsi_ioctl.o constants.o \
 			scsicam.o scsi_proc.o scsi_error.o \
 			scsi_obsolete.o scsi_queue.o scsi_lib.o \
@@ -154,6 +161,7 @@ a100u2w-objs	:= inia100.o i60uscsi.o
 zalon7xx_mod-objs := zalon7xx.o ncr53c8xx.o
 cpqfc-objs	:= cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o \
 		   cpqfcTSworker.o cpqfcTStrigger.o
+libata-objs	:= libata-core.o libata-scsi.o
 
 include $(TOPDIR)/Rules.make
 
@@ -179,6 +187,9 @@ zalon7xx_mod.o: $(zalon7xx_mod-objs)
 cpqfc.o: $(cpqfc-objs)
 	$(LD) -r -o $@ $(cpqfc-objs)
 
+libata.o: $(libata-objs)
+	$(LD) -r -o $@ $(libata-objs)
+
 53c8xx_d.h: 53c7,8xx.scr script_asm.pl
 	ln -sf 53c7,8xx.scr fake8.c
 	$(CPP) $(CPPFLAGS) -traditional -DCHIP=810 fake8.c | grep -v '^#' | $(PERL) script_asm.pl 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/NCR53C9x.c linux-2.4.27-pre3/drivers/scsi/NCR53C9x.c
--- linux-2.4.26/drivers/scsi/NCR53C9x.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/NCR53C9x.c	2004-05-18 16:51:56.000000000 +0000
@@ -917,7 +917,7 @@ static void esp_get_dmabufs(struct NCR_E
 		if (esp->dma_mmu_get_scsi_one)
 			esp->dma_mmu_get_scsi_one(esp, sp);
 		else
-			sp->SCp.have_data_in = (int) sp->SCp.ptr =
+			sp->SCp.ptr =
 				(char *) virt_to_phys(sp->request_buffer);
 	} else {
 		sp->SCp.buffer = (struct scatterlist *) sp->buffer;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/ips.c linux-2.4.27-pre3/drivers/scsi/ips.c
--- linux-2.4.26/drivers/scsi/ips.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/ips.c	2004-05-18 16:50:49.000000000 +0000
@@ -170,12 +170,11 @@
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
 
-#include <linux/blk.h>
+#include <linux/blkdev.h>
 #include <linux/types.h>
 
 #include <scsi/sg.h>
 
-#include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
 #include "ips.h"
@@ -198,17 +197,22 @@ MODULE_PARM(ips, "s");
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "6.11"
-#define IPS_VERSION_LOW         ".07 "
+#define IPS_VERSION_HIGH        "7.00"
+#define IPS_VERSION_LOW         ".15 "
 
 #if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
 #warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
 #endif
 
-#if LINUX_VERSION_CODE <= LinuxVersionCode(2,5,0)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+#include <linux/blk.h>
+#include "sd.h"
 #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)
+#ifndef __devexit_p
+#define __devexit_p(x) x
+#endif
 #else
 #define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \
                                      page_address((sg)->page)+(sg)->offset : 0)
@@ -240,42 +244,70 @@ static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS
 static unsigned int ips_next_controller;
 static unsigned int ips_num_controllers;
 static unsigned int ips_released_controllers;
+static int ips_hotplug;
 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_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 int ips_cd_boot;			/* Booting from Manager CD         */
 static char *ips_FlashData = NULL;	/* CD Boot - Flash Data Buffer      */
 static dma_addr_t ips_flashbusaddr;
-static long ips_FlashDataInUse;	/* CD Boot - Flash Data In Use Flag */
+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;
+static Scsi_Host_Template ips_driver_template = {
+	.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,
+	.proc_name		= "ips",
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	.proc_info		= ips_proc_info,
+	.slave_configure	= ips_slave_configure,
+#else
+	.proc_info		= ips_proc24_info,
+	.select_queue_depths	= ips_select_queue_depth,
+#endif
+	.bios_param		= ips_biosparam,
+	.this_id		= -1,
+	.sg_tablesize		= IPS_MAX_SG,
+	.cmd_per_lun		= 3,
+	.use_clustering		= ENABLE_CLUSTERING,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	.use_new_eh_code	= 1,
+#ifdef RHEL3
+    .vary_io            = 1,
+#endif
+#endif
+};
+
+IPS_DEFINE_COMPAT_TABLE( Compatable );	/* Version Compatability Table      */
 
-IPS_DEFINE_COMPAT_TABLE(Compatable);	/* Version Compatability Table      */
 
-   /* 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 all ServeRAID Adapters */
+static struct  pci_device_id  ips_pci_table[] = {
+	{ 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, }
 };
 
-MODULE_DEVICE_TABLE(pci, ips_pci_table);
+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);
-
+   
+static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
+static void __devexit 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,
+	.name		= ips_hot_plug_name,
+	.id_table	= ips_pci_table,
+	.probe		= ips_insert_device,
+	.remove		= __devexit_p(ips_remove_device),
 };
+           
 
 /*
  * Necessary forward function protoypes
@@ -299,7 +331,10 @@ static char ips_adapter_name[][30] = {
 	"ServeRAID 5i",
 	"ServeRAID 5i",
 	"ServeRAID 6M",
-	"ServeRAID 6i"
+	"ServeRAID 6i",
+	"ServeRAID 7t",
+	"ServeRAID 7k",
+	"ServeRAID 7M"
 };
 
 static struct notifier_block ips_notifier = {
@@ -371,9 +406,8 @@ 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_biosparam(Disk *, kdev_t, int *);
 const char *ips_info(struct Scsi_Host *);
-void do_ipsintr(int, void *, struct pt_regs *);
+irqreturn_t 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 *);
 static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
@@ -424,8 +458,8 @@ static void ips_chkstatus(ips_ha_t *, IP
 static void ips_enable_int_copperhead(ips_ha_t *);
 static void ips_enable_int_copperhead_memio(ips_ha_t *);
 static void ips_enable_int_morpheus(ips_ha_t *);
-static void ips_intr_copperhead(ips_ha_t *);
-static void ips_intr_morpheus(ips_ha_t *);
+static int ips_intr_copperhead(ips_ha_t *);
+static int ips_intr_morpheus(ips_ha_t *);
 static void ips_next(ips_ha_t *, int);
 static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);
 static void ipsintr_done(ips_ha_t *, struct ips_scb *);
@@ -467,7 +501,7 @@ static void ips_scmd_buf_write(Scsi_Cmnd
 			       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(struct Scsi_Host *, char *, char **, off_t, 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 *, ...);
@@ -561,15 +595,12 @@ ips_detect(Scsi_Host_Template * SHT)
 		ips_setup(ips);
 #endif
 
-	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++;
 	}
-
+	ips_hotplug = 1;
 	return (ips_num_controllers);
 }
 
@@ -680,15 +711,13 @@ ips_release(struct Scsi_Host *sh)
 	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);
+	IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
 
 	/* 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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n");
 
-	printk(KERN_NOTICE "(%s%d) Flushing Complete.\n", ips_name,
-	       ha->host_num);
+	IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n");
 
 	ips_sh[i] = NULL;
 	ips_ha[i] = NULL;
@@ -703,7 +732,8 @@ ips_release(struct Scsi_Host *sh)
 	/* free IRQ */
 	free_irq(ha->irq, ha);
 
-	scsi_unregister(sh);
+	IPS_REMOVE_HOST(sh);
+	scsi_host_put(sh);
 
 	ips_released_controllers++;
 
@@ -727,7 +757,8 @@ ips_halt(struct notifier_block *nb, ulon
 	int i;
 
 	if ((event != SYS_RESTART) && (event != SYS_HALT) &&
-	    (event != SYS_POWER_OFF)) return (NOTIFY_DONE);
+	    (event != SYS_POWER_OFF))
+		return (NOTIFY_DONE);
 
 	for (i = 0; i < ips_next_controller; i++) {
 		ha = (ips_ha_t *) ips_ha[i];
@@ -754,17 +785,16 @@ ips_halt(struct notifier_block *nb, ulon
 		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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
 
 		/* 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);
+		    IPS_FAILURE)
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Incomplete Flush.\n");
 		else
-			printk(KERN_NOTICE "(%s%d) Flushing Complete.\n",
-			       ips_name, ha->host_num);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Flushing Complete.\n");
 	}
 
 	return (NOTIFY_OK);
@@ -791,7 +821,7 @@ ips_eh_abort(Scsi_Cmnd * SC)
 	if (!SC)
 		return (FAILED);
 
-	ha = (ips_ha_t *) SC->host->hostdata;
+	ha = (ips_ha_t *) SC->device->host->hostdata;
 
 	if (!ha)
 		return (FAILED);
@@ -859,7 +889,7 @@ ips_eh_reset(Scsi_Cmnd * SC)
 		return (FAILED);
 	}
 
-	ha = (ips_ha_t *) SC->host->hostdata;
+	ha = (ips_ha_t *) SC->device->host->hostdata;
 
 	if (!ha) {
 		DEBUG(1, "Reset called with NULL ha struct");
@@ -916,9 +946,8 @@ ips_eh_reset(Scsi_Cmnd * SC)
 		/* 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);
+			IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+				   "Reset Request - Flushed Cache\n");
 			return (SUCCESS);
 		}
 	}
@@ -932,16 +961,14 @@ ips_eh_reset(Scsi_Cmnd * SC)
 	 * command must have already been sent
 	 * reset the controller
 	 */
-	printk(KERN_NOTICE "(%s%d) Resetting controller.\n",
-	       ips_name, ha->host_num);
+	IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n");
 	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);
+		IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+			   "Controller reset failed - controller now offline.\n");
 
 		/* Now fail all of the active commands */
 		DEBUG_VAR(1, "(%s%d) Failing active commands",
@@ -969,9 +996,8 @@ ips_eh_reset(Scsi_Cmnd * SC)
 	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);
+		IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+			   "Controller reset failed - controller now offline.\n");
 
 		/* Now fail all of the active commands */
 		DEBUG_VAR(1, "(%s%d) Failing active commands",
@@ -1050,7 +1076,7 @@ ips_queue(Scsi_Cmnd * SC, void (*done) (
 
 	METHOD_TRACE("ips_queue", 1);
 
-	ha = (ips_ha_t *) SC->host->hostdata;
+	ha = (ips_ha_t *) SC->device->host->hostdata;
 
 	if (!ha)
 		return (1);
@@ -1076,10 +1102,13 @@ ips_queue(Scsi_Cmnd * SC, void (*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);
+		  ha->host_num,
+		  SC->cmnd[0],
+		  SC->device->channel, SC->device->id, SC->device->lun);
 
 	/* Check for command to initiator IDs */
-	if ((SC->channel > 0) && (SC->target == ha->ha_id[SC->channel])) {
+	if ((SC->device->channel > 0)
+	    && (SC->device->id == ha->ha_id[SC->device->channel])) {
 		SC->result = DID_NO_CONNECT << 16;
 		done(SC);
 
@@ -1140,18 +1169,24 @@ ips_queue(Scsi_Cmnd * SC, void (*done) (
 /*   Set bios geometry for the controller                                   */
 /*                                                                          */
 /****************************************************************************/
-int
+static int
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 ips_biosparam(Disk * disk, kdev_t dev, int geom[])
 {
-	ips_ha_t *ha;
+	ips_ha_t *ha = (ips_ha_t *) disk->device->host->hostdata;
+	unsigned long capacity = disk->capacity;
+#else
+ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+	      sector_t capacity, int geom[])
+{
+	ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata;
+#endif
 	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);
@@ -1163,7 +1198,7 @@ ips_biosparam(Disk * disk, kdev_t dev, i
 		/* ?!?! Enquiry command failed */
 		return (0);
 
-	if ((disk->capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) {
+	if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) {
 		heads = IPS_NORM_HEADS;
 		sectors = IPS_NORM_SECTORS;
 	} else {
@@ -1171,7 +1206,7 @@ ips_biosparam(Disk * disk, kdev_t dev, i
 		sectors = IPS_COMP_SECTORS;
 	}
 
-	cylinders = disk->capacity / (heads * sectors);
+	cylinders = (unsigned long) capacity / (heads * sectors);
 
 	DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
 		  heads, sectors, cylinders);
@@ -1183,7 +1218,25 @@ ips_biosparam(Disk * disk, kdev_t dev, i
 	return (0);
 }
 
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
+/* ips_proc24_info is a wrapper around ips_proc_info *
+ * for compatibility with the 2.4 scsi parameters    */
+static int
+ips_proc24_info(char *buffer, char **start, off_t offset, int length,
+		              int hostno, int func)
+{
+	int i;
+
+	for (i = 0; i < ips_next_controller; i++) {
+		if (ips_sh[i] && ips_sh[i]->host_no == hostno) {
+			return ips_proc_info(ips_sh[i], buffer, start,
+					     offset, length, func);
+		}
+	}
+	return -EINVAL;	
+}
+
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_select_queue_depth                                     */
@@ -1264,38 +1317,40 @@ ips_slave_configure(Scsi_Device * SDptr)
 /*   Wrapper for the interrupt handler                                      */
 /*                                                                          */
 /****************************************************************************/
-void
-do_ipsintr(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t
+do_ipsintr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	ips_ha_t *ha;
 	unsigned long cpu_flags;
 	struct Scsi_Host *host;
+	int irqstatus;
 
 	METHOD_TRACE("do_ipsintr", 2);
 
 	ha = (ips_ha_t *) dev_id;
 	if (!ha)
-		return;
+		return IRQ_NONE;
 	host = ips_sh[ha->host_num];
 	/* interrupt during initialization */
 	if (!host) {
 		(*ha->func.intr) (ha);
-		return;
+		return IRQ_HANDLED;
 	}
 
 	IPS_LOCK_SAVE(host->host_lock, cpu_flags);
 
 	if (!ha->active) {
 		IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
-		return;
+		return IRQ_HANDLED;
 	}
 
-	(*ha->func.intr) (ha);
+	irqstatus = (*ha->func.intr) (ha);
 
 	IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
 
 	/* start the next command */
 	ips_next(ha, IPS_INTR_ON);
+	return IRQ_RETVAL(irqstatus);
 }
 
 /****************************************************************************/
@@ -1309,7 +1364,7 @@ do_ipsintr(int irq, void *dev_id, struct
 /*   ASSUMES interrupts are disabled                                        */
 /*                                                                          */
 /****************************************************************************/
-void
+int
 ips_intr_copperhead(ips_ha_t * ha)
 {
 	ips_stat_t *sp;
@@ -1320,10 +1375,10 @@ ips_intr_copperhead(ips_ha_t * ha)
 	METHOD_TRACE("ips_intr", 2);
 
 	if (!ha)
-		return;
+		return 0;
 
 	if (!ha->active)
-		return;
+		return 0;
 
 	intrstatus = (*ha->func.isintr) (ha);
 
@@ -1332,7 +1387,7 @@ ips_intr_copperhead(ips_ha_t * ha)
 		 * Unexpected/Shared interrupt
 		 */
 
-		return;
+		return 0;
 	}
 
 	while (TRUE) {
@@ -1359,6 +1414,7 @@ ips_intr_copperhead(ips_ha_t * ha)
 		 */
 		(*scb->callback) (ha, scb);
 	}			/* end while */
+	return 1;
 }
 
 /****************************************************************************/
@@ -1372,7 +1428,7 @@ ips_intr_copperhead(ips_ha_t * ha)
 /*   ASSUMES interrupts are disabled                                        */
 /*                                                                          */
 /****************************************************************************/
-void
+int
 ips_intr_morpheus(ips_ha_t * ha)
 {
 	ips_stat_t *sp;
@@ -1383,10 +1439,10 @@ ips_intr_morpheus(ips_ha_t * ha)
 	METHOD_TRACE("ips_intr_morpheus", 2);
 
 	if (!ha)
-		return;
+		return 0;
 
 	if (!ha->active)
-		return;
+		return 0;
 
 	intrstatus = (*ha->func.isintr) (ha);
 
@@ -1395,7 +1451,7 @@ ips_intr_morpheus(ips_ha_t * ha)
 		 * Unexpected/Shared interrupt
 		 */
 
-		return;
+		return 0;
 	}
 
 	while (TRUE) {
@@ -1413,9 +1469,8 @@ ips_intr_morpheus(ips_ha_t * ha)
 			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);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Spurious interrupt; no ccb.\n");
 
 			continue;
 		}
@@ -1429,6 +1484,7 @@ ips_intr_morpheus(ips_ha_t * ha)
 		 */
 		(*scb->callback) (ha, scb);
 	}			/* end while */
+	return 1;
 }
 
 /****************************************************************************/
@@ -1479,8 +1535,8 @@ ips_info(struct Scsi_Host *SH)
 /*                                                                          */
 /****************************************************************************/
 int
-ips_proc_info(char *buffer, char **start, off_t offset,
-	      int length, int hostno, int func)
+ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+	      int length, int func)
 {
 	int i;
 	int ret;
@@ -1491,7 +1547,7 @@ ips_proc_info(char *buffer, char **start
 	/* Find our host structure */
 	for (i = 0; i < ips_next_controller; i++) {
 		if (ips_sh[i]) {
-			if (ips_sh[i]->host_no == hostno) {
+			if (ips_sh[i] == host) {
 				ha = (ips_ha_t *) ips_sh[i]->hostdata;
 				break;
 			}
@@ -1537,9 +1593,9 @@ ips_is_passthru(Scsi_Cmnd * SC)
 		return (0);
 
 	if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
-	    (SC->channel == 0) &&
-	    (SC->target == IPS_ADAPTER_ID) &&
-	    (SC->lun == 0) && SC->request_buffer) {
+	    (SC->device->channel == 0) &&
+	    (SC->device->id == IPS_ADAPTER_ID) &&
+	    (SC->device->lun == 0) && SC->request_buffer) {
 		if ((!SC->use_sg) && SC->request_bufflen &&
 		    (((char *) SC->request_buffer)[0] == 'C') &&
 		    (((char *) SC->request_buffer)[1] == 'O') &&
@@ -1671,7 +1727,8 @@ ips_make_passthru(ips_ha_t * ha, Scsi_Cm
 			}
 
 			if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
-			    pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) {
+			    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));
@@ -1741,7 +1798,8 @@ ips_flash_copperhead(ips_ha_t * ha, ips_
 		if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize >
 		    ha->flash_len) {
 			ips_free_flash_copperhead(ha);
-			printk(KERN_WARNING "failed size sanity check\n");
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "failed size sanity check\n");
 			return IPS_FAILURE;
 		}
 	}
@@ -1773,24 +1831,29 @@ ips_flash_bios(ips_ha_t * ha, ips_passth
 	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;
+		    (!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)) {
+		    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)) {
+		    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);
@@ -1823,7 +1886,7 @@ ips_flash_bios(ips_ha_t * ha, ips_passth
 /*                                                                          */
 /* Routine Description:                                                     */
 /*   Fill in a single scb sg_list element from an address                   */
-/*   return a -1 if a breakup occured                                       */
+/*   return a -1 if a breakup occurred                                      */
 /****************************************************************************/
 static inline int
 ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr,
@@ -1888,9 +1951,9 @@ ips_flash_firmware(ips_ha_t * ha, ips_pa
 	/* 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->bus = scb->scsi_cmd->device->channel;
+	scb->target_id = scb->scsi_cmd->device->id;
+	scb->lun = scb->scsi_cmd->device->lun;
 	scb->sg_len = 0;
 	scb->data_len = 0;
 	scb->flags = 0;
@@ -1957,9 +2020,9 @@ ips_usrcmd(ips_ha_t * ha, ips_passthru_t
 	/* 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->bus = scb->scsi_cmd->device->channel;
+	scb->target_id = scb->scsi_cmd->device->id;
+	scb->lun = scb->scsi_cmd->device->lun;
 	scb->sg_len = 0;
 	scb->data_len = 0;
 	scb->flags = 0;
@@ -2103,27 +2166,60 @@ ips_host_info(ips_ha_t * ha, char *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]);
+    /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
+    /* That keeps everything happy for "text" operations on the proc file.                    */
+
+	if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
+        if (ha->nvram->bios_low[3] == 0) { 
+            copy_info(&info,
+			          "\tBIOS Version                      : %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]);
+
+        } else {
+		    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]);
+        }
+
+    }
+
+    if (ha->enq->CodeBlkVersion[7] == 0) {
+        copy_info(&info,
+		          "\tFirmware Version                  : %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]);
+    } else {
+        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]);
+    }
+
+    if (ha->enq->BootBlkVersion[7] == 0) {
+        copy_info(&info,
+		          "\tBoot Block Version                : %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]);
+    } else {
+        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);
@@ -2285,6 +2381,12 @@ ips_identify_controller(ips_ha_t * ha)
 		case IPS_SUBDEVICEID_6I:
 			ha->ad_type = IPS_ADTYPE_SERVERAID6I;
 			break;
+		case IPS_SUBDEVICEID_7k:
+			ha->ad_type = IPS_ADTYPE_SERVERAID7k;
+			break;
+		case IPS_SUBDEVICEID_7M:
+			ha->ad_type = IPS_ADTYPE_SERVERAID7M;
+			break;
 		}
 		break;
 	}
@@ -2310,7 +2412,7 @@ ips_get_bios_version(ips_ha_t * ha, int 
 	uint8_t *buffer;
 	char hexDigits[] =
 	    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
-		    'D', 'E', 'F' };
+     'D', 'E', 'F' };
 
 	METHOD_TRACE("ips_get_bios_version", 1);
 
@@ -2422,9 +2524,10 @@ ips_get_bios_version(ips_ha_t * ha, int 
 		scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr;
 
 		/* issue the command */
-		if (
-		    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
-		     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+		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 */
 
@@ -2485,17 +2588,15 @@ ips_hainit(ips_ha_t * ha)
 	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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to read config from controller.\n");
 
 		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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to read controller status.\n");
 
 		return (0);
 	}
@@ -2504,18 +2605,16 @@ ips_hainit(ips_ha_t * ha)
 	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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to read subsystem parameters.\n");
 
 		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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to write driver info to controller.\n");
 
 		return (0);
 	}
@@ -2713,8 +2812,10 @@ ips_next(ips_ha_t * ha, int intr)
 
 	p = ha->scb_waitlist.head;
 	while ((p) && (scb = ips_getscb(ha))) {
-		if ((p->channel > 0)
-		    && (ha->dcdb_active[p->channel - 1] & (1 << p->target))) {
+		if ((p->device->channel > 0)
+		    && (ha->
+			dcdb_active[p->device->channel -
+				    1] & (1 << p->device->id))) {
 			ips_freescb(ha, scb);
 			p = (Scsi_Cmnd *) p->host_scribble;
 			continue;
@@ -2731,9 +2832,9 @@ ips_next(ips_ha_t * ha, int intr)
 
 		memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer));
 
-		scb->target_id = SC->target;
-		scb->lun = SC->lun;
-		scb->bus = SC->channel;
+		scb->target_id = SC->device->id;
+		scb->lun = SC->device->lun;
+		scb->bus = SC->device->channel;
 		scb->scsi_cmd = SC;
 		scb->breakup = 0;
 		scb->data_len = 0;
@@ -3301,17 +3402,16 @@ ipsintr_done(ips_ha_t * ha, ips_scb_t * 
 	METHOD_TRACE("ipsintr_done", 2);
 
 	if (!scb) {
-		printk(KERN_WARNING "(%s%d) Spurious interrupt; scb NULL.\n",
-		       ips_name, ha->host_num);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Spurious interrupt; scb NULL.\n");
 
 		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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Spurious interrupt; scsi_cmd not set.\n");
 
 		return;
 	}
@@ -3465,8 +3565,9 @@ ips_map_status(ips_ha_t * ha, ips_scb_t 
 	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,
+			  ips_name, ha->host_num,
+			  scb->scsi_cmd->device->channel,
+			  scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun,
 			  scb->basic_status, scb->extended_status,
 			  scb->extended_status ==
 			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0,
@@ -3502,7 +3603,8 @@ ips_map_status(ips_ha_t * ha, ips_scb_t 
 
 		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)) {
+			    (scb->cmd.dcdb.op_code ==
+			     IPS_CMD_EXTENDED_DCDB_SG)) {
 				tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
 				transfer_len = tapeDCDB->transfer_length;
 			} else {
@@ -3516,9 +3618,8 @@ ips_map_status(ips_ha_t * ha, ips_scb_t 
 
 				/* Restrict access to physical DASD */
 				if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
-				    ((((char
-					*) scb->scsi_cmd->buffer)[0] & 0x1f) ==
-				     TYPE_DISK)) {
+				    ((((char *) scb->scsi_cmd->
+				       buffer)[0] & 0x1f) == TYPE_DISK)) {
 					/* underflow -- no error               */
 					/* restrict access to physical DASD    */
 					errcode = DID_TIME_OUT;
@@ -3543,8 +3644,7 @@ ips_map_status(ips_ha_t * ha, ips_scb_t 
 
 		case IPS_ERR_CKCOND:
 			if (scb->bus) {
-				if (
-				    (scb->cmd.dcdb.op_code ==
+				if ((scb->cmd.dcdb.op_code ==
 				     IPS_CMD_EXTENDED_DCDB)
 				    || (scb->cmd.dcdb.op_code ==
 					IPS_CMD_EXTENDED_DCDB_SG)) {
@@ -3822,13 +3922,10 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * 
 							    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->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);
@@ -3873,11 +3970,11 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * 
 							    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->
+				    ((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 =
@@ -4253,7 +4350,8 @@ ips_online(ips_ha_t * ha, ips_scb_t * sc
 	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
 	    IPS_LD_CRS
 	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
-	    IPS_LD_SYS) return (1);
+	    IPS_LD_SYS)
+		return (1);
 	else
 		return (0);
 }
@@ -4397,6 +4495,13 @@ ips_msense(ips_ha_t * ha, ips_scb_t * sc
 		mdata.pdata.pg4.RotationalOffset = 0;
 		mdata.pdata.pg4.MediumRotationRate = 0;
 		break;
+	case 0x8:
+		mdata.pdata.pg8.PageCode = 8;
+		mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8);
+		mdata.hdr.DataLength =
+		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength;
+		/* everything else is left set to 0 */
+		break;
 
 	default:
 		return (0);
@@ -4469,9 +4574,9 @@ ips_free(ips_ha_t * ha)
 					    sizeof (IPS_IO_CMD), ha->adapt,
 					    ha->adapt->hw_status_start);
 			ha->adapt = NULL;
-		}  	
-        	
-        if (ha->logical_drive_info) {
+		}
+
+		if (ha->logical_drive_info) {
 			pci_free_consistent(ha->pcidev,
 					    sizeof (IPS_LD_INFO),
                         ha->logical_drive_info,
@@ -4800,7 +4905,7 @@ 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);
-	inb(ha->io_addr + IPS_REG_HISR);	// Ensure PCI Posting Completes
+	inb(ha->io_addr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/
 }
 
 /****************************************************************************/
@@ -4817,7 +4922,7 @@ ips_enable_int_copperhead_memio(ips_ha_t
 	METHOD_TRACE("ips_enable_int_copperhead_memio", 1);
 
 	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
-	readb(ha->mem_ptr + IPS_REG_HISR);	// Ensure PCI Posting Completes
+	readb(ha->mem_ptr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/
 }
 
 /****************************************************************************/
@@ -4838,7 +4943,7 @@ ips_enable_int_morpheus(ips_ha_t * ha)
 	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
+	readl(ha->mem_ptr + IPS_REG_I960_OIMR);	/*Ensure PCI Posting Completes*/
 }
 
 /****************************************************************************/
@@ -4880,9 +4985,9 @@ ips_init_copperhead(ips_ha_t * ha)
 	}
 
 	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]);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "reset controller fails (post status %x %x).\n",
+			   PostByte[0], PostByte[1]);
 
 		return (0);
 	}
@@ -4974,9 +5079,9 @@ ips_init_copperhead_memio(ips_ha_t * ha)
 	}
 
 	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]);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "reset controller fails (post status %x %x).\n",
+			   PostByte[0], PostByte[1]);
 
 		return (0);
 	}
@@ -5063,8 +5168,8 @@ ips_init_morpheus(ips_ha_t * ha)
 
 	if (i >= 45) {
 		/* error occurred */
-		printk(KERN_WARNING "(%s%d) timeout waiting for post.\n",
-		       ips_name, ha->host_num);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "timeout waiting for post.\n");
 
 		return (0);
 	}
@@ -5072,7 +5177,8 @@ ips_init_morpheus(ips_ha_t * ha)
 	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");
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Flashing Battery PIC, Please wait ...\n");
 
 		/* Clear the interrupt bit */
 		Isr = (uint32_t) IPS_BIT_I960_MSG0I;
@@ -5087,9 +5193,8 @@ ips_init_morpheus(ips_ha_t * ha)
 		}
 
 		if (i >= 120) {
-			printk(KERN_WARNING
-			       "(%s%d) timeout waiting for Battery PIC Flash\n",
-			       ips_name, ha->host_num);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "timeout waiting for Battery PIC Flash\n");
 			return (0);
 		}
 
@@ -5100,9 +5205,8 @@ ips_init_morpheus(ips_ha_t * ha)
 	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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "reset controller fails (post status %x).\n", Post);
 
 		return (0);
 	}
@@ -5120,8 +5224,8 @@ ips_init_morpheus(ips_ha_t * ha)
 
 	if (i >= 240) {
 		/* error occurred */
-		printk(KERN_WARNING "(%s%d) timeout waiting for config.\n",
-		       ips_name, ha->host_num);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "timeout waiting for config.\n");
 
 		return (0);
 	}
@@ -5450,19 +5554,18 @@ ips_issue_copperhead(ips_ha_t * ha, ips_
 
 	TimeOut = 0;
 
-	while ((val = le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) &
-	       IPS_BIT_SEM) {
+	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);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "ips_issue val [0x%x].\n", val);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "ips_issue semaphore chk timeout.\n");
 
 			return (IPS_FAILURE);
 		}		/* end if */
@@ -5512,11 +5615,10 @@ ips_issue_copperhead_memio(ips_ha_t * ha
 			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);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "ips_issue val [0x%x].\n", val);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "ips_issue semaphore chk timeout.\n");
 
 			return (IPS_FAILURE);
 		}		/* end if */
@@ -5755,8 +5857,8 @@ ips_write_driver_status(ips_ha_t * ha, i
 	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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to read NVRAM page 5.\n");
 
 		return (0);
 	}
@@ -5793,8 +5895,8 @@ ips_write_driver_status(ips_ha_t * ha, i
 
 	/* 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_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to write NVRAM page 5.\n");
 
 		return (0);
 	}
@@ -5839,9 +5941,9 @@ ips_read_adapter_status(ips_ha_t * ha, i
 	scb->cmd.basic_io.sg_addr = ha->enq_busaddr;
 
 	/* send command */
-	if (
-	    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
-	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	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);
 
@@ -5882,9 +5984,9 @@ ips_read_subsystem_parameters(ips_ha_t *
 	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
 
 	/* send command */
-	if (
-	    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
-	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	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);
 
@@ -5927,9 +6029,9 @@ ips_read_config(ips_ha_t * ha, int intr)
 	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
 
 	/* send command */
-	if (
-	    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
-	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	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));
@@ -5940,7 +6042,8 @@ ips_read_config(ips_ha_t * ha, int intr)
 
 		/* 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);
+		    IPS_CMD_CMPLT_WERROR)
+			return (1);
 
 		return (0);
 	}
@@ -5985,9 +6088,9 @@ ips_readwrite_page5(ips_ha_t * ha, int w
 		memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));
 	
 	/* issue the command */
-	if (
-	    ((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) ==
-	     IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)
+	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->nvram, 0, sizeof (IPS_NVRAM_P5));
@@ -6032,9 +6135,9 @@ ips_clear_adapter(ips_ha_t * ha, int int
 	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)
+	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);
 
@@ -6053,9 +6156,9 @@ ips_clear_adapter(ips_ha_t * ha, int int
 	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)
+	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);
 
@@ -6722,7 +6825,7 @@ ips_version_check(ips_ha_t * ha, int int
 	uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1];
 	uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1];
 	int MatchError;
-	int  rc;
+	int rc;
 	char BiosString[10];
 	char FirmwareString[10];
 
@@ -6739,8 +6842,8 @@ ips_version_check(ips_ha_t * ha, int int
 
 	rc = IPS_FAILURE;
 	if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {	/* If Versioning is Supported */
-        memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA));
 		/* Get the Version Info with a Get Version Command */
+        memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA));
 		rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr);
 		if (rc == IPS_SUCCESS)
 			memcpy(FirmwareVersion, VersionInfo->compatibilityId,
@@ -6780,14 +6883,14 @@ ips_version_check(ips_ha_t * ha, int int
 			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");
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Warning ! ! ! ServeRAID Version Mismatch\n");
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
+				   BiosString, FirmwareString, IPS_VERSION_HIGH,
+				   IPS_VERSION_LOW);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "These levels should match to avoid possible compatibility problems.\n");
 		}
 	} else {
 		ha->nvram->version_mismatch = 0;
@@ -6825,7 +6928,7 @@ ips_get_version_info(ips_ha_t * ha, dma_
 	scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA);
 	scb->cmd.version_info.reserved2 = 0;
 	scb->data_len = sizeof (IPS_VERSION_DATA);
-    scb->data_busaddr = Buffer;
+	scb->data_busaddr = Buffer;
 	scb->cmd.version_info.buffer_addr = Buffer;
 	scb->flags = 0;
 
@@ -6896,6 +6999,8 @@ ips_order_controllers(void)
 			for (j = position; j < ips_num_controllers; j++) {
 				switch (ips_ha[j]->ad_type) {
 				case IPS_ADTYPE_SERVERAID6M:
+				case IPS_ADTYPE_SERVERAID7k:
+				case IPS_ADTYPE_SERVERAID7M:
 					if (nvram->adapter_order[i] == 'M') {
 						ips_shift_controllers(position,
 								      j);
@@ -6979,28 +7084,28 @@ 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));
+	ips_ha_t *ha, *oldha = ips_ha[index];
+	sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t));
 	if (!sh) {
-		printk(KERN_WARNING
-		       "Unable to register controller with SCSI subsystem\n");
+		IPS_PRINTK(KERN_WARNING, oldha->pcidev,
+			   "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);
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Unable to install interrupt handler\n");
+		scsi_host_put(sh);
 		return -1;
 	}
 
 	kfree(oldha);
 	ips_sh[index] = sh;
 	ips_ha[index] = ha;
-	scsi_set_pci_device(sh, ha->pcidev);
+	IPS_SCSI_SET_DEVICE(sh, ha);
 
 	/* Store away needed values for later use */
 	sh->io_port = ha->io_addr;
@@ -7013,7 +7118,7 @@ ips_register_scsi(int index)
 	sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
 	sh->use_clustering = sh->hostt->use_clustering;
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
 	sh->max_sectors = 128;
 #endif
 
@@ -7022,6 +7127,7 @@ ips_register_scsi(int index)
 	sh->max_channel = ha->nbus - 1;
 	sh->can_queue = ha->max_cmds - 1;
 
+	IPS_ADD_HOST(sh, NULL);
 	return 0;
 }
 
@@ -7031,7 +7137,7 @@ ips_register_scsi(int index)
 /*   Routine Description:                                                    */
 /*     Remove one Adapter ( Hot Plugging )                                   */
 /*---------------------------------------------------------------------------*/
-static void
+static void __devexit
 ips_remove_device(struct pci_dev *pci_dev)
 {
 	int i;
@@ -7064,7 +7170,7 @@ ips_module_init(void)
 		return -ENODEV;
 	ips_driver_template.module = THIS_MODULE;
 	ips_order_controllers();
-	if (scsi_register_module(MODULE_SCSI_HA, &ips_driver_template)) {
+	if (IPS_REGISTER_HOSTS(&ips_driver_template)) {
 		pci_unregister_driver(&ips_pci_driver);
 		return -ENODEV;
 	}
@@ -7082,7 +7188,7 @@ ips_module_init(void)
 static void __exit
 ips_module_exit(void)
 {
-	scsi_unregister_module(MODULE_SCSI_HA, &ips_driver_template);
+	IPS_UNREGISTER_HOSTS(&ips_driver_template);
 	pci_unregister_driver(&ips_pci_driver);
 	unregister_reboot_notifier(&ips_notifier);
 }
@@ -7106,7 +7212,6 @@ ips_insert_device(struct pci_dev *pci_de
 	int rc;
 
 	METHOD_TRACE("ips_insert_device", 1);
-
 	if (pci_enable_device(pci_dev))
 		return -1;
 
@@ -7114,6 +7219,12 @@ ips_insert_device(struct pci_dev *pci_de
 	if (rc == SUCCESS)
 		rc = ips_init_phase2(index);
 
+	if (ips_hotplug)
+		if (ips_register_scsi(index)) {
+			ips_free(ips_ha[index]);
+			rc = -1;
+		}
+
 	if (rc == SUCCESS)
 		ips_num_controllers++;
 
@@ -7192,9 +7303,9 @@ ips_init_phase1(struct pci_dev *pci_dev,
 		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);
+			IPS_PRINTK(KERN_WARNING, pci_dev,
+				   "Couldn't allocate IO Memory space %x len %d.\n",
+				   mem_addr, mem_len);
 			return -1;
 		}
 
@@ -7210,16 +7321,16 @@ ips_init_phase1(struct pci_dev *pci_dev,
 	/* 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);
+			IPS_PRINTK(KERN_WARNING, pci_dev,
+				   "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");
+		IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n");
 		return -1;
 	}
 
@@ -7228,7 +7339,8 @@ ips_init_phase1(struct pci_dev *pci_dev,
 	/* found a controller */
 	ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);
 	if (ha == NULL) {
-		printk(KERN_WARNING "Unable to allocate temporary ha struct\n");
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate temporary ha struct\n");
 		return -1;
 	}
 
@@ -7272,54 +7384,57 @@ ips_init_phase1(struct pci_dev *pci_dev,
 		ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7,
 						     &ips_flashbusaddr);
 	}
-	
+
 	ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ),
 				       &ha->enq_busaddr);
 	if (!ha->enq) {
-		printk(KERN_WARNING
-		       "Unable to allocate host inquiry structure\n");
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "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");
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "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->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO),
-                                                  &dma_address);
+
+
+
+	ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address);
 	if (!ha->logical_drive_info) {
-		printk(KERN_WARNING
-		       "Unable to allocate host logical drive info structure\n");
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate logical drive info structure\n");
 		return ips_abort_init(ha, index);
 	}
 	ha->logical_drive_info_dma_addr = dma_address;
-    
+
+
 	ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL);
 
 	if (!ha->conf) {
-		printk(KERN_WARNING "Unable to allocate host conf structure\n");
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate host conf structure\n");
 		return ips_abort_init(ha, index);
 	}
 
 	ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL);
 
 	if (!ha->nvram) {
-		printk(KERN_WARNING
-		       "Unable to allocate host NVRAM structure\n");
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate host NVRAM structure\n");
 		return ips_abort_init(ha, index);
 	}
 
 	ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL);
 
 	if (!ha->subsys) {
-		printk(KERN_WARNING
-		       "Unable to allocate host subsystem structure\n");
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate host subsystem structure\n");
 		return ips_abort_init(ha, index);
 	}
 
@@ -7327,13 +7442,13 @@ ips_init_phase1(struct pci_dev *pci_dev,
 	 * successful allocation is now required */
 	if (ips_ioctlsize < PAGE_SIZE)
 		ips_ioctlsize = PAGE_SIZE;
-	
+
 	ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize,
 					      &ha->ioctl_busaddr);
 	ha->ioctl_len = ips_ioctlsize;
-
 	if (!ha->ioctl_data) {
-		printk(KERN_WARNING "Unable to allocate IOCTL data\n");
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate IOCTL data\n");
 		return ips_abort_init(ha, index);
 	}
 
@@ -7359,8 +7474,8 @@ ips_init_phase1(struct pci_dev *pci_dev,
 			/*
 			 * Initialization failed
 			 */
-			printk(KERN_WARNING
-			       "Unable to initialize controller\n");
+			IPS_PRINTK(KERN_WARNING, pci_dev,
+				   "Unable to initialize controller\n");
 			return ips_abort_init(ha, index);
 		}
 	}
@@ -7393,7 +7508,8 @@ ips_init_phase2(int index)
 
 	/* 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");
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Unable to install interrupt handler\n");
 		return ips_abort_init(ha, index);
 	}
 
@@ -7402,13 +7518,15 @@ ips_init_phase2(int index)
 	 */
 	ha->max_cmds = 1;
 	if (!ips_allocatescbs(ha)) {
-		printk(KERN_WARNING "Unable to allocate a CCB\n");
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "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");
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Unable to initialize controller\n");
 		free_irq(ha->irq, ha);
 		return ips_abort_init(ha, index);
 	}
@@ -7417,7 +7535,8 @@ ips_init_phase2(int index)
 
 	/* allocate CCBs */
 	if (!ips_allocatescbs(ha)) {
-		printk(KERN_WARNING "Unable to allocate CCBs\n");
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Unable to allocate CCBs\n");
 		free_irq(ha->irq, ha);
 		return ips_abort_init(ha, index);
 	}
@@ -7425,7 +7544,7 @@ ips_init_phase2(int index)
 	return SUCCESS;
 }
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,9)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
 MODULE_LICENSE("GPL");
 #endif
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/ips.h linux-2.4.27-pre3/drivers/scsi/ips.h
--- linux-2.4.26/drivers/scsi/ips.h	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/ips.h	2004-05-18 16:51:59.000000000 +0000
@@ -59,21 +59,13 @@
    extern int ips_eh_abort(Scsi_Cmnd *);
    extern int ips_eh_reset(Scsi_Cmnd *);
    extern int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
-   extern int ips_biosparam(Disk *, kdev_t, int *);
    extern const char * ips_info(struct Scsi_Host *);
 
    /*
     * Some handy macros
     */
-   #ifndef LinuxVersionCode
-      #define LinuxVersionCode(x,y,z)  (((x)<<16)+((y)<<8)+(z))
-   #endif
-
-   #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,20) || defined CONFIG_HIGHIO
+   #if LINUX_VERSION_CODE >= KERNEL_VERSION(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)
@@ -98,11 +90,36 @@
     #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)
+   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
       #define pci_set_dma_mask(dev,mask) ( mask > 0xffffffff ? 1:0 )
       #define scsi_set_pci_device(sh,dev) (0)
    #endif
 
+   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+      typedef void irqreturn_t;
+      #define IRQ_NONE
+      #define IRQ_HANDLED
+      #define IRQ_RETVAL(x)
+      #define IPS_REGISTER_HOSTS(SHT)      scsi_register_module(MODULE_SCSI_HA,SHT)
+      #define IPS_UNREGISTER_HOSTS(SHT)    scsi_unregister_module(MODULE_SCSI_HA,SHT)
+      #define IPS_ADD_HOST(shost,device)
+      #define IPS_REMOVE_HOST(shost)
+      #define IPS_SCSI_SET_DEVICE(sh,ha)   scsi_set_pci_device(sh, (ha)->pcidev)
+      #define IPS_PRINTK(level, pcidev, format, arg...)                 \
+            printk(level "%s %s:" format , "ips" ,     \
+            (pcidev)->slot_name , ## arg)
+      #define scsi_host_alloc(sh,size)         scsi_register(sh,size)
+      #define scsi_host_put(sh)             scsi_unregister(sh)
+   #else
+      #define IPS_REGISTER_HOSTS(SHT)      (!ips_detect(SHT))
+      #define IPS_UNREGISTER_HOSTS(SHT)
+      #define IPS_ADD_HOST(shost,device)   do { scsi_add_host(shost,device); scsi_scan_host(shost); } while (0)
+      #define IPS_REMOVE_HOST(shost)       scsi_remove_host(shost)
+      #define IPS_SCSI_SET_DEVICE(sh,ha)   scsi_set_device(sh, &(ha)->pcidev->dev)
+      #define IPS_PRINTK(level, pcidev, format, arg...)                 \
+            dev_printk(level , &((pcidev)->dev) , format , ## arg)
+   #endif
+
    #ifndef MDELAY
       #define MDELAY mdelay
    #endif
@@ -229,6 +246,8 @@
    #define IPS_SUBDEVICEID_5I1          0x0258
    #define IPS_SUBDEVICEID_6M           0x0279
    #define IPS_SUBDEVICEID_6I           0x028C
+   #define IPS_SUBDEVICEID_7k           0x028E
+   #define IPS_SUBDEVICEID_7M           0x028F
    #define IPS_IOCTL_SIZE               8192
    #define IPS_STATUS_SIZE              4
    #define IPS_STATUS_Q_SIZE            (IPS_MAX_CMDS+1) * IPS_STATUS_SIZE
@@ -313,6 +332,9 @@
    #define IPS_ADTYPE_SERVERAID5I1      0x0D
    #define IPS_ADTYPE_SERVERAID6M       0x0E
    #define IPS_ADTYPE_SERVERAID6I       0x0F
+   #define IPS_ADTYPE_SERVERAID7t       0x10
+   #define IPS_ADTYPE_SERVERAID7k       0x11
+   #define IPS_ADTYPE_SERVERAID7M       0x12
 
    /*
     * Adapter Command/Status Packet Definitions
@@ -426,46 +448,15 @@
    /*
     * Scsi_Host Template
     */
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+   static int ips_proc24_info(char *, char **, off_t, int, int, int);
    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 \
-}
+   static int ips_biosparam(Disk *disk, kdev_t dev, int geom[]);
 #else
-#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 \
-}
+   int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+   static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int geom[]);
+   int ips_slave_configure(Scsi_Device *SDptr);
 #endif
 
 /*
@@ -941,6 +932,20 @@ typedef struct {
 } IPS_SCSI_MODE_PAGE4;
 
 /*
+ * Sense Data Format - Page 8
+ */
+typedef struct {
+   uint8_t  PageCode;
+   uint8_t  PageLength;
+   uint8_t  flags;
+   uint8_t  RetentPrio;
+   uint16_t DisPrefetchLen;
+   uint16_t MinPrefetchLen;
+   uint16_t MaxPrefetchLen;
+   uint16_t MaxPrefetchCeiling;
+} IPS_SCSI_MODE_PAGE8;
+
+/*
  * Sense Data Format - Block Descriptor (DASD)
  */
 typedef struct {
@@ -967,6 +972,7 @@ typedef struct {
    union {
       IPS_SCSI_MODE_PAGE3 pg3;
       IPS_SCSI_MODE_PAGE4 pg4;
+      IPS_SCSI_MODE_PAGE8 pg8;
    } pdata;
 } IPS_SCSI_MODE_PAGE_DATA;
 
@@ -1056,7 +1062,7 @@ typedef struct {
    int       (*programbios)(struct ips_ha *, char *, uint32_t, uint32_t);
    int       (*verifybios)(struct ips_ha *, char *, uint32_t, uint32_t);
    void      (*statinit)(struct ips_ha *);
-   void      (*intr)(struct ips_ha *);
+   int       (*intr)(struct ips_ha *);
    void      (*enableint)(struct ips_ha *);
    uint32_t (*statupd)(struct ips_ha *);
 } ips_hw_func_t;
@@ -1082,7 +1088,7 @@ typedef struct ips_ha {
    ips_scb_queue_t    scb_activelist;     /* Active SCB list            */
    IPS_IO_CMD        *dummy;              /* dummy command              */
    IPS_ADAPTER       *adapt;              /* Adapter status area        */
-   IPS_LD_INFO       *logical_drive_info; /* Logical Drive Info         */
+   IPS_LD_INFO       *logical_drive_info; /* Adapter Logical Drive Info */
    dma_addr_t         logical_drive_info_dma_addr; /* Logical Drive Info DMA Address */
    IPS_ENQ           *enq;                /* Adapter Enquiry data       */
    IPS_CONF          *conf;               /* Adapter config data        */
@@ -1131,8 +1137,8 @@ typedef struct ips_scb {
    uint8_t           bus;
    uint8_t           lun;
    uint8_t           cdb[12];
-   uint32_t          scb_busaddr;      
-   uint32_t          old_data_busaddr;         // Obsolete field left in to not break utilities
+   uint32_t          scb_busaddr;
+   uint32_t          old_data_busaddr;  // Obsolete, but kept for old utility compatibility
    uint32_t          timeout;
    uint8_t           basic_status;
    uint8_t           extended_status;
@@ -1202,29 +1208,30 @@ typedef struct {
 *
 *************************************************************************/
 
-#define IPS_VER_MAJOR 6
-#define IPS_VER_MAJOR_STRING "6"
-#define IPS_VER_MINOR 11
-#define IPS_VER_MINOR_STRING "11"
-#define IPS_VER_BUILD 07
-#define IPS_VER_BUILD_STRING "07"
-#define IPS_VER_STRING "6.11.07"
-#define IPS_RELEASE_ID 0x00010001
-#define IPS_BUILD_IDENT 2224
-#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."
+#define IPS_VER_MAJOR 7
+#define IPS_VER_MAJOR_STRING "7"
+#define IPS_VER_MINOR 00
+#define IPS_VER_MINOR_STRING "00"
+#define IPS_VER_BUILD 15
+#define IPS_VER_BUILD_STRING "15"
+#define IPS_VER_STRING "7.00.15"
+#define IPS_RELEASE_ID 0x00020000
+#define IPS_BUILD_IDENT 625
+#define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved."
+#define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to 2004. All Rights Reserved."
+#define IPS_DELLCOPYRIGHT_STRING "(c) Copyright Dell 2004. All Rights Reserved."
+#define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002."
 
 /* Version numbers for various adapters */
 #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.10.24"
-#define IPS_VER_SERVERAID4H "6.11.07"
-#define IPS_VER_SERVERAID4MLx "6.11.07"
-#define IPS_VER_SARASOTA "6.11.07"
-#define IPS_VER_MARCO "6.11.07"
-#define IPS_VER_SEBRING "6.11.07"
+#define IPS_VER_SERVERAID4H "7.00.15"
+#define IPS_VER_SERVERAID4MLx "7.00.15"
+#define IPS_VER_SARASOTA "7.00.15"
+#define IPS_VER_MARCO "7.00.15"
+#define IPS_VER_SEBRING "7.00.15"
 
 /* Compatability IDs for various adapters */
 #define IPS_COMPAT_UNKNOWN ""
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/libata-core.c linux-2.4.27-pre3/drivers/scsi/libata-core.c
--- linux-2.4.26/drivers/scsi/libata-core.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/libata-core.c	2004-05-18 16:53:39.000000000 +0000
@@ -0,0 +1,3503 @@
+/*
+   libata-core.c - helper library for ATA
+
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/highmem.h>
+#include <linux/spinlock.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/tqueue.h>
+#include <scsi/scsi.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+
+#include "libata.h"
+
+static unsigned int ata_busy_sleep (struct ata_port *ap,
+				    unsigned long tmout_pat,
+			    	    unsigned long tmout);
+static void __ata_dev_select (struct ata_port *ap, unsigned int device);
+static void ata_dma_complete(struct ata_port *ap, u8 host_stat,
+			     unsigned int done_late);
+static void ata_host_set_pio(struct ata_port *ap);
+static void ata_host_set_udma(struct ata_port *ap);
+static void ata_dev_set_pio(struct ata_port *ap, unsigned int device);
+static void ata_dev_set_udma(struct ata_port *ap, unsigned int device);
+static void ata_set_mode(struct ata_port *ap);
+static int ata_qc_issue_prot(struct ata_queued_cmd *qc);
+
+static unsigned int ata_unique_id = 1;
+static LIST_HEAD(ata_probe_list);
+static spinlock_t ata_module_lock = SPIN_LOCK_UNLOCKED;
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Library module for ATA devices");
+MODULE_LICENSE("GPL");
+
+static const char * thr_state_name[] = {
+	"THR_UNKNOWN",
+	"THR_PORT_RESET",
+	"THR_AWAIT_DEATH",
+	"THR_PROBE_FAILED",
+	"THR_IDLE",
+	"THR_PROBE_SUCCESS",
+	"THR_PROBE_START",
+};
+
+/**
+ *	ata_thr_state_name - convert thread state enum to string
+ *	@thr_state: thread state to be converted to string
+ *
+ *	Converts the specified thread state id to a constant C string.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	The THR_xxx-prefixed string naming the specified thread
+ *	state id, or the string "<invalid THR_xxx state>".
+ */
+
+static const char *ata_thr_state_name(unsigned int thr_state)
+{
+	if (thr_state < ARRAY_SIZE(thr_state_name))
+		return thr_state_name[thr_state];
+	return "<invalid THR_xxx state>";
+}
+
+/**
+ *	msleep - sleep for a number of milliseconds
+ *	@msecs: number of milliseconds to sleep
+ *
+ *	Issues schedule_timeout call for the specified number
+ *	of milliseconds.
+ *
+ *	LOCKING:
+ *	None.
+ */
+
+static void msleep(unsigned long msecs)
+{
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(msecs_to_jiffies(msecs) + 1);
+}
+
+/**
+ *	ata_tf_load_pio - send taskfile registers to host controller
+ *	@ioaddr: set of IO ports to which output is sent
+ *	@tf: ATA taskfile register set
+ *
+ *	Outputs ATA taskfile to standard ATA host controller using PIO.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		outb(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		outb(tf->hob_feature, ioaddr->feature_addr);
+		outb(tf->hob_nsect, ioaddr->nsect_addr);
+		outb(tf->hob_lbal, ioaddr->lbal_addr);
+		outb(tf->hob_lbam, ioaddr->lbam_addr);
+		outb(tf->hob_lbah, ioaddr->lbah_addr);
+		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+			tf->hob_feature,
+			tf->hob_nsect,
+			tf->hob_lbal,
+			tf->hob_lbam,
+			tf->hob_lbah);
+	}
+
+	if (is_addr) {
+		outb(tf->feature, ioaddr->feature_addr);
+		outb(tf->nsect, ioaddr->nsect_addr);
+		outb(tf->lbal, ioaddr->lbal_addr);
+		outb(tf->lbam, ioaddr->lbam_addr);
+		outb(tf->lbah, ioaddr->lbah_addr);
+		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+			tf->feature,
+			tf->nsect,
+			tf->lbal,
+			tf->lbam,
+			tf->lbah);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		outb(tf->device, ioaddr->device_addr);
+		VPRINTK("device 0x%X\n", tf->device);
+	}
+
+	ata_wait_idle(ap);
+}
+
+/**
+ *	ata_tf_load_mmio - send taskfile registers to host controller
+ *	@ioaddr: set of IO ports to which output is sent
+ *	@tf: ATA taskfile register set
+ *
+ *	Outputs ATA taskfile to standard ATA host controller using MMIO.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		writeb(tf->ctl, ap->ioaddr.ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		writeb(tf->hob_feature, (void *) ioaddr->feature_addr);
+		writeb(tf->hob_nsect, (void *) ioaddr->nsect_addr);
+		writeb(tf->hob_lbal, (void *) ioaddr->lbal_addr);
+		writeb(tf->hob_lbam, (void *) ioaddr->lbam_addr);
+		writeb(tf->hob_lbah, (void *) ioaddr->lbah_addr);
+		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+			tf->hob_feature,
+			tf->hob_nsect,
+			tf->hob_lbal,
+			tf->hob_lbam,
+			tf->hob_lbah);
+	}
+
+	if (is_addr) {
+		writeb(tf->feature, (void *) ioaddr->feature_addr);
+		writeb(tf->nsect, (void *) ioaddr->nsect_addr);
+		writeb(tf->lbal, (void *) ioaddr->lbal_addr);
+		writeb(tf->lbam, (void *) ioaddr->lbam_addr);
+		writeb(tf->lbah, (void *) ioaddr->lbah_addr);
+		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+			tf->feature,
+			tf->nsect,
+			tf->lbal,
+			tf->lbam,
+			tf->lbah);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		writeb(tf->device, (void *) ioaddr->device_addr);
+		VPRINTK("device 0x%X\n", tf->device);
+	}
+
+	ata_wait_idle(ap);
+}
+
+/**
+ *	ata_exec_command_pio - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues PIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+       	outb(tf->command, ap->ioaddr.command_addr);
+	ata_pause(ap);
+}
+
+
+/**
+ *	ata_exec_command_mmio - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues MMIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+       	writeb(tf->command, (void *) ap->ioaddr.command_addr);
+	ata_pause(ap);
+}
+
+/**
+ *	ata_exec - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues PIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	Obtains host_set lock.
+ */
+
+static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	unsigned long flags;
+
+	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	ap->ops->exec_command(ap, tf);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+}
+
+/**
+ *	ata_tf_to_host - issue ATA taskfile to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues ATA taskfile register set to ATA host controller,
+ *	via PIO, with proper synchronization with interrupt handler and
+ *	other threads.
+ *
+ *	LOCKING:
+ *	Obtains host_set lock.
+ */
+
+static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	ap->ops->tf_load(ap, tf);
+
+	ata_exec(ap, tf);
+}
+
+/**
+ *	ata_tf_to_host_nolock - issue ATA taskfile to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues ATA taskfile register set to ATA host controller,
+ *	via PIO, with proper synchronization with interrupt handler and
+ *	other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	ap->ops->tf_load(ap, tf);
+	ap->ops->exec_command(ap, tf);
+}
+
+/**
+ *	ata_tf_read_pio - input device's ATA taskfile shadow registers
+ *	@ioaddr: set of IO ports from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Reads ATA taskfile registers for currently-selected device
+ *	into @tf via PIO.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	tf->nsect = inb(ioaddr->nsect_addr);
+	tf->lbal = inb(ioaddr->lbal_addr);
+	tf->lbam = inb(ioaddr->lbam_addr);
+	tf->lbah = inb(ioaddr->lbah_addr);
+	tf->device = inb(ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+		tf->hob_feature = inb(ioaddr->error_addr);
+		tf->hob_nsect = inb(ioaddr->nsect_addr);
+		tf->hob_lbal = inb(ioaddr->lbal_addr);
+		tf->hob_lbam = inb(ioaddr->lbam_addr);
+		tf->hob_lbah = inb(ioaddr->lbah_addr);
+	}
+}
+
+/**
+ *	ata_tf_read_mmio - input device's ATA taskfile shadow registers
+ *	@ioaddr: set of IO ports from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Reads ATA taskfile registers for currently-selected device
+ *	into @tf via MMIO.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	tf->nsect = readb((void *)ioaddr->nsect_addr);
+	tf->lbal = readb((void *)ioaddr->lbal_addr);
+	tf->lbam = readb((void *)ioaddr->lbam_addr);
+	tf->lbah = readb((void *)ioaddr->lbah_addr);
+	tf->device = readb((void *)ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		writeb(tf->ctl | ATA_HOB, ap->ioaddr.ctl_addr);
+		tf->hob_feature = readb((void *)ioaddr->error_addr);
+		tf->hob_nsect = readb((void *)ioaddr->nsect_addr);
+		tf->hob_lbal = readb((void *)ioaddr->lbal_addr);
+		tf->hob_lbam = readb((void *)ioaddr->lbam_addr);
+		tf->hob_lbah = readb((void *)ioaddr->lbah_addr);
+	}
+}
+
+/**
+ *	ata_check_status_pio - Read device status reg & clear interrupt
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile status register for currently-selected device
+ *	via PIO and return it's value. This also clears pending interrupts
+ *      from this device
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+u8 ata_check_status_pio(struct ata_port *ap)
+{
+	return inb(ap->ioaddr.status_addr);
+}
+
+/**
+ *	ata_check_status_mmio - Read device status reg & clear interrupt
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile status register for currently-selected device
+ *	via MMIO and return it's value. This also clears pending interrupts
+ *      from this device
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+u8 ata_check_status_mmio(struct ata_port *ap)
+{
+       	return readb((void *) ap->ioaddr.status_addr);
+}
+
+/**
+ *	ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
+ *	@tf: Taskfile to convert
+ *	@fis: Buffer into which data will output
+ *
+ *	Converts a standard ATA taskfile to a Serial ATA
+ *	FIS structure (Register - Host to Device).
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp)
+{
+	fis[0] = 0x27;	/* Register - Host to Device FIS */
+	fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
+					    bit 7 indicates Command FIS */
+	fis[2] = tf->command;
+	fis[3] = tf->feature;
+
+	fis[4] = tf->lbal;
+	fis[5] = tf->lbam;
+	fis[6] = tf->lbah;
+	fis[7] = tf->device;
+
+	fis[8] = tf->hob_lbal;
+	fis[9] = tf->hob_lbam;
+	fis[10] = tf->hob_lbah;
+	fis[11] = tf->hob_feature;
+
+	fis[12] = tf->nsect;
+	fis[13] = tf->hob_nsect;
+	fis[14] = 0;
+	fis[15] = tf->ctl;
+
+	fis[16] = 0;
+	fis[17] = 0;
+	fis[18] = 0;
+	fis[19] = 0;
+}
+
+/**
+ *	ata_tf_from_fis - Convert SATA FIS to ATA taskfile
+ *	@fis: Buffer from which data will be input
+ *	@tf: Taskfile to output
+ *
+ *	Converts a standard ATA taskfile to a Serial ATA
+ *	FIS structure (Register - Host to Device).
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf)
+{
+	tf->command	= fis[2];	/* status */
+	tf->feature	= fis[3];	/* error */
+
+	tf->lbal	= fis[4];
+	tf->lbam	= fis[5];
+	tf->lbah	= fis[6];
+	tf->device	= fis[7];
+
+	tf->hob_lbal	= fis[8];
+	tf->hob_lbam	= fis[9];
+	tf->hob_lbah	= fis[10];
+
+	tf->nsect	= fis[12];
+	tf->hob_nsect	= fis[13];
+}
+
+/**
+ *	ata_prot_to_cmd - determine which read/write opcodes to use
+ *	@protocol: ATA_PROT_xxx taskfile protocol
+ *	@lba48: true is lba48 is present
+ *
+ *	Given necessary input, determine which read/write commands
+ *	to use to transfer data.
+ *
+ *	LOCKING:
+ *	None.
+ */
+static int ata_prot_to_cmd(int protocol, int lba48)
+{
+	int rcmd = 0, wcmd = 0;
+
+	switch (protocol) {
+	case ATA_PROT_PIO:
+		if (lba48) {
+			rcmd = ATA_CMD_PIO_READ_EXT;
+			wcmd = ATA_CMD_PIO_WRITE_EXT;
+		} else {
+			rcmd = ATA_CMD_PIO_READ;
+			wcmd = ATA_CMD_PIO_WRITE;
+		}
+		break;
+
+	case ATA_PROT_DMA:
+		if (lba48) {
+			rcmd = ATA_CMD_READ_EXT;
+			wcmd = ATA_CMD_WRITE_EXT;
+		} else {
+			rcmd = ATA_CMD_READ;
+			wcmd = ATA_CMD_WRITE;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	return rcmd | (wcmd << 8);
+}
+
+/**
+ *	ata_dev_set_protocol - set taskfile protocol and r/w commands
+ *	@dev: device to examine and configure
+ *
+ *	Examine the device configuration, after we have
+ *	read the identify-device page and configured the
+ *	data transfer mode.  Set internal state related to
+ *	the ATA taskfile protocol (pio, pio mult, dma, etc.)
+ *	and calculate the proper read/write commands to use.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+static void ata_dev_set_protocol(struct ata_device *dev)
+{
+	int pio = (dev->flags & ATA_DFLAG_PIO);
+	int lba48 = (dev->flags & ATA_DFLAG_LBA48);
+	int proto, cmd;
+
+	if (pio)
+		proto = dev->xfer_protocol = ATA_PROT_PIO;
+	else
+		proto = dev->xfer_protocol = ATA_PROT_DMA;
+
+	cmd = ata_prot_to_cmd(proto, lba48);
+	if (cmd < 0)
+		BUG();
+
+	dev->read_cmd = cmd & 0xff;
+	dev->write_cmd = (cmd >> 8) & 0xff;
+}
+
+static const char * udma_str[] = {
+	"UDMA/16",
+	"UDMA/25",
+	"UDMA/33",
+	"UDMA/44",
+	"UDMA/66",
+	"UDMA/100",
+	"UDMA/133",
+	"UDMA7",
+};
+
+/**
+ *	ata_udma_string - convert UDMA bit offset to string
+ *	@udma_mask: mask of bits supported; only highest bit counts.
+ *
+ *	Determine string which represents the highest speed
+ *	(highest bit in @udma_mask).
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Constant C string representing highest speed listed in
+ *	@udma_mask, or the constant C string "<n/a>".
+ */
+
+static const char *ata_udma_string(unsigned int udma_mask)
+{
+	int i;
+
+	for (i = 7; i >= 0; i--) {
+		if (udma_mask & (1 << i))
+			return udma_str[i];
+	}
+
+	return "<n/a>";
+}
+
+/**
+ *	ata_pio_devchk - PATA device presence detection
+ *	@ap: ATA channel to examine
+ *	@device: Device to examine (starting at zero)
+ *
+ *	This technique was originally described in
+ *	Hale Landis's ATADRVR (www.ata-atapi.com), and
+ *	later found its way into the ATA/ATAPI spec.
+ *
+ *	Write a pattern to the ATA shadow registers,
+ *	and if a device is present, it will respond by
+ *	correctly storing and echoing back the
+ *	ATA shadow register contents.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static unsigned int ata_pio_devchk(struct ata_port *ap,
+				   unsigned int device)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u8 nsect, lbal;
+
+	__ata_dev_select(ap, device);
+
+	outb(0x55, ioaddr->nsect_addr);
+	outb(0xaa, ioaddr->lbal_addr);
+
+	outb(0xaa, ioaddr->nsect_addr);
+	outb(0x55, ioaddr->lbal_addr);
+
+	outb(0x55, ioaddr->nsect_addr);
+	outb(0xaa, ioaddr->lbal_addr);
+
+	nsect = inb(ioaddr->nsect_addr);
+	lbal = inb(ioaddr->lbal_addr);
+
+	if ((nsect == 0x55) && (lbal == 0xaa))
+		return 1;	/* we found a device */
+
+	return 0;		/* nothing found */
+}
+
+/**
+ *	ata_mmio_devchk - PATA device presence detection
+ *	@ap: ATA channel to examine
+ *	@device: Device to examine (starting at zero)
+ *
+ *	This technique was originally described in
+ *	Hale Landis's ATADRVR (www.ata-atapi.com), and
+ *	later found its way into the ATA/ATAPI spec.
+ *
+ *	Write a pattern to the ATA shadow registers,
+ *	and if a device is present, it will respond by
+ *	correctly storing and echoing back the
+ *	ATA shadow register contents.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static unsigned int ata_mmio_devchk(struct ata_port *ap,
+				    unsigned int device)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u8 nsect, lbal;
+
+	__ata_dev_select(ap, device);
+
+	writeb(0x55, (void *) ioaddr->nsect_addr);
+	writeb(0xaa, (void *) ioaddr->lbal_addr);
+
+	writeb(0xaa, (void *) ioaddr->nsect_addr);
+	writeb(0x55, (void *) ioaddr->lbal_addr);
+
+	writeb(0x55, (void *) ioaddr->nsect_addr);
+	writeb(0xaa, (void *) ioaddr->lbal_addr);
+
+	nsect = readb((void *) ioaddr->nsect_addr);
+	lbal = readb((void *) ioaddr->lbal_addr);
+
+	if ((nsect == 0x55) && (lbal == 0xaa))
+		return 1;	/* we found a device */
+
+	return 0;		/* nothing found */
+}
+
+/**
+ *	ata_dev_devchk - PATA device presence detection
+ *	@ap: ATA channel to examine
+ *	@device: Device to examine (starting at zero)
+ *
+ *	Dispatch ATA device presence detection, depending
+ *	on whether we are using PIO or MMIO to talk to the
+ *	ATA shadow registers.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static unsigned int ata_dev_devchk(struct ata_port *ap,
+				    unsigned int device)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		return ata_mmio_devchk(ap, device);
+	return ata_pio_devchk(ap, device);
+}
+
+/**
+ *	ata_dev_classify - determine device type based on ATA-spec signature
+ *	@tf: ATA taskfile register set for device to be identified
+ *
+ *	Determine from taskfile register contents whether a device is
+ *	ATA or ATAPI, as per "Signature and persistence" section
+ *	of ATA/PI spec (volume 1, sect 5.14).
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
+ *	the event of failure.
+ */
+
+static unsigned int ata_dev_classify(struct ata_taskfile *tf)
+{
+	/* Apple's open source Darwin code hints that some devices only
+	 * put a proper signature into the LBA mid/high registers,
+	 * So, we only check those.  It's sufficient for uniqueness.
+	 */
+
+	if (((tf->lbam == 0) && (tf->lbah == 0)) ||
+	    ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+		DPRINTK("found ATA device by sig\n");
+		return ATA_DEV_ATA;
+	}
+
+	if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
+	    ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+		DPRINTK("found ATAPI device by sig\n");
+		return ATA_DEV_ATAPI;
+	}
+
+	DPRINTK("unknown device\n");
+	return ATA_DEV_UNKNOWN;
+}
+
+/**
+ *	ata_dev_try_classify - Parse returned ATA device signature
+ *	@ap: ATA channel to examine
+ *	@device: Device to examine (starting at zero)
+ *
+ *	After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
+ *	an ATA/ATAPI-defined set of values is placed in the ATA
+ *	shadow registers, indicating the results of device detection
+ *	and diagnostics.
+ *
+ *	Select the ATA device, and read the values from the ATA shadow
+ *	registers.  Then parse according to the Error register value,
+ *	and the spec-defined values examined by ata_dev_classify().
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
+{
+	struct ata_device *dev = &ap->device[device];
+	struct ata_taskfile tf;
+	unsigned int class;
+	u8 err;
+
+	__ata_dev_select(ap, device);
+
+	memset(&tf, 0, sizeof(tf));
+
+	err = ata_chk_err(ap);
+	ap->ops->tf_read(ap, &tf);
+
+	dev->class = ATA_DEV_NONE;
+
+	/* see if device passed diags */
+	if (err == 1)
+		/* do nothing */ ;
+	else if ((device == 0) && (err == 0x81))
+		/* do nothing */ ;
+	else
+		return err;
+
+	/* determine if device if ATA or ATAPI */
+	class = ata_dev_classify(&tf);
+	if (class == ATA_DEV_UNKNOWN)
+		return err;
+	if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+		return err;
+
+	dev->class = class;
+
+	return err;
+}
+
+/**
+ *	ata_dev_id_string - Convert IDENTIFY DEVICE page into string
+ *	@dev: Device whose IDENTIFY DEVICE results we will examine
+ *	@s: string into which data is output
+ *	@ofs: offset into identify device page
+ *	@len: length of string to return
+ *
+ *	The strings in the IDENTIFY DEVICE page are broken up into
+ *	16-bit chunks.  Run through the string, and output each
+ *	8-bit chunk linearly, regardless of platform.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
+		       unsigned int ofs, unsigned int len)
+{
+	unsigned int c;
+
+	while (len > 0) {
+		c = dev->id[ofs] >> 8;
+		*s = c;
+		s++;
+
+		c = dev->id[ofs] & 0xff;
+		*s = c;
+		s++;
+
+		ofs++;
+		len -= 2;
+	}
+}
+
+/**
+ *	ata_dev_parse_strings - Store useful IDENTIFY DEVICE page strings
+ *	@dev: Device whose IDENTIFY DEVICE page info we use
+ *
+ *	We store 'vendor' and 'product' strings read from the device,
+ *	for later use in the SCSI simulator's INQUIRY data.
+ *
+ *	Set these strings here, in the case of 'product', using
+ *	data read from the ATA IDENTIFY DEVICE page.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static void ata_dev_parse_strings(struct ata_device *dev)
+{
+	assert (dev->class == ATA_DEV_ATA);
+	memcpy(dev->vendor, "ATA     ", 8);
+
+	ata_dev_id_string(dev, dev->product, ATA_ID_PROD_OFS,
+			  sizeof(dev->product));
+}
+
+/**
+ *	__ata_dev_select - Select device 0/1 on ATA bus
+ *	@ap: ATA channel to manipulate
+ *	@device: ATA device (numbered from zero) to select
+ *
+ *	Use the method defined in the ATA specification to
+ *	make either device 0, or device 1, active on the
+ *	ATA channel.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static void __ata_dev_select (struct ata_port *ap, unsigned int device)
+{
+	u8 tmp;
+
+	if (device == 0)
+		tmp = ATA_DEVICE_OBS;
+	else
+		tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+	if (ap->flags & ATA_FLAG_MMIO) {
+		writeb(tmp, (void *) ap->ioaddr.device_addr);
+	} else {
+		outb(tmp, ap->ioaddr.device_addr);
+	}
+	ata_pause(ap);		/* needed; also flushes, for mmio */
+}
+
+/**
+ *	ata_dev_select - Select device 0/1 on ATA bus
+ *	@ap: ATA channel to manipulate
+ *	@device: ATA device (numbered from zero) to select
+ *	@wait: non-zero to wait for Status register BSY bit to clear
+ *	@can_sleep: non-zero if context allows sleeping
+ *
+ *	Use the method defined in the ATA specification to
+ *	make either device 0, or device 1, active on the
+ *	ATA channel.
+ *
+ *	This is a high-level version of __ata_dev_select(),
+ *	which additionally provides the services of inserting
+ *	the proper pauses and status polling, where needed.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+void ata_dev_select(struct ata_port *ap, unsigned int device,
+			   unsigned int wait, unsigned int can_sleep)
+{
+	VPRINTK("ENTER, ata%u: device %u, wait %u\n",
+		ap->id, device, wait);
+
+	if (wait)
+		ata_wait_idle(ap);
+
+	__ata_dev_select(ap, device);
+
+	if (wait) {
+		if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+			msleep(150);
+		ata_wait_idle(ap);
+	}
+}
+
+/**
+ *	ata_dump_id - IDENTIFY DEVICE info debugging output
+ *	@dev: Device whose IDENTIFY DEVICE page we will dump
+ *
+ *	Dump selected 16-bit words from a detected device's
+ *	IDENTIFY PAGE page.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static inline void ata_dump_id(struct ata_device *dev)
+{
+	DPRINTK("49==0x%04x  "
+		"53==0x%04x  "
+		"63==0x%04x  "
+		"64==0x%04x  "
+		"75==0x%04x  \n",
+		dev->id[49],
+		dev->id[53],
+		dev->id[63],
+		dev->id[64],
+		dev->id[75]);
+	DPRINTK("80==0x%04x  "
+		"81==0x%04x  "
+		"82==0x%04x  "
+		"83==0x%04x  "
+		"84==0x%04x  \n",
+		dev->id[80],
+		dev->id[81],
+		dev->id[82],
+		dev->id[83],
+		dev->id[84]);
+	DPRINTK("88==0x%04x  "
+		"93==0x%04x\n",
+		dev->id[88],
+		dev->id[93]);
+}
+
+/**
+ *	ata_dev_identify - obtain IDENTIFY x DEVICE page
+ *	@ap: port on which device we wish to probe resides
+ *	@device: device bus address, starting at zero
+ *
+ *	Following bus reset, we issue the IDENTIFY [PACKET] DEVICE
+ *	command, and read back the 512-byte device information page.
+ *	The device information page is fed to us via the standard
+ *	PIO-IN protocol, but we hand-code it here. (TODO: investigate
+ *	using standard PIO-IN paths)
+ *
+ *	After reading the device information page, we use several
+ *	bits of information from it to initialize data structures
+ *	that will be used during the lifetime of the ata_device.
+ *	Other data from the info page is used to disqualify certain
+ *	older ATA devices we do not wish to support.
+ *
+ *	LOCKING:
+ *	Inherited from caller.  Some functions called by this function
+ *	obtain the host_set lock.
+ */
+
+static void ata_dev_identify(struct ata_port *ap, unsigned int device)
+{
+	struct ata_device *dev = &ap->device[device];
+	unsigned int i;
+	u16 tmp, udma_modes;
+	u8 status;
+	struct ata_taskfile tf;
+	unsigned int using_edd;
+
+	if (!ata_dev_present(dev)) {
+		DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
+			ap->id, device);
+		return;
+	}
+
+	if (ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET))
+		using_edd = 0;
+	else
+		using_edd = 1;
+
+	DPRINTK("ENTER, host %u, dev %u\n", ap->id, device);
+
+	assert (dev->class == ATA_DEV_ATA || dev->class == ATA_DEV_ATAPI ||
+		dev->class == ATA_DEV_NONE);
+
+	ata_dev_select(ap, device, 1, 1); /* select device 0/1 */
+
+retry:
+	ata_tf_init(ap, &tf, device);
+	tf.ctl |= ATA_NIEN;
+	tf.protocol = ATA_PROT_PIO;
+
+	if (dev->class == ATA_DEV_ATA) {
+		tf.command = ATA_CMD_ID_ATA;
+		DPRINTK("do ATA identify\n");
+	} else {
+		tf.command = ATA_CMD_ID_ATAPI;
+		DPRINTK("do ATAPI identify\n");
+	}
+
+	ata_tf_to_host(ap, &tf);
+
+	/* crazy ATAPI devices... */
+	if (dev->class == ATA_DEV_ATAPI)
+		msleep(150);
+
+	if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT))
+		goto err_out;
+
+	status = ata_chk_status(ap);
+	if (status & ATA_ERR) {
+		/*
+		 * arg!  EDD works for all test cases, but seems to return
+		 * the ATA signature for some ATAPI devices.  Until the
+		 * reason for this is found and fixed, we fix up the mess
+		 * here.  If IDENTIFY DEVICE returns command aborted
+		 * (as ATAPI devices do), then we issue an
+		 * IDENTIFY PACKET DEVICE.
+		 *
+		 * ATA software reset (SRST, the default) does not appear
+		 * to have this problem.
+		 */
+		if ((using_edd) && (tf.command == ATA_CMD_ID_ATA)) {
+			u8 err = ata_chk_err(ap);
+			if (err & ATA_ABORTED) {
+				dev->class = ATA_DEV_ATAPI;
+				goto retry;
+			}
+		}
+		goto err_out;
+	}
+
+	/* make sure we have BSY=0, DRQ=1 */
+	if ((status & ATA_DRQ) == 0) {
+		printk(KERN_WARNING "ata%u: dev %u (ATA%s?) not returning id page (0x%x)\n",
+		       ap->id, device,
+		       dev->class == ATA_DEV_ATA ? "" : "PI",
+		       status);
+		goto err_out;
+	}
+
+	/* read IDENTIFY [X] DEVICE page */
+	if (ap->flags & ATA_FLAG_MMIO) {
+		for (i = 0; i < ATA_ID_WORDS; i++)
+			dev->id[i] = readw((void *)ap->ioaddr.data_addr);
+	} else
+		for (i = 0; i < ATA_ID_WORDS; i++)
+			dev->id[i] = inw(ap->ioaddr.data_addr);
+
+	/* wait for host_idle */
+	status = ata_wait_idle(ap);
+	if (status & (ATA_BUSY | ATA_DRQ)) {
+		printk(KERN_WARNING "ata%u: dev %u (ATA%s?) error after id page (0x%x)\n",
+		       ap->id, device,
+		       dev->class == ATA_DEV_ATA ? "" : "PI",
+		       status);
+		goto err_out;
+	}
+
+	ata_irq_on(ap);	/* re-enable interrupts */
+
+	/* print device capabilities */
+	printk(KERN_DEBUG "ata%u: dev %u cfg "
+	       "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+	       ap->id, device, dev->id[49],
+	       dev->id[82], dev->id[83], dev->id[84],
+	       dev->id[85], dev->id[86], dev->id[87],
+	       dev->id[88]);
+
+	/*
+	 * common ATA, ATAPI feature tests
+	 */
+
+	/* we require LBA and DMA support (bits 8 & 9 of word 49) */
+	if (!ata_id_has_dma(dev) || !ata_id_has_lba(dev)) {
+		printk(KERN_DEBUG "ata%u: no dma/lba\n", ap->id);
+		goto err_out_nosup;
+	}
+
+	/* we require UDMA support */
+	udma_modes =
+	tmp = dev->id[ATA_ID_UDMA_MODES];
+	if ((tmp & 0xff) == 0) {
+		printk(KERN_DEBUG "ata%u: no udma\n", ap->id);
+		goto err_out_nosup;
+	}
+
+	ata_dump_id(dev);
+
+	ata_dev_parse_strings(dev);
+
+	/* ATA-specific feature tests */
+	if (dev->class == ATA_DEV_ATA) {
+		if (!ata_id_is_ata(dev))	/* sanity check */
+			goto err_out_nosup;
+
+		tmp = dev->id[ATA_ID_MAJOR_VER];
+		for (i = 14; i >= 1; i--)
+			if (tmp & (1 << i))
+				break;
+
+		/* we require at least ATA-3 */
+		if (i < 3) {
+			printk(KERN_DEBUG "ata%u: no ATA-3\n", ap->id);
+			goto err_out_nosup;
+		}
+
+		if (ata_id_has_lba48(dev)) {
+			dev->flags |= ATA_DFLAG_LBA48;
+			dev->n_sectors = ata_id_u64(dev, 100);
+		} else {
+			dev->n_sectors = ata_id_u32(dev, 60);
+		}
+
+		ap->host->max_cmd_len = 16;
+
+		/* print device info to dmesg */
+		printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors: %s\n",
+		       ap->id, device,
+		       ata_udma_string(udma_modes),
+		       (unsigned long long)dev->n_sectors,
+		       dev->flags & ATA_DFLAG_LBA48 ? " lba48" : "");
+	}
+
+	/* ATAPI-specific feature tests */
+	else {
+		if (ata_id_is_ata(dev))		/* sanity check */
+			goto err_out_nosup;
+
+		/* see if 16-byte commands supported */
+		tmp = dev->id[0] & 0x3;
+		if (tmp == 1)
+			ap->host->max_cmd_len = 16;
+
+		/* print device info to dmesg */
+		printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
+		       ap->id, device,
+		       ata_udma_string(udma_modes));
+	}
+
+	DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
+	return;
+
+err_out_nosup:
+	printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
+	       ap->id, device);
+err_out:
+	ata_irq_on(ap);	/* re-enable interrupts */
+	dev->class++;	/* converts ATA_DEV_xxx into ATA_DEV_xxx_UNSUP */
+	DPRINTK("EXIT, err\n");
+}
+
+/**
+ *	ata_port_reset -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+static void ata_port_reset(struct ata_port *ap)
+{
+	unsigned int i, found = 0;
+
+	ap->ops->phy_reset(ap);
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		goto err_out;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		ata_dev_identify(ap, i);
+		if (ata_dev_present(&ap->device[i])) {
+			found = 1;
+			if (ap->ops->dev_config)
+				ap->ops->dev_config(ap, &ap->device[i]);
+		}
+	}
+
+	if ((!found) || (ap->flags & ATA_FLAG_PORT_DISABLED))
+		goto err_out_disable;
+
+	ata_set_mode(ap);
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		goto err_out_disable;
+
+	ap->thr_state = THR_PROBE_SUCCESS;
+
+	return;
+
+err_out_disable:
+	ap->ops->port_disable(ap);
+err_out:
+	ap->thr_state = THR_PROBE_FAILED;
+}
+
+/**
+ *	ata_port_probe -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+void ata_port_probe(struct ata_port *ap)
+{
+	ap->flags &= ~ATA_FLAG_PORT_DISABLED;
+}
+
+/**
+ *	sata_phy_reset -
+ *	@ap:
+ *
+ *	LOCKING:
+ *
+ */
+void sata_phy_reset(struct ata_port *ap)
+{
+	u32 sstatus;
+	unsigned long timeout = jiffies + (HZ * 5);
+
+	if (ap->flags & ATA_FLAG_SATA_RESET) {
+		scr_write(ap, SCR_CONTROL, 0x301); /* issue phy wake/reset */
+		scr_read(ap, SCR_STATUS);	/* dummy read; flush */
+		udelay(400);			/* FIXME: a guess */
+	}
+	scr_write(ap, SCR_CONTROL, 0x300);	/* issue phy wake/clear reset */
+
+	/* wait for phy to become ready, if necessary */
+	do {
+		msleep(200);
+		sstatus = scr_read(ap, SCR_STATUS);
+		if ((sstatus & 0xf) != 1)
+			break;
+	} while (time_before(jiffies, timeout));
+
+	/* TODO: phy layer with polling, timeouts, etc. */
+	if (sata_dev_present(ap))
+		ata_port_probe(ap);
+	else {
+		sstatus = scr_read(ap, SCR_STATUS);
+		printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n",
+		       ap->id, sstatus);
+		ata_port_disable(ap);
+	}
+
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		return;
+
+	if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+		ata_port_disable(ap);
+		return;
+	}
+
+	ata_bus_reset(ap);
+}
+
+/**
+ *	ata_port_disable -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+void ata_port_disable(struct ata_port *ap)
+{
+	ap->device[0].class = ATA_DEV_NONE;
+	ap->device[1].class = ATA_DEV_NONE;
+	ap->flags |= ATA_FLAG_PORT_DISABLED;
+}
+
+/**
+ *	ata_set_mode - Program timings and issue SET FEATURES - XFER
+ *	@ap: port on which timings will be programmed
+ *
+ *	LOCKING:
+ *
+ */
+static void ata_set_mode(struct ata_port *ap)
+{
+	unsigned int force_pio, i;
+
+	ata_host_set_pio(ap);
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		return;
+
+	ata_host_set_udma(ap);
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		return;
+
+#ifdef ATA_FORCE_PIO
+	force_pio = 1;
+#else
+	force_pio = 0;
+#endif
+
+	if (force_pio) {
+		ata_dev_set_pio(ap, 0);
+		ata_dev_set_pio(ap, 1);
+	} else {
+		ata_dev_set_udma(ap, 0);
+		ata_dev_set_udma(ap, 1);
+	}
+
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		return;
+
+	if (ap->ops->post_set_mode)
+		ap->ops->post_set_mode(ap);
+
+	for (i = 0; i < 2; i++) {
+		struct ata_device *dev = &ap->device[i];
+		ata_dev_set_protocol(dev);
+	}
+}
+
+/**
+ *	ata_busy_sleep - sleep until BSY clears, or timeout
+ *	@ap: port containing status register to be polled
+ *	@tmout_pat: impatience timeout
+ *	@tmout: overall timeout
+ *
+ *	LOCKING:
+ *
+ */
+
+static unsigned int ata_busy_sleep (struct ata_port *ap,
+				    unsigned long tmout_pat,
+			    	    unsigned long tmout)
+{
+	unsigned long timer_start, timeout;
+	u8 status;
+
+	status = ata_busy_wait(ap, ATA_BUSY, 300);
+	timer_start = jiffies;
+	timeout = timer_start + tmout_pat;
+	while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+		msleep(50);
+		status = ata_busy_wait(ap, ATA_BUSY, 3);
+	}
+
+	if (status & ATA_BUSY)
+		printk(KERN_WARNING "ata%u is slow to respond, "
+		       "please be patient\n", ap->id);
+
+	timeout = timer_start + tmout;
+	while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+		msleep(50);
+		status = ata_chk_status(ap);
+	}
+
+	if (status & ATA_BUSY) {
+		printk(KERN_ERR "ata%u failed to respond (%lu secs)\n",
+		       ap->id, tmout / HZ);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int dev0 = devmask & (1 << 0);
+	unsigned int dev1 = devmask & (1 << 1);
+	unsigned long timeout;
+
+	/* if device 0 was found in ata_dev_devchk, wait for its
+	 * BSY bit to clear
+	 */
+	if (dev0)
+		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+	/* if device 1 was found in ata_dev_devchk, wait for
+	 * register access, then wait for BSY to clear
+	 */
+	timeout = jiffies + ATA_TMOUT_BOOT;
+	while (dev1) {
+		u8 nsect, lbal;
+
+		__ata_dev_select(ap, 1);
+		if (ap->flags & ATA_FLAG_MMIO) {
+			nsect = readb((void *) ioaddr->nsect_addr);
+			lbal = readb((void *) ioaddr->lbal_addr);
+		} else {
+			nsect = inb(ioaddr->nsect_addr);
+			lbal = inb(ioaddr->lbal_addr);
+		}
+		if ((nsect == 1) && (lbal == 1))
+			break;
+		if (time_after(jiffies, timeout)) {
+			dev1 = 0;
+			break;
+		}
+		msleep(50);	/* give drive a breather */
+	}
+	if (dev1)
+		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+	/* is all this really necessary? */
+	__ata_dev_select(ap, 0);
+	if (dev1)
+		__ata_dev_select(ap, 1);
+	if (dev0)
+		__ata_dev_select(ap, 0);
+}
+
+/**
+ *	ata_bus_edd -
+ *	@ap:
+ *
+ *	LOCKING:
+ *
+ */
+
+static unsigned int ata_bus_edd(struct ata_port *ap)
+{
+	struct ata_taskfile tf;
+
+	/* set up execute-device-diag (bus reset) taskfile */
+	/* also, take interrupts to a known state (disabled) */
+	DPRINTK("execute-device-diag\n");
+	ata_tf_init(ap, &tf, 0);
+	tf.ctl |= ATA_NIEN;
+	tf.command = ATA_CMD_EDD;
+	tf.protocol = ATA_PROT_NODATA;
+
+	/* do bus reset */
+	ata_tf_to_host(ap, &tf);
+
+	/* spec says at least 2ms.  but who knows with those
+	 * crazy ATAPI devices...
+	 */
+	msleep(150);
+
+	return ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+}
+
+static unsigned int ata_bus_softreset(struct ata_port *ap,
+				      unsigned int devmask)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	DPRINTK("ata%u: bus reset via SRST\n", ap->id);
+
+	/* software reset.  causes dev0 to be selected */
+	if (ap->flags & ATA_FLAG_MMIO) {
+		writeb(ap->ctl, ioaddr->ctl_addr);
+		udelay(20);	/* FIXME: flush */
+		writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+		udelay(20);	/* FIXME: flush */
+		writeb(ap->ctl, ioaddr->ctl_addr);
+	} else {
+		outb(ap->ctl, ioaddr->ctl_addr);
+		udelay(10);
+		outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+		udelay(10);
+		outb(ap->ctl, ioaddr->ctl_addr);
+	}
+
+	/* spec mandates ">= 2ms" before checking status.
+	 * We wait 150ms, because that was the magic delay used for
+	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+	 * between when the ATA command register is written, and then
+	 * status is checked.  Because waiting for "a while" before
+	 * checking status is fine, post SRST, we perform this magic
+	 * delay here as well.
+	 */
+	msleep(150);
+
+	ata_bus_post_reset(ap, devmask);
+
+	return 0;
+}
+
+/**
+ *	ata_bus_reset - reset host port and associated ATA channel
+ *	@ap: port to reset
+ *
+ *	This is typically the first time we actually start issuing
+ *	commands to the ATA channel.  We wait for BSY to clear, then
+ *	issue EXECUTE DEVICE DIAGNOSTIC command, polling for its
+ *	result.  Determine what devices, if any, are on the channel
+ *	by looking at the device 0/1 error register.  Look at the signature
+ *	stored in each device's taskfile registers, to determine if
+ *	the device is ATA or ATAPI.
+ *
+ *	LOCKING:
+ *	Inherited from caller.  Some functions called by this function
+ *	obtain the host_set lock.
+ *
+ *	SIDE EFFECTS:
+ *	Sets ATA_FLAG_PORT_DISABLED if bus reset fails.
+ */
+
+void ata_bus_reset(struct ata_port *ap)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+	u8 err;
+	unsigned int dev0, dev1 = 0, rc = 0, devmask = 0;
+
+	DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
+
+	/* determine if device 0/1 are present */
+	if (ap->flags & ATA_FLAG_SATA_RESET)
+		dev0 = 1;
+	else {
+		dev0 = ata_dev_devchk(ap, 0);
+		if (slave_possible)
+			dev1 = ata_dev_devchk(ap, 1);
+	}
+
+	if (dev0)
+		devmask |= (1 << 0);
+	if (dev1)
+		devmask |= (1 << 1);
+
+	/* select device 0 again */
+	__ata_dev_select(ap, 0);
+
+	/* issue bus reset */
+	if (ap->flags & ATA_FLAG_SRST)
+		rc = ata_bus_softreset(ap, devmask);
+	else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) {
+		/* set up device control */
+		if (ap->flags & ATA_FLAG_MMIO)
+			writeb(ap->ctl, ioaddr->ctl_addr);
+		else
+			outb(ap->ctl, ioaddr->ctl_addr);
+		rc = ata_bus_edd(ap);
+	}
+
+	if (rc)
+		goto err_out;
+
+	/*
+	 * determine by signature whether we have ATA or ATAPI devices
+	 */
+	err = ata_dev_try_classify(ap, 0);
+	if ((slave_possible) && (err != 0x81))
+		ata_dev_try_classify(ap, 1);
+
+	/* re-enable interrupts */
+	ata_irq_on(ap);
+
+	/* is double-select really necessary? */
+	if (ap->device[1].class != ATA_DEV_NONE)
+		__ata_dev_select(ap, 1);
+	if (ap->device[0].class != ATA_DEV_NONE)
+		__ata_dev_select(ap, 0);
+
+	/* if no devices were detected, disable this port */
+	if ((ap->device[0].class == ATA_DEV_NONE) &&
+	    (ap->device[1].class == ATA_DEV_NONE))
+		goto err_out;
+
+	if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
+		/* set up device control for ATA_FLAG_SATA_RESET */
+		if (ap->flags & ATA_FLAG_MMIO)
+			writeb(ap->ctl, ioaddr->ctl_addr);
+		else
+			outb(ap->ctl, ioaddr->ctl_addr);
+	}
+
+	DPRINTK("EXIT\n");
+	return;
+
+err_out:
+	printk(KERN_ERR "ata%u: disabling port\n", ap->id);
+	ap->ops->port_disable(ap);
+
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_host_set_pio -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+static void ata_host_set_pio(struct ata_port *ap)
+{
+	struct ata_device *master, *slave;
+	unsigned int pio, i;
+	u16 mask;
+
+	master = &ap->device[0];
+	slave = &ap->device[1];
+
+	assert (ata_dev_present(master) || ata_dev_present(slave));
+
+	mask = ap->pio_mask;
+	if (ata_dev_present(master))
+		mask &= (master->id[ATA_ID_PIO_MODES] & 0x03);
+	if (ata_dev_present(slave))
+		mask &= (slave->id[ATA_ID_PIO_MODES] & 0x03);
+
+	/* require pio mode 3 or 4 support for host and all devices */
+	if (mask == 0) {
+		printk(KERN_WARNING "ata%u: no PIO3/4 support, ignoring\n",
+		       ap->id);
+		goto err_out;
+	}
+
+	pio = (mask & ATA_ID_PIO4) ? 4 : 3;
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		if (ata_dev_present(&ap->device[i])) {
+			ap->device[i].pio_mode = (pio == 3) ?
+				XFER_PIO_3 : XFER_PIO_4;
+			if (ap->ops->set_piomode)
+				ap->ops->set_piomode(ap, &ap->device[i], pio);
+		}
+
+	return;
+
+err_out:
+	ap->ops->port_disable(ap);
+}
+
+/**
+ *	ata_host_set_udma -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+static void ata_host_set_udma(struct ata_port *ap)
+{
+	struct ata_device *master, *slave;
+	u16 mask;
+	unsigned int i, j;
+	int udma_mode = -1;
+
+	master = &ap->device[0];
+	slave = &ap->device[1];
+
+	assert (ata_dev_present(master) || ata_dev_present(slave));
+	assert ((ap->flags & ATA_FLAG_PORT_DISABLED) == 0);
+
+	DPRINTK("udma masks: host 0x%X, master 0x%X, slave 0x%X\n",
+		ap->udma_mask,
+		(!ata_dev_present(master)) ? 0xff :
+			(master->id[ATA_ID_UDMA_MODES] & 0xff),
+		(!ata_dev_present(slave)) ? 0xff :
+			(slave->id[ATA_ID_UDMA_MODES] & 0xff));
+
+	mask = ap->udma_mask;
+	if (ata_dev_present(master))
+		mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
+	if (ata_dev_present(slave))
+		mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
+
+	i = XFER_UDMA_7;
+	while (i >= XFER_UDMA_0) {
+		j = i - XFER_UDMA_0;
+		DPRINTK("mask 0x%X i 0x%X j %u\n", mask, i, j);
+		if (mask & (1 << j)) {
+			udma_mode = i;
+			break;
+		}
+
+		i--;
+	}
+
+	/* require udma for host and all attached devices */
+	if (udma_mode < 0) {
+		printk(KERN_WARNING "ata%u: no UltraDMA support, ignoring\n",
+		       ap->id);
+		goto err_out;
+	}
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		if (ata_dev_present(&ap->device[i])) {
+			ap->device[i].udma_mode = udma_mode;
+			if (ap->ops->set_udmamode)
+				ap->ops->set_udmamode(ap, &ap->device[i],
+						      udma_mode);
+		}
+
+	return;
+
+err_out:
+	ap->ops->port_disable(ap);
+}
+
+/**
+ *	ata_dev_set_xfermode -
+ *	@ap:
+ *	@dev:
+ *
+ *	LOCKING:
+ */
+
+static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
+{
+	struct ata_taskfile tf;
+
+	/* set up set-features taskfile */
+	DPRINTK("set features - xfer mode\n");
+	ata_tf_init(ap, &tf, dev->devno);
+	tf.ctl |= ATA_NIEN;
+	tf.command = ATA_CMD_SET_FEATURES;
+	tf.feature = SETFEATURES_XFER;
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf.protocol = ATA_PROT_NODATA;
+	if (dev->flags & ATA_DFLAG_PIO)
+		tf.nsect = dev->pio_mode;
+	else
+		tf.nsect = dev->udma_mode;
+
+	/* do bus reset */
+	ata_tf_to_host(ap, &tf);
+
+	/* crazy ATAPI devices... */
+	if (dev->class == ATA_DEV_ATAPI)
+		msleep(150);
+
+	ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+	ata_irq_on(ap);	/* re-enable interrupts */
+
+	ata_wait_idle(ap);
+
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_dev_set_udma -
+ *	@ap:
+ *	@device:
+ *
+ *	LOCKING:
+ */
+
+static void ata_dev_set_udma(struct ata_port *ap, unsigned int device)
+{
+	struct ata_device *dev = &ap->device[device];
+
+	if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
+		return;
+
+	ata_dev_set_xfermode(ap, dev);
+
+	assert((dev->udma_mode >= XFER_UDMA_0) &&
+	       (dev->udma_mode <= XFER_UDMA_7));
+	printk(KERN_INFO "ata%u: dev %u configured for %s\n",
+	       ap->id, device,
+	       udma_str[dev->udma_mode - XFER_UDMA_0]);
+}
+
+/**
+ *	ata_dev_set_pio -
+ *	@ap:
+ *	@device:
+ *
+ *	LOCKING:
+ */
+
+static void ata_dev_set_pio(struct ata_port *ap, unsigned int device)
+{
+	struct ata_device *dev = &ap->device[device];
+
+	if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
+		return;
+
+	/* force PIO mode */
+	dev->flags |= ATA_DFLAG_PIO;
+
+	ata_dev_set_xfermode(ap, dev);
+
+	assert((dev->pio_mode >= XFER_PIO_3) &&
+	       (dev->pio_mode <= XFER_PIO_4));
+	printk(KERN_INFO "ata%u: dev %u configured for PIO%c\n",
+	       ap->id, device,
+	       dev->pio_mode == 3 ? '3' : '4');
+}
+
+/**
+ *	ata_sg_clean -
+ *	@qc:
+ *
+ *	LOCKING:
+ */
+
+static void ata_sg_clean(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct scsi_cmnd *cmd = qc->scsicmd;
+	struct scatterlist *sg = qc->sg;
+	int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	assert(dir == SCSI_DATA_READ || dir == SCSI_DATA_WRITE);
+	assert(qc->flags & ATA_QCFLAG_SG);
+	assert(sg != NULL);
+
+	if (!cmd->use_sg)
+		assert(qc->n_elem == 1);
+
+	DPRINTK("unmapping %u sg elements\n", qc->n_elem);
+
+	if (cmd->use_sg)
+		pci_unmap_sg(ap->host_set->pdev, sg, qc->n_elem, dir);
+	else
+		pci_unmap_single(ap->host_set->pdev, sg_dma_address(&sg[0]),
+				 sg_dma_len(&sg[0]), dir);
+
+	qc->flags &= ~ATA_QCFLAG_SG;
+	qc->sg = NULL;
+}
+
+/**
+ *	ata_fill_sg -
+ *	@qc:
+ *
+ *	LOCKING:
+ *
+ */
+void ata_fill_sg(struct ata_queued_cmd *qc)
+{
+	struct scatterlist *sg = qc->sg;
+	struct ata_port *ap = qc->ap;
+	unsigned int idx, nelem;
+
+	assert(sg != NULL);
+	assert(qc->n_elem > 0);
+
+	idx = 0;
+	for (nelem = qc->n_elem; nelem; nelem--,sg++) {
+		u32 addr, boundary;
+		u32 sg_len, len;
+
+		/* determine if physical DMA addr spans 64K boundary.
+		 * Note h/w doesn't support 64-bit, so we unconditionally
+		 * truncate dma_addr_t to u32.
+		 */
+		addr = (u32) sg_dma_address(sg);
+		sg_len = sg_dma_len(sg);
+
+		while (sg_len) {
+			boundary = (addr & ~0xffff) + (0xffff + 1);
+			len = sg_len;
+			if ((addr + sg_len) > boundary)
+				len = boundary - addr;
+
+			ap->prd[idx].addr = cpu_to_le32(addr);
+			ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+			idx++;
+			sg_len -= len;
+			addr += len;
+		}
+	}
+
+	if (idx)
+		ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+
+/**
+ *	ata_sg_setup_one -
+ *	@qc:
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *
+ */
+
+static int ata_sg_setup_one(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct scsi_cmnd *cmd = qc->scsicmd;
+	int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	struct scatterlist *sg = qc->sg;
+	unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG);
+	dma_addr_t dma_address;
+
+	assert(sg == &qc->sgent);
+	assert(qc->n_elem == 1);
+
+	sg->address = cmd->request_buffer;
+	sg->page = virt_to_page(cmd->request_buffer);
+	sg->offset = (unsigned long) cmd->request_buffer & ~PAGE_MASK;
+	sg_dma_len(sg) = cmd->request_bufflen;
+
+	if (!have_sg)
+		return 0;
+
+	dma_address = pci_map_single(ap->host_set->pdev, cmd->request_buffer,
+				     cmd->request_bufflen, dir);
+
+	sg_dma_address(sg) = dma_address;
+
+	DPRINTK("mapped buffer of %d bytes for %s\n", cmd->request_bufflen,
+		qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+	return 0;
+}
+
+/**
+ *	ata_sg_setup -
+ *	@qc:
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *
+ */
+
+static int ata_sg_setup(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct scsi_cmnd *cmd = qc->scsicmd;
+	struct scatterlist *sg;
+	int n_elem;
+	unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG);
+
+	VPRINTK("ENTER, ata%u, use_sg %d\n", ap->id, cmd->use_sg);
+	assert(cmd->use_sg > 0);
+
+	sg = (struct scatterlist *)cmd->request_buffer;
+	if (have_sg) {
+		int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+		n_elem = pci_map_sg(ap->host_set->pdev, sg, cmd->use_sg, dir);
+		if (n_elem < 1)
+			return -1;
+		DPRINTK("%d sg elements mapped\n", n_elem);
+	} else {
+		n_elem = cmd->use_sg;
+	}
+	qc->n_elem = n_elem;
+
+	return 0;
+}
+
+/**
+ *	ata_pio_poll -
+ *	@ap:
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static unsigned long ata_pio_poll(struct ata_port *ap)
+{
+	u8 status;
+	unsigned int poll_state = PIO_ST_UNKNOWN;
+	unsigned int reg_state = PIO_ST_UNKNOWN;
+	const unsigned int tmout_state = PIO_ST_TMOUT;
+
+	switch (ap->pio_task_state) {
+	case PIO_ST:
+	case PIO_ST_POLL:
+		poll_state = PIO_ST_POLL;
+		reg_state = PIO_ST;
+		break;
+	case PIO_ST_LAST:
+	case PIO_ST_LAST_POLL:
+		poll_state = PIO_ST_LAST_POLL;
+		reg_state = PIO_ST_LAST;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	status = ata_chk_status(ap);
+	if (status & ATA_BUSY) {
+		if (time_after(jiffies, ap->pio_task_timeout)) {
+			ap->pio_task_state = tmout_state;
+			return 0;
+		}
+		ap->pio_task_state = poll_state;
+		return ATA_SHORT_PAUSE;
+	}
+
+	ap->pio_task_state = reg_state;
+	return 0;
+}
+
+/**
+ *	ata_pio_complete -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+static void ata_pio_complete (struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc;
+	u8 drv_stat;
+
+	/*
+	 * This is purely hueristic.  This is a fast path.
+	 * Sometimes when we enter, BSY will be cleared in
+	 * a chk-status or two.  If not, the drive is probably seeking
+	 * or something.  Snooze for a couple msecs, then
+	 * chk-status again.  If still busy, fall back to
+	 * PIO_ST_POLL state.
+	 */
+	drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
+	if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
+		msleep(2);
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
+		if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
+			ap->pio_task_state = PIO_ST_LAST_POLL;
+			ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
+			return;
+		}
+	}
+
+	drv_stat = ata_wait_idle(ap);
+	if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
+		ap->pio_task_state = PIO_ST_ERR;
+		return;
+	}
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	assert(qc != NULL);
+
+	ap->pio_task_state = PIO_ST_IDLE;
+
+	ata_irq_on(ap);
+
+	ata_qc_complete(qc, drv_stat, 0);
+}
+
+/**
+ *	ata_pio_sector -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+static void ata_pio_sector(struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc;
+	struct scatterlist *sg;
+	struct scsi_cmnd *cmd;
+	unsigned char *buf;
+	u8 status;
+
+	/*
+	 * This is purely hueristic.  This is a fast path.
+	 * Sometimes when we enter, BSY will be cleared in
+	 * a chk-status or two.  If not, the drive is probably seeking
+	 * or something.  Snooze for a couple msecs, then
+	 * chk-status again.  If still busy, fall back to
+	 * PIO_ST_POLL state.
+	 */
+	status = ata_busy_wait(ap, ATA_BUSY, 5);
+	if (status & ATA_BUSY) {
+		msleep(2);
+		status = ata_busy_wait(ap, ATA_BUSY, 10);
+		if (status & ATA_BUSY) {
+			ap->pio_task_state = PIO_ST_POLL;
+			ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
+			return;
+		}
+	}
+
+	/* handle BSY=0, DRQ=0 as error */
+	if ((status & ATA_DRQ) == 0) {
+		ap->pio_task_state = PIO_ST_ERR;
+		return;
+	}
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	assert(qc != NULL);
+
+	cmd = qc->scsicmd;
+	sg = qc->sg;
+
+	if (qc->cursect == (qc->nsect - 1))
+		ap->pio_task_state = PIO_ST_LAST;
+
+	buf = kmap(sg[qc->cursg].page) +
+	      sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE);
+
+	qc->cursect++;
+	qc->cursg_ofs++;
+
+	if (cmd->use_sg)
+		if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) {
+			qc->cursg++;
+			qc->cursg_ofs = 0;
+		}
+
+	DPRINTK("data %s, drv_stat 0x%X\n",
+		qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read",
+		status);
+
+	/* do the actual data transfer */
+	/* FIXME: mmio-ize */
+	if (qc->tf.flags & ATA_TFLAG_WRITE)
+		outsl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS);
+	else
+		insl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS);
+
+	kunmap(sg[qc->cursg].page);
+}
+
+static void ata_pio_task(void *_data)
+{
+	struct ata_port *ap = _data;
+	unsigned long timeout = 0;
+
+	switch (ap->pio_task_state) {
+	case PIO_ST:
+		ata_pio_sector(ap);
+		break;
+
+	case PIO_ST_LAST:
+		ata_pio_complete(ap);
+		break;
+
+	case PIO_ST_POLL:
+	case PIO_ST_LAST_POLL:
+		timeout = ata_pio_poll(ap);
+		break;
+
+	case PIO_ST_TMOUT:
+		printk(KERN_ERR "ata%d: FIXME: PIO_ST_TMOUT\n", /* FIXME */
+		       ap->id);
+		timeout = 11 * HZ;
+		break;
+
+	case PIO_ST_ERR:
+		printk(KERN_ERR "ata%d: FIXME: PIO_ST_ERR\n", /* FIXME */
+		       ap->id);
+		timeout = 11 * HZ;
+		break;
+	}
+
+	if (timeout) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(timeout);
+	}
+
+	if ((ap->pio_task_state != PIO_ST_IDLE) &&
+	    (ap->pio_task_state != PIO_ST_TMOUT) &&
+	    (ap->pio_task_state != PIO_ST_ERR))
+		schedule_task(&ap->pio_task);
+}
+
+/**
+ *	ata_eng_timeout - Handle timeout of queued command
+ *	@ap: Port on which timed-out command is active
+ *
+ *	Some part of the kernel (currently, only the SCSI layer)
+ *	has noticed that the active command on port @ap has not
+ *	completed after a specified length of time.  Handle this
+ *	condition by disabling DMA (if necessary) and completing
+ *	transactions, with error if necessary.
+ *
+ *	This also handles the case of the "lost interrupt", where
+ *	for some reason (possibly hardware bug, possibly driver bug)
+ *	an interrupt was not delivered to the driver, even though the
+ *	transaction completed successfully.
+ *
+ *	LOCKING:
+ *	Inherited from SCSI layer (none, can sleep)
+ */
+
+void ata_eng_timeout(struct ata_port *ap)
+{
+	u8 host_stat, drv_stat;
+	struct ata_queued_cmd *qc;
+
+	DPRINTK("ENTER\n");
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+		goto out;
+	}
+
+	/* hack alert!  We cannot use the supplied completion
+	 * function from inside the ->eh_strategy_handler() thread.
+	 * libata is the only user of ->eh_strategy_handler() in
+	 * any kernel, so the default scsi_done() assumes it is
+	 * not being called from the SCSI EH.
+	 */
+	qc->scsidone = scsi_finish_command;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		if (ap->flags & ATA_FLAG_MMIO) {
+			void *mmio = (void *) ap->ioaddr.bmdma_addr;
+			host_stat = readb(mmio + ATA_DMA_STATUS);
+		} else
+			host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+
+		printk(KERN_ERR "ata%u: DMA timeout, stat 0x%x\n",
+		       ap->id, host_stat);
+
+		ata_dma_complete(ap, host_stat, 1);
+		break;
+
+	case ATA_PROT_NODATA:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat, 1);
+		break;
+
+	default:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat, 1);
+		break;
+	}
+
+out:
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_qc_new -
+ *	@ap:
+ *	@dev:
+ *
+ *	LOCKING:
+ */
+
+static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc = NULL;
+	unsigned int i;
+
+	for (i = 0; i < ATA_MAX_QUEUE; i++)
+		if (!test_and_set_bit(i, &ap->qactive)) {
+			qc = ata_qc_from_tag(ap, i);
+			break;
+		}
+
+	if (qc)
+		qc->tag = i;
+
+	return qc;
+}
+
+/**
+ *	ata_qc_new_init -
+ *	@ap:
+ *	@dev:
+ *
+ *	LOCKING:
+ */
+
+struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
+				      struct ata_device *dev)
+{
+	struct ata_queued_cmd *qc;
+
+	qc = ata_qc_new(ap);
+	if (qc) {
+		qc->sg = NULL;
+		qc->flags = 0;
+		qc->scsicmd = NULL;
+		qc->ap = ap;
+		qc->dev = dev;
+		qc->cursect = qc->cursg = qc->cursg_ofs = 0;
+		qc->nsect = 0;
+
+		ata_tf_init(ap, &qc->tf, dev->devno);
+
+		if (likely((dev->flags & ATA_DFLAG_PIO) == 0))
+			qc->flags |= ATA_QCFLAG_DMA;
+		if (dev->flags & ATA_DFLAG_LBA48)
+			qc->tf.flags |= ATA_TFLAG_LBA48;
+	}
+
+	return qc;
+}
+
+/**
+ *	ata_qc_complete -
+ *	@qc:
+ *	@drv_stat:
+ *	@done_late:
+ *
+ *	LOCKING:
+ *
+ */
+
+void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat, unsigned int done_late)
+{
+	struct ata_port *ap = qc->ap;
+	struct scsi_cmnd *cmd = qc->scsicmd;
+	unsigned int tag, do_clear = 0;
+
+	assert(qc != NULL);	/* ata_qc_from_tag _might_ return NULL */
+	assert(qc->flags & ATA_QCFLAG_ACTIVE);
+
+	if (likely(qc->flags & ATA_QCFLAG_SG))
+		ata_sg_clean(qc);
+
+	if (cmd) {
+		if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) {
+			if (qc->flags & ATA_QCFLAG_ATAPI)
+				cmd->result = SAM_STAT_CHECK_CONDITION;
+			else
+				ata_to_sense_error(qc);
+		} else {
+			if (done_late)
+				cmd->done_late = 1;
+			cmd->result = SAM_STAT_GOOD;
+		}
+
+		qc->scsidone(cmd);
+	}
+
+	qc->flags &= ~ATA_QCFLAG_ACTIVE;
+	tag = qc->tag;
+	if (likely(ata_tag_valid(tag))) {
+		if (tag == ap->active_tag)
+			ap->active_tag = ATA_TAG_POISON;
+		qc->tag = ATA_TAG_POISON;
+		do_clear = 1;
+	}
+
+	if (qc->waiting)
+		complete(qc->waiting);
+
+	if (likely(do_clear))
+		clear_bit(tag, &ap->qactive);
+}
+
+/**
+ *	ata_qc_issue - issue taskfile to device
+ *	@qc: command to issue to device
+ *
+ *	Prepare an ATA command to submission to device.
+ *	This includes mapping the data into a DMA-able
+ *	area, filling in the S/G table, and finally
+ *	writing the taskfile to hardware, starting the command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, negative on error.
+ */
+
+int ata_qc_issue(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct scsi_cmnd *cmd = qc->scsicmd;
+
+	/* set up SG table */
+	if (cmd->use_sg) {
+		if (ata_sg_setup(qc))
+			goto err_out;
+	} else {
+		if (ata_sg_setup_one(qc))
+			goto err_out;
+	}
+
+	ap->ops->fill_sg(qc);
+
+	qc->ap->active_tag = qc->tag;
+	qc->flags |= ATA_QCFLAG_ACTIVE;
+
+	return ata_qc_issue_prot(qc);
+
+err_out:
+	return -1;
+}
+
+/**
+ *	ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
+ *	@qc: command to issue to device
+ *
+ *	Using various libata functions and hooks, this function
+ *	starts an ATA command.  ATA commands are grouped into
+ *	classes called "protocols", and issuing each type of protocol
+ *	is slightly different.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, negative on error.
+ */
+
+static int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+
+	ata_dev_select(ap, qc->dev->devno, 1, 0);
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_NODATA:
+		ata_tf_to_host_nolock(ap, &qc->tf);
+		break;
+
+	case ATA_PROT_DMA:
+		ap->ops->tf_load(ap, &qc->tf);	 /* load tf registers */
+		ap->ops->bmdma_start(qc);	    /* initiate bmdma */
+		break;
+
+	case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
+		qc->flags |= ATA_QCFLAG_POLL;
+		qc->tf.ctl |= ATA_NIEN;	/* disable interrupts */
+		ata_tf_to_host_nolock(ap, &qc->tf);
+		ap->pio_task_state = PIO_ST;
+		schedule_task(&ap->pio_task);
+		break;
+
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_bmdma_start_mmio -
+ *	@qc:
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 host_stat, dmactl;
+	void *mmio = (void *) ap->ioaddr.bmdma_addr;
+
+	/* load PRD table addr. */
+	mb();	/* make sure PRD table writes are visible to controller */
+	writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+
+	/* specify data direction, triple-check start bit is clear */
+	dmactl = readb(mmio + ATA_DMA_CMD);
+	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+	if (!rw)
+		dmactl |= ATA_DMA_WR;
+	writeb(dmactl, mmio + ATA_DMA_CMD);
+
+	/* clear interrupt, error bits */
+	host_stat = readb(mmio + ATA_DMA_STATUS);
+	writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, mmio + ATA_DMA_STATUS);
+
+	/* issue r/w command */
+	ap->ops->exec_command(ap, &qc->tf);
+
+	/* start host DMA transaction */
+	writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+
+	/* Strictly, one may wish to issue a readb() here, to
+	 * flush the mmio write.  However, control also passes
+	 * to the hardware at this point, and it will interrupt
+	 * us when we are to resume control.  So, in effect,
+	 * we don't care when the mmio write flushes.
+	 * Further, a read of the DMA status register _immediately_
+	 * following the write may not be what certain flaky hardware
+	 * is expected, so I think it is best to not add a readb()
+	 * without first all the MMIO ATA cards/mobos.
+	 * Or maybe I'm just being paranoid.
+	 */
+}
+
+/**
+ *	ata_bmdma_start_pio -
+ *	@qc:
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 host_stat, dmactl;
+
+	/* load PRD table addr. */
+	outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+	/* specify data direction, triple-check start bit is clear */
+	dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+	if (!rw)
+		dmactl |= ATA_DMA_WR;
+	outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+	/* clear interrupt, error bits */
+	host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+	outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+	     ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+
+	/* issue r/w command */
+	ap->ops->exec_command(ap, &qc->tf);
+
+	/* start host DMA transaction */
+	outb(dmactl | ATA_DMA_START,
+	     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+}
+
+/**
+ *	ata_dma_complete -
+ *	@ap:
+ *	@host_stat:
+ *	@done_late:
+ *
+ *	LOCKING:
+ */
+
+static void ata_dma_complete(struct ata_port *ap, u8 host_stat,
+			     unsigned int done_late)
+{
+	VPRINTK("ENTER\n");
+
+	if (ap->flags & ATA_FLAG_MMIO) {
+		void *mmio = (void *) ap->ioaddr.bmdma_addr;
+
+		/* clear start/stop bit */
+		writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+		       mmio + ATA_DMA_CMD);
+
+		/* ack intr, err bits */
+		writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+		       mmio + ATA_DMA_STATUS);
+	} else {
+		/* clear start/stop bit */
+		outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
+		     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+		/* ack intr, err bits */
+		outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+		     ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+	}
+
+
+	/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+	ata_altstatus(ap);		/* dummy read */
+
+	DPRINTK("host %u, host_stat==0x%X, drv_stat==0x%X\n",
+		ap->id, (u32) host_stat, (u32) ata_chk_status(ap));
+
+	/* get drive status; clear intr; complete txn */
+	ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+			ata_wait_idle(ap), done_late);
+}
+
+/**
+ *	ata_host_intr - Handle host interrupt for given (port, task)
+ *	@ap: Port on which interrupt arrived (possibly...)
+ *	@qc: Taskfile currently active in engine
+ *
+ *	Handle host interrupt for given queued command.  Currently,
+ *	only DMA interrupts are handled.  All other commands are
+ *	handled via polling with interrupts disabled (nIEN bit).
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	One if interrupt was handled, zero if not (shared irq).
+ */
+
+inline unsigned int ata_host_intr (struct ata_port *ap,
+				   struct ata_queued_cmd *qc)
+{
+	u8 status, host_stat;
+	unsigned int handled = 0;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		if (ap->flags & ATA_FLAG_MMIO) {
+			void *mmio = (void *) ap->ioaddr.bmdma_addr;
+			host_stat = readb(mmio + ATA_DMA_STATUS);
+		} else
+			host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+		VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat);
+
+		if (!(host_stat & ATA_DMA_INTR)) {
+			ap->stats.idle_irq++;
+			break;
+		}
+
+		ata_dma_complete(ap, host_stat, 0);
+		handled = 1;
+		break;
+
+	case ATA_PROT_NODATA:	/* command completion, but no data xfer */
+		status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+		DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+		ata_qc_complete(qc, status, 0);
+		handled = 1;
+		break;
+
+	default:
+		ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+		if ((ap->stats.idle_irq % 1000) == 0) {
+			handled = 1;
+			ata_irq_ack(ap, 0); /* debug trap */
+			printk(KERN_WARNING "ata%d: irq trap\n", ap->id);
+		}
+#endif
+		break;
+	}
+
+	return handled;
+}
+
+/**
+ *	ata_interrupt -
+ *	@irq:
+ *	@dev_instance:
+ *	@regs:
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	unsigned int i;
+	unsigned int handled = 0;
+	unsigned long flags;
+
+	/* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+	spin_lock_irqsave(&host_set->lock, flags);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		struct ata_port *ap;
+
+		ap = host_set->ports[i];
+		if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
+				handled += ata_host_intr(ap, qc);
+		}
+	}
+
+	spin_unlock_irqrestore(&host_set->lock, flags);
+
+	return IRQ_RETVAL(handled);
+}
+
+/**
+ *	ata_thread_iter -
+ *	@ap:
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static unsigned long ata_thread_iter(struct ata_port *ap)
+{
+	long timeout = 0;
+
+	DPRINTK("ata%u: thr_state %s\n",
+		ap->id, ata_thr_state_name(ap->thr_state));
+
+	switch (ap->thr_state) {
+	case THR_UNKNOWN:
+		ap->thr_state = THR_PORT_RESET;
+		break;
+
+	case THR_PROBE_START:
+		ap->thr_state = THR_PORT_RESET;
+		break;
+
+	case THR_PORT_RESET:
+		ata_port_reset(ap);
+		break;
+
+	case THR_PROBE_SUCCESS:
+		up(&ap->probe_sem);
+		ap->thr_state = THR_IDLE;
+		break;
+
+	case THR_PROBE_FAILED:
+		up(&ap->probe_sem);
+		ap->thr_state = THR_AWAIT_DEATH;
+		break;
+
+	case THR_AWAIT_DEATH:
+	case THR_IDLE:
+		timeout = -1;
+		break;
+
+	default:
+		printk(KERN_DEBUG "ata%u: unknown thr state %s\n",
+		       ap->id, ata_thr_state_name(ap->thr_state));
+		break;
+	}
+
+	DPRINTK("ata%u: new thr_state %s, returning %ld\n",
+		ap->id, ata_thr_state_name(ap->thr_state), timeout);
+	return timeout;
+}
+
+void atapi_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+
+	qc->flags |= ATA_QCFLAG_ACTIVE;
+	ap->active_tag = qc->tag;
+
+	ata_dev_select(ap, qc->dev->devno, 1, 0);
+	ata_tf_to_host_nolock(ap, &qc->tf);
+	schedule_task(&ap->packet_task);
+
+	VPRINTK("EXIT\n");
+}
+
+/**
+ *	atapi_packet_task - Write CDB bytes to hardware
+ *	@_data: Port to which ATAPI device is attached.
+ *
+ *	When device has indicated its readiness to accept
+ *	a CDB, this function is called.  Send the CDB.
+ *	If DMA is to be performed, exit immediately.
+ *	Otherwise, we are in polling mode, so poll
+ *	status under operation succeeds or fails.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ */
+
+static void atapi_packet_task(void *_data)
+{
+	struct ata_port *ap = _data;
+	struct ata_queued_cmd *qc;
+	u8 status;
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	assert(qc != NULL);
+	assert(qc->flags & ATA_QCFLAG_ACTIVE);
+
+	/* sleep-wait for BSY to clear */
+	DPRINTK("busy wait\n");
+	if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB))
+		goto err_out;
+
+	/* make sure DRQ is set */
+	status = ata_chk_status(ap);
+	if ((status & ATA_DRQ) == 0)
+		goto err_out;
+
+	/* send SCSI cdb */
+	/* FIXME: mmio-ize */
+	DPRINTK("send cdb\n");
+	outsl(ap->ioaddr.data_addr,
+	      qc->scsicmd->cmnd, ap->host->max_cmd_len / 4);
+
+	/* if we are DMA'ing, irq handler takes over from here */
+	if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+		/* FIXME: start DMA here */
+	} else {
+		ap->pio_task_state = PIO_ST;
+		schedule_task(&ap->pio_task);
+	}
+
+	return;
+
+err_out:
+	ata_qc_complete(qc, ATA_ERR, 0);
+}
+
+int ata_port_start (struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+
+	ap->prd = pci_alloc_consistent(pdev, ATA_PRD_TBL_SZ, &ap->prd_dma);
+	if (!ap->prd)
+		return -ENOMEM;
+
+	DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
+
+	return 0;
+}
+
+void ata_port_stop (struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+
+	pci_free_consistent(pdev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+}
+
+static void ata_probe_task(void *_data)
+{
+	struct ata_port *ap = _data;
+	long timeout;
+
+	timeout = ata_thread_iter(ap);
+	if (timeout < 0)
+		return;
+
+	if (timeout > 0) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(timeout);
+	}
+
+	schedule_task(&ap->probe_task);
+}
+
+/**
+ *	ata_host_remove -
+ *	@ap:
+ *	@do_unregister:
+ *
+ *	LOCKING:
+ */
+
+static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
+{
+	struct Scsi_Host *sh = ap->host;
+
+	DPRINTK("ENTER\n");
+
+	if (do_unregister)
+		scsi_unregister(sh);
+
+	ap->ops->port_stop(ap);
+}
+
+/**
+ *	ata_host_init -
+ *	@host:
+ *	@ent:
+ *	@port_no:
+ *
+ *	LOCKING:
+ *
+ */
+
+static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
+			  struct ata_host_set *host_set,
+			  struct ata_probe_ent *ent, unsigned int port_no)
+{
+	unsigned int i;
+
+	host->max_id = 16;
+	host->max_lun = 1;
+	host->max_channel = 1;
+	host->unique_id = ata_unique_id++;
+	host->max_cmd_len = 12;
+	host->pci_dev = ent->pdev;
+
+	ap->flags = ATA_FLAG_PORT_DISABLED;
+	ap->id = host->unique_id;
+	ap->host = host;
+	ap->ctl = ATA_DEVCTL_OBS;
+	ap->host_set = host_set;
+	ap->port_no = port_no;
+	ap->pio_mask = ent->pio_mask;
+	ap->udma_mask = ent->udma_mask;
+	ap->flags |= ent->host_flags;
+	ap->ops = ent->port_ops;
+	ap->thr_state = THR_PROBE_START;
+	ap->cbl = ATA_CBL_NONE;
+	ap->device[0].flags = ATA_DFLAG_MASTER;
+	ap->active_tag = ATA_TAG_POISON;
+	ap->last_ctl = 0xFF;
+
+	INIT_TQUEUE(&ap->packet_task, atapi_packet_task, ap);
+	INIT_TQUEUE(&ap->pio_task, ata_pio_task, ap);
+	INIT_TQUEUE(&ap->probe_task, ata_probe_task, ap);
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		ap->device[i].devno = i;
+
+	init_MUTEX_LOCKED(&ap->probe_sem);
+
+#ifdef ATA_IRQ_TRAP
+	ap->stats.unhandled_irq = 1;
+	ap->stats.idle_irq = 1;
+#endif
+
+	memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
+}
+
+/**
+ *	ata_host_add -
+ *	@ent:
+ *	@host_set:
+ *	@port_no:
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static struct ata_port * ata_host_add(struct ata_probe_ent *ent,
+				      struct ata_host_set *host_set,
+				      unsigned int port_no)
+{
+	struct Scsi_Host *host;
+	struct ata_port *ap;
+	int rc;
+
+	DPRINTK("ENTER\n");
+	host = scsi_register(ent->sht, sizeof(struct ata_port));
+	if (!host)
+		return NULL;
+
+	ap = (struct ata_port *) &host->hostdata[0];
+
+	ata_host_init(ap, host, host_set, ent, port_no);
+
+	rc = ap->ops->port_start(ap);
+	if (rc)
+		goto err_out;
+
+	return ap;
+
+err_out:
+	scsi_unregister(host);
+	return NULL;
+}
+
+/**
+ *	ata_device_add -
+ *	@ent:
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+int ata_device_add(struct ata_probe_ent *ent)
+{
+	unsigned int count = 0, i;
+	struct pci_dev *pdev = ent->pdev;
+	struct ata_host_set *host_set;
+
+	DPRINTK("ENTER\n");
+	/* alloc a container for our list of ATA ports (buses) */
+	host_set = kmalloc(sizeof(struct ata_host_set) +
+			   (ent->n_ports * sizeof(void *)), GFP_KERNEL);
+	if (!host_set)
+		return 0;
+	memset(host_set, 0, sizeof(struct ata_host_set) + (ent->n_ports * sizeof(void *)));
+	spin_lock_init(&host_set->lock);
+
+	host_set->pdev = pdev;
+	host_set->n_ports = ent->n_ports;
+	host_set->irq = ent->irq;
+	host_set->mmio_base = ent->mmio_base;
+	host_set->private_data = ent->private_data;
+
+	/* register each port bound to this device */
+	for (i = 0; i < ent->n_ports; i++) {
+		struct ata_port *ap;
+
+		ap = ata_host_add(ent, host_set, i);
+		if (!ap)
+			goto err_out;
+
+		host_set->ports[i] = ap;
+
+		/* print per-port info to dmesg */
+		printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX "
+				 "bmdma 0x%lX irq %lu\n",
+			ap->id,
+			ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
+			ata_udma_string(ent->udma_mask),
+	       		ap->ioaddr.cmd_addr,
+	       		ap->ioaddr.ctl_addr,
+	       		ap->ioaddr.bmdma_addr,
+	       		ent->irq);
+
+		count++;
+	}
+
+	if (!count) {
+		kfree(host_set);
+		return 0;
+	}
+
+	/* obtain irq, that is shared between channels */
+	if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
+			DRV_NAME, host_set))
+		goto err_out;
+
+	/* perform each probe synchronously */
+	DPRINTK("probe begin\n");
+	for (i = 0; i < count; i++) {
+		struct ata_port *ap;
+
+		ap = host_set->ports[i];
+
+		DPRINTK("ata%u: probe begin\n", ap->id);
+		schedule_task(&ap->probe_task);		/* start probe */
+
+		DPRINTK("ata%u: probe-wait begin\n", ap->id);
+		down(&ap->probe_sem);	/* wait for end */
+
+		DPRINTK("ata%u: probe-wait end\n", ap->id);
+	}
+
+	pci_set_drvdata(pdev, host_set);
+
+	VPRINTK("EXIT, returning %u\n", ent->n_ports);
+	return ent->n_ports; /* success */
+
+err_out:
+	for (i = 0; i < count; i++) {
+		ata_host_remove(host_set->ports[i], 1);
+	}
+	kfree(host_set);
+	VPRINTK("EXIT, returning 0\n");
+	return 0;
+}
+
+/**
+ *	ata_scsi_detect -
+ *	@sht:
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+int ata_scsi_detect(Scsi_Host_Template *sht)
+{
+	struct list_head *node;
+	struct ata_probe_ent *ent;
+	int count = 0;
+
+	VPRINTK("ENTER\n");
+
+	sht->use_new_eh_code = 1;	/* IORL hack, part deux */
+
+	spin_lock(&ata_module_lock);
+	while (!list_empty(&ata_probe_list)) {
+		node = ata_probe_list.next;
+		ent = list_entry(node, struct ata_probe_ent, node);
+		list_del(node);
+
+		spin_unlock(&ata_module_lock);
+
+		count += ata_device_add(ent);
+		kfree(ent);
+
+		spin_lock(&ata_module_lock);
+	}
+	spin_unlock(&ata_module_lock);
+
+	VPRINTK("EXIT, returning %d\n", count);
+	return count;
+}
+
+/**
+ *	ata_scsi_release - SCSI layer callback hook for host unload
+ *	@host: libata host to be unloaded
+ *
+ *	Performs all duties necessary to shut down a libata port:
+ *	Kill port kthread, disable port, and release resources.
+ *
+ *	LOCKING:
+ *	Inherited from SCSI layer.
+ *
+ *	RETURNS:
+ *	One.
+ */
+
+int ata_scsi_release(struct Scsi_Host *host)
+{
+	struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+
+	DPRINTK("ENTER\n");
+
+	ap->ops->port_disable(ap);
+	ata_host_remove(ap, 0);
+
+	DPRINTK("EXIT\n");
+	return 1;
+}
+
+/**
+ *	ata_std_ports - initialize ioaddr with standard port offsets.
+ *	@ioaddr:
+ */
+void ata_std_ports(struct ata_ioports *ioaddr)
+{
+	ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
+	ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR;
+	ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE;
+	ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT;
+	ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL;
+	ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM;
+	ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH;
+	ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE;
+	ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
+	ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
+}
+
+/**
+ *	ata_pci_init_one -
+ *	@pdev:
+ *	@port_info:
+ *	@n_ports:
+ *
+ *	LOCKING:
+ *	Inherited from PCI layer (may sleep).
+ *
+ *	RETURNS:
+ *
+ */
+
+int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
+		      unsigned int n_ports)
+{
+	struct ata_probe_ent *probe_ent, *probe_ent2 = NULL;
+	struct ata_port_info *port0, *port1;
+	u8 tmp8, mask;
+	unsigned int legacy_mode = 0;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	port0 = port_info[0];
+	if (n_ports > 1)
+		port1 = port_info[1];
+	else
+		port1 = port0;
+
+	if ((port0->host_flags & ATA_FLAG_NO_LEGACY) == 0) {
+		/* TODO: support transitioning to native mode? */
+		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+		mask = (1 << 2) | (1 << 0);
+		if ((tmp8 & mask) != mask)
+			legacy_mode = (1 << 3);
+	}
+
+	/* FIXME... */
+	if ((!legacy_mode) && (n_ports > 1)) {
+		printk(KERN_ERR "ata: BUG: native mode, n_ports > 1\n");
+		return -EINVAL;
+	}
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	if (legacy_mode) {
+		if (!request_region(0x1f0, 8, "libata"))
+			printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
+		else
+			legacy_mode |= (1 << 0);
+
+		if (!request_region(0x170, 8, "libata"))
+			printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
+		else
+			legacy_mode |= (1 << 1);
+	}
+
+	/* we have legacy mode, but all ports are unavailable */
+	if (legacy_mode == (1 << 3)) {
+		rc = -EBUSY;
+		goto err_out_regions;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (!probe_ent) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->pdev = pdev;
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	if (legacy_mode) {
+		probe_ent2 = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+		if (!probe_ent2) {
+			rc = -ENOMEM;
+			goto err_out_free_ent;
+		}
+
+		memset(probe_ent2, 0, sizeof(*probe_ent));
+		probe_ent2->pdev = pdev;
+		INIT_LIST_HEAD(&probe_ent2->node);
+	}
+
+	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
+	probe_ent->sht = port0->sht;
+	probe_ent->host_flags = port0->host_flags;
+	probe_ent->pio_mask = port0->pio_mask;
+	probe_ent->udma_mask = port0->udma_mask;
+	probe_ent->port_ops = port0->port_ops;
+
+	if (legacy_mode) {
+		probe_ent->port[0].cmd_addr = 0x1f0;
+		probe_ent->port[0].altstatus_addr =
+		probe_ent->port[0].ctl_addr = 0x3f6;
+		probe_ent->n_ports = 1;
+		probe_ent->irq = 14;
+		ata_std_ports(&probe_ent->port[0]);
+
+		probe_ent2->port[0].cmd_addr = 0x170;
+		probe_ent2->port[0].altstatus_addr =
+		probe_ent2->port[0].ctl_addr = 0x376;
+		probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8;
+		probe_ent2->n_ports = 1;
+		probe_ent2->irq = 15;
+		ata_std_ports(&probe_ent2->port[0]);
+
+		probe_ent2->sht = port1->sht;
+		probe_ent2->host_flags = port1->host_flags;
+		probe_ent2->pio_mask = port1->pio_mask;
+		probe_ent2->udma_mask = port1->udma_mask;
+		probe_ent2->port_ops = port1->port_ops;
+	} else {
+		probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
+		ata_std_ports(&probe_ent->port[0]);
+		probe_ent->port[0].altstatus_addr =
+		probe_ent->port[0].ctl_addr =
+			pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+
+		probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
+		ata_std_ports(&probe_ent->port[1]);
+		probe_ent->port[1].altstatus_addr =
+		probe_ent->port[1].ctl_addr =
+			pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+		probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+
+		probe_ent->n_ports = 2;
+		probe_ent->irq = pdev->irq;
+		probe_ent->irq_flags = SA_SHIRQ;
+	}
+
+	pci_set_master(pdev);
+
+	spin_lock(&ata_module_lock);
+	if (legacy_mode) {
+		if (legacy_mode & (1 << 0))
+			list_add_tail(&probe_ent->node, &ata_probe_list);
+		else
+			kfree(probe_ent);
+		if (legacy_mode & (1 << 1))
+			list_add_tail(&probe_ent2->node, &ata_probe_list);
+		else
+			kfree(probe_ent2);
+	} else {
+		list_add_tail(&probe_ent->node, &ata_probe_list);
+	}
+	spin_unlock(&ata_module_lock);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	if (legacy_mode & (1 << 0))
+		release_region(0x1f0, 8);
+	if (legacy_mode & (1 << 1))
+		release_region(0x170, 8);
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+/**
+ *	ata_pci_remove_one - PCI layer callback for device removal
+ *	@pdev: PCI device that was removed
+ *
+ *	PCI layer indicates to libata via this hook that
+ *	hot-unplug or module unload event has occured.
+ *	Handle this by unregistering all objects associated
+ *	with this PCI device.  Free those objects.  Then finally
+ *	release PCI resources and disable device.
+ *
+ *	LOCKING:
+ *	Inherited from PCI layer (may sleep).
+ */
+
+void ata_pci_remove_one (struct pci_dev *pdev)
+{
+	struct ata_host_set *host_set = pci_get_drvdata(pdev);
+	struct ata_port *ap;
+	unsigned int i;
+	Scsi_Host_Template *sht;
+	int rc;
+
+	/* FIXME: this unregisters all ports attached to the
+	 * Scsi_Host_Template given.  We _might_ have multiple
+	 * templates (though we don't ATM), so this is ok... for now.
+	 */
+	ap = host_set->ports[0];
+	sht = ap->host->hostt;
+	rc = scsi_unregister_module(MODULE_SCSI_HA, sht);
+	/* FIXME: handle 'rc' failure? */
+
+	free_irq(host_set->irq, host_set);
+	if (host_set->mmio_base)
+		iounmap(host_set->mmio_base);
+	if (host_set->ports[0]->ops->host_stop)
+		host_set->ports[0]->ops->host_stop(host_set);
+
+	pci_release_regions(pdev);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		struct ata_ioports *ioaddr;
+
+		ap = host_set->ports[i];
+		ioaddr = &ap->ioaddr;
+
+		if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
+			if (ioaddr->cmd_addr == 0x1f0)
+				release_region(0x1f0, 8);
+			else if (ioaddr->cmd_addr == 0x170)
+				release_region(0x170, 8);
+		}
+	}
+
+	kfree(host_set);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+/**
+ *	ata_add_to_probe_list - add an entry to the list of things
+ *	to be probed.
+ *	@probe_ent: describes device to be probed.
+ *
+ *	LOCKING:
+ */
+
+void ata_add_to_probe_list(struct ata_probe_ent *probe_ent)
+{
+	spin_lock(&ata_module_lock);
+	list_add_tail(&probe_ent->node, &ata_probe_list);
+	spin_unlock(&ata_module_lock);
+}
+
+/* move to PCI subsystem */
+int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits)
+{
+	unsigned long tmp = 0;
+
+	switch (bits->width) {
+	case 1: {
+		u8 tmp8 = 0;
+		pci_read_config_byte(pdev, bits->reg, &tmp8);
+		tmp = tmp8;
+		break;
+	}
+	case 2: {
+		u16 tmp16 = 0;
+		pci_read_config_word(pdev, bits->reg, &tmp16);
+		tmp = tmp16;
+		break;
+	}
+	case 4: {
+		u32 tmp32 = 0;
+		pci_read_config_dword(pdev, bits->reg, &tmp32);
+		tmp = tmp32;
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+
+	tmp &= bits->mask;
+
+	return (tmp == bits->val) ? 1 : 0;
+}
+
+
+/**
+ *	ata_init -
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static int __init ata_init(void)
+{
+	printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
+	return 0;
+}
+
+static void __exit ata_exit(void)
+{
+}
+
+module_init(ata_init);
+module_exit(ata_exit);
+
+/*
+ * libata is essentially a library of internal helper functions for
+ * low-level ATA host controller drivers.  As such, the API/ABI is
+ * likely to change as new drivers are added and updated.
+ * Do not depend on ABI/API stability.
+ */
+
+EXPORT_SYMBOL_GPL(pci_test_config_bits);
+EXPORT_SYMBOL_GPL(ata_std_bios_param);
+EXPORT_SYMBOL_GPL(ata_std_ports);
+EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_qc_complete);
+EXPORT_SYMBOL_GPL(ata_eng_timeout);
+EXPORT_SYMBOL_GPL(ata_tf_load_pio);
+EXPORT_SYMBOL_GPL(ata_tf_load_mmio);
+EXPORT_SYMBOL_GPL(ata_tf_read_pio);
+EXPORT_SYMBOL_GPL(ata_tf_read_mmio);
+EXPORT_SYMBOL_GPL(ata_tf_to_fis);
+EXPORT_SYMBOL_GPL(ata_tf_from_fis);
+EXPORT_SYMBOL_GPL(ata_check_status_pio);
+EXPORT_SYMBOL_GPL(ata_check_status_mmio);
+EXPORT_SYMBOL_GPL(ata_exec_command_pio);
+EXPORT_SYMBOL_GPL(ata_exec_command_mmio);
+EXPORT_SYMBOL_GPL(ata_port_start);
+EXPORT_SYMBOL_GPL(ata_port_stop);
+EXPORT_SYMBOL_GPL(ata_interrupt);
+EXPORT_SYMBOL_GPL(ata_fill_sg);
+EXPORT_SYMBOL_GPL(ata_bmdma_start_pio);
+EXPORT_SYMBOL_GPL(ata_bmdma_start_mmio);
+EXPORT_SYMBOL_GPL(ata_port_probe);
+EXPORT_SYMBOL_GPL(sata_phy_reset);
+EXPORT_SYMBOL_GPL(ata_bus_reset);
+EXPORT_SYMBOL_GPL(ata_port_disable);
+EXPORT_SYMBOL_GPL(ata_pci_init_one);
+EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
+EXPORT_SYMBOL_GPL(ata_scsi_error);
+EXPORT_SYMBOL_GPL(ata_scsi_detect);
+EXPORT_SYMBOL_GPL(ata_add_to_probe_list);
+EXPORT_SYMBOL_GPL(ata_scsi_release);
+EXPORT_SYMBOL_GPL(ata_host_intr);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/libata-scsi.c linux-2.4.27-pre3/drivers/scsi/libata-scsi.c
--- linux-2.4.26/drivers/scsi/libata-scsi.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/libata-scsi.c	2004-05-18 16:51:25.000000000 +0000
@@ -0,0 +1,1151 @@
+/*
+   libata-scsi.c - helper library for ATA
+
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi.h>
+#include "scsi.h"
+#include "hosts.h"
+#include "sd.h"
+#include <linux/libata.h>
+
+#include "libata.h"
+
+typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd);
+static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
+			      struct scsi_cmnd *cmd,
+			      void (*done)(struct scsi_cmnd *));
+
+
+/**
+ *	ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd.
+ *	@disk: SCSI device for which BIOS geometry is to be determined
+ *	@dev: device major/minor
+ *	@ip: location to which geometry will be output
+ *
+ *	Generic bios head/sector/cylinder calculator
+ *	used by sd. Most BIOSes nowadays expect a XXX/255/16  (CHS) 
+ *	mapping. Some situations may arise where the disk is not 
+ *	bootable if this is not used.
+ *
+ *	LOCKING:
+ *	Defined by the SCSI layer.  We don't really care.
+ *
+ *	RETURNS:
+ *	Zero.
+ */
+int ata_std_bios_param(Disk * disk,	/* SCSI disk */
+		       kdev_t dev,	/* Device major, minor */
+		  int *ip /* Heads, sectors, cylinders in that order */ )
+{
+	ip[0] = 255;
+	ip[1] = 63;
+	ip[2] = disk->capacity / (ip[0] * ip[1]);
+
+	return 0;
+}
+
+
+/**
+ *	ata_scsi_qc_new - acquire new ata_queued_cmd reference
+ *	@ap: ATA port to which the new command is attached
+ *	@dev: ATA device to which the new command is attached
+ *	@cmd: SCSI command that originated this ATA command
+ *	@done: SCSI command completion function
+ *
+ *	Obtain a reference to an unused ata_queued_cmd structure,
+ *	which is the basic libata structure representing a single
+ *	ATA command sent to the hardware.
+ *
+ *	If a command was available, fill in the SCSI-specific
+ *	portions of the structure with information on the
+ *	current command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Command allocated, or %NULL if none available.
+ */
+struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap,
+				       struct ata_device *dev,
+				       struct scsi_cmnd *cmd,
+				       void (*done)(struct scsi_cmnd *))
+{
+	struct ata_queued_cmd *qc;
+
+	qc = ata_qc_new_init(ap, dev);
+	if (qc) {
+		qc->scsicmd = cmd;
+		qc->scsidone = done;
+
+		if (cmd->use_sg) {
+			qc->sg = (struct scatterlist *) cmd->request_buffer;
+			qc->n_elem = cmd->use_sg;
+		} else {
+			qc->sg = &qc->sgent;
+			qc->n_elem = 1;
+		}
+	} else {
+		cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
+		done(cmd);
+	}
+
+	return qc;
+}
+
+/**
+ *	ata_to_sense_error - convert ATA error to SCSI error
+ *	@qc: Command that we are erroring out
+ *
+ *	Converts an ATA error into a SCSI error.
+ *
+ *	Right now, this routine is laughably primitive.  We
+ *	don't even examine what ATA told us, we just look at
+ *	the command data direction, and return a fatal SCSI
+ *	sense error based on that.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_to_sense_error(struct ata_queued_cmd *qc)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+
+	cmd->result = SAM_STAT_CHECK_CONDITION;
+
+	cmd->sense_buffer[0] = 0x70;
+	cmd->sense_buffer[2] = MEDIUM_ERROR;
+	cmd->sense_buffer[7] = 14 - 8;	/* addnl. sense len. FIXME: correct? */
+
+	/* additional-sense-code[-qualifier] */
+	if (cmd->sc_data_direction == SCSI_DATA_READ) {
+		cmd->sense_buffer[12] = 0x11; /* "unrecovered read error" */
+		cmd->sense_buffer[13] = 0x04;
+	} else {
+		cmd->sense_buffer[12] = 0x0C; /* "write error -             */
+		cmd->sense_buffer[13] = 0x02; /*  auto-reallocation failed" */
+	}
+}
+
+/**
+ *	ata_scsi_error - SCSI layer error handler callback
+ *	@host: SCSI host on which error occurred
+ *
+ *	Handles SCSI-layer-thrown error events.
+ *
+ *	LOCKING:
+ *	Inherited from SCSI layer (none, can sleep)
+ *
+ *	RETURNS:
+ *	Zero.
+ */
+
+int ata_scsi_error(struct Scsi_Host *host)
+{
+	struct ata_port *ap;
+
+	DPRINTK("ENTER\n");
+
+	ap = (struct ata_port *) &host->hostdata[0];
+	ap->ops->eng_timeout(ap);
+
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+/**
+ *	ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
+ *	@qc: Storage for translated ATA taskfile
+ *	@scsicmd: SCSI command to translate
+ *
+ *	Converts any of six SCSI read/write commands into the
+ *	ATA counterpart, including starting sector (LBA),
+ *	sector count, and taking into account the device's LBA48
+ *	support.
+ *
+ *	Commands %READ_6, %READ_10, %READ_16, %WRITE_6, %WRITE_10, and
+ *	%WRITE_16 are currently supported.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct ata_taskfile *tf = &qc->tf;
+	unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
+
+	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf->hob_nsect = 0;
+	tf->hob_lbal = 0;
+	tf->hob_lbam = 0;
+	tf->hob_lbah = 0;
+	tf->protocol = qc->dev->xfer_protocol;
+	tf->device |= ATA_LBA;
+
+	if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
+	    scsicmd[0] == READ_16) {
+		tf->command = qc->dev->read_cmd;
+	} else {
+		tf->command = qc->dev->write_cmd;
+		tf->flags |= ATA_TFLAG_WRITE;
+	}
+
+	if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) {
+		if (lba48) {
+			tf->hob_nsect = scsicmd[7];
+			tf->hob_lbal = scsicmd[2];
+
+			qc->nsect = ((unsigned int)scsicmd[7] << 8) |
+					scsicmd[8];
+		} else {
+			/* if we don't support LBA48 addressing, the request
+			 * -may- be too large. */
+			if ((scsicmd[2] & 0xf0) || scsicmd[7])
+				return 1;
+
+			/* stores LBA27:24 in lower 4 bits of device reg */
+			tf->device |= scsicmd[2];
+
+			qc->nsect = scsicmd[8];
+		}
+
+		tf->nsect = scsicmd[8];
+		tf->lbal = scsicmd[5];
+		tf->lbam = scsicmd[4];
+		tf->lbah = scsicmd[3];
+
+		VPRINTK("ten-byte command\n");
+		return 0;
+	}
+
+	if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
+		qc->nsect = tf->nsect = scsicmd[4];
+		tf->lbal = scsicmd[3];
+		tf->lbam = scsicmd[2];
+		tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */
+
+		VPRINTK("six-byte command\n");
+		return 0;
+	}
+
+	if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
+		/* rule out impossible LBAs and sector counts */
+		if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11])
+			return 1;
+
+		if (lba48) {
+			tf->hob_nsect = scsicmd[12];
+			tf->hob_lbal = scsicmd[6];
+			tf->hob_lbam = scsicmd[5];
+			tf->hob_lbah = scsicmd[4];
+
+			qc->nsect = ((unsigned int)scsicmd[12] << 8) |
+					scsicmd[13];
+		} else {
+			/* once again, filter out impossible non-zero values */
+			if (scsicmd[4] || scsicmd[5] || scsicmd[12] ||
+			    (scsicmd[6] & 0xf0))
+				return 1;
+
+			/* stores LBA27:24 in lower 4 bits of device reg */
+			tf->device |= scsicmd[2];
+
+			qc->nsect = scsicmd[13];
+		}
+
+		tf->nsect = scsicmd[13];
+		tf->lbal = scsicmd[9];
+		tf->lbam = scsicmd[8];
+		tf->lbah = scsicmd[7];
+
+		VPRINTK("sixteen-byte command\n");
+		return 0;
+	}
+
+	DPRINTK("no-byte command\n");
+	return 1;
+}
+
+/**
+ *	ata_scsi_translate - Translate then issue SCSI command to ATA device
+ *	@ap: ATA port to which the command is addressed
+ *	@dev: ATA device to which the command is addressed
+ *	@cmd: SCSI command to execute
+ *	@done: SCSI command completion function
+ *
+ *	Our ->queuecommand() function has decided that the SCSI
+ *	command issued can be directly translated into an ATA
+ *	command, rather than handled internally.
+ *
+ *	This function sets up an ata_queued_cmd structure for the
+ *	SCSI command, and sends that ata_queued_cmd to the hardware.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
+			      struct scsi_cmnd *cmd,
+			      void (*done)(struct scsi_cmnd *),
+			      ata_xlat_func_t xlat_func)
+{
+	struct ata_queued_cmd *qc;
+	u8 *scsicmd = cmd->cmnd;
+
+	VPRINTK("ENTER\n");
+
+	if (unlikely(cmd->request_bufflen < 1)) {
+		printk(KERN_WARNING "ata%u(%u): empty request buffer\n",
+		       ap->id, dev->devno);
+		goto err_out;
+	}
+
+	qc = ata_scsi_qc_new(ap, dev, cmd, done);
+	if (!qc)
+		return;
+
+	if (cmd->sc_data_direction == SCSI_DATA_READ ||
+	    cmd->sc_data_direction == SCSI_DATA_WRITE)
+		qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */
+
+	if (xlat_func(qc, scsicmd))
+		goto err_out;
+
+	/* select device, send command to hardware */
+	if (ata_qc_issue(qc))
+		goto err_out;
+
+	VPRINTK("EXIT\n");
+	return;
+
+err_out:
+	ata_bad_cdb(cmd, done);
+	DPRINTK("EXIT - badcmd\n");
+}
+
+/**
+ *	ata_scsi_rbuf_get - Map response buffer.
+ *	@cmd: SCSI command containing buffer to be mapped.
+ *	@buf_out: Pointer to mapped area.
+ *
+ *	Maps buffer contained within SCSI command @cmd.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Length of response buffer.
+ */
+
+static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
+{
+	u8 *buf;
+	unsigned int buflen;
+
+	if (cmd->use_sg) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *) cmd->request_buffer;
+		buf = kmap_atomic(sg->page, KM_USER0) + sg->offset;
+		buflen = sg->length;
+	} else {
+		buf = cmd->request_buffer;
+		buflen = cmd->request_bufflen;
+	}
+
+	memset(buf, 0, buflen);
+	*buf_out = buf;
+	return buflen;
+}
+
+/**
+ *	ata_scsi_rbuf_put - Unmap response buffer.
+ *	@cmd: SCSI command containing buffer to be unmapped.
+ *
+ *	Unmaps response buffer contained within @cmd.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd)
+{
+	if (cmd->use_sg) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *) cmd->request_buffer;
+		kunmap_atomic(sg->page, KM_USER0);
+	}
+}
+
+/**
+ *	ata_scsi_rbuf_fill - wrapper for SCSI command simulators
+ *	@args: Port / device / SCSI command of interest.
+ *	@actor: Callback hook for desired SCSI command simulator
+ *
+ *	Takes care of the hard work of simulating a SCSI command...
+ *	Mapping the response buffer, calling the command's handler,
+ *	and handling the handler's return value.  This return value
+ *	indicates whether the handler wishes the SCSI command to be
+ *	completed successfully, or not.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+		        unsigned int (*actor) (struct ata_scsi_args *args,
+			     		   u8 *rbuf, unsigned int buflen))
+{
+	u8 *rbuf;
+	unsigned int buflen, rc;
+	struct scsi_cmnd *cmd = args->cmd;
+
+	buflen = ata_scsi_rbuf_get(cmd, &rbuf);
+	rc = actor(args, rbuf, buflen);
+	ata_scsi_rbuf_put(cmd);
+
+	if (rc)
+		ata_bad_cdb(cmd, args->done);
+	else {
+		cmd->result = SAM_STAT_GOOD;
+		args->done(cmd);
+	}
+}
+
+/**
+ *	ata_scsiop_inq_std - Simulate INQUIRY command
+ *	@args: Port / device / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Returns standard device identification data associated
+ *	with non-EVPD INQUIRY command output.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
+			       unsigned int buflen)
+{
+	const u8 hdr[] = {
+		TYPE_DISK,
+		0,
+		0x5,	/* claim SPC-3 version compatibility */
+		2,
+		96 - 4
+	};
+
+	VPRINTK("ENTER\n");
+
+	memcpy(rbuf, hdr, sizeof(hdr));
+
+	if (buflen > 36) {
+		memcpy(&rbuf[8], args->dev->vendor, 8);
+		memcpy(&rbuf[16], args->dev->product, 16);
+		memcpy(&rbuf[32], DRV_VERSION, 4);
+	}
+
+	if (buflen > 63) {
+		const u8 versions[] = {
+			0x60,	/* SAM-3 (no version claimed) */
+
+			0x03,
+			0x20,	/* SBC-2 (no version claimed) */
+
+			0x02,
+			0x60	/* SPC-3 (no version claimed) */
+		};
+
+		memcpy(rbuf + 59, versions, sizeof(versions));
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_inq_00 - Simulate INQUIRY EVPD page 0, list of pages
+ *	@args: Port / device / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Returns list of inquiry EVPD pages available.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen)
+{
+	const u8 pages[] = {
+		0x00,	/* page 0x00, this page */
+		0x80,	/* page 0x80, unit serial no page */
+		0x83	/* page 0x83, device ident page */
+	};
+	rbuf[3] = sizeof(pages);	/* number of supported EVPD pages */
+
+	if (buflen > 6)
+		memcpy(rbuf + 4, pages, sizeof(pages));
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_inq_80 - Simulate INQUIRY EVPD page 80, device serial number
+ *	@args: Port / device / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Returns ATA device serial number.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen)
+{
+	const u8 hdr[] = {
+		0,
+		0x80,			/* this page code */
+		0,
+		ATA_SERNO_LEN,		/* page len */
+	};
+	memcpy(rbuf, hdr, sizeof(hdr));
+
+	if (buflen > (ATA_SERNO_LEN + 4))
+		ata_dev_id_string(args->dev, (unsigned char *) &rbuf[4],
+				  ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+
+	return 0;
+}
+
+static const char *inq_83_str = "Linux ATA-SCSI simulator";
+
+/**
+ *	ata_scsiop_inq_83 - Simulate INQUIRY EVPD page 83, device identity
+ *	@args: Port / device / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Returns device identification.  Currently hardcoded to
+ *	return "Linux ATA-SCSI simulator".
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen)
+{
+	rbuf[1] = 0x83;			/* this page code */
+	rbuf[3] = 4 + strlen(inq_83_str);	/* page len */
+
+	/* our one and only identification descriptor (vendor-specific) */
+	if (buflen > (strlen(inq_83_str) + 4 + 4)) {
+		rbuf[4 + 0] = 2;	/* code set: ASCII */
+		rbuf[4 + 3] = strlen(inq_83_str);
+		memcpy(rbuf + 4 + 4, inq_83_str, strlen(inq_83_str));
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_noop -
+ *	@args: Port / device / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	No operation.  Simply returns success to caller, to indicate
+ *	that the caller should successfully complete this SCSI command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
+			    unsigned int buflen)
+{
+	VPRINTK("ENTER\n");
+	return 0;
+}
+
+/**
+ *	ata_msense_push - Push data onto MODE SENSE data output buffer
+ *	@ptr_io: (input/output) Location to store more output data
+ *	@last: End of output data buffer
+ *	@buf: Pointer to BLOB being added to output buffer
+ *	@buflen: Length of BLOB
+ *
+ *	Store MODE SENSE data on an output buffer.
+ *
+ *	LOCKING:
+ *	None.
+ */
+
+static void ata_msense_push(u8 **ptr_io, const u8 *last,
+			    const u8 *buf, unsigned int buflen)
+{
+	u8 *ptr = *ptr_io;
+
+	if ((ptr + buflen - 1) > last)
+		return;
+
+	memcpy(ptr, buf, buflen);
+
+	ptr += buflen;
+
+	*ptr_io = ptr;
+}
+
+/**
+ *	ata_msense_caching - Simulate MODE SENSE caching info page
+ *	@dev: Device associated with this MODE SENSE command
+ *	@ptr_io: (input/output) Location to store more output data
+ *	@last: End of output data buffer
+ *
+ *	Generate a caching info page, which conditionally indicates
+ *	write caching to the SCSI layer, depending on device
+ *	capabilities.
+ *
+ *	LOCKING:
+ *	None.
+ */
+
+static unsigned int ata_msense_caching(struct ata_device *dev, u8 **ptr_io,
+				       const u8 *last)
+{
+	u8 page[7] = { 0xf, 0, 0x10, 0, 0x8, 0xa, 0 };
+	if (dev->flags & ATA_DFLAG_WCACHE)
+		page[6] = 0x4;
+
+	ata_msense_push(ptr_io, last, page, sizeof(page));
+	return sizeof(page);
+}
+
+/**
+ *	ata_msense_ctl_mode - Simulate MODE SENSE control mode page
+ *	@dev: Device associated with this MODE SENSE command
+ *	@ptr_io: (input/output) Location to store more output data
+ *	@last: End of output data buffer
+ *
+ *	Generate a generic MODE SENSE control mode page.
+ *
+ *	LOCKING:
+ *	None.
+ */
+
+static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
+{
+	const u8 page[] = {0xa, 0xa, 2, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30};
+
+	ata_msense_push(ptr_io, last, page, sizeof(page));
+	return sizeof(page);
+}
+
+/**
+ *	ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
+ *	@args: Port / device / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Simulate MODE SENSE commands.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
+				  unsigned int buflen)
+{
+	u8 *scsicmd = args->cmd->cmnd, *p, *last;
+	struct ata_device *dev = args->dev;
+	unsigned int page_control, six_byte, output_len;
+
+	VPRINTK("ENTER\n");
+
+	six_byte = (scsicmd[0] == MODE_SENSE);
+
+	/* we only support saved and current values (which we treat
+	 * in the same manner)
+	 */
+	page_control = scsicmd[2] >> 6;
+	if ((page_control != 0) && (page_control != 3))
+		return 1;
+
+	if (six_byte)
+		output_len = 4;
+	else
+		output_len = 8;
+
+	p = rbuf + output_len;
+	last = rbuf + buflen - 1;
+
+	switch(scsicmd[2] & 0x3f) {
+	case 0x08:		/* caching */
+		output_len += ata_msense_caching(dev, &p, last);
+		break;
+
+	case 0x0a: {		/* control mode */
+		output_len += ata_msense_ctl_mode(&p, last);
+		break;
+		}
+
+	case 0x3f:		/* all pages */
+		output_len += ata_msense_caching(dev, &p, last);
+		output_len += ata_msense_ctl_mode(&p, last);
+		break;
+
+	default:		/* invalid page code */
+		return 1;
+	}
+
+	if (six_byte) {
+		output_len--;
+		rbuf[0] = output_len;
+	} else {
+		output_len -= 2;
+		rbuf[0] = output_len >> 8;
+		rbuf[1] = output_len;
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands
+ *	@args: Port / device / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Simulate READ CAPACITY commands.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
+			        unsigned int buflen)
+{
+	u64 n_sectors = args->dev->n_sectors;
+	u32 tmp;
+
+	VPRINTK("ENTER\n");
+
+	n_sectors--;		/* one off */
+
+	tmp = n_sectors;	/* note: truncates, if lba48 */
+	if (args->cmd->cmnd[0] == READ_CAPACITY) {
+		rbuf[0] = tmp >> (8 * 3);
+		rbuf[1] = tmp >> (8 * 2);
+		rbuf[2] = tmp >> (8 * 1);
+		rbuf[3] = tmp;
+
+		tmp = ATA_SECT_SIZE;
+		rbuf[6] = tmp >> 8;
+		rbuf[7] = tmp;
+
+	} else {
+		rbuf[2] = n_sectors >> (8 * 7);
+		rbuf[3] = n_sectors >> (8 * 6);
+		rbuf[4] = n_sectors >> (8 * 5);
+		rbuf[5] = n_sectors >> (8 * 4);
+		rbuf[6] = tmp >> (8 * 3);
+		rbuf[7] = tmp >> (8 * 2);
+		rbuf[8] = tmp >> (8 * 1);
+		rbuf[9] = tmp;
+
+		tmp = ATA_SECT_SIZE;
+		rbuf[12] = tmp >> 8;
+		rbuf[13] = tmp;
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_report_luns - Simulate REPORT LUNS command
+ *	@args: Port / device / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Simulate REPORT LUNS command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
+				   unsigned int buflen)
+{
+	VPRINTK("ENTER\n");
+	rbuf[3] = 8;	/* just one lun, LUN 0, size 8 bytes */
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_badcmd - End a SCSI request with an error
+ *	@cmd: SCSI request to be handled
+ *	@done: SCSI command completion function
+ *	@asc: SCSI-defined additional sense code
+ *	@ascq: SCSI-defined additional sense code qualifier
+ *
+ *	Helper function that completes a SCSI command with
+ *	%SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
+ *	and the specified additional sense codes.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
+{
+	DPRINTK("ENTER\n");
+	cmd->result = SAM_STAT_CHECK_CONDITION;
+
+	cmd->sense_buffer[0] = 0x70;
+	cmd->sense_buffer[2] = ILLEGAL_REQUEST;
+	cmd->sense_buffer[7] = 14 - 8;	/* addnl. sense len. FIXME: correct? */
+	cmd->sense_buffer[12] = asc;
+	cmd->sense_buffer[13] = ascq;
+
+	done(cmd);
+}
+
+/**
+ *	atapi_scsi_queuecmd - Send CDB to ATAPI device
+ *	@ap: Port to which ATAPI device is attached.
+ *	@dev: Target device for CDB.
+ *	@cmd: SCSI command being sent to device.
+ *	@done: SCSI command completion function.
+ *
+ *	Sends CDB to ATAPI device.  If the Linux SCSI layer sends a
+ *	non-data command, then this function handles the command
+ *	directly, via polling.  Otherwise, the bmdma engine is started.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void atapi_scsi_queuecmd(struct ata_port *ap, struct ata_device *dev,
+			       struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	struct ata_queued_cmd *qc;
+	u8 *scsicmd = cmd->cmnd;
+
+	VPRINTK("ENTER, drv_stat = 0x%x\n", ata_chk_status(ap));
+
+	if (cmd->sc_data_direction == SCSI_DATA_UNKNOWN) {
+		DPRINTK("unknown data, scsicmd 0x%x\n", scsicmd[0]);
+		ata_bad_cdb(cmd, done);
+		return;
+	}
+
+	switch(scsicmd[0]) {
+	case READ_6:
+	case WRITE_6:
+	case MODE_SELECT:
+	case MODE_SENSE:
+		DPRINTK("read6/write6/modesel/modesense trap\n");
+		ata_bad_scsiop(cmd, done);
+		return;
+
+	default:
+		/* do nothing */
+		break;
+	}
+
+	qc = ata_scsi_qc_new(ap, dev, cmd, done);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: command queue empty\n", ap->id);
+		return;
+	}
+
+	qc->flags |= ATA_QCFLAG_ATAPI;
+
+	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	if (cmd->sc_data_direction == SCSI_DATA_WRITE) {
+		qc->tf.flags |= ATA_TFLAG_WRITE;
+		DPRINTK("direction: write\n");
+	}
+
+	qc->tf.command = ATA_CMD_PACKET;
+
+	if (cmd->sc_data_direction == SCSI_DATA_NONE) {
+		qc->tf.protocol = ATA_PROT_ATAPI;
+		qc->flags |= ATA_QCFLAG_POLL;
+		qc->tf.ctl |= ATA_NIEN;	/* disable interrupts */
+	} else {
+		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+		qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */
+		qc->tf.feature |= ATAPI_PKT_DMA;
+	}
+
+	atapi_start(qc);
+}
+
+/**
+ *	ata_scsi_find_dev - lookup ata_device from scsi_cmnd
+ *	@ap: ATA port to which the device is attached
+ *	@cmd: SCSI command to be sent to the device
+ *
+ *	Given various information provided in struct scsi_cmnd,
+ *	map that onto an ATA bus, and using that mapping
+ *	determine which ata_device is associated with the
+ *	SCSI command to be sent.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Associated ATA device, or %NULL if not found.
+ */
+
+static inline struct ata_device *
+ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd)
+{
+	struct ata_device *dev;
+
+	/* skip commands not addressed to targets we simulate */
+	if (likely(cmd->target < ATA_MAX_DEVICES))
+		dev = &ap->device[cmd->target];
+	else
+		return NULL;
+
+	if (unlikely((cmd->channel != 0) ||
+		     (cmd->lun != 0)))
+		return NULL;
+
+	if (unlikely(!ata_dev_present(dev)))
+		return NULL;
+
+#ifndef ATA_ENABLE_ATAPI
+	if (unlikely(dev->class == ATA_DEV_ATAPI))
+		return NULL;
+#endif
+
+	return dev;
+}
+
+/**
+ *	ata_get_xlat_func - check if SCSI to ATA translation is possible
+ *	@cmd: SCSI command opcode to consider
+ *
+ *	Look up the SCSI command given, and determine whether the
+ *	SCSI command is to be translated or simulated.
+ *
+ *	RETURNS:
+ *	Pointer to translation function if possible, %NULL if not.
+ */
+
+static inline ata_xlat_func_t ata_get_xlat_func(u8 cmd)
+{
+	switch (cmd) {
+	case READ_6:
+	case READ_10:
+	case READ_16:
+
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_16:
+		return ata_scsi_rw_xlat;
+	}
+
+	return NULL;
+}
+
+/**
+ *	ata_scsi_dump_cdb - dump SCSI command contents to dmesg
+ *	@ap: ATA port to which the command was being sent
+ *	@cmd: SCSI command to dump
+ *
+ *	Prints the contents of a SCSI command via printk().
+ */
+
+static inline void ata_scsi_dump_cdb(struct ata_port *ap,
+				     struct scsi_cmnd *cmd)
+{
+#ifdef ATA_DEBUG
+	u8 *scsicmd = cmd->cmnd;
+
+	DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		ap->id,
+		cmd->channel, cmd->target, cmd->lun,
+		scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3],
+		scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7],
+		scsicmd[8]);
+#endif
+}
+
+/**
+ *	ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
+ *	@cmd: SCSI command to be sent
+ *	@done: Completion function, called when command is complete
+ *
+ *	In some cases, this function translates SCSI commands into
+ *	ATA taskfiles, and queues the taskfiles to be sent to
+ *	hardware.  In other cases, this function simulates a
+ *	SCSI device by evaluating and responding to certain
+ *	SCSI commands.  This creates the overall effect of
+ *	ATA and ATAPI devices appearing as SCSI devices.
+ *
+ *	LOCKING:
+ *	Releases scsi-layer-held lock, and obtains host_set lock.
+ *
+ *	RETURNS:
+ *	Zero.
+ */
+
+int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	struct ata_port *ap;
+	struct ata_device *dev;
+
+	/* Note: spin_lock_irqsave is held by caller... */
+	spin_unlock(&io_request_lock);
+
+	ap = (struct ata_port *) &cmd->host->hostdata[0];
+
+	spin_lock(&ap->host_set->lock);
+
+	ata_scsi_dump_cdb(ap, cmd);
+
+	dev = ata_scsi_find_dev(ap, cmd);
+	if (unlikely(!dev)) {
+		cmd->result = (DID_BAD_TARGET << 16);
+		done(cmd);
+		goto out_unlock;
+	}
+
+	if (dev->class == ATA_DEV_ATA) {
+		ata_xlat_func_t xlat_func = ata_get_xlat_func(cmd->cmnd[0]);
+
+		if (xlat_func)
+			ata_scsi_translate(ap, dev, cmd, done, xlat_func);
+		else
+			ata_scsi_simulate(ap, dev, cmd, done);
+	} else
+		atapi_scsi_queuecmd(ap, dev, cmd, done);
+
+out_unlock:
+	spin_unlock(&ap->host_set->lock);
+	spin_lock(&io_request_lock);
+	return 0;
+}
+
+/**
+ *	ata_scsi_simulate - simulate SCSI command on ATA device
+ *	@ap: Port to which ATA device is attached.
+ *	@dev: Target device for CDB.
+ *	@cmd: SCSI command being sent to device.
+ *	@done: SCSI command completion function.
+ *
+ *	Interprets and directly executes a select list of SCSI commands
+ *	that can be handled internally.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
+			      struct scsi_cmnd *cmd,
+			      void (*done)(struct scsi_cmnd *))
+{
+	struct ata_scsi_args args;
+	u8 *scsicmd = cmd->cmnd;
+
+	args.ap = ap;
+	args.dev = dev;
+	args.cmd = cmd;
+	args.done = done;
+
+	switch(scsicmd[0]) {
+		case TEST_UNIT_READY:		/* FIXME: correct? */
+		case FORMAT_UNIT:		/* FIXME: correct? */
+		case SEND_DIAGNOSTIC:		/* FIXME: correct? */
+			ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+			break;
+
+		case INQUIRY:
+			if (scsicmd[1] & 2)	           /* is CmdDt set?  */
+				ata_bad_cdb(cmd, done);
+			else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
+			else if (scsicmd[2] == 0x00)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
+			else if (scsicmd[2] == 0x80)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
+			else if (scsicmd[2] == 0x83)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
+			else
+				ata_bad_cdb(cmd, done);
+			break;
+
+		case MODE_SENSE:
+		case MODE_SENSE_10:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
+			break;
+
+		case MODE_SELECT:	/* unconditionally return */
+		case MODE_SELECT_10:	/* bad-field-in-cdb */
+			ata_bad_cdb(cmd, done);
+			break;
+
+		case READ_CAPACITY:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+			break;
+
+		case SERVICE_ACTION_IN:
+			if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+			else
+				ata_bad_cdb(cmd, done);
+			break;
+
+		case REPORT_LUNS:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
+			break;
+
+		/* mandantory commands we haven't implemented yet */
+		case REQUEST_SENSE:
+
+		/* all other commands */
+		default:
+			ata_bad_scsiop(cmd, done);
+			break;
+	}
+}
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/libata.h linux-2.4.27-pre3/drivers/scsi/libata.h
--- linux-2.4.26/drivers/scsi/libata.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/libata.h	2004-05-18 16:51:59.000000000 +0000
@@ -0,0 +1,91 @@
+/*
+   libata.h - helper library for ATA
+
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+ */
+
+#ifndef __LIBATA_H__
+#define __LIBATA_H__
+
+#define DRV_NAME	"libata"
+#define DRV_VERSION	"1.02"	/* must be exactly four chars */
+
+struct ata_scsi_args {
+	struct ata_port		*ap;
+	struct ata_device	*dev;
+	struct scsi_cmnd		*cmd;
+	void			(*done)(struct scsi_cmnd *);
+};
+
+
+/* libata-core.c */
+extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
+			      unsigned int ofs, unsigned int len);
+extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
+				      struct ata_device *dev);
+extern int ata_qc_issue(struct ata_queued_cmd *qc);
+extern void ata_dev_select(struct ata_port *ap, unsigned int device,
+                           unsigned int wait, unsigned int can_sleep);
+extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf);
+extern void atapi_start(struct ata_queued_cmd *qc);
+
+
+/* libata-scsi.c */
+extern void ata_to_sense_error(struct ata_queued_cmd *qc);
+extern int ata_scsi_error(struct Scsi_Host *host);
+extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
+			       unsigned int buflen);
+
+extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen);
+
+extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen);
+extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen);
+extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
+			    unsigned int buflen);
+extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
+				  unsigned int buflen);
+extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
+				  unsigned int buflen);
+extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
+			        unsigned int buflen);
+extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
+				   unsigned int buflen);
+extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
+			    void (*done)(struct scsi_cmnd *),
+			    u8 asc, u8 ascq);
+extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, 
+                        unsigned int (*actor) (struct ata_scsi_args *args,
+                                           u8 *rbuf, unsigned int buflen));
+
+static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	ata_scsi_badcmd(cmd, done, 0x20, 0x00);
+}
+
+static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	ata_scsi_badcmd(cmd, done, 0x24, 0x00);
+}
+
+#endif /* __LIBATA_H__ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/megaraid2.c linux-2.4.27-pre3/drivers/scsi/megaraid2.c
--- linux-2.4.26/drivers/scsi/megaraid2.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/megaraid2.c	2004-05-18 16:51:55.000000000 +0000
@@ -14,7 +14,10 @@
  *	  - speed-ups (list handling fixes, issued_list, optimizations.)
  *	  - lots of cleanups.
  *
- * Version : v2.10.1 (Dec 03, 2003) - Atul Mukker <Atul.Mukker@lsil.com>
+ * Version : v2.10.3 (Apr 08, 2004)
+ *
+ * Authors:	Atul Mukker <Atul.Mukker@lsil.com>
+ *		Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
  *
  * Description: Linux device driver for LSI Logic MegaRAID controller
  *
@@ -23,8 +26,6 @@
  *
  * This driver is supported by LSI Logic, with assistance from Red Hat, Dell,
  * and others. Please send updates to the public mailing list
- * linux-megaraid-devel@dell.com, and subscribe to and read archives of this
- * list at http://lists.us.dell.com/.
  *
  * For history of changes, see ChangeLog.megaraid.
  *
@@ -45,6 +46,10 @@
 
 #include "megaraid2.h"
 
+#ifdef LSI_CONFIG_COMPAT
+#include <asm/ioctl32.h>
+#endif
+
 MODULE_AUTHOR ("LSI Logic Corporation");
 MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");
 MODULE_LICENSE ("GPL");
@@ -206,6 +211,10 @@ megaraid_detect(Scsi_Host_Template *host
 		 */
 		major = register_chrdev(0, "megadev", &megadev_fops);
 
+		if (major < 0) {
+			printk(KERN_WARNING
+				"megaraid: failed to register char device.\n");
+		}
 		/*
 		 * Register the Shutdown Notification hook in kernel
 		 */
@@ -214,6 +223,13 @@ megaraid_detect(Scsi_Host_Template *host
 				"MegaRAID Shutdown routine not registered!!\n");
 		}
 
+#ifdef LSI_CONFIG_COMPAT
+		/*
+		 * Register the 32-bit ioctl conversion
+		 */
+		register_ioctl32_conversion(MEGAIOCCMD, megadev_compat_ioctl);
+#endif
+
 	}
 
 	return hba_count;
@@ -311,6 +327,7 @@ mega_find_card(Scsi_Host_Template *host_
 				(subsysvid != DELL_SUBSYS_VID) &&
 				(subsysvid != HP_SUBSYS_VID) &&
 				(subsysvid != INTEL_SUBSYS_VID) &&
+				(subsysvid != FSC_SUBSYS_VID) &&
 				(subsysvid != LSI_SUBSYS_VID) ) continue;
 
 
@@ -403,7 +420,8 @@ mega_find_card(Scsi_Host_Template *host_
 		scsi_set_host_lock(&adapter->lock);
 #  endif
 #else
-		/* And this is the remainder of the 2.4 kernel series */
+		/* And this is the remainder of the 2.4 kernel
+		series */
 		adapter->host_lock = &io_request_lock;
 #endif
 
@@ -620,12 +638,15 @@ mega_find_card(Scsi_Host_Template *host_
 
 		/* Set the Mode of addressing to 64 bit if we can */
 		if((adapter->flag & BOARD_64BIT)&&(sizeof(dma_addr_t) == 8)) {
-			pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
-			adapter->has_64bit_addr = 1;
+			if (pci_set_dma_mask(pdev, 0xffffffffffffffffULL) == 0)
+				adapter->has_64bit_addr = 1;
 		}
-		else  {
-			pci_set_dma_mask(pdev, 0xffffffff);
-			adapter->has_64bit_addr = 0;
+		if (!adapter->has_64bit_addr)  {
+			if (pci_set_dma_mask(pdev, 0xffffffffULL) != 0) {
+				printk("megaraid%d: DMA not available.\n",
+					host->host_no);
+				goto fail_attach;
+			}
 		}
 
 		init_MUTEX(&adapter->int_mtx);
@@ -2249,26 +2270,28 @@ mega_free_scb(adapter_t *adapter, scb_t 
 		break;
 
 	case MEGA_BULK_DATA:
-		pci_unmap_page(adapter->dev, scb->dma_h_bulkdata,
-			scb->cmd->request_bufflen, scb->dma_direction);
-
 		if( scb->dma_direction == PCI_DMA_FROMDEVICE ) {
 			pci_dma_sync_single(adapter->dev, scb->dma_h_bulkdata,
 					scb->cmd->request_bufflen,
 					PCI_DMA_FROMDEVICE);
 		}
 
+		pci_unmap_page(adapter->dev, scb->dma_h_bulkdata,
+			scb->cmd->request_bufflen, scb->dma_direction);
+
 		break;
 
 	case MEGA_SGLIST:
-		pci_unmap_sg(adapter->dev, scb->cmd->request_buffer,
-			scb->cmd->use_sg, scb->dma_direction);
-
 		if( scb->dma_direction == PCI_DMA_FROMDEVICE ) {
-			pci_dma_sync_sg(adapter->dev, scb->cmd->request_buffer,
-					scb->cmd->use_sg, PCI_DMA_FROMDEVICE);
+			pci_dma_sync_sg(adapter->dev,
+				(struct scatterlist *)scb->cmd->request_buffer,
+				scb->cmd->use_sg, PCI_DMA_FROMDEVICE);
 		}
 
+		pci_unmap_sg(adapter->dev,
+			(struct scatterlist *)scb->cmd->request_buffer,
+			scb->cmd->use_sg, scb->dma_direction);
+
 		break;
 
 	default:
@@ -2402,8 +2425,9 @@ mega_build_sglist(adapter_t *adapter, sc
 	*len = (u32)cmd->request_bufflen;
 
 	if( scb->dma_direction == PCI_DMA_TODEVICE ) {
-		pci_dma_sync_sg(adapter->dev, cmd->request_buffer,
-				cmd->use_sg, PCI_DMA_TODEVICE);
+		pci_dma_sync_sg(adapter->dev,
+			(struct scatterlist *)cmd->request_buffer,
+			cmd->use_sg, PCI_DMA_TODEVICE);
 	}
 
 	/* Return count of SG requests */
@@ -2474,7 +2498,9 @@ megaraid_release(struct Scsi_Host *host)
 	memset(raw_mbox, 0, sizeof(raw_mbox));
 	raw_mbox[0] = FLUSH_ADAPTER;
 
-	irq_disable(adapter);
+	if (adapter->flag & BOARD_IOMAP)
+		irq_disable(adapter);
+
 	free_irq(adapter->host->irq, adapter);
 
 	/* Issue a blocking (interrupts disabled) command to the card */
@@ -2549,7 +2575,9 @@ megaraid_release(struct Scsi_Host *host)
 		/*
 		 * Unregister the character device interface to the driver.
 		 */
-		unregister_chrdev(major, "megadev");
+		if (major >= 0) {
+			unregister_chrdev(major, "megadev");
+		}
 
 		unregister_reboot_notifier(&mega_notifier);
 
@@ -2568,6 +2596,9 @@ megaraid_release(struct Scsi_Host *host)
 	 */
 	scsi_unregister(host);
 
+#ifdef LSI_CONFIG_COMPAT
+	unregister_ioctl32_conversion(MEGAIOCCMD);
+#endif
 
 	printk("ok.\n");
 
@@ -3392,7 +3423,11 @@ proc_pdrv(adapter_t *adapter, char *page
 
 	max_channels = adapter->product_info.nchannels;
 
-	if( channel >= max_channels ) return 0;
+	if (channel >= max_channels) {
+		pci_free_consistent(pdev, 256, scsi_inq, scsi_inq_dma_handle);
+		mega_free_inquiry(inquiry, dma_handle, pdev);
+		return 0;
+	}
 
 	for( tgt = 0; tgt <= MAX_TARGET; tgt++ ) {
 
@@ -3860,153 +3895,6 @@ proc_rdrv(adapter_t *adapter, char *page
 
 
 /**
- * megaraid_biosparam()
- * @disk
- * @dev
- * @geom
- *
- * Return the disk geometry for a particular disk
- * Input:
- *	Disk *disk - Disk geometry
- *	kdev_t dev - Device node
- *	int *geom  - Returns geometry fields
- *		geom[0] = heads
- *		geom[1] = sectors
- *		geom[2] = cylinders
- */
-static int
-megaraid_biosparam(Disk *disk, kdev_t dev, int *geom)
-{
-	int heads, sectors, cylinders;
-	adapter_t *adapter;
-
-	/* Get pointer to host config structure */
-	adapter = (adapter_t *)disk->device->host->hostdata;
-
-	if (IS_RAID_CH(adapter, disk->device->channel)) {
-			/* Default heads (64) & sectors (32) */
-			heads = 64;
-			sectors = 32;
-			cylinders = disk->capacity / (heads * sectors);
-
-			/*
-			 * Handle extended translation size for logical drives
-			 * > 1Gb
-			 */
-			if (disk->capacity >= 0x200000) {
-				heads = 255;
-				sectors = 63;
-				cylinders = disk->capacity / (heads * sectors);
-			}
-
-			/* return result */
-			geom[0] = heads;
-			geom[1] = sectors;
-			geom[2] = cylinders;
-	}
-	else {
-		if( !mega_partsize(disk, dev, geom) )
-			return 0;
-
-		printk(KERN_WARNING
-		"megaraid: invalid partition on this disk on channel %d\n",
-				disk->device->channel);
-
-		/* Default heads (64) & sectors (32) */
-		heads = 64;
-		sectors = 32;
-		cylinders = disk->capacity / (heads * sectors);
-
-		/* Handle extended translation size for logical drives > 1Gb */
-		if (disk->capacity >= 0x200000) {
-			heads = 255;
-			sectors = 63;
-			cylinders = disk->capacity / (heads * sectors);
-		}
-
-		/* return result */
-		geom[0] = heads;
-		geom[1] = sectors;
-		geom[2] = cylinders;
-	}
-
-	return 0;
-}
-
-/*
- * mega_partsize()
- * @disk
- * @geom
- *
- * Purpose : to determine the BIOS mapping used to create the partition
- *	table, storing the results (cyls, hds, and secs) in geom
- *
- * Note:	Code is picked from scsicam.h
- *
- * Returns : -1 on failure, 0 on success.
- */
-static int
-mega_partsize(Disk *disk, kdev_t dev, int *geom)
-{
-	struct buffer_head *bh;
-	struct partition *p, *largest = NULL;
-	int i, largest_cyl;
-	int heads, cyls, sectors;
-	int capacity = disk->capacity;
-
-	int ma = MAJOR(dev);
-	int mi = (MINOR(dev) & ~0xf);
-
-	int block = 1024; 
-
-	if (blksize_size[ma])
-		block = blksize_size[ma][mi];
-
-	if (!(bh = bread(MKDEV(ma,mi), 0, block)))
-		return -1;
-
-	if (*(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
-
-		for (largest_cyl = -1,
-			p = (struct partition *)(0x1BE + bh->b_data), i = 0;
-			i < 4; ++i, ++p) {
-
-			if (!p->sys_ind) continue;
-
-			cyls = p->end_cyl + ((p->end_sector & 0xc0) << 2);
-
-			if (cyls >= largest_cyl) {
-				largest_cyl = cyls;
-				largest = p;
-			}
-		}
-	}
-
-	if (largest) {
-		heads = largest->end_head + 1;
-		sectors = largest->end_sector & 0x3f;
-
-		if (!heads || !sectors) {
-			brelse(bh);
-			return -1;
-		}
-
-		cyls = capacity/(heads * sectors);
-
-		geom[0] = heads;
-		geom[1] = sectors;
-		geom[2] = cyls;
-
-		brelse(bh);
-		return 0;
-	}
-
-	brelse(bh);
-	return -1;
-}
-
-
-/**
  * megaraid_reboot_notify()
  * @this - unused
  * @code - shutdown code
@@ -4040,7 +3928,9 @@ megaraid_reboot_notify (struct notifier_
 		memset(raw_mbox, 0, sizeof(raw_mbox));
 		raw_mbox[0] = FLUSH_ADAPTER;
 
-		irq_disable(adapter);
+		if (adapter->flag & BOARD_IOMAP)
+			irq_disable(adapter);
+
 		free_irq(adapter->host->irq, adapter);
 
 		/*
@@ -4179,6 +4069,18 @@ megadev_open (struct inode *inode, struc
 }
 
 
+#ifdef LSI_CONFIG_COMPAT
+static int
+megadev_compat_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg,
+		struct file *filep)
+{
+	struct inode *inode = filep->f_dentry->d_inode;
+
+	return megadev_ioctl(inode, filep, cmd, arg);
+}
+#endif
+
+
 /**
  * megadev_ioctl()
  * @inode - Our device inode
@@ -4386,8 +4288,8 @@ megadev_ioctl(struct inode *inode, struc
 			/*
 			 * The user passthru structure
 			 */
-			upthru = (mega_passthru *)MBOX(uioc)->xferaddr;
-
+			upthru = (mega_passthru *)
+					((ulong)(MBOX(uioc)->xferaddr));
 			/*
 			 * Copy in the user passthru here.
 			 */
@@ -4434,8 +4336,9 @@ megadev_ioctl(struct inode *inode, struc
 				/*
 				 * Get the user data
 				 */
-				if( copy_from_user(data, (char *)uxferaddr,
-							pthru->dataxferlen) ) {
+				if( copy_from_user(data,
+						(char *)((ulong)uxferaddr),
+						pthru->dataxferlen) ) {
 					rval = (-EFAULT);
 					goto freemem_and_return;
 				}
@@ -4460,8 +4363,8 @@ megadev_ioctl(struct inode *inode, struc
 			 * Is data going up-stream
 			 */
 			if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) {
-				if( copy_to_user((char *)uxferaddr, data,
-							pthru->dataxferlen) ) {
+				if( copy_to_user((char *)((ulong)uxferaddr),
+						data, pthru->dataxferlen) ) {
 					rval = (-EFAULT);
 				}
 			}
@@ -4509,12 +4412,13 @@ freemem_and_return:
 				/*
 				 * Get the user data
 				 */
-				if( copy_from_user(data, (char *)uxferaddr,
-							uioc.xferlen) ) {
+				if( copy_from_user(data,
+						(char *)((ulong)uxferaddr),
+						uioc.xferlen) ) {
 
 					pci_free_consistent(pdev,
-							uioc.xferlen,
-							data, data_dma_hndl);
+						uioc.xferlen, data,
+						data_dma_hndl);
 
 					return (-EFAULT);
 				}
@@ -4545,8 +4449,8 @@ freemem_and_return:
 			 * Is data going up-stream
 			 */
 			if( uioc.xferlen && (uioc.flags & UIOC_RD) ) {
-				if( copy_to_user((char *)uxferaddr, data,
-							uioc.xferlen) ) {
+				if( copy_to_user((char *)((ulong)uxferaddr),
+						data, uioc.xferlen) ) {
 
 					rval = (-EFAULT);
 				}
@@ -4731,7 +4635,7 @@ mega_n_to_m(void *arg, megacmd_t *mc)
 
 			umc = MBOX_P(uiocp);
 
-			upthru = (mega_passthru *)umc->xferaddr;
+			upthru = (mega_passthru *)((ulong)(umc->xferaddr));
 
 			if( put_user(mc->status, (u8 *)&upthru->scsistatus) )
 				return (-EFAULT);
@@ -4749,7 +4653,7 @@ mega_n_to_m(void *arg, megacmd_t *mc)
 			if (copy_from_user(&kmc, umc, sizeof(megacmd_t)))
 				return -EFAULT;
 
-			upthru = (mega_passthru *)kmc.xferaddr;
+			upthru = (mega_passthru *)((ulong)kmc.xferaddr);
 
 			if( put_user(mc->status, (u8 *)&upthru->scsistatus) )
 				return (-EFAULT);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/megaraid2.h linux-2.4.27-pre3/drivers/scsi/megaraid2.h
--- linux-2.4.26/drivers/scsi/megaraid2.h	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/megaraid2.h	2004-05-18 16:50:50.000000000 +0000
@@ -6,7 +6,7 @@
 
 
 #define MEGARAID_VERSION	\
-	"v2.10.1 (Release Date: Wed Dec  3 15:34:42 EST 2003)\n"
+	"v2.10.3 (Release Date: Thu Apr  8 16:16:05 EDT 2004)\n"
 
 /*
  * Driver features - change the values to enable or disable features in the
@@ -44,12 +44,6 @@
  */
 #define MEGA_HAVE_ENH_PROC	1
 
-#define MAX_DEV_TYPE	32
-
-#ifndef PCI_VENDOR_ID_LSI_LOGIC
-#define PCI_VENDOR_ID_LSI_LOGIC		0x1000
-#endif
-
 #ifndef PCI_VENDOR_ID_AMI
 #define PCI_VENDOR_ID_AMI		0x101E
 #endif
@@ -87,6 +81,7 @@
 #define	HP_SUBSYS_VID			0x103C
 #define LSI_SUBSYS_VID			0x1000
 #define INTEL_SUBSYS_VID		0x8086
+#define FSC_SUBSYS_VID			0x1734
 
 #define HBA_SIGNATURE	      		0x3344
 #define HBA_SIGNATURE_471	  	0xCCCC
@@ -134,7 +129,6 @@
 	.info =				megaraid_info,		\
 	.command =			megaraid_command,	\
 	.queuecommand =			megaraid_queue,		\
-	.bios_param =			megaraid_biosparam,	\
 	.max_sectors =			MAX_SECTORS_PER_IO,	\
 	.can_queue =			MAX_COMMANDS,		\
 	.this_id =			DEFAULT_INITIATOR_ID,	\
@@ -662,6 +656,9 @@ typedef struct {
  */
 #define MEGAIOC_MAGIC  	'm'
 
+/* Mega IOCTL command */
+#define MEGAIOCCMD     	_IOWR(MEGAIOC_MAGIC, 0, struct uioctl_t)
+
 #define MEGAIOC_QNADAP		'm'	/* Query # of adapters */
 #define MEGAIOC_QDRVRVER	'e'	/* Query driver version */
 #define MEGAIOC_QADAPINFO   	'g'	/* Query adapter information */
@@ -1115,7 +1112,6 @@ static int megaraid_release (struct Scsi
 static int megaraid_command (Scsi_Cmnd *);
 static int megaraid_abort(Scsi_Cmnd *);
 static int megaraid_reset(Scsi_Cmnd *);
-static int megaraid_biosparam (Disk *, kdev_t, int *);
 
 static int mega_build_sglist (adapter_t *adapter, scb_t *scb,
 			      u32 *buffer, u32 *length);
@@ -1129,6 +1125,16 @@ static void mega_8_to_40ld (mraid_inquir
 static int megaraid_reboot_notify (struct notifier_block *,
 				   unsigned long, void *);
 static int megadev_open (struct inode *, struct file *);
+
+#if defined(CONFIG_COMPAT) || defined( __x86_64__) || defined(IA32_EMULATION)
+#define LSI_CONFIG_COMPAT
+#endif
+
+#ifdef LSI_CONFIG_COMPAT
+static int megadev_compat_ioctl(unsigned int, unsigned int, unsigned long,
+	struct file *);
+#endif
+
 static int megadev_ioctl (struct inode *, struct file *, unsigned int,
 		unsigned long);
 static int mega_m_to_n(void *, nitioctl_t *);
@@ -1172,7 +1178,6 @@ static mega_passthru* mega_prepare_passt
 static mega_ext_passthru* mega_prepare_extpassthru(adapter_t *,
 		scb_t *, Scsi_Cmnd *, int, int);
 static void mega_enum_raid_scsi(adapter_t *);
-static int mega_partsize(Disk *, kdev_t, int *);
 static void mega_get_boot_drv(adapter_t *);
 static inline int mega_get_ldrv_num(adapter_t *, Scsi_Cmnd *, int);
 static int mega_support_random_del(adapter_t *);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/oktagon_esp.c linux-2.4.27-pre3/drivers/scsi/oktagon_esp.c
--- linux-2.4.26/drivers/scsi/oktagon_esp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/oktagon_esp.c	2004-05-18 16:51:02.000000000 +0000
@@ -548,7 +548,7 @@ static void dma_invalidate(struct NCR_ES
 
 void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
-        sp->SCp.have_data_in = (int) sp->SCp.ptr =
+        sp->SCp.ptr =
                 sp->request_buffer;
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/sata_promise.c linux-2.4.27-pre3/drivers/scsi/sata_promise.c
--- linux-2.4.26/drivers/scsi/sata_promise.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/sata_promise.c	2004-05-18 16:50:49.000000000 +0000
@@ -0,0 +1,661 @@
+/*
+ *  sata_promise.c - Promise SATA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+#include <asm/io.h>
+#include "sata_promise.h"
+
+#define DRV_NAME	"sata_promise"
+#define DRV_VERSION	"1.00"
+
+
+enum {
+	PDC_PKT_SUBMIT		= 0x40, /* Command packet pointer addr */
+	PDC_INT_SEQMASK		= 0x40,	/* Mask of asserted SEQ INTs */
+	PDC_TBG_MODE		= 0x41,	/* TBG mode */
+	PDC_FLASH_CTL		= 0x44, /* Flash control register */
+	PDC_PCI_CTL		= 0x48, /* PCI control and status register */
+	PDC_GLOBAL_CTL		= 0x48, /* Global control/status (per port) */
+	PDC_CTLSTAT		= 0x60,	/* IDE control and status (per port) */
+	PDC_SATA_PLUG_CSR	= 0x6C, /* SATA Plug control/status reg */
+	PDC_SLEW_CTL		= 0x470, /* slew rate control reg */
+
+	PDC_ERR_MASK		= (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+				  (1<<8) | (1<<9) | (1<<10),
+
+	board_2037x		= 0,	/* FastTrak S150 TX2plus */
+	board_20319		= 1,	/* FastTrak S150 TX4 */
+
+	PDC_HAS_PATA		= (1 << 1), /* PDC20375 has PATA */
+
+	PDC_RESET		= (1 << 11), /* HDMA reset */
+};
+
+
+struct pdc_port_priv {
+	u8			*pkt;
+	dma_addr_t		pkt_dma;
+};
+
+static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void pdc_dma_start(struct ata_queued_cmd *qc);
+static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void pdc_eng_timeout(struct ata_port *ap);
+static int pdc_port_start(struct ata_port *ap);
+static void pdc_port_stop(struct ata_port *ap);
+static void pdc_phy_reset(struct ata_port *ap);
+static void pdc_fill_sg(struct ata_queued_cmd *qc);
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static inline void pdc_dma_complete (struct ata_port *ap,
+                                     struct ata_queued_cmd *qc, int have_err);
+
+static Scsi_Host_Template pdc_sata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.detect			= ata_scsi_detect,
+	.release		= ata_scsi_release,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.use_new_eh_code	= ATA_SHT_NEW_EH_CODE,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations pdc_sata_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= pdc_tf_load_mmio,
+	.tf_read		= ata_tf_read_mmio,
+	.check_status		= ata_check_status_mmio,
+	.exec_command		= pdc_exec_command_mmio,
+	.phy_reset		= pdc_phy_reset,
+	.bmdma_start            = pdc_dma_start,
+	.fill_sg		= pdc_fill_sg,
+	.eng_timeout		= pdc_eng_timeout,
+	.irq_handler		= pdc_interrupt,
+	.scr_read		= pdc_sata_scr_read,
+	.scr_write		= pdc_sata_scr_write,
+	.port_start		= pdc_port_start,
+	.port_stop		= pdc_port_stop,
+};
+
+static struct ata_port_info pdc_port_info[] = {
+	/* board_2037x */
+	{
+		.sht		= &pdc_sata_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x03, /* pio3-4 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_sata_ops,
+	},
+
+	/* board_20319 */
+	{
+		.sht		= &pdc_sata_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x03, /* pio3-4 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_sata_ops,
+	},
+};
+
+static struct pci_device_id pdc_sata_pci_tbl[] = {
+	{ PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_20319 },
+	{ PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_20319 },
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver pdc_sata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= pdc_sata_pci_tbl,
+	.probe			= pdc_sata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static int pdc_port_start(struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+	struct pdc_port_priv *pp;
+	int rc;
+
+	rc = ata_port_start(ap);
+	if (rc)
+		return rc;
+
+	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+	if (!pp) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	memset(pp, 0, sizeof(*pp));
+
+	pp->pkt = pci_alloc_consistent(pdev, 128, &pp->pkt_dma);
+	if (!pp->pkt) {
+		rc = -ENOMEM;
+		goto err_out_kfree;
+	}
+
+	ap->private_data = pp;
+
+	return 0;
+
+err_out_kfree:
+	kfree(pp);
+err_out:
+	ata_port_stop(ap);
+	return rc;
+}
+
+
+static void pdc_port_stop(struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+	struct pdc_port_priv *pp = ap->private_data;
+
+	ap->private_data = NULL;
+	pci_free_consistent(pdev, 128, pp->pkt, pp->pkt_dma);
+	kfree(pp);
+	ata_port_stop(ap);
+}
+
+
+static void pdc_reset_port(struct ata_port *ap)
+{
+	void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+	unsigned int i;
+	u32 tmp;
+
+	for (i = 11; i > 0; i--) {
+		tmp = readl(mmio);
+		if (tmp & PDC_RESET)
+			break;
+
+		udelay(100);
+
+		tmp |= PDC_RESET;
+		writel(tmp, mmio);
+	}
+
+	tmp &= ~PDC_RESET;
+	writel(tmp, mmio);
+	readl(mmio);	/* flush */
+}
+
+static void pdc_phy_reset(struct ata_port *ap)
+{
+	pdc_reset_port(ap);
+	sata_phy_reset(ap);
+}
+
+static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+			       u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void pdc_fill_sg(struct ata_queued_cmd *qc)
+{
+	struct pdc_port_priv *pp = qc->ap->private_data;
+	unsigned int i;
+
+	VPRINTK("ENTER\n");
+
+	ata_fill_sg(qc);
+
+	i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,  qc->dev->devno, pp->pkt);
+
+	if (qc->tf.flags & ATA_TFLAG_LBA48)
+		i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
+	else
+		i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
+
+	pdc_pkt_footer(&qc->tf, pp->pkt, i);
+}
+
+static inline void pdc_dma_complete (struct ata_port *ap,
+                                     struct ata_queued_cmd *qc,
+				     int have_err)
+{
+	u8 err_bit = have_err ? ATA_ERR : 0;
+
+	/* get drive status; clear intr; complete txn */
+	ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+			ata_wait_idle(ap) | err_bit, 0);
+}
+
+static void pdc_eng_timeout(struct ata_port *ap)
+{
+	u8 drv_stat;
+	struct ata_queued_cmd *qc;
+
+	DPRINTK("ENTER\n");
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+		goto out;
+	}
+
+	/* hack alert!  We cannot use the supplied completion
+	 * function from inside the ->eh_strategy_handler() thread.
+	 * libata is the only user of ->eh_strategy_handler() in
+	 * any kernel, so the default scsi_done() assumes it is
+	 * not being called from the SCSI EH.
+	 */
+	qc->scsidone = scsi_finish_command;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		printk(KERN_ERR "ata%u: DMA timeout\n", ap->id);
+		ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+			        ata_wait_idle(ap) | ATA_ERR, 0);
+		break;
+
+	case ATA_PROT_NODATA:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat, 1);
+		break;
+
+	default:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat, 1);
+		break;
+	}
+
+out:
+	DPRINTK("EXIT\n");
+}
+
+static inline unsigned int pdc_host_intr( struct ata_port *ap,
+                                          struct ata_queued_cmd *qc)
+{
+	u8 status;
+	unsigned int handled = 0, have_err = 0;
+	u32 tmp;
+	void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+
+	tmp = readl(mmio);
+	if (tmp & PDC_ERR_MASK) {
+		have_err = 1;
+		pdc_reset_port(ap);
+	}
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		pdc_dma_complete(ap, qc, have_err);
+		handled = 1;
+		break;
+
+	case ATA_PROT_NODATA:   /* command completion, but no data xfer */
+		status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+		DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+		if (have_err)
+			status |= ATA_ERR;
+		ata_qc_complete(qc, status, 0);
+		handled = 1;
+		break;
+
+        default:
+                ap->stats.idle_irq++;
+                break;
+        }
+
+        return handled;
+}
+
+static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	struct ata_port *ap;
+	u32 mask = 0;
+	unsigned int i, tmp;
+	unsigned int handled = 0;
+	void *mmio_base;
+
+	VPRINTK("ENTER\n");
+
+	if (!host_set || !host_set->mmio_base) {
+		VPRINTK("QUICK EXIT\n");
+		return IRQ_NONE;
+	}
+
+	mmio_base = host_set->mmio_base;
+
+	/* reading should also clear interrupts */
+	mask = readl(mmio_base + PDC_INT_SEQMASK);
+
+	if (mask == 0xffffffff) {
+		VPRINTK("QUICK EXIT 2\n");
+		return IRQ_NONE;
+	}
+	mask &= 0xffff;		/* only 16 tags possible */
+	if (!mask) {
+		VPRINTK("QUICK EXIT 3\n");
+		return IRQ_NONE;
+	}
+
+        spin_lock(&host_set->lock);
+
+        for (i = 0; i < host_set->n_ports; i++) {
+		VPRINTK("port %u\n", i);
+		ap = host_set->ports[i];
+		tmp = mask & (1 << (i + 1));
+		if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
+				handled += pdc_host_intr(ap, qc);
+		}
+	}
+
+        spin_unlock(&host_set->lock);
+
+	VPRINTK("EXIT\n");
+
+	return IRQ_RETVAL(handled);
+}
+
+static void pdc_dma_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_port_priv *pp = ap->private_data;
+	unsigned int port_no = ap->port_no;
+	u8 seq = (u8) (port_no + 1);
+
+	VPRINTK("ENTER, ap %p\n", ap);
+
+	writel(0x00000001, ap->host_set->mmio_base + (seq * 4));
+	readl(ap->host_set->mmio_base + (seq * 4));	/* flush */
+
+	pp->pkt[2] = seq;
+	wmb();			/* flush PRD, pkt writes */
+	writel(pp->pkt_dma, (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+	readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
+}
+
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (tf->protocol == ATA_PROT_PIO)
+		ata_tf_load_mmio(ap, tf);
+}
+
+
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (tf->protocol == ATA_PROT_PIO)
+		ata_exec_command_mmio(ap, tf);
+}
+
+
+static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base;
+	port->data_addr		= base;
+	port->feature_addr	=
+	port->error_addr	= base + 0x4;
+	port->nsect_addr	= base + 0x8;
+	port->lbal_addr		= base + 0xc;
+	port->lbam_addr		= base + 0x10;
+	port->lbah_addr		= base + 0x14;
+	port->device_addr	= base + 0x18;
+	port->command_addr	=
+	port->status_addr	= base + 0x1c;
+	port->altstatus_addr	=
+	port->ctl_addr		= base + 0x38;
+}
+
+
+static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+{
+	void *mmio = pe->mmio_base;
+	u32 tmp;
+
+	/*
+	 * Except for the hotplug stuff, this is voodoo from the
+	 * Promise driver.  Label this entire section
+	 * "TODO: figure out why we do this"
+	 */
+
+	/* change FIFO_SHD to 8 dwords, enable BMR_BURST */
+	tmp = readl(mmio + PDC_FLASH_CTL);
+	tmp |= 0x12000;	/* bit 16 (fifo 8 dw) and 13 (bmr burst?) */
+	writel(tmp, mmio + PDC_FLASH_CTL);
+
+	/* clear plug/unplug flags for all ports */
+	tmp = readl(mmio + PDC_SATA_PLUG_CSR);
+	writel(tmp | 0xff, mmio + PDC_SATA_PLUG_CSR);
+
+	/* mask plug/unplug ints */
+	tmp = readl(mmio + PDC_SATA_PLUG_CSR);
+	writel(tmp | 0xff0000, mmio + PDC_SATA_PLUG_CSR);
+
+	/* reduce TBG clock to 133 Mhz. */
+	tmp = readl(mmio + PDC_TBG_MODE);
+	tmp &= ~0x30000; /* clear bit 17, 16*/
+	tmp |= 0x10000;  /* set bit 17:16 = 0:1 */
+	writel(tmp, mmio + PDC_TBG_MODE);
+
+	readl(mmio + PDC_TBG_MODE);	/* flush */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(msecs_to_jiffies(10) + 1);
+
+	/* adjust slew rate control register. */
+	tmp = readl(mmio + PDC_SLEW_CTL);
+	tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */
+	tmp  |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */
+	writel(tmp, mmio + PDC_SLEW_CTL);
+}
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base;
+	unsigned int board_idx = (unsigned int) ent->driver_data;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/*
+	 * If this driver happens to only be useful on Apple's K2, then
+	 * we should check that here as it has a normal Serverworks ID
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->pdev = pdev;
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 3),
+		            pci_resource_len(pdev, 3));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	probe_ent->sht		= pdc_port_info[board_idx].sht;
+	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;
+	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
+	probe_ent->udma_mask	= pdc_port_info[board_idx].udma_mask;
+	probe_ent->port_ops	= pdc_port_info[board_idx].port_ops;
+
+       	probe_ent->irq = pdev->irq;
+       	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
+	pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
+
+	probe_ent->port[0].scr_addr = base + 0x400;
+	probe_ent->port[1].scr_addr = base + 0x500;
+
+	/* notice 4-port boards */
+	switch (board_idx) {
+	case board_20319:
+       		probe_ent->n_ports = 4;
+
+		pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
+		pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+
+		probe_ent->port[2].scr_addr = base + 0x600;
+		probe_ent->port[3].scr_addr = base + 0x700;
+		break;
+	case board_2037x:
+       		probe_ent->n_ports = 2;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	pci_set_master(pdev);
+
+	/* initialize adapter */
+	pdc_host_init(board_idx, probe_ent);
+
+	ata_add_to_probe_list(probe_ent);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+
+static int __init pdc_sata_init(void)
+{
+	int rc;
+
+	rc = pci_module_init(&pdc_sata_pci_driver);
+	if (rc)
+		return rc;
+
+	rc = scsi_register_module(MODULE_SCSI_HA, &pdc_sata_sht);
+	if (rc) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	return 0;
+
+err_out:
+	pci_unregister_driver(&pdc_sata_pci_driver);
+	return rc;
+}
+
+
+static void __exit pdc_sata_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &pdc_sata_sht);
+	pci_unregister_driver(&pdc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Promise SATA TX2/TX4 low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
+
+module_init(pdc_sata_init);
+module_exit(pdc_sata_exit);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/sata_promise.h linux-2.4.27-pre3/drivers/scsi/sata_promise.h
--- linux-2.4.26/drivers/scsi/sata_promise.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/sata_promise.h	2004-05-18 16:55:04.000000000 +0000
@@ -0,0 +1,154 @@
+/*
+ *  sata_promise.h - Promise SATA common definitions and inline funcs
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#ifndef __SATA_PROMISE_H__
+#define __SATA_PROMISE_H__
+
+#include <linux/ata.h>
+
+enum pdc_packet_bits {
+	PDC_PKT_READ		= (1 << 2),
+	PDC_PKT_NODATA		= (1 << 3),
+
+	PDC_PKT_SIZEMASK	= (1 << 7) | (1 << 6) | (1 << 5),
+	PDC_PKT_CLEAR_BSY	= (1 << 4),
+	PDC_PKT_WAIT_DRDY	= (1 << 3) | (1 << 4),
+	PDC_LAST_REG		= (1 << 3),
+
+	PDC_REG_DEVCTL		= (1 << 3) | (1 << 2) | (1 << 1),
+};
+
+static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
+					  dma_addr_t sg_table,
+					  unsigned int devno, u8 *buf)
+{
+	u8 dev_reg;
+	u32 *buf32 = (u32 *) buf;
+
+	/* set control bits (byte 0), zero delay seq id (byte 3),
+	 * and seq id (byte 2)
+	 */
+	switch (tf->protocol) {
+	case ATA_PROT_DMA:
+		if (!(tf->flags & ATA_TFLAG_WRITE))
+			buf32[0] = cpu_to_le32(PDC_PKT_READ);
+		else
+			buf32[0] = 0;
+		break;
+
+	case ATA_PROT_NODATA:
+		buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
+		break;
+
+	default:
+		BUG();
+		break;
+	}
+
+	buf32[1] = cpu_to_le32(sg_table);	/* S/G table addr */
+	buf32[2] = 0;				/* no next-packet */
+
+	if (devno == 0)
+		dev_reg = ATA_DEVICE_OBS;
+	else
+		dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+	/* select device */
+	buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+	buf[13] = dev_reg;
+
+	/* device control register */
+	buf[14] = (1 << 5) | PDC_REG_DEVCTL;
+	buf[15] = tf->ctl;
+
+	return 16; 	/* offset of next byte */
+}
+
+static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
+				  unsigned int i)
+{
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		buf[i++] = (1 << 5) | ATA_REG_DEVICE;
+		buf[i++] = tf->device;
+	}
+
+	/* and finally the command itself; also includes end-of-pkt marker */
+	buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
+	buf[i++] = tf->command;
+
+	return i;
+}
+
+static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+	/* the "(1 << 5)" should be read "(count << 5)" */
+
+	/* ATA command block registers */
+	buf[i++] = (1 << 5) | ATA_REG_FEATURE;
+	buf[i++] = tf->feature;
+
+	buf[i++] = (1 << 5) | ATA_REG_NSECT;
+	buf[i++] = tf->nsect;
+
+	buf[i++] = (1 << 5) | ATA_REG_LBAL;
+	buf[i++] = tf->lbal;
+
+	buf[i++] = (1 << 5) | ATA_REG_LBAM;
+	buf[i++] = tf->lbam;
+
+	buf[i++] = (1 << 5) | ATA_REG_LBAH;
+	buf[i++] = tf->lbah;
+
+	return i;
+}
+
+static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+	/* the "(2 << 5)" should be read "(count << 5)" */
+
+	/* ATA command block registers */
+	buf[i++] = (2 << 5) | ATA_REG_FEATURE;
+	buf[i++] = tf->hob_feature;
+	buf[i++] = tf->feature;
+
+	buf[i++] = (2 << 5) | ATA_REG_NSECT;
+	buf[i++] = tf->hob_nsect;
+	buf[i++] = tf->nsect;
+
+	buf[i++] = (2 << 5) | ATA_REG_LBAL;
+	buf[i++] = tf->hob_lbal;
+	buf[i++] = tf->lbal;
+
+	buf[i++] = (2 << 5) | ATA_REG_LBAM;
+	buf[i++] = tf->hob_lbam;
+	buf[i++] = tf->lbam;
+
+	buf[i++] = (2 << 5) | ATA_REG_LBAH;
+	buf[i++] = tf->hob_lbah;
+	buf[i++] = tf->lbah;
+
+	return i;
+}
+
+
+#endif /* __SATA_PROMISE_H__ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/sata_sil.c linux-2.4.27-pre3/drivers/scsi/sata_sil.c
--- linux-2.4.26/drivers/scsi/sata_sil.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/sata_sil.c	2004-05-18 16:53:26.000000000 +0000
@@ -0,0 +1,448 @@
+/*
+ *  sata_sil.c - Silicon Image SATA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2003 Red Hat, Inc.
+ *  Copyright 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_sil"
+#define DRV_VERSION	"0.54"
+
+enum {
+	sil_3112		= 0,
+	sil_3114		= 1,
+
+	SIL_SYSCFG		= 0x48,
+	SIL_MASK_IDE0_INT	= (1 << 22),
+	SIL_MASK_IDE1_INT	= (1 << 23),
+	SIL_MASK_IDE2_INT	= (1 << 24),
+	SIL_MASK_IDE3_INT	= (1 << 25),
+	SIL_MASK_2PORT		= SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT,
+	SIL_MASK_4PORT		= SIL_MASK_2PORT |
+				  SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
+
+	SIL_IDE2_BMDMA		= 0x200,
+
+	SIL_INTR_STEERING	= (1 << 1),
+	SIL_QUIRK_MOD15WRITE	= (1 << 0),
+	SIL_QUIRK_UDMA5MAX	= (1 << 1),
+};
+
+static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
+static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void sil_post_set_mode (struct ata_port *ap);
+
+static struct pci_device_id sil_pci_tbl[] = {
+	{ 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
+	{ }	/* terminate list */
+};
+
+
+/* TODO firmware versions should be added - eric */
+struct sil_drivelist {
+	const char * product;
+	unsigned int quirk;
+} sil_blacklist [] = {
+	{ "ST320012AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST330013AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST340017AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST360015AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST380023AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST3120023AS",	SIL_QUIRK_MOD15WRITE },
+	{ "ST340014ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "ST360014ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "ST380011ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "ST3120022ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "ST3160021ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "Maxtor 4D060H3",	SIL_QUIRK_UDMA5MAX },
+	{ }
+};
+
+static struct pci_driver sil_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= sil_pci_tbl,
+	.probe			= sil_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template sil_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.detect			= ata_scsi_detect,
+	.release		= ata_scsi_release,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.use_new_eh_code	= ATA_SHT_NEW_EH_CODE,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations sil_ops = {
+	.port_disable		= ata_port_disable,
+	.dev_config		= sil_dev_config,
+	.tf_load		= ata_tf_load_mmio,
+	.tf_read		= ata_tf_read_mmio,
+	.check_status		= ata_check_status_mmio,
+	.exec_command		= ata_exec_command_mmio,
+	.phy_reset		= sata_phy_reset,
+	.post_set_mode		= sil_post_set_mode,
+	.bmdma_start            = ata_bmdma_start_mmio,
+	.fill_sg		= ata_fill_sg,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= ata_interrupt,
+	.scr_read		= sil_scr_read,
+	.scr_write		= sil_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_info sil_port_info[] = {
+	/* sil_3112 */
+	{
+		.sht		= &sil_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x03,			/* pio3-4 */
+		.udma_mask	= 0x3f,			/* udma0-5 */
+		.port_ops	= &sil_ops,
+	}, /* sil_3114 */
+	{
+		.sht		= &sil_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x03,			/* pio3-4 */
+		.udma_mask	= 0x3f,			/* udma0-5 */
+		.port_ops	= &sil_ops,
+	},
+};
+
+/* per-port register offsets */
+/* TODO: we can probably calculate rather than use a table */
+static const struct {
+	unsigned long tf;	/* ATA taskfile register block */
+	unsigned long ctl;	/* ATA control/altstatus register block */
+	unsigned long bmdma;	/* DMA register block */
+	unsigned long scr;	/* SATA control register block */
+	unsigned long sien;	/* SATA Interrupt Enable register */
+	unsigned long xfer_mode;/* data transfer mode register */
+} sil_port[] = {
+	/* port 0 ... */
+	{ 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4 },
+	{ 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4 },
+	{ 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4 },
+	{ 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4 },
+	/* ... port 3 */
+};
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
+
+static void sil_post_set_mode (struct ata_port *ap)
+{
+	struct ata_host_set *host_set = ap->host_set;
+	struct ata_device *dev;
+	void *addr = host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
+	u32 tmp, dev_mode[2];
+	unsigned int i;
+
+	for (i = 0; i < 2; i++) {
+		dev = &ap->device[i];
+		if (!ata_dev_present(dev))
+			dev_mode[i] = 0;	/* PIO0/1/2 */
+		else if (dev->flags & ATA_DFLAG_PIO)
+			dev_mode[i] = 1;	/* PIO3/4 */
+		else
+			dev_mode[i] = 3;	/* UDMA */
+		/* value 2 indicates MDMA */
+	}
+
+	tmp = readl(addr);
+	tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0));
+	tmp |= dev_mode[0];
+	tmp |= (dev_mode[1] << 4);
+	writel(tmp, addr);
+	readl(addr);	/* flush */
+}
+
+static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
+{
+	unsigned long offset = ap->ioaddr.scr_addr;
+
+	switch (sc_reg) {
+	case SCR_STATUS:
+		return offset + 4;
+	case SCR_ERROR:
+		return offset + 8;
+	case SCR_CONTROL:
+		return offset;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	return 0;
+}
+
+static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	void *mmio = (void *) sil_scr_addr(ap, sc_reg);
+	if (mmio)
+		return readl(mmio);
+	return 0xffffffffU;
+}
+
+static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	void *mmio = (void *) sil_scr_addr(ap, sc_reg);
+	if (mmio)
+		writel(val, mmio);
+}
+
+/**
+ *	sil_dev_config - Apply device/host-specific errata fixups
+ *	@ap: Port containing device to be examined
+ *	@dev: Device to be examined
+ *
+ *	After the IDENTIFY [PACKET] DEVICE step is complete, and a
+ *	device is known to be present, this function is called.
+ *	We apply two errata fixups which are specific to Silicon Image,
+ *	a Seagate and a Maxtor fixup.
+ *
+ *	For certain Seagate devices, we must limit the maximum sectors
+ *	to under 8K.
+ *
+ *	For certain Maxtor devices, we must not program the drive
+ *	beyond udma5.
+ *
+ *	Both fixups are unfairly pessimistic.  As soon as I get more
+ *	information on these errata, I will create a more exhaustive
+ *	list, and apply the fixups to only the specific
+ *	devices/hosts/firmwares that need it.
+ *
+ *	20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
+ *	The Maxtor quirk is in the blacklist, but I'm keeping the original
+ *	pessimistic fix for the following reasons:
+ *	- There seems to be less info on it, only one device gleaned off the
+ *	Windows	driver, maybe only one is affected.  More info would be greatly
+ *	appreciated.
+ *	- But then again UDMA5 is hardly anything to complain about
+ */
+static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
+{
+	unsigned int n, quirks = 0;
+	const char *s = &dev->product[0];
+	unsigned int len = strnlen(s, sizeof(dev->product));
+
+	/* ATAPI specifies that empty space is blank-filled; remove blanks */
+	while ((len > 0) && (s[len - 1] == ' '))
+		len--;
+
+	for (n = 0; sil_blacklist[n].product; n++) 
+		if (!memcmp(sil_blacklist[n].product, s,
+			    strlen(sil_blacklist[n].product))) {
+			quirks = sil_blacklist[n].quirk;
+			break;
+		}
+	
+	/* limit requests to 15 sectors */
+	if (quirks & SIL_QUIRK_MOD15WRITE) {
+		printk(KERN_INFO "ata%u(%u): applying Seagate errata fix\n",
+		       ap->id, dev->devno);
+		ap->host->max_sectors = 15;
+		ap->host->hostt->max_sectors = 15;
+		return;
+	}
+
+	/* limit to udma5 */
+	if (quirks & SIL_QUIRK_UDMA5MAX) {
+		printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n",
+		       ap->id, dev->devno, s);
+		ap->udma_mask &= ATA_UDMA5;
+		return;
+	}
+}
+
+static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base;
+	int rc;
+	unsigned int i;
+	u32 tmp, irq_mask;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/*
+	 * If this driver happens to only be useful on Apple's K2, then
+	 * we should check that here as it has a normal Serverworks ID
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	INIT_LIST_HEAD(&probe_ent->node);
+	probe_ent->pdev = pdev;
+	probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
+	probe_ent->sht = sil_port_info[ent->driver_data].sht;
+	probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
+	probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
+	probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
+       	probe_ent->irq = pdev->irq;
+       	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->host_flags = sil_port_info[ent->driver_data].host_flags;
+
+	mmio_base = ioremap(pci_resource_start(pdev, 5),
+		            pci_resource_len(pdev, 5));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+
+	probe_ent->mmio_base = mmio_base;
+
+	base = (unsigned long) mmio_base;
+
+	for (i = 0; i < probe_ent->n_ports; i++) {
+		probe_ent->port[i].cmd_addr = base + sil_port[i].tf;
+		probe_ent->port[i].altstatus_addr =
+		probe_ent->port[i].ctl_addr = base + sil_port[i].ctl;
+		probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma;
+		probe_ent->port[i].scr_addr = base + sil_port[i].scr;
+		ata_std_ports(&probe_ent->port[i]);
+	}
+
+	if (ent->driver_data == sil_3114) {
+		irq_mask = SIL_MASK_4PORT;
+
+		/* flip the magic "make 4 ports work" bit */
+		tmp = readl(mmio_base + SIL_IDE2_BMDMA);
+		if ((tmp & SIL_INTR_STEERING) == 0)
+			writel(tmp | SIL_INTR_STEERING,
+			       mmio_base + SIL_IDE2_BMDMA);
+
+	} else {
+		irq_mask = SIL_MASK_2PORT;
+	}
+
+	/* make sure IDE0/1/2/3 interrupts are not masked */
+	tmp = readl(mmio_base + SIL_SYSCFG);
+	if (tmp & irq_mask) {
+		tmp &= ~irq_mask;
+		writel(tmp, mmio_base + SIL_SYSCFG);
+		readl(mmio_base + SIL_SYSCFG);	/* flush */
+	}
+
+	/* mask all SATA phy-related interrupts */
+	/* TODO: unmask bit 6 (SError N bit) for hotplug */
+	for (i = 0; i < probe_ent->n_ports; i++)
+		writel(0, mmio_base + sil_port[i].sien);
+
+	pci_set_master(pdev);
+
+	ata_add_to_probe_list(probe_ent);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+static int __init sil_init(void)
+{
+	int rc;
+
+	rc = pci_module_init(&sil_pci_driver);
+	if (rc)
+		return rc;
+
+	rc = scsi_register_module(MODULE_SCSI_HA, &sil_sht);
+	if (rc) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	return 0;
+
+err_out:
+	pci_unregister_driver(&sil_pci_driver);
+	return rc;
+}
+
+static void __exit sil_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &sil_sht);
+	pci_unregister_driver(&sil_pci_driver);
+}
+
+
+module_init(sil_init);
+module_exit(sil_exit);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/sata_sis.c linux-2.4.27-pre3/drivers/scsi/sata_sis.c
--- linux-2.4.26/drivers/scsi/sata_sis.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/sata_sis.c	2004-05-18 16:52:57.000000000 +0000
@@ -0,0 +1,293 @@
+/*
+ *  sata_sis.c - Silicon Integrated Systems SATA
+ *
+ *  Maintained by:  Uwe Koziolek
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2004 Uwe Koziolek
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_sis"
+#define DRV_VERSION	"0.10"
+
+enum {
+	sis_180			= 0,
+	SIS_SCR_PCI_BAR		= 5,
+
+	/* PCI configuration registers */
+	SIS_GENCTL		= 0x54, /* IDE General Control register */
+	SIS_SCR_BASE		= 0xc0, /* sata0 phy SCR registers */
+	SIS_SATA1_OFS		= 0x10, /* offset from sata0->sata1 phy regs */
+
+	/* random bits */
+	SIS_FLAG_CFGSCR		= (1 << 30), /* host flag: SCRs via PCI cfg */
+
+	GENCTL_IOMAPPED_SCR	= (1 << 26), /* if set, SCRs are in IO space */
+};
+
+static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+static struct pci_device_id sis_pci_tbl[] = {
+	{ PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+	{ PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver sis_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= sis_pci_tbl,
+	.probe			= sis_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template sis_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.detect			= ata_scsi_detect,
+	.release		= ata_scsi_release,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= ATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.use_new_eh_code	= ATA_SHT_NEW_EH_CODE,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations sis_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= ata_tf_load_pio,
+	.tf_read		= ata_tf_read_pio,
+	.check_status		= ata_check_status_pio,
+	.exec_command		= ata_exec_command_pio,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_start            = ata_bmdma_start_pio,
+	.fill_sg		= ata_fill_sg,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= ata_interrupt,
+	.scr_read		= sis_scr_read,
+	.scr_write		= sis_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+
+MODULE_AUTHOR("Uwe Koziolek");
+MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
+
+static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg)
+{
+	unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
+
+	if (port_no)
+		addr += SIS_SATA1_OFS;
+	return addr;
+}
+
+static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg);
+	u32 val;
+
+	if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
+		return 0xffffffff;
+	pci_read_config_dword(ap->host_set->pdev, cfg_addr, &val);
+	return val;
+}
+
+static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+{
+	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr);
+
+	if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
+		return;
+	pci_write_config_dword(ap->host_set->pdev, cfg_addr, val);
+}
+
+static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+
+	if (ap->flags & SIS_FLAG_CFGSCR)
+		return sis_scr_cfg_read(ap, sc_reg);
+	return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+
+	if (ap->flags & SIS_FLAG_CFGSCR)
+		sis_scr_cfg_write(ap, sc_reg, val);
+	else
+		outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_enable_intx(struct pci_dev *pdev)
+{
+	u16 pci_command;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_INTX_DISABLE) {
+		pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+	}
+}
+
+static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct ata_probe_ent *probe_ent = NULL;
+	int rc;
+	u32 genctl;
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (!probe_ent) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->pdev = pdev;
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	probe_ent->sht = &sis_sht;
+	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+				ATA_FLAG_NO_LEGACY;
+
+	/* check and see if the SCRs are in IO space or PCI cfg space */
+	pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
+	if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
+		probe_ent->host_flags |= SIS_FLAG_CFGSCR;
+	
+	/* if hardware thinks SCRs are in IO space, but there are
+	 * no IO resources assigned, change to PCI cfg space.
+	 */
+	if ((!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) &&
+	    ((pci_resource_start(pdev, SIS_SCR_PCI_BAR) == 0) ||
+	     (pci_resource_len(pdev, SIS_SCR_PCI_BAR) < 128))) {
+		genctl &= ~GENCTL_IOMAPPED_SCR;
+		pci_write_config_dword(pdev, SIS_GENCTL, genctl);
+		probe_ent->host_flags |= SIS_FLAG_CFGSCR;
+	}
+
+	probe_ent->pio_mask = 0x03;
+	probe_ent->udma_mask = 0x7f;
+	probe_ent->port_ops = &sis_ops;
+
+	probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
+	ata_std_ports(&probe_ent->port[0]);
+	probe_ent->port[0].ctl_addr =
+		pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
+	if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR))
+		probe_ent->port[0].scr_addr =
+			pci_resource_start(pdev, SIS_SCR_PCI_BAR);
+
+	probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
+	ata_std_ports(&probe_ent->port[1]);
+	probe_ent->port[1].ctl_addr =
+		pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+	probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+	if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR))
+		probe_ent->port[1].scr_addr =
+			pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64;
+
+	probe_ent->n_ports = 2;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+
+	pci_set_master(pdev);
+	pci_enable_intx(pdev);
+
+	ata_add_to_probe_list(probe_ent);
+
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pdev);
+
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+
+}
+
+static int __init sis_init(void)
+{
+	int rc = pci_module_init(&sis_pci_driver);
+	if (rc)
+		return rc;
+
+	rc = scsi_register_module(MODULE_SCSI_HA, &sis_sht);
+	if (rc) {
+		pci_unregister_driver(&sis_pci_driver);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit sis_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &sis_sht);
+	pci_unregister_driver(&sis_pci_driver);
+}
+
+module_init(sis_init);
+module_exit(sis_exit);
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/sata_svw.c linux-2.4.27-pre3/drivers/scsi/sata_svw.c
--- linux-2.4.26/drivers/scsi/sata_svw.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/sata_svw.c	2004-05-18 16:54:04.000000000 +0000
@@ -0,0 +1,414 @@
+/*
+ *  sata_svw.c - ServerWorks / Apple K2 SATA
+ *
+ *  Maintained by: Benjamin Herrenschmidt <benh@kernel.crashing.org> and
+ *		   Jeff Garzik <jgarzik@pobox.com>
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ *  Bits from Jeff Garzik, Copyright RedHat, Inc.
+ *
+ *  This driver probably works with non-Apple versions of the
+ *  Broadcom chipset...
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif /* CONFIG_PPC_OF */
+
+#define DRV_NAME	"sata_svw"
+#define DRV_VERSION	"1.04"
+
+/* Taskfile registers offsets */
+#define K2_SATA_TF_CMD_OFFSET		0x00
+#define K2_SATA_TF_DATA_OFFSET		0x00
+#define K2_SATA_TF_ERROR_OFFSET		0x04
+#define K2_SATA_TF_NSECT_OFFSET		0x08
+#define K2_SATA_TF_LBAL_OFFSET		0x0c
+#define K2_SATA_TF_LBAM_OFFSET		0x10
+#define K2_SATA_TF_LBAH_OFFSET		0x14
+#define K2_SATA_TF_DEVICE_OFFSET	0x18
+#define K2_SATA_TF_CMDSTAT_OFFSET      	0x1c
+#define K2_SATA_TF_CTL_OFFSET		0x20
+
+/* DMA base */
+#define K2_SATA_DMA_CMD_OFFSET		0x30
+
+/* SCRs base */
+#define K2_SATA_SCR_STATUS_OFFSET	0x40
+#define K2_SATA_SCR_ERROR_OFFSET	0x44
+#define K2_SATA_SCR_CONTROL_OFFSET	0x48
+
+/* Others */
+#define K2_SATA_SICR1_OFFSET		0x80
+#define K2_SATA_SICR2_OFFSET		0x84
+#define K2_SATA_SIM_OFFSET		0x88
+
+/* Port stride */
+#define K2_SATA_PORT_OFFSET		0x100
+
+
+static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+			       u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		writeb(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
+		writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
+		writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
+		writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
+		writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+	} else if (is_addr) {
+		writew(tf->feature, ioaddr->feature_addr);
+		writew(tf->nsect, ioaddr->nsect_addr);
+		writew(tf->lbal, ioaddr->lbal_addr);
+		writew(tf->lbam, ioaddr->lbam_addr);
+		writew(tf->lbah, ioaddr->lbah_addr);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE)
+		writeb(tf->device, ioaddr->device_addr);
+
+	ata_wait_idle(ap);
+}
+
+
+static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u16 nsect, lbal, lbam, lbah;
+
+	nsect = tf->nsect = readw(ioaddr->nsect_addr);
+	lbal = tf->lbal = readw(ioaddr->lbal_addr);
+	lbam = tf->lbam = readw(ioaddr->lbam_addr);
+	lbah = tf->lbah = readw(ioaddr->lbah_addr);
+	tf->device = readw(ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		tf->hob_feature = readw(ioaddr->error_addr) >> 8;
+		tf->hob_nsect = nsect >> 8;
+		tf->hob_lbal = lbal >> 8;
+		tf->hob_lbam = lbam >> 8;
+		tf->hob_lbah = lbah >> 8;
+        }
+}
+
+
+static u8 k2_stat_check_status(struct ata_port *ap)
+{
+       	return readl((void *) ap->ioaddr.status_addr);
+}
+
+#ifdef CONFIG_PPC_OF
+/*
+ * k2_sata_proc_info
+ * inout : decides on the direction of the dataflow and the meaning of the
+ *	   variables
+ * buffer: If inout==FALSE data is being written to it else read from it
+ * *start: If inout==FALSE start of the valid data in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file
+ *	   from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer
+ *	   else number of bytes in the buffer
+ */
+static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
+			     off_t offset, int count, int inout)
+{
+	struct ata_port *ap;
+	struct device_node *np;
+	int len, index;
+
+	/* Find  the ata_port */
+	ap = (struct ata_port *) &shost->hostdata[0];
+	if (ap == NULL)
+		return 0;
+
+	/* Find the OF node for the PCI device proper */
+	np = pci_device_to_OF_node(ap->host_set->pdev);
+	if (np == NULL)
+		return 0;
+
+	/* Match it to a port node */
+	index = (ap == ap->host_set->ports[0]) ? 0 : 1;
+	for (np = np->child; np != NULL; np = np->sibling) {
+		u32 *reg = (u32 *)get_property(np, "reg", NULL);
+		if (!reg)
+			continue;
+		if (index == *reg)
+			break;
+	}
+	if (np == NULL)
+		return 0;
+
+	len = sprintf(page, "devspec: %s\n", np->full_name);
+
+	return len;
+}
+#endif /* CONFIG_PPC_OF */
+
+
+static Scsi_Host_Template k2_sata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.detect			= ata_scsi_detect,
+	.release		= ata_scsi_release,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.use_new_eh_code	= ATA_SHT_NEW_EH_CODE,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+#ifdef CONFIG_PPC_OF
+	.proc_info		= k2_sata_proc_info,
+#endif
+	.bios_param		= ata_std_bios_param,
+};
+
+
+static struct ata_port_operations k2_sata_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= k2_sata_tf_load,
+	.tf_read		= k2_sata_tf_read,
+	.check_status		= k2_stat_check_status,
+	.exec_command		= ata_exec_command_mmio,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_start            = ata_bmdma_start_mmio,
+	.fill_sg		= ata_fill_sg,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= ata_interrupt,
+	.scr_read		= k2_sata_scr_read,
+	.scr_write		= k2_sata_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base + K2_SATA_TF_CMD_OFFSET;
+	port->data_addr		= base + K2_SATA_TF_DATA_OFFSET;
+	port->feature_addr	=
+	port->error_addr	= base + K2_SATA_TF_ERROR_OFFSET;
+	port->nsect_addr	= base + K2_SATA_TF_NSECT_OFFSET;
+	port->lbal_addr		= base + K2_SATA_TF_LBAL_OFFSET;
+	port->lbam_addr		= base + K2_SATA_TF_LBAM_OFFSET;
+	port->lbah_addr		= base + K2_SATA_TF_LBAH_OFFSET;
+	port->device_addr	= base + K2_SATA_TF_DEVICE_OFFSET;
+	port->command_addr	=
+	port->status_addr	= base + K2_SATA_TF_CMDSTAT_OFFSET;
+	port->altstatus_addr	=
+	port->ctl_addr		= base + K2_SATA_TF_CTL_OFFSET;
+	port->bmdma_addr	= base + K2_SATA_DMA_CMD_OFFSET;
+	port->scr_addr		= base + K2_SATA_SCR_STATUS_OFFSET;
+}
+
+
+static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/*
+	 * If this driver happens to only be useful on Apple's K2, then
+	 * we should check that here as it has a normal Serverworks ID
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+	/*
+	 * Check if we have resources mapped at all (second function may
+	 * have been disabled by firmware)
+	 */
+	if (pci_resource_len(pdev, 5) == 0)
+		return -ENODEV;
+
+	/* Request PCI regions */
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->pdev = pdev;
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 5),
+		            pci_resource_len(pdev, 5));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	/* Clear a magic bit in SCR1 according to Darwin, those help
+	 * some funky seagate drives (though so far, those were already
+	 * set by the firmware on the machines I had access to
+	 */
+	writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
+	       mmio_base + K2_SATA_SICR1_OFFSET);
+
+	/* Clear SATA error & interrupts we don't use */
+	writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
+	writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
+
+	probe_ent->sht = &k2_sata_sht;
+	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+				ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO;
+	probe_ent->port_ops = &k2_sata_ops;
+	probe_ent->n_ports = 4;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	/* We don't care much about the PIO/UDMA masks, but the core won't like us
+	 * if we don't fill these
+	 */
+	probe_ent->pio_mask = 0x1f;
+	probe_ent->udma_mask = 0x7f;
+
+	/* We have 4 ports per PCI function */
+	k2_sata_setup_port(&probe_ent->port[0], base + 0 * K2_SATA_PORT_OFFSET);
+	k2_sata_setup_port(&probe_ent->port[1], base + 1 * K2_SATA_PORT_OFFSET);
+	k2_sata_setup_port(&probe_ent->port[2], base + 2 * K2_SATA_PORT_OFFSET);
+	k2_sata_setup_port(&probe_ent->port[3], base + 3 * K2_SATA_PORT_OFFSET);
+
+	pci_set_master(pdev);
+
+	ata_add_to_probe_list(probe_ent);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+
+static struct pci_device_id k2_sata_pci_tbl[] = {
+	{ 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ }
+};
+
+
+static struct pci_driver k2_sata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= k2_sata_pci_tbl,
+	.probe			= k2_sata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static int __init k2_sata_init(void)
+{
+	int rc;
+
+	rc = pci_module_init(&k2_sata_pci_driver);
+	if (rc)
+		return rc;
+
+	rc = scsi_register_module(MODULE_SCSI_HA, &k2_sata_sht);
+	if (rc) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	return 0;
+
+err_out:
+	pci_unregister_driver(&k2_sata_pci_driver);
+	return rc;
+}
+
+
+static void __exit k2_sata_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &k2_sata_sht);
+	pci_unregister_driver(&k2_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Benjamin Herrenschmidt");
+MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, k2_sata_pci_tbl);
+
+module_init(k2_sata_init);
+module_exit(k2_sata_exit);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/sata_sx4.c linux-2.4.27-pre3/drivers/scsi/sata_sx4.c
--- linux-2.4.26/drivers/scsi/sata_sx4.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/sata_sx4.c	2004-05-18 16:53:11.000000000 +0000
@@ -0,0 +1,1453 @@
+/*
+ *  sata_sx4.c - Promise SATA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+#include <asm/io.h>
+#include "sata_promise.h"
+
+#define DRV_NAME	"sata_sx4"
+#define DRV_VERSION	"0.50"
+
+
+enum {
+	PDC_PRD_TBL		= 0x44,	/* Direct command DMA table addr */
+
+	PDC_PKT_SUBMIT		= 0x40, /* Command packet pointer addr */
+	PDC_HDMA_PKT_SUBMIT	= 0x100, /* Host DMA packet pointer addr */
+	PDC_INT_SEQMASK		= 0x40,	/* Mask of asserted SEQ INTs */
+	PDC_HDMA_CTLSTAT	= 0x12C, /* Host DMA control / status */
+
+	PDC_20621_SEQCTL	= 0x400,
+	PDC_20621_SEQMASK	= 0x480,
+	PDC_20621_GENERAL_CTL	= 0x484,
+	PDC_20621_PAGE_SIZE	= (32 * 1024),
+
+	/* chosen, not constant, values; we design our own DIMM mem map */
+	PDC_20621_DIMM_WINDOW	= 0x0C,	/* page# for 32K DIMM window */
+	PDC_20621_DIMM_BASE	= 0x00200000,
+	PDC_20621_DIMM_DATA	= (64 * 1024),
+	PDC_DIMM_DATA_STEP	= (256 * 1024),
+	PDC_DIMM_WINDOW_STEP	= (8 * 1024),
+	PDC_DIMM_HOST_PRD	= (6 * 1024),
+	PDC_DIMM_HOST_PKT	= (128 * 0),
+	PDC_DIMM_HPKT_PRD	= (128 * 1),
+	PDC_DIMM_ATA_PKT	= (128 * 2),
+	PDC_DIMM_APKT_PRD	= (128 * 3),
+	PDC_DIMM_HEADER_SZ	= PDC_DIMM_APKT_PRD + 128,
+	PDC_PAGE_WINDOW		= 0x40,
+	PDC_PAGE_DATA		= PDC_PAGE_WINDOW +
+				  (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
+	PDC_PAGE_SET		= PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
+
+	PDC_CHIP0_OFS		= 0xC0000, /* offset of chip #0 */
+
+	PDC_20621_ERR_MASK	= (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+				  (1<<23),
+
+	board_20621		= 0,	/* FastTrak S150 SX4 */
+
+	PDC_RESET		= (1 << 11), /* HDMA reset */
+
+	PDC_MAX_HDMA		= 32,
+	PDC_HDMA_Q_MASK		= (PDC_MAX_HDMA - 1),
+
+	PDC_DIMM0_SPD_DEV_ADDRESS     = 0x50,
+	PDC_DIMM1_SPD_DEV_ADDRESS     = 0x51,
+	PDC_MAX_DIMM_MODULE           = 0x02,
+	PDC_I2C_CONTROL_OFFSET        = 0x48,
+	PDC_I2C_ADDR_DATA_OFFSET      = 0x4C,
+	PDC_DIMM0_CONTROL_OFFSET      = 0x80,
+	PDC_DIMM1_CONTROL_OFFSET      = 0x84,
+	PDC_SDRAM_CONTROL_OFFSET      = 0x88,
+	PDC_I2C_WRITE                 = 0x00000000,
+	PDC_I2C_READ                  = 0x00000040,	
+	PDC_I2C_START                 = 0x00000080,
+	PDC_I2C_MASK_INT              = 0x00000020,
+	PDC_I2C_COMPLETE              = 0x00010000,
+	PDC_I2C_NO_ACK                = 0x00100000,
+	PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
+	PDC_DIMM_SPD_SUBADDRESS_END   = 0x7F,
+	PDC_DIMM_SPD_ROW_NUM          = 3,
+	PDC_DIMM_SPD_COLUMN_NUM       = 4,
+	PDC_DIMM_SPD_MODULE_ROW       = 5,
+	PDC_DIMM_SPD_TYPE             = 11,
+	PDC_DIMM_SPD_FRESH_RATE       = 12,         
+	PDC_DIMM_SPD_BANK_NUM         = 17,	
+	PDC_DIMM_SPD_CAS_LATENCY      = 18,
+	PDC_DIMM_SPD_ATTRIBUTE        = 21,    
+	PDC_DIMM_SPD_ROW_PRE_CHARGE   = 27,
+	PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,      
+	PDC_DIMM_SPD_RAS_CAS_DELAY    = 29,
+	PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
+	PDC_DIMM_SPD_SYSTEM_FREQ      = 126,
+	PDC_CTL_STATUS		      = 0x08,	
+	PDC_DIMM_WINDOW_CTLR	      = 0x0C,
+	PDC_TIME_CONTROL              = 0x3C,
+	PDC_TIME_PERIOD               = 0x40,
+	PDC_TIME_COUNTER              = 0x44,
+	PDC_GENERAL_CTLR	      = 0x484,
+	PCI_PLL_INIT                  = 0x8A531824,
+	PCI_X_TCOUNT                  = 0xEE1E5CFF
+};
+
+
+struct pdc_port_priv {
+	u8			dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
+	u8			*pkt;
+	dma_addr_t		pkt_dma;
+};
+
+struct pdc_host_priv {
+	void			*dimm_mmio;
+
+	unsigned int		doing_hdma;
+	unsigned int		hdma_prod;
+	unsigned int		hdma_cons;
+	struct {
+		struct ata_queued_cmd *qc;
+		unsigned int	seq;
+		unsigned long	pkt_ofs;
+	} hdma[32];
+};
+
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void pdc20621_dma_start(struct ata_queued_cmd *qc);
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void pdc_eng_timeout(struct ata_port *ap);
+static void pdc_20621_phy_reset (struct ata_port *ap);
+static int pdc_port_start(struct ata_port *ap);
+static void pdc_port_stop(struct ata_port *ap);
+static void pdc20621_fill_sg(struct ata_queued_cmd *qc);
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc20621_host_stop(struct ata_host_set *host_set);
+static inline void pdc_dma_complete (struct ata_port *ap,
+                                     struct ata_queued_cmd *qc, int have_err);
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, 
+				      u32 device, u32 subaddr, u32 *pdata);
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, 
+				   void *psource, u32 offset, u32 size);
+#endif
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, 
+				 void *psource, u32 offset, u32 size);
+
+
+static Scsi_Host_Template pdc_sata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.detect			= ata_scsi_detect,
+	.release		= ata_scsi_release,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.use_new_eh_code	= ATA_SHT_NEW_EH_CODE,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations pdc_20621_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= pdc_tf_load_mmio,
+	.tf_read		= ata_tf_read_mmio,
+	.check_status		= ata_check_status_mmio,
+	.exec_command		= pdc_exec_command_mmio,
+	.phy_reset		= pdc_20621_phy_reset,
+	.bmdma_start            = pdc20621_dma_start,
+	.fill_sg		= pdc20621_fill_sg,
+	.eng_timeout		= pdc_eng_timeout,
+	.irq_handler		= pdc20621_interrupt,
+	.port_start		= pdc_port_start,
+	.port_stop		= pdc_port_stop,
+	.host_stop		= pdc20621_host_stop,
+};
+
+static struct ata_port_info pdc_port_info[] = {
+	/* board_20621 */
+	{
+		.sht		= &pdc_sata_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x03, /* pio3-4 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_20621_ops,
+	},
+
+};
+
+static struct pci_device_id pdc_sata_pci_tbl[] = {
+	{ PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_20621 },
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver pdc_sata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= pdc_sata_pci_tbl,
+	.probe			= pdc_sata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static void pdc20621_host_stop(struct ata_host_set *host_set)
+{
+	struct pdc_host_priv *hpriv = host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	iounmap(dimm_mmio);
+	kfree(hpriv);
+}
+
+static int pdc_port_start(struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+	struct pdc_port_priv *pp;
+	int rc;
+
+	rc = ata_port_start(ap);
+	if (rc)
+		return rc;
+
+	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+	if (!pp) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	memset(pp, 0, sizeof(*pp));
+
+	pp->pkt = pci_alloc_consistent(pdev, 128, &pp->pkt_dma);
+	if (!pp->pkt) {
+		rc = -ENOMEM;
+		goto err_out_kfree;
+	}
+
+	ap->private_data = pp;
+
+	return 0;
+
+err_out_kfree:
+	kfree(pp);
+err_out:
+	ata_port_stop(ap);
+	return rc;
+}
+
+
+static void pdc_port_stop(struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+	struct pdc_port_priv *pp = ap->private_data;
+
+	ap->private_data = NULL;
+	pci_free_consistent(pdev, 128, pp->pkt, pp->pkt_dma);
+	kfree(pp);
+	ata_port_stop(ap);
+}
+
+
+static void pdc_20621_phy_reset (struct ata_port *ap)
+{
+	VPRINTK("ENTER\n");
+        ap->cbl = ATA_CBL_SATA;
+        ata_port_probe(ap);
+        ata_bus_reset(ap);
+}
+
+static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
+				    	   unsigned int portno,
+					   unsigned int total_len)
+{
+	u32 addr;
+	unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
+	u32 *buf32 = (u32 *) buf;
+
+	/* output ATA packet S/G table */
+	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+	       (PDC_DIMM_DATA_STEP * portno);
+	VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
+	buf32[dw] = cpu_to_le32(addr);
+	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+	VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
+		PDC_20621_DIMM_BASE +
+		       (PDC_DIMM_WINDOW_STEP * portno) +
+		       PDC_DIMM_APKT_PRD,
+		buf32[dw], buf32[dw + 1]);
+}
+
+static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
+				    	    unsigned int portno,
+					    unsigned int total_len)
+{
+	u32 addr;
+	unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
+	u32 *buf32 = (u32 *) buf;
+
+	/* output Host DMA packet S/G table */
+	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+	       (PDC_DIMM_DATA_STEP * portno);
+
+	buf32[dw] = cpu_to_le32(addr);
+	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+	VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
+		PDC_20621_DIMM_BASE +
+		       (PDC_DIMM_WINDOW_STEP * portno) +
+		       PDC_DIMM_HPKT_PRD,
+		buf32[dw], buf32[dw + 1]);
+}
+
+static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
+					    unsigned int devno, u8 *buf,
+					    unsigned int portno)
+{
+	unsigned int i, dw;
+	u32 *buf32 = (u32 *) buf;
+	u8 dev_reg;
+
+	unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+			       (PDC_DIMM_WINDOW_STEP * portno) +
+			       PDC_DIMM_APKT_PRD;
+	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+
+	i = PDC_DIMM_ATA_PKT;
+
+	/*
+	 * Set up ATA packet
+	 */
+	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+		buf[i++] = PDC_PKT_READ;
+	else if (tf->protocol == ATA_PROT_NODATA)
+		buf[i++] = PDC_PKT_NODATA;
+	else
+		buf[i++] = 0;
+	buf[i++] = 0;			/* reserved */
+	buf[i++] = portno + 1;		/* seq. id */
+	buf[i++] = 0xff;		/* delay seq. id */
+
+	/* dimm dma S/G, and next-pkt */
+	dw = i >> 2;
+	buf32[dw] = cpu_to_le32(dimm_sg);
+	buf32[dw + 1] = 0;
+	i += 8;
+
+	if (devno == 0)
+		dev_reg = ATA_DEVICE_OBS;
+	else
+		dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+	/* select device */
+	buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+	buf[i++] = dev_reg;
+
+	/* device control register */
+	buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
+	buf[i++] = tf->ctl;
+
+	return i;
+}
+
+static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
+				     unsigned int portno)
+{
+	unsigned int dw;
+	u32 tmp, *buf32 = (u32 *) buf;
+
+	unsigned int host_sg = PDC_20621_DIMM_BASE +
+			       (PDC_DIMM_WINDOW_STEP * portno) +
+			       PDC_DIMM_HOST_PRD;
+	unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+			       (PDC_DIMM_WINDOW_STEP * portno) +
+			       PDC_DIMM_HPKT_PRD;
+	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+	VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
+
+	dw = PDC_DIMM_HOST_PKT >> 2;
+
+	/*
+	 * Set up Host DMA packet
+	 */
+	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+		tmp = PDC_PKT_READ;
+	else
+		tmp = 0;
+	tmp |= ((portno + 1 + 4) << 16);	/* seq. id */
+	tmp |= (0xff << 24);			/* delay seq. id */
+	buf32[dw + 0] = cpu_to_le32(tmp);
+	buf32[dw + 1] = cpu_to_le32(host_sg);
+	buf32[dw + 2] = cpu_to_le32(dimm_sg);
+	buf32[dw + 3] = 0;
+
+	VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
+		PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
+			PDC_DIMM_HOST_PKT,
+		buf32[dw + 0],
+		buf32[dw + 1],
+		buf32[dw + 2],
+		buf32[dw + 3]);
+}
+
+static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
+{
+	struct scatterlist *sg = qc->sg;
+	struct ata_port *ap = qc->ap;
+	struct pdc_port_priv *pp = ap->private_data;
+	void *mmio = ap->host_set->mmio_base;
+	struct pdc_host_priv *hpriv = ap->host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+	unsigned int portno = ap->port_no;
+	unsigned int i, last, idx, total_len = 0, sgt_len;
+	u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
+
+	VPRINTK("ata%u: ENTER\n", ap->id);
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	/*
+	 * Build S/G table
+	 */
+	last = qc->n_elem;
+	idx = 0;
+	for (i = 0; i < last; i++) {
+		buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i]));
+		buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i]));
+		total_len += sg[i].length;
+	}
+	buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
+	sgt_len = idx * 4;
+
+	/*
+	 * Build ATA, host DMA packets
+	 */
+	pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+	pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
+
+	pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+	i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+
+	if (qc->tf.flags & ATA_TFLAG_LBA48)
+		i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+	else
+		i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+
+	pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+
+	/* copy three S/G tables and two packets to DIMM MMIO window */
+	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+		    &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
+		    PDC_DIMM_HOST_PRD,
+		    &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
+
+	/* force host FIFO dump */
+	writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+
+	readl(dimm_mmio);	/* MMIO PCI posting flush */
+
+	VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
+}
+
+static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
+				 unsigned int seq,
+				 u32 pkt_ofs)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_host_set *host_set = ap->host_set;
+	void *mmio = host_set->mmio_base;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+	readl(mmio + PDC_20621_SEQCTL + (seq * 4));	/* flush */
+
+	writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
+	readl(mmio + PDC_HDMA_PKT_SUBMIT);	/* flush */
+}
+
+static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
+				unsigned int seq,
+				u32 pkt_ofs)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_host_priv *pp = ap->host_set->private_data;
+	unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
+
+	if (!pp->doing_hdma) {
+		__pdc20621_push_hdma(qc, seq, pkt_ofs);
+		pp->doing_hdma = 1;
+		return;
+	}
+
+	pp->hdma[idx].qc = qc;
+	pp->hdma[idx].seq = seq;
+	pp->hdma[idx].pkt_ofs = pkt_ofs;
+	pp->hdma_prod++;
+}
+
+static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_host_priv *pp = ap->host_set->private_data;
+	unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
+
+	/* if nothing on queue, we're done */
+	if (pp->hdma_prod == pp->hdma_cons) {
+		pp->doing_hdma = 0;
+		return;
+	}
+
+	__pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
+			     pp->hdma[idx].pkt_ofs);
+	pp->hdma_cons++;
+}
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int port_no = ap->port_no;
+	struct pdc_host_priv *hpriv = ap->host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
+	dimm_mmio += PDC_DIMM_HOST_PKT;
+
+	printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
+	printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
+	printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
+	printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
+}
+#else
+static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
+#endif /* ATA_VERBOSE_DEBUG */
+
+static void pdc20621_dma_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_host_set *host_set = ap->host_set;
+	unsigned int port_no = ap->port_no;
+	void *mmio = host_set->mmio_base;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 seq = (u8) (port_no + 1);
+	unsigned int doing_hdma = 0, port_ofs;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	VPRINTK("ata%u: ENTER\n", ap->id);
+
+	port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+
+	/* if writing, we (1) DMA to DIMM, then (2) do ATA command */
+	if (rw) {
+		doing_hdma = 1;
+		seq += 4;
+	}
+
+	wmb();			/* flush PRD, pkt writes */
+
+	if (doing_hdma) {
+		pdc20621_dump_hdma(qc);
+		pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
+		VPRINTK("queued ofs 0x%x (%u), seq %u\n",
+			port_ofs + PDC_DIMM_HOST_PKT,
+			port_ofs + PDC_DIMM_HOST_PKT,
+			seq);
+	} else {
+		writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+		readl(mmio + PDC_20621_SEQCTL + (seq * 4));	/* flush */
+
+		writel(port_ofs + PDC_DIMM_ATA_PKT,
+		       (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+		readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+		VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
+			port_ofs + PDC_DIMM_ATA_PKT,
+			port_ofs + PDC_DIMM_ATA_PKT,
+			seq);
+	}
+}
+
+static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
+                                          struct ata_queued_cmd *qc,
+					  unsigned int doing_hdma,
+					  void *mmio)
+{
+	unsigned int port_no = ap->port_no;
+	unsigned int port_ofs =
+		PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+	u8 status;
+	unsigned int handled = 0;
+
+	VPRINTK("ENTER\n");
+
+	if ((qc->tf.protocol == ATA_PROT_DMA) &&	/* read */
+	    (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+
+		/* step two - DMA from DIMM to host */
+		if (doing_hdma) {
+			VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+			pdc_dma_complete(ap, qc, 0);
+			pdc20621_pop_hdma(qc);
+		}
+
+		/* step one - exec ATA command */
+		else {
+			u8 seq = (u8) (port_no + 1 + 4);
+			VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+			/* submit hdma pkt */
+			pdc20621_dump_hdma(qc);
+			pdc20621_push_hdma(qc, seq,
+					   port_ofs + PDC_DIMM_HOST_PKT);
+		}
+		handled = 1;
+
+	} else if (qc->tf.protocol == ATA_PROT_DMA) {	/* write */
+
+		/* step one - DMA from host to DIMM */
+		if (doing_hdma) {
+			u8 seq = (u8) (port_no + 1);
+			VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+			/* submit ata pkt */
+			writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+			readl(mmio + PDC_20621_SEQCTL + (seq * 4));
+			writel(port_ofs + PDC_DIMM_ATA_PKT,
+			       (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+			readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+		}
+
+		/* step two - execute ATA command */
+		else {
+			VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+			pdc_dma_complete(ap, qc, 0);
+			pdc20621_pop_hdma(qc);
+		}
+		handled = 1;
+
+	/* command completion, but no data xfer */
+	} else if (qc->tf.protocol == ATA_PROT_NODATA) {
+
+		status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+		DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+		ata_qc_complete(qc, status, 0);
+		handled = 1;
+
+	} else {
+		ap->stats.idle_irq++;
+	}
+
+	return handled;
+}
+
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	struct ata_port *ap;
+	u32 mask = 0;
+	unsigned int i, tmp, port_no;
+	unsigned int handled = 0;
+	void *mmio_base;
+
+	VPRINTK("ENTER\n");
+
+	if (!host_set || !host_set->mmio_base) {
+		VPRINTK("QUICK EXIT\n");
+		return IRQ_NONE;
+	}
+
+	mmio_base = host_set->mmio_base;
+
+	/* reading should also clear interrupts */
+	mmio_base += PDC_CHIP0_OFS;
+	mask = readl(mmio_base + PDC_20621_SEQMASK);
+	VPRINTK("mask == 0x%x\n", mask);
+
+	if (mask == 0xffffffff) {
+		VPRINTK("QUICK EXIT 2\n");
+		return IRQ_NONE;
+	}
+	mask &= 0xffff;		/* only 16 tags possible */
+	if (!mask) {
+		VPRINTK("QUICK EXIT 3\n");
+		return IRQ_NONE;
+	}
+
+        spin_lock(&host_set->lock);
+
+        for (i = 1; i < 9; i++) {
+		port_no = i - 1;
+		if (port_no > 3)
+			port_no -= 4;
+		if (port_no >= host_set->n_ports)
+			ap = NULL;
+		else
+			ap = host_set->ports[port_no];
+		tmp = mask & (1 << i);
+		VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
+		if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
+				handled += pdc20621_host_intr(ap, qc, (i > 4),
+							      mmio_base);
+		}
+	}
+
+        spin_unlock(&host_set->lock);
+
+	VPRINTK("mask == 0x%x\n", mask);
+
+	VPRINTK("EXIT\n");
+
+	return IRQ_RETVAL(handled);
+}
+
+static inline void pdc_dma_complete (struct ata_port *ap,
+                                     struct ata_queued_cmd *qc,
+				     int have_err)
+{
+	u8 err_bit = have_err ? ATA_ERR : 0;
+
+	/* get drive status; clear intr; complete txn */
+	ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+			ata_wait_idle(ap) | err_bit, 0);
+}
+
+static void pdc_eng_timeout(struct ata_port *ap)
+{
+	u8 drv_stat;
+	struct ata_queued_cmd *qc;
+
+	DPRINTK("ENTER\n");
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+		goto out;
+	}
+
+	/* hack alert!  We cannot use the supplied completion
+	 * function from inside the ->eh_strategy_handler() thread.
+	 * libata is the only user of ->eh_strategy_handler() in
+	 * any kernel, so the default scsi_done() assumes it is
+	 * not being called from the SCSI EH.
+	 */
+	qc->scsidone = scsi_finish_command;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		printk(KERN_ERR "ata%u: DMA timeout\n", ap->id);
+		ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+			        ata_wait_idle(ap) | ATA_ERR, 0);
+		break;
+
+	case ATA_PROT_NODATA:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat, 1);
+		break;
+
+	default:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat, 1);
+		break;
+	}
+
+out:
+	DPRINTK("EXIT\n");
+}
+
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (tf->protocol == ATA_PROT_PIO)
+		ata_tf_load_mmio(ap, tf);
+}
+
+
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (tf->protocol == ATA_PROT_PIO)
+		ata_exec_command_mmio(ap, tf);
+}
+
+
+static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base;
+	port->data_addr		= base;
+	port->feature_addr	=
+	port->error_addr	= base + 0x4;
+	port->nsect_addr	= base + 0x8;
+	port->lbal_addr		= base + 0xc;
+	port->lbam_addr		= base + 0x10;
+	port->lbah_addr		= base + 0x14;
+	port->device_addr	= base + 0x18;
+	port->command_addr	=
+	port->status_addr	= base + 0x1c;
+	port->altstatus_addr	=
+	port->ctl_addr		= base + 0x38;
+}
+
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, 
+				   u32 offset, u32 size)
+{
+	u32 window_size;
+	u16 idx;
+	u8 page_mask;
+	long dist;
+	void *mmio = pe->mmio_base;
+	struct pdc_host_priv *hpriv = pe->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	page_mask = 0x00;	
+   	window_size = 0x2000 * 4; /* 32K byte uchar size */  
+	idx = (u16) (offset / window_size); 
+
+	writel(0x01, mmio + PDC_GENERAL_CTLR);
+	readl(mmio + PDC_GENERAL_CTLR);
+	writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+	readl(mmio + PDC_DIMM_WINDOW_CTLR);
+
+	offset -= (idx * window_size);
+	idx++;
+	dist = ((long) (window_size - (offset + size))) >= 0 ? size : 
+		(long) (window_size - offset);
+	memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), 
+		      dist);
+
+	psource += dist;    
+	size -= dist;
+	for (; (long) size >= (long) window_size ;) {
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
+			      window_size / 4);
+		psource += window_size;
+		size -= window_size;
+		idx ++;
+	}
+
+	if (size) {
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
+			      size / 4);
+	}
+}
+#endif
+
+
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, 
+				 u32 offset, u32 size)
+{
+	u32 window_size;
+	u16 idx;
+	u8 page_mask;
+	long dist;
+	void *mmio = pe->mmio_base;
+	struct pdc_host_priv *hpriv = pe->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	/* hard-code chip #0 */   
+	mmio += PDC_CHIP0_OFS;
+
+	page_mask = 0x00;	
+   	window_size = 0x2000 * 4;       /* 32K byte uchar size */  
+	idx = (u16) (offset / window_size);
+
+	writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+	readl(mmio + PDC_DIMM_WINDOW_CTLR);
+	offset -= (idx * window_size); 
+	idx++;
+	dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
+		(long) (window_size - offset);
+	memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist);
+	writel(0x01, mmio + PDC_GENERAL_CTLR);
+	readl(mmio + PDC_GENERAL_CTLR);
+
+	psource += dist;    
+	size -= dist;
+	for (; (long) size >= (long) window_size ;) {
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_toio((char *) (dimm_mmio), (char *) psource, 
+			    window_size / 4);
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+		psource += window_size;
+		size -= window_size;
+		idx ++;
+	}
+    
+	if (size) {
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4);
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+	}
+}
+
+
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, 
+				      u32 subaddr, u32 *pdata)
+{
+	void *mmio = pe->mmio_base;
+	u32 i2creg  = 0;
+	u32 status;     
+	u32 count =0;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	i2creg |= device << 24;
+	i2creg |= subaddr << 16;
+
+	/* Set the device and subaddress */
+	writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
+	readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+
+	/* Write Control to perform read operation, mask int */
+	writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, 
+	       mmio + PDC_I2C_CONTROL_OFFSET);
+
+	for (count = 0; count <= 1000; count ++) {
+		status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
+		if (status & PDC_I2C_COMPLETE) {
+			status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+			break;
+		} else if (count == 1000)
+			return 0;
+	}
+
+	*pdata = (status >> 8) & 0x000000ff;
+	return 1;           
+}
+
+
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+{
+	u32 data=0 ;
+  	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+			     PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
+   		if (data == 100)
+			return 100;
+  	} else
+		return 0;
+ 	
+   	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
+		if(data <= 0x75) 
+			return 133;
+   	} else
+		return 0;
+   	
+   	return 0;
+}
+
+
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+{
+	u32 spd0[50];
+	u32 data = 0;
+   	int size, i;
+   	u8 bdimmsize; 
+   	void *mmio = pe->mmio_base;
+	static const struct {
+		unsigned int reg;
+		unsigned int ofs;
+	} pdc_i2c_read_data [] = {
+		{ PDC_DIMM_SPD_TYPE, 11 },		
+		{ PDC_DIMM_SPD_FRESH_RATE, 12 },
+		{ PDC_DIMM_SPD_COLUMN_NUM, 4 }, 
+		{ PDC_DIMM_SPD_ATTRIBUTE, 21 },
+		{ PDC_DIMM_SPD_ROW_NUM, 3 },
+		{ PDC_DIMM_SPD_BANK_NUM, 17 },
+		{ PDC_DIMM_SPD_MODULE_ROW, 5 },
+		{ PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
+		{ PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
+		{ PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
+		{ PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
+		{ PDC_DIMM_SPD_CAS_LATENCY, 18 },       
+	};
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
+		pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+				  pdc_i2c_read_data[i].reg, 
+				  &spd0[pdc_i2c_read_data[i].ofs]);
+  
+   	data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
+   	data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | 
+		((((spd0[27] + 9) / 10) - 1) << 8) ;
+   	data |= (((((spd0[29] > spd0[28]) 
+		    ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; 
+   	data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
+   
+   	if (spd0[18] & 0x08) 
+		data |= ((0x03) << 14);
+   	else if (spd0[18] & 0x04)
+		data |= ((0x02) << 14);
+   	else if (spd0[18] & 0x01)
+		data |= ((0x01) << 14);
+   	else
+		data |= (0 << 14);
+
+  	/* 
+	   Calculate the size of bDIMMSize (power of 2) and
+	   merge the DIMM size by program start/end address.
+	*/
+
+   	bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
+   	size = (1 << bdimmsize) >> 20;	/* size = xxx(MB) */
+   	data |= (((size / 16) - 1) << 16);
+   	data |= (0 << 23);
+	data |= 8;
+   	writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); 
+	readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
+   	return size;                          
+}
+
+
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+{
+	u32 data, spd0;
+   	int error, i;
+   	void *mmio = pe->mmio_base;
+
+	/* hard-code chip #0 */
+   	mmio += PDC_CHIP0_OFS;
+
+   	/*
+	  Set To Default : DIMM Module Global Control Register (0x022259F1)
+	  DIMM Arbitration Disable (bit 20)
+	  DIMM Data/Control Output Driving Selection (bit12 - bit15)
+	  Refresh Enable (bit 17)
+	*/
+
+	data = 0x022259F1;   
+	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+	readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+	/* Turn on for ECC */
+	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+			  PDC_DIMM_SPD_TYPE, &spd0);
+	if (spd0 == 0x02) {
+		data |= (0x01 << 16);
+		writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+		readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+		printk(KERN_ERR "Local DIMM ECC Enabled\n");
+   	}
+
+   	/* DIMM Initialization Select/Enable (bit 18/19) */
+   	data &= (~(1<<18));
+   	data |= (1<<19);
+   	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+   	error = 1;                     
+   	for (i = 1; i <= 10; i++) {   /* polling ~5 secs */
+		data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+		if (!(data & (1<<19))) {
+	   		error = 0;
+	   		break;     
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((i * 100) * HZ / 1000 + 1);
+   	}
+   	return error;
+}
+	
+
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+{
+	int speed, size, length; 
+	u32 addr,spd0,pci_status;
+	u32 tmp=0;
+	u32 time_period=0;
+	u32 tcount=0;
+	u32 ticks=0;
+	u32 clock=0;
+	u32 fparam=0;
+   	void *mmio = pe->mmio_base;
+
+	/* hard-code chip #0 */
+   	mmio += PDC_CHIP0_OFS;
+
+	/* Initialize PLL based upon PCI Bus Frequency */
+
+	/* Initialize Time Period Register */
+	writel(0xffffffff, mmio + PDC_TIME_PERIOD);
+	time_period = readl(mmio + PDC_TIME_PERIOD);
+	VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
+
+	/* Enable timer */
+	writel(0x00001a0, mmio + PDC_TIME_CONTROL);
+	readl(mmio + PDC_TIME_CONTROL);
+
+	/* Wait 3 seconds */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(3 * HZ);
+
+	/* 
+	   When timer is enabled, counter is decreased every internal
+	   clock cycle.
+	*/
+
+	tcount = readl(mmio + PDC_TIME_COUNTER);
+	VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
+
+	/* 
+	   If SX4 is on PCI-X bus, after 3 seconds, the timer counter
+	   register should be >= (0xffffffff - 3x10^8).
+	*/
+	if(tcount >= PCI_X_TCOUNT) {
+		ticks = (time_period - tcount);
+		VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
+	
+		clock = (ticks / 300000);
+		VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
+		
+		clock = (clock * 33);
+		VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
+
+		/* PLL F Param (bit 22:16) */
+		fparam = (1400000 / clock) - 2;
+		VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
+		
+		/* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
+		pci_status = (0x8a001824 | (fparam << 16));
+	} else
+		pci_status = PCI_PLL_INIT;
+
+	/* Initialize PLL. */
+	VPRINTK("pci_status: 0x%x\n", pci_status);
+	writel(pci_status, mmio + PDC_CTL_STATUS);
+	readl(mmio + PDC_CTL_STATUS);
+
+	/* 
+	   Read SPD of DIMM by I2C interface,
+	   and program the DIMM Module Controller.
+	*/
+ 	if (!(speed = pdc20621_detect_dimm(pe))) {
+		printk(KERN_ERR "Detect Local DIMM Fail\n");  
+		return 1;	/* DIMM error */
+   	}
+   	VPRINTK("Local DIMM Speed = %d\n", speed);
+
+   	/* Programming DIMM0 Module Control Register (index_CID0:80h) */ 
+   	size = pdc20621_prog_dimm0(pe);
+   	VPRINTK("Local DIMM Size = %dMB\n",size);
+
+   	/* Programming DIMM Module Global Control Register (index_CID0:88h) */ 
+   	if (pdc20621_prog_dimm_global(pe)) {
+		printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
+		return 1;
+   	}
+
+#ifdef ATA_VERBOSE_DEBUG
+	{
+		u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
+  				'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
+ 				 '1','.','1','0',
+  				'9','8','0','3','1','6','1','2',0,0};
+		u8 test_parttern2[40] = {0};
+
+		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
+		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
+
+		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
+		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+		       test_parttern2[1], &(test_parttern2[2]));
+		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 
+				       40);
+		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+		       test_parttern2[1], &(test_parttern2[2]));
+
+		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
+		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+		       test_parttern2[1], &(test_parttern2[2]));
+	}
+#endif
+
+	/* ECC initiliazation. */
+
+	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+			  PDC_DIMM_SPD_TYPE, &spd0);
+	if (spd0 == 0x02) {
+		VPRINTK("Start ECC initialization\n");
+		addr = 0;
+		length = size * 1024 * 1024;
+		while (addr < length) {
+			pdc20621_put_to_dimm(pe, (void *) &tmp, addr, 
+					     sizeof(u32));
+			addr += sizeof(u32);
+		}
+		VPRINTK("Finish ECC initialization\n");
+	}
+	return 0;
+}
+
+
+static void pdc_20621_init(struct ata_probe_ent *pe)
+{
+	u32 tmp;
+	void *mmio = pe->mmio_base;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	/*
+	 * Select page 0x40 for our 32k DIMM window
+	 */
+	tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
+	tmp |= PDC_PAGE_WINDOW;	/* page 40h; arbitrarily selected */
+	writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
+
+	/*
+	 * Reset Host DMA
+	 */
+	tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+	tmp |= PDC_RESET;
+	writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */
+
+	udelay(10);
+
+	tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+	tmp &= ~PDC_RESET;
+	writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */
+}
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base, *dimm_mmio = NULL;
+	struct pdc_host_priv *hpriv = NULL;
+	unsigned int board_idx = (unsigned int) ent->driver_data;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/*
+	 * If this driver happens to only be useful on Apple's K2, then
+	 * we should check that here as it has a normal Serverworks ID
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->pdev = pdev;
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 3),
+		            pci_resource_len(pdev, 3));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+	if (!hpriv) {
+		rc = -ENOMEM;
+		goto err_out_iounmap;
+	}
+	memset(hpriv, 0, sizeof(*hpriv));
+
+	dimm_mmio = ioremap(pci_resource_start(pdev, 4),
+			    pci_resource_len(pdev, 4));
+	if (!dimm_mmio) {
+		kfree(hpriv);
+		rc = -ENOMEM;
+		goto err_out_iounmap;
+	}
+
+	hpriv->dimm_mmio = dimm_mmio;
+
+	probe_ent->sht		= pdc_port_info[board_idx].sht;
+	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;
+	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
+	probe_ent->udma_mask	= pdc_port_info[board_idx].udma_mask;
+	probe_ent->port_ops	= pdc_port_info[board_idx].port_ops;
+
+       	probe_ent->irq = pdev->irq;
+       	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	probe_ent->private_data = hpriv;
+	base += PDC_CHIP0_OFS;
+
+	pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
+	pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
+
+	/* notice 4-port boards */
+	switch (board_idx) {
+	case board_20621:
+       		probe_ent->n_ports = 4;
+
+		pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
+		pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	pci_set_master(pdev);
+
+	/* initialize adapter */
+	/* initialize local dimm */
+	if (pdc20621_dimm_init(probe_ent)) {
+		rc = -ENOMEM;
+		goto err_out_iounmap_dimm;
+	}
+	pdc_20621_init(probe_ent);
+
+	ata_add_to_probe_list(probe_ent);
+
+	return 0;
+
+err_out_iounmap_dimm:		/* only get to this label if 20621 */
+	kfree(hpriv);
+	iounmap(dimm_mmio);
+err_out_iounmap:
+	iounmap(mmio_base);
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+
+static int __init pdc_sata_init(void)
+{
+	int rc;
+
+	rc = pci_module_init(&pdc_sata_pci_driver);
+	if (rc)
+		return rc;
+
+	rc = scsi_register_module(MODULE_SCSI_HA, &pdc_sata_sht);
+	if (rc) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	return 0;
+
+err_out:
+	pci_unregister_driver(&pdc_sata_pci_driver);
+	return rc;
+}
+
+
+static void __exit pdc_sata_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &pdc_sata_sht);
+	pci_unregister_driver(&pdc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Promise SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
+
+module_init(pdc_sata_init);
+module_exit(pdc_sata_exit);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/sata_via.c linux-2.4.27-pre3/drivers/scsi/sata_via.c
--- linux-2.4.26/drivers/scsi/sata_via.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/sata_via.c	2004-05-18 16:55:10.000000000 +0000
@@ -0,0 +1,329 @@
+/*
+   sata_via.c - VIA Serial ATA controllers
+
+   Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+   		   Please ALWAYS copy linux-ide@vger.kernel.org
+ 		   on emails.
+
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME	"sata_via"
+#define DRV_VERSION	"0.20"
+
+enum {
+	via_sata		= 0,
+
+	SATA_CHAN_ENAB		= 0x40, /* SATA channel enable */
+	SATA_INT_GATE		= 0x41, /* SATA interrupt gating */
+	SATA_NATIVE_MODE	= 0x42, /* Native mode enable */
+	SATA_PATA_SHARING	= 0x49, /* PATA/SATA sharing func ctrl */
+
+	PORT0			= (1 << 1),
+	PORT1			= (1 << 0),
+
+	ENAB_ALL		= PORT0 | PORT1,
+
+	INT_GATE_ALL		= PORT0 | PORT1,
+
+	NATIVE_MODE_ALL		= (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
+
+	SATA_EXT_PHY		= (1 << 6), /* 0==use PATA, 1==ext phy */
+	SATA_2DEV		= (1 << 5), /* SATA is master/slave */
+};
+
+static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+static struct pci_device_id svia_pci_tbl[] = {
+	{ 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, via_sata },
+
+	{ }	/* terminate list */
+};
+
+static struct pci_driver svia_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= svia_pci_tbl,
+	.probe			= svia_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template svia_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.detect			= ata_scsi_detect,
+	.release		= ata_scsi_release,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.use_new_eh_code	= ATA_SHT_NEW_EH_CODE,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations svia_sata_ops = {
+	.port_disable		= ata_port_disable,
+
+	.tf_load		= ata_tf_load_pio,
+	.tf_read		= ata_tf_read_pio,
+	.check_status		= ata_check_status_pio,
+	.exec_command		= ata_exec_command_pio,
+
+	.phy_reset		= sata_phy_reset,
+
+	.bmdma_start            = ata_bmdma_start_pio,
+	.fill_sg		= ata_fill_sg,
+	.eng_timeout		= ata_eng_timeout,
+
+	.irq_handler		= ata_interrupt,
+
+	.scr_read		= svia_scr_read,
+	.scr_write		= svia_scr_write,
+
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
+
+static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return inl(ap->ioaddr.scr_addr + (4 * sc_reg));
+}
+
+static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+}
+
+static const unsigned int svia_bar_sizes[] = {
+	8, 4, 8, 4, 16, 256
+};
+
+static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
+{
+	return addr + (port * 128);
+}
+
+/**
+ *	svia_init_one -
+ *	@pdev:
+ *	@ent:
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	unsigned int i;
+	int rc;
+	struct ata_probe_ent *probe_ent;
+	u8 tmp8;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
+	if (tmp8 & SATA_2DEV) {
+		printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		rc = -EIO;
+		goto err_out_regions;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
+		if ((pci_resource_start(pdev, i) == 0) ||
+		    (pci_resource_len(pdev, i) < svia_bar_sizes[i])) {
+			printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
+			       pci_name(pdev), i,
+			       pci_resource_start(pdev, i),
+			       pci_resource_len(pdev, i));
+			rc = -ENODEV;
+			goto err_out_regions;
+		}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (!probe_ent) {
+		printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+		       pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	INIT_LIST_HEAD(&probe_ent->node);
+	probe_ent->pdev = pdev;
+	probe_ent->sht = &svia_sht;
+	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST |
+				ATA_FLAG_NO_LEGACY;
+	probe_ent->port_ops = &svia_sata_ops;
+	probe_ent->n_ports = 2;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->pio_mask = 0x1f;
+	probe_ent->udma_mask = 0x7f;
+
+	probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
+	ata_std_ports(&probe_ent->port[0]);
+	probe_ent->port[0].altstatus_addr =
+	probe_ent->port[0].ctl_addr =
+		pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
+	probe_ent->port[0].scr_addr =
+		svia_scr_addr(pci_resource_start(pdev, 5), 0);
+
+	probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
+	ata_std_ports(&probe_ent->port[1]);
+	probe_ent->port[1].altstatus_addr =
+	probe_ent->port[1].ctl_addr =
+		pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+	probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+	probe_ent->port[1].scr_addr =
+		svia_scr_addr(pci_resource_start(pdev, 5), 1);
+
+	pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
+	printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n",
+	       pci_name(pdev),
+	       (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
+
+	/* make sure SATA channels are enabled */
+	pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
+	if ((tmp8 & ENAB_ALL) != ENAB_ALL) {
+		printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		tmp8 |= ENAB_ALL;
+		pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
+	}
+
+	/* make sure interrupts for each channel sent to us */
+	pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
+	if ((tmp8 & INT_GATE_ALL) != INT_GATE_ALL) {
+		printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		tmp8 |= INT_GATE_ALL;
+		pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
+	}
+
+	/* make sure native mode is enabled */
+	pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
+	if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
+		printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		tmp8 |= NATIVE_MODE_ALL;
+		pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
+	}
+
+	pci_set_master(pdev);
+
+	ata_add_to_probe_list(probe_ent);
+
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+/**
+ *	svia_init -
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static int __init svia_init(void)
+{
+	int rc;
+
+	rc = pci_module_init(&svia_pci_driver);
+	if (rc)
+		return rc;
+	
+	rc = scsi_register_module(MODULE_SCSI_HA, &svia_sht);
+	if (rc) {
+		pci_unregister_driver(&svia_pci_driver);
+		/* TODO: does scsi_register_module return errno val? */
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ *	svia_exit -
+ *
+ *	LOCKING:
+ *
+ */
+
+static void __exit svia_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &svia_sht);
+	pci_unregister_driver(&svia_pci_driver);
+}
+
+module_init(svia_init);
+module_exit(svia_exit);
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/sata_vsc.c linux-2.4.27-pre3/drivers/scsi/sata_vsc.c
--- linux-2.4.26/drivers/scsi/sata_vsc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/sata_vsc.c	2004-05-18 16:53:43.000000000 +0000
@@ -0,0 +1,400 @@
+/*
+ *  sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
+ *
+ *  Maintained by:  Jeremy Higdon @ SGI
+ * 		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2004 SGI
+ *
+ *  Bits from Jeff Garzik, Copyright RedHat, Inc.
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file "COPYING" in the main directory of this archive
+ *  for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_vsc"
+#define DRV_VERSION	"0.01"
+
+/* Interrupt register offsets (from chip base address) */
+#define VSC_SATA_INT_STAT_OFFSET	0x00
+#define VSC_SATA_INT_MASK_OFFSET	0x04
+
+/* Taskfile registers offsets */
+#define VSC_SATA_TF_CMD_OFFSET		0x00
+#define VSC_SATA_TF_DATA_OFFSET		0x00
+#define VSC_SATA_TF_ERROR_OFFSET	0x04
+#define VSC_SATA_TF_FEATURE_OFFSET	0x06
+#define VSC_SATA_TF_NSECT_OFFSET	0x08
+#define VSC_SATA_TF_LBAL_OFFSET		0x0c
+#define VSC_SATA_TF_LBAM_OFFSET		0x10
+#define VSC_SATA_TF_LBAH_OFFSET		0x14
+#define VSC_SATA_TF_DEVICE_OFFSET	0x18
+#define VSC_SATA_TF_STATUS_OFFSET	0x1c
+#define VSC_SATA_TF_COMMAND_OFFSET	0x1d
+#define VSC_SATA_TF_ALTSTATUS_OFFSET	0x28
+#define VSC_SATA_TF_CTL_OFFSET		0x29
+
+/* DMA base */
+#define VSC_SATA_UP_DESCRIPTOR_OFFSET	0x64
+#define VSC_SATA_UP_DATA_BUFFER_OFFSET	0x6C
+#define VSC_SATA_DMA_CMD_OFFSET		0x70
+
+/* SCRs base */
+#define VSC_SATA_SCR_STATUS_OFFSET	0x100
+#define VSC_SATA_SCR_ERROR_OFFSET	0x104
+#define VSC_SATA_SCR_CONTROL_OFFSET	0x108
+
+/* Port stride */
+#define VSC_SATA_PORT_OFFSET		0x200
+
+
+static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+			       u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
+{
+	unsigned long mask_addr;
+	u8 mask;
+
+	mask_addr = (unsigned long) ap->host_set->mmio_base +
+		VSC_SATA_INT_MASK_OFFSET + ap->port_no;
+	mask = readb(mask_addr);
+	if (ctl & ATA_NIEN)
+		mask |= 0x80;
+	else
+		mask &= 0x7F;
+	writeb(mask, mask_addr);
+}
+
+
+static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	/*
+	 * The only thing the ctl register is used for is SRST.
+	 * That is not enabled or disabled via tf_load.
+	 * However, if ATA_NIEN is changed, then we need to change the interrupt register.
+	 */
+	if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) {
+		ap->last_ctl = tf->ctl;
+		vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN);
+	}
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
+		writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
+		writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
+		writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
+		writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+	} else if (is_addr) {
+		writew(tf->feature, ioaddr->feature_addr);
+		writew(tf->nsect, ioaddr->nsect_addr);
+		writew(tf->lbal, ioaddr->lbal_addr);
+		writew(tf->lbam, ioaddr->lbam_addr);
+		writew(tf->lbah, ioaddr->lbah_addr);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE)
+		writeb(tf->device, ioaddr->device_addr);
+
+	ata_wait_idle(ap);
+}
+
+
+static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u16 nsect, lbal, lbam, lbah;
+
+	nsect = tf->nsect = readw(ioaddr->nsect_addr);
+	lbal = tf->lbal = readw(ioaddr->lbal_addr);
+	lbam = tf->lbam = readw(ioaddr->lbam_addr);
+	lbah = tf->lbah = readw(ioaddr->lbah_addr);
+	tf->device = readw(ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		tf->hob_feature = readb(ioaddr->error_addr);
+		tf->hob_nsect = nsect >> 8;
+		tf->hob_lbal = lbal >> 8;
+		tf->hob_lbam = lbam >> 8;
+		tf->hob_lbah = lbah >> 8;
+        }
+}
+
+
+/*
+ * vsc_sata_interrupt
+ *
+ * Read the interrupt register and process for the devices that have them pending.
+ */
+irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	unsigned int i;
+	unsigned int handled = 0;
+	u32 int_status;
+
+	spin_lock(&host_set->lock);
+
+	int_status = readl(host_set->mmio_base + VSC_SATA_INT_STAT_OFFSET);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		if (int_status & ((u32) 0xFF << (8 * i))) {
+			struct ata_port *ap;
+
+			ap = host_set->ports[i];
+			if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+				struct ata_queued_cmd *qc;
+
+				qc = ata_qc_from_tag(ap, ap->active_tag);
+				if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
+					handled += ata_host_intr(ap, qc);
+			}
+		}
+	}
+
+	spin_unlock(&host_set->lock);
+
+	return IRQ_RETVAL(handled);
+}
+
+
+static Scsi_Host_Template vsc_sata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.detect			= ata_scsi_detect,
+	.release		= ata_scsi_release,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.use_new_eh_code	= ATA_SHT_NEW_EH_CODE,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.bios_param		= ata_std_bios_param,
+};
+
+
+static struct ata_port_operations vsc_sata_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= vsc_sata_tf_load,
+	.tf_read		= vsc_sata_tf_read,
+	.exec_command		= ata_exec_command_mmio,
+	.check_status		= ata_check_status_mmio,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_start            = ata_bmdma_start_mmio,
+	.fill_sg		= ata_fill_sg,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= vsc_sata_interrupt,
+	.scr_read		= vsc_sata_scr_read,
+	.scr_write		= vsc_sata_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base + VSC_SATA_TF_CMD_OFFSET;
+	port->data_addr		= base + VSC_SATA_TF_DATA_OFFSET;
+	port->error_addr	= base + VSC_SATA_TF_ERROR_OFFSET;
+	port->feature_addr	= base + VSC_SATA_TF_FEATURE_OFFSET;
+	port->nsect_addr	= base + VSC_SATA_TF_NSECT_OFFSET;
+	port->lbal_addr		= base + VSC_SATA_TF_LBAL_OFFSET;
+	port->lbam_addr		= base + VSC_SATA_TF_LBAM_OFFSET;
+	port->lbah_addr		= base + VSC_SATA_TF_LBAH_OFFSET;
+	port->device_addr	= base + VSC_SATA_TF_DEVICE_OFFSET;
+	port->status_addr	= base + VSC_SATA_TF_STATUS_OFFSET;
+	port->command_addr	= base + VSC_SATA_TF_COMMAND_OFFSET;
+	port->altstatus_addr	= base + VSC_SATA_TF_ALTSTATUS_OFFSET;
+	port->ctl_addr		= base + VSC_SATA_TF_CTL_OFFSET;
+	port->bmdma_addr	= base + VSC_SATA_DMA_CMD_OFFSET;
+	port->scr_addr		= base + VSC_SATA_SCR_STATUS_OFFSET;
+	writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
+	writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
+}
+
+
+static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	/*
+	 * Check if we have needed resource mapped.
+	 */
+	if (pci_resource_len(pdev, 0) == 0) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	/*
+	 * Use 32 bit DMA mask, because 64 bit address support is poor.
+	 */
+	rc = pci_set_dma_mask(pdev, 0xFFFFFFFFULL);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->pdev = pdev;
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 0),
+		            pci_resource_len(pdev, 0));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	/*
+	 * Due to a bug in the chip, the default cache line size can't be used
+	 */
+	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
+
+	probe_ent->sht = &vsc_sata_sht;
+	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET;
+	probe_ent->port_ops = &vsc_sata_ops;
+	probe_ent->n_ports = 4;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	/* We don't care much about the PIO/UDMA masks, but the core won't like us
+	 * if we don't fill these
+	 */
+	probe_ent->pio_mask = 0x1f;
+	probe_ent->udma_mask = 0x7f;
+
+	/* We have 4 ports per PCI function */
+	vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET);
+	vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET);
+	vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET);
+	vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET);
+
+	pci_set_master(pdev);
+
+	ata_add_to_probe_list(probe_ent);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+
+/*
+ * 0x1725/0x7174 is the Vitesse VSC-7174
+ * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical
+ * compatibility is untested as of yet
+ */
+static struct pci_device_id vsc_sata_pci_tbl[] = {
+	{ 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+	{ 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+	{ }
+};
+
+
+static struct pci_driver vsc_sata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= vsc_sata_pci_tbl,
+	.probe			= vsc_sata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static int __init vsc_sata_init(void)
+{
+	int rc;
+
+	DPRINTK("pci_module_init\n");
+	rc = pci_module_init(&vsc_sata_pci_driver);
+	if (rc)
+		return rc;
+
+	DPRINTK("scsi_register_host\n");
+	rc = scsi_register_module(MODULE_SCSI_HA, &vsc_sata_sht);
+	if (rc) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	DPRINTK("done\n");
+	return 0;
+
+err_out:
+	pci_unregister_driver(&vsc_sata_pci_driver);
+	return rc;
+}
+
+
+static void __exit vsc_sata_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &vsc_sata_sht);
+	pci_unregister_driver(&vsc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeremy Higdon");
+MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl);
+
+module_init(vsc_sata_init);
+module_exit(vsc_sata_exit);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/scsi/scsi_scan.c linux-2.4.27-pre3/drivers/scsi/scsi_scan.c
--- linux-2.4.26/drivers/scsi/scsi_scan.c	2004-04-14 13:05:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/scsi/scsi_scan.c	2004-05-18 16:54:34.000000000 +0000
@@ -148,7 +148,7 @@ static struct dev_info device_list[] =
 	{"EMULEX", "MD21/S2     ESDI", "*", BLIST_SINGLELUN},
 	{"CANON", "IPUBJD", "*", BLIST_SPARSELUN},
 	{"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
-	{"DEC","HSG80","*", BLIST_FORCELUN | BLIST_NOSTARTONADD},
+	{"DEC","HSG80","*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD},
 	{"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN},
 	{"COMPAQ","CR3500","*", BLIST_FORCELUN},
 	{"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/sound/724hwmcode.h linux-2.4.27-pre3/drivers/sound/724hwmcode.h
--- linux-2.4.26/drivers/sound/724hwmcode.h	2000-11-12 02:33:13.000000000 +0000
+++ linux-2.4.27-pre3/drivers/sound/724hwmcode.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,1575 +0,0 @@
-//=============================================================================
-// Copyright (c) 1997-1999	Yamaha Corporation.	All Rights Reserved.
-//
-//	Title:
-//		hwmcode.c
-//	Desc:
-//		micro-code for CTRL & DSP
-//=============================================================================
-#ifndef _HWMCODE_
-#define _HWMCODE_
-
-static unsigned long int	DspInst[] __initdata = {
-	0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
-	0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
-	0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
-	0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000
-};
-
-static unsigned long int	CntrlInst[] __initdata = {
-	0x000007, 0x240007, 0x0C0007, 0x1C0007,
-	0x060007, 0x700002, 0x000020, 0x030040,
-	0x007104, 0x004286, 0x030040, 0x000F0D,
-	0x000810, 0x20043A, 0x000282, 0x00020D,
-	0x000810, 0x20043A, 0x001282, 0x200E82,
-	0x001A82, 0x032D0D, 0x000810, 0x10043A,
-	0x02D38D, 0x000810, 0x18043A, 0x00010D,
-	0x020015, 0x0000FD, 0x000020, 0x038860,
-	0x039060, 0x038060, 0x038040, 0x038040,
-	0x038040, 0x018040, 0x000A7D, 0x038040,
-	0x038040, 0x018040, 0x200402, 0x000882,
-	0x08001A, 0x000904, 0x015986, 0x000007,
-	0x260007, 0x000007, 0x000007, 0x018A06,
-	0x000007, 0x030C8D, 0x000810, 0x18043A,
-	0x260007, 0x00087D, 0x018042, 0x00160A,
-	0x04A206, 0x000007, 0x00218D, 0x000810,
-	0x08043A, 0x21C206, 0x000007, 0x0007FD,
-	0x018042, 0x08000A, 0x000904, 0x029386,
-	0x000195, 0x090D04, 0x000007, 0x000820,
-	0x0000F5, 0x000B7D, 0x01F060, 0x0000FD,
-	0x032206, 0x018040, 0x000A7D, 0x038042,
-	0x13804A, 0x18000A, 0x001820, 0x059060,
-	0x058860, 0x018040, 0x0000FD, 0x018042,
-	0x70000A, 0x000115, 0x071144, 0x032386,
-	0x030000, 0x007020, 0x034A06, 0x018040,
-	0x00348D, 0x000810, 0x08043A, 0x21EA06,
-	0x000007, 0x02D38D, 0x000810, 0x18043A,
-	0x018206, 0x000007, 0x240007, 0x000F8D,
-	0x000810, 0x00163A, 0x002402, 0x005C02,
-	0x0028FD, 0x000020, 0x018040, 0x08000D,
-	0x000815, 0x510984, 0x000007, 0x00004D,
-	0x000E5D, 0x000E02, 0x00418D, 0x000810,
-	0x08043A, 0x2C8A06, 0x000007, 0x00008D,
-	0x000924, 0x000F02, 0x00458D, 0x000810,
-	0x08043A, 0x2C8A06, 0x000007, 0x00387D,
-	0x018042, 0x08000A, 0x001015, 0x010984,
-	0x018386, 0x000007, 0x01AA06, 0x000007,
-	0x0008FD, 0x018042, 0x18000A, 0x001904,
-	0x218086, 0x280007, 0x001810, 0x28043A,
-	0x280C02, 0x00000D, 0x000810, 0x28143A,
-	0x08808D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00020D, 0x189904, 0x000007,
-	0x00402D, 0x0000BD, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x055A86, 0x000007,
-	0x000100, 0x000A20, 0x00047D, 0x018040,
-	0x018042, 0x20000A, 0x003015, 0x012144,
-	0x034986, 0x000007, 0x002104, 0x034986,
-	0x000007, 0x000F8D, 0x000810, 0x280C3A,
-	0x023944, 0x06C986, 0x000007, 0x001810,
-	0x28043A, 0x08810D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x002810, 0x78003A,
-	0x00688D, 0x000810, 0x08043A, 0x288A06,
-	0x000007, 0x00400D, 0x001015, 0x189904,
-	0x292904, 0x393904, 0x000007, 0x060206,
-	0x000007, 0x0004F5, 0x00007D, 0x000020,
-	0x00008D, 0x010860, 0x018040, 0x00047D,
-	0x038042, 0x21804A, 0x18000A, 0x021944,
-	0x215886, 0x000007, 0x004075, 0x71F104,
-	0x000007, 0x010042, 0x28000A, 0x002904,
-	0x212086, 0x000007, 0x003C0D, 0x30A904,
-	0x000007, 0x00077D, 0x018042, 0x08000A,
-	0x000904, 0x07DA86, 0x00057D, 0x002820,
-	0x03B060, 0x07F206, 0x018040, 0x003020,
-	0x03A860, 0x018040, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x07FA86, 0x000007,
-	0x00057D, 0x018042, 0x28040A, 0x000E8D,
-	0x000810, 0x280C3A, 0x00000D, 0x000810,
-	0x28143A, 0x09000D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x003DFD, 0x000020,
-	0x018040, 0x00107D, 0x008D8D, 0x000810,
-	0x08043A, 0x288A06, 0x000007, 0x000815,
-	0x08001A, 0x010984, 0x095186, 0x00137D,
-	0x200500, 0x280F20, 0x338F60, 0x3B8F60,
-	0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
-	0x038A60, 0x018040, 0x007FBD, 0x383DC4,
-	0x000007, 0x001A7D, 0x001375, 0x018042,
-	0x09004A, 0x10000A, 0x0B8D04, 0x139504,
-	0x000007, 0x000820, 0x019060, 0x001104,
-	0x212086, 0x010040, 0x0017FD, 0x018042,
-	0x08000A, 0x000904, 0x212286, 0x000007,
-	0x00197D, 0x038042, 0x09804A, 0x10000A,
-	0x000924, 0x001664, 0x0011FD, 0x038042,
-	0x2B804A, 0x19804A, 0x00008D, 0x218944,
-	0x000007, 0x002244, 0x0AE186, 0x000007,
-	0x001A64, 0x002A24, 0x00197D, 0x080102,
-	0x100122, 0x000820, 0x039060, 0x018040,
-	0x003DFD, 0x00008D, 0x000820, 0x018040,
-	0x001375, 0x001A7D, 0x010042, 0x09804A,
-	0x10000A, 0x00021D, 0x0189E4, 0x2992E4,
-	0x309144, 0x000007, 0x00060D, 0x000A15,
-	0x000C1D, 0x001025, 0x00A9E4, 0x012BE4,
-	0x000464, 0x01B3E4, 0x0232E4, 0x000464,
-	0x000464, 0x000464, 0x000464, 0x00040D,
-	0x08B1C4, 0x000007, 0x000820, 0x000BF5,
-	0x030040, 0x00197D, 0x038042, 0x09804A,
-	0x000A24, 0x08000A, 0x080E64, 0x000007,
-	0x100122, 0x000820, 0x031060, 0x010040,
-	0x0064AC, 0x00027D, 0x000020, 0x018040,
-	0x00107D, 0x018042, 0x0011FD, 0x3B804A,
-	0x09804A, 0x20000A, 0x000095, 0x1A1144,
-	0x00A144, 0x0D2086, 0x00040D, 0x00B984,
-	0x0D2186, 0x0018FD, 0x018042, 0x0010FD,
-	0x09804A, 0x28000A, 0x000095, 0x010924,
-	0x002A64, 0x0D1186, 0x000007, 0x002904,
-	0x0D2286, 0x000007, 0x0D2A06, 0x080002,
-	0x00008D, 0x00387D, 0x000820, 0x018040,
-	0x00127D, 0x018042, 0x10000A, 0x003904,
-	0x0DD186, 0x00080D, 0x7FFFB5, 0x00B984,
-	0x0DA186, 0x000025, 0x0E7A06, 0x00002D,
-	0x000015, 0x00082D, 0x02C78D, 0x000820,
-	0x0EC206, 0x00000D, 0x7F8035, 0x00B984,
-	0x0E7186, 0x400025, 0x00008D, 0x110944,
-	0x000007, 0x00018D, 0x109504, 0x000007,
-	0x009164, 0x000424, 0x000424, 0x000424,
-	0x100102, 0x280002, 0x02C68D, 0x000820,
-	0x0EC206, 0x00018D, 0x00042D, 0x00008D,
-	0x109504, 0x000007, 0x00020D, 0x109184,
-	0x000007, 0x02C70D, 0x000820, 0x00008D,
-	0x0038FD, 0x018040, 0x003BFD, 0x001020,
-	0x03A860, 0x000815, 0x313184, 0x212184,
-	0x000007, 0x03B060, 0x03A060, 0x018040,
-	0x0022FD, 0x000095, 0x010924, 0x000424,
-	0x000424, 0x001264, 0x100102, 0x000820,
-	0x039060, 0x018040, 0x001924, 0x00FB8D,
-	0x00397D, 0x000820, 0x058040, 0x038042,
-	0x09844A, 0x000606, 0x08040A, 0x000424,
-	0x000424, 0x00117D, 0x018042, 0x08000A,
-	0x000A24, 0x280502, 0x280C02, 0x09800D,
-	0x000820, 0x0002FD, 0x018040, 0x200007,
-	0x0022FD, 0x018042, 0x08000A, 0x000095,
-	0x280DC4, 0x011924, 0x00197D, 0x018042,
-	0x0011FD, 0x09804A, 0x10000A, 0x0000B5,
-	0x113144, 0x0A8D04, 0x000007, 0x080A44,
-	0x129504, 0x000007, 0x0023FD, 0x001020,
-	0x038040, 0x101244, 0x000007, 0x000820,
-	0x039060, 0x018040, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x10FA86, 0x000007,
-	0x003BFD, 0x000100, 0x000A10, 0x0B807A,
-	0x13804A, 0x090984, 0x000007, 0x000095,
-	0x013D04, 0x118086, 0x10000A, 0x100002,
-	0x090984, 0x000007, 0x038042, 0x11804A,
-	0x090D04, 0x000007, 0x10000A, 0x090D84,
-	0x000007, 0x00257D, 0x000820, 0x018040,
-	0x00010D, 0x000810, 0x28143A, 0x00127D,
-	0x018042, 0x20000A, 0x00197D, 0x018042,
-	0x00117D, 0x31804A, 0x10000A, 0x003124,
-	0x01280D, 0x00397D, 0x000820, 0x058040,
-	0x038042, 0x09844A, 0x000606, 0x08040A,
-	0x300102, 0x003124, 0x000424, 0x000424,
-	0x001224, 0x280502, 0x001A4C, 0x130186,
-	0x700002, 0x00002D, 0x030000, 0x00387D,
-	0x018042, 0x10000A, 0x132A06, 0x002124,
-	0x0000AD, 0x100002, 0x00010D, 0x000924,
-	0x006B24, 0x01368D, 0x00397D, 0x000820,
-	0x058040, 0x038042, 0x09844A, 0x000606,
-	0x08040A, 0x003264, 0x00008D, 0x000A24,
-	0x001020, 0x00227D, 0x018040, 0x013C0D,
-	0x000810, 0x08043A, 0x29D206, 0x000007,
-	0x002820, 0x00207D, 0x018040, 0x00117D,
-	0x038042, 0x13804A, 0x33800A, 0x00387D,
-	0x018042, 0x08000A, 0x000904, 0x163A86,
-	0x000007, 0x00008D, 0x030964, 0x01478D,
-	0x00397D, 0x000820, 0x058040, 0x038042,
-	0x09844A, 0x000606, 0x08040A, 0x380102,
-	0x000424, 0x000424, 0x001224, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x14A286,
-	0x000007, 0x280502, 0x001A4C, 0x163986,
-	0x000007, 0x032164, 0x00632C, 0x003DFD,
-	0x018042, 0x08000A, 0x000095, 0x090904,
-	0x000007, 0x000820, 0x001A4C, 0x156186,
-	0x018040, 0x030000, 0x157A06, 0x002124,
-	0x00010D, 0x000924, 0x006B24, 0x015B8D,
-	0x00397D, 0x000820, 0x058040, 0x038042,
-	0x09844A, 0x000606, 0x08040A, 0x003A64,
-	0x000095, 0x001224, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x15DA86, 0x000007,
-	0x01628D, 0x000810, 0x08043A, 0x29D206,
-	0x000007, 0x14D206, 0x000007, 0x007020,
-	0x08010A, 0x10012A, 0x0020FD, 0x038860,
-	0x039060, 0x018040, 0x00227D, 0x018042,
-	0x003DFD, 0x08000A, 0x31844A, 0x000904,
-	0x16D886, 0x18008B, 0x00008D, 0x189904,
-	0x00312C, 0x17AA06, 0x000007, 0x00324C,
-	0x173386, 0x000007, 0x001904, 0x173086,
-	0x000007, 0x000095, 0x199144, 0x00222C,
-	0x003124, 0x00636C, 0x000E3D, 0x001375,
-	0x000BFD, 0x010042, 0x09804A, 0x10000A,
-	0x038AEC, 0x0393EC, 0x00224C, 0x17A986,
-	0x000007, 0x00008D, 0x189904, 0x00226C,
-	0x00322C, 0x30050A, 0x301DAB, 0x002083,
-	0x0018FD, 0x018042, 0x08000A, 0x018924,
-	0x300502, 0x001083, 0x001875, 0x010042,
-	0x10000A, 0x00008D, 0x010924, 0x001375,
-	0x330542, 0x330CCB, 0x332CCB, 0x3334CB,
-	0x333CCB, 0x3344CB, 0x334CCB, 0x3354CB,
-	0x305C8B, 0x006083, 0x0002F5, 0x010042,
-	0x08000A, 0x000904, 0x187A86, 0x000007,
-	0x001E2D, 0x0005FD, 0x018042, 0x08000A,
-	0x028924, 0x280502, 0x00060D, 0x000810,
-	0x280C3A, 0x00008D, 0x000810, 0x28143A,
-	0x0A808D, 0x000820, 0x0002F5, 0x010040,
-	0x220007, 0x001275, 0x030042, 0x21004A,
-	0x00008D, 0x1A0944, 0x000007, 0x01980D,
-	0x000810, 0x08043A, 0x2B2206, 0x000007,
-	0x0001F5, 0x030042, 0x0D004A, 0x10000A,
-	0x089144, 0x000007, 0x000820, 0x010040,
-	0x0025F5, 0x0A3144, 0x000007, 0x000820,
-	0x032860, 0x030040, 0x00217D, 0x038042,
-	0x0B804A, 0x10000A, 0x000820, 0x031060,
-	0x030040, 0x00008D, 0x000124, 0x00012C,
-	0x000E64, 0x001A64, 0x00636C, 0x08010A,
-	0x10012A, 0x000820, 0x031060, 0x030040,
-	0x0020FD, 0x018042, 0x08000A, 0x00227D,
-	0x018042, 0x10000A, 0x000820, 0x031060,
-	0x030040, 0x00197D, 0x018042, 0x08000A,
-	0x0022FD, 0x038042, 0x10000A, 0x000820,
-	0x031060, 0x030040, 0x090D04, 0x000007,
-	0x000820, 0x030040, 0x038042, 0x0B804A,
-	0x10000A, 0x000820, 0x031060, 0x030040,
-	0x038042, 0x13804A, 0x19804A, 0x110D04,
-	0x198D04, 0x000007, 0x08000A, 0x001020,
-	0x031860, 0x030860, 0x030040, 0x00008D,
-	0x0B0944, 0x000007, 0x000820, 0x010040,
-	0x0005F5, 0x030042, 0x08000A, 0x000820,
-	0x010040, 0x0000F5, 0x010042, 0x08000A,
-	0x000904, 0x1C6086, 0x001E75, 0x030042,
-	0x01044A, 0x000C0A, 0x1C7206, 0x000007,
-	0x000402, 0x000C02, 0x00177D, 0x001AF5,
-	0x018042, 0x03144A, 0x031C4A, 0x03244A,
-	0x032C4A, 0x03344A, 0x033C4A, 0x03444A,
-	0x004C0A, 0x00043D, 0x0013F5, 0x001AFD,
-	0x030042, 0x0B004A, 0x1B804A, 0x13804A,
-	0x20000A, 0x089144, 0x19A144, 0x0389E4,
-	0x0399EC, 0x005502, 0x005D0A, 0x030042,
-	0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
-	0x089144, 0x19A144, 0x0389E4, 0x0399EC,
-	0x006502, 0x006D0A, 0x030042, 0x0B004A,
-	0x19004A, 0x2B804A, 0x13804A, 0x21804A,
-	0x30000A, 0x089144, 0x19A144, 0x2AB144,
-	0x0389E4, 0x0399EC, 0x007502, 0x007D0A,
-	0x03A9E4, 0x000702, 0x00107D, 0x000415,
-	0x018042, 0x08000A, 0x0109E4, 0x000F02,
-	0x002AF5, 0x0019FD, 0x010042, 0x09804A,
-	0x10000A, 0x000934, 0x001674, 0x0029F5,
-	0x010042, 0x10000A, 0x00917C, 0x002075,
-	0x010042, 0x08000A, 0x000904, 0x1ED286,
-	0x0026F5, 0x0027F5, 0x030042, 0x09004A,
-	0x10000A, 0x000A3C, 0x00167C, 0x001A75,
-	0x000BFD, 0x010042, 0x51804A, 0x48000A,
-	0x160007, 0x001075, 0x010042, 0x282C0A,
-	0x281D12, 0x282512, 0x001F32, 0x1E0007,
-	0x0E0007, 0x001975, 0x010042, 0x002DF5,
-	0x0D004A, 0x10000A, 0x009144, 0x1FB286,
-	0x010042, 0x28340A, 0x000E5D, 0x00008D,
-	0x000375, 0x000820, 0x010040, 0x05D2F4,
-	0x54D104, 0x00735C, 0x205386, 0x000007,
-	0x0C0007, 0x080007, 0x0A0007, 0x02040D,
-	0x000810, 0x08043A, 0x332206, 0x000007,
-	0x205A06, 0x000007, 0x080007, 0x002275,
-	0x010042, 0x20000A, 0x002104, 0x212086,
-	0x001E2D, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x209286, 0x000007, 0x002010,
-	0x30043A, 0x00057D, 0x0180C3, 0x08000A,
-	0x028924, 0x280502, 0x280C02, 0x0A810D,
-	0x000820, 0x0002F5, 0x010040, 0x220007,
-	0x0004FD, 0x018042, 0x70000A, 0x030000,
-	0x007020, 0x06FA06, 0x018040, 0x02180D,
-	0x000810, 0x08043A, 0x2B2206, 0x000007,
-	0x0002FD, 0x018042, 0x08000A, 0x000904,
-	0x218A86, 0x000007, 0x01F206, 0x000007,
-	0x000875, 0x0009FD, 0x00010D, 0x220A06,
-	0x000295, 0x000B75, 0x00097D, 0x00000D,
-	0x000515, 0x010042, 0x18000A, 0x001904,
-	0x287886, 0x0006F5, 0x001020, 0x010040,
-	0x0004F5, 0x000820, 0x010040, 0x000775,
-	0x010042, 0x09804A, 0x10000A, 0x001124,
-	0x000904, 0x22BA86, 0x000815, 0x080102,
-	0x101204, 0x22DA06, 0x000575, 0x081204,
-	0x000007, 0x100102, 0x000575, 0x000425,
-	0x021124, 0x100102, 0x000820, 0x031060,
-	0x010040, 0x001924, 0x287886, 0x00008D,
-	0x000464, 0x009D04, 0x278886, 0x180102,
-	0x000575, 0x010042, 0x28040A, 0x00018D,
-	0x000924, 0x280D02, 0x00000D, 0x000924,
-	0x281502, 0x10000D, 0x000820, 0x0002F5,
-	0x010040, 0x200007, 0x001175, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x23C286,
-	0x000007, 0x000100, 0x080B20, 0x130B60,
-	0x1B0B60, 0x030A60, 0x010040, 0x050042,
-	0x3D004A, 0x35004A, 0x2D004A, 0x20000A,
-	0x0006F5, 0x010042, 0x28140A, 0x0004F5,
-	0x010042, 0x08000A, 0x000315, 0x010D04,
-	0x24CA86, 0x004015, 0x000095, 0x010D04,
-	0x24B886, 0x100022, 0x10002A, 0x24E206,
-	0x000007, 0x333104, 0x2AA904, 0x000007,
-	0x032124, 0x280502, 0x001124, 0x000424,
-	0x000424, 0x003224, 0x00292C, 0x00636C,
-	0x25F386, 0x000007, 0x02B164, 0x000464,
-	0x000464, 0x00008D, 0x000A64, 0x280D02,
-	0x10008D, 0x000820, 0x0002F5, 0x010040,
-	0x220007, 0x00008D, 0x38B904, 0x000007,
-	0x03296C, 0x30010A, 0x0002F5, 0x010042,
-	0x08000A, 0x000904, 0x25BA86, 0x000007,
-	0x02312C, 0x28050A, 0x00008D, 0x01096C,
-	0x280D0A, 0x10010D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x001124, 0x000424,
-	0x000424, 0x003224, 0x300102, 0x032944,
-	0x267A86, 0x000007, 0x300002, 0x0004F5,
-	0x010042, 0x08000A, 0x000315, 0x010D04,
-	0x26C086, 0x003124, 0x000464, 0x300102,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x26CA86, 0x000007, 0x003124, 0x300502,
-	0x003924, 0x300583, 0x000883, 0x0005F5,
-	0x010042, 0x28040A, 0x00008D, 0x008124,
-	0x280D02, 0x00008D, 0x008124, 0x281502,
-	0x10018D, 0x000820, 0x0002F5, 0x010040,
-	0x220007, 0x001025, 0x000575, 0x030042,
-	0x09004A, 0x10000A, 0x0A0904, 0x121104,
-	0x000007, 0x001020, 0x050860, 0x050040,
-	0x0006FD, 0x018042, 0x09004A, 0x10000A,
-	0x0000A5, 0x0A0904, 0x121104, 0x000007,
-	0x000820, 0x019060, 0x010040, 0x0002F5,
-	0x010042, 0x08000A, 0x000904, 0x284286,
-	0x000007, 0x230A06, 0x000007, 0x000606,
-	0x000007, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x289286, 0x000007, 0x000100,
-	0x080B20, 0x138B60, 0x1B8B60, 0x238B60,
-	0x2B8B60, 0x338B60, 0x3B8B60, 0x438B60,
-	0x4B8B60, 0x538B60, 0x5B8B60, 0x638B60,
-	0x6B8B60, 0x738B60, 0x7B8B60, 0x038F60,
-	0x0B8F60, 0x138F60, 0x1B8F60, 0x238F60,
-	0x2B8F60, 0x338F60, 0x3B8F60, 0x438F60,
-	0x4B8F60, 0x538F60, 0x5B8F60, 0x638F60,
-	0x6B8F60, 0x738F60, 0x7B8F60, 0x038A60,
-	0x000606, 0x018040, 0x00008D, 0x000A64,
-	0x280D02, 0x000A24, 0x00027D, 0x018042,
-	0x10000A, 0x001224, 0x0003FD, 0x018042,
-	0x08000A, 0x000904, 0x2A8286, 0x000007,
-	0x00018D, 0x000A24, 0x000464, 0x000464,
-	0x080102, 0x000924, 0x000424, 0x000424,
-	0x100102, 0x02000D, 0x009144, 0x2AD986,
-	0x000007, 0x0001FD, 0x018042, 0x08000A,
-	0x000A44, 0x2ABB86, 0x018042, 0x0A000D,
-	0x000820, 0x0002FD, 0x018040, 0x200007,
-	0x00027D, 0x001020, 0x000606, 0x018040,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x2B2A86, 0x000007, 0x00037D, 0x018042,
-	0x08000A, 0x000904, 0x2B5A86, 0x000007,
-	0x000075, 0x002E7D, 0x010042, 0x0B804A,
-	0x000020, 0x000904, 0x000686, 0x010040,
-	0x31844A, 0x30048B, 0x000883, 0x00008D,
-	0x000810, 0x28143A, 0x00008D, 0x000810,
-	0x280C3A, 0x000675, 0x010042, 0x08000A,
-	0x003815, 0x010924, 0x280502, 0x0B000D,
-	0x000820, 0x0002F5, 0x010040, 0x000606,
-	0x220007, 0x000464, 0x000464, 0x000606,
-	0x000007, 0x000134, 0x007F8D, 0x00093C,
-	0x281D12, 0x282512, 0x001F32, 0x0E0007,
-	0x00010D, 0x00037D, 0x000820, 0x018040,
-	0x05D2F4, 0x000007, 0x080007, 0x00037D,
-	0x018042, 0x08000A, 0x000904, 0x2D0286,
-	0x000007, 0x000606, 0x000007, 0x000007,
-	0x000012, 0x100007, 0x320007, 0x600007,
-	0x100080, 0x48001A, 0x004904, 0x2D6186,
-	0x000007, 0x001210, 0x58003A, 0x000145,
-	0x5C5D04, 0x000007, 0x000080, 0x48001A,
-	0x004904, 0x2DB186, 0x000007, 0x001210,
-	0x50003A, 0x005904, 0x2E0886, 0x000045,
-	0x0000C5, 0x7FFFF5, 0x7FFF7D, 0x07D524,
-	0x004224, 0x500102, 0x200502, 0x000082,
-	0x40001A, 0x004104, 0x2E3986, 0x000007,
-	0x003865, 0x40001A, 0x004020, 0x00104D,
-	0x04C184, 0x301B86, 0x000040, 0x040007,
-	0x000165, 0x000145, 0x004020, 0x000040,
-	0x000765, 0x080080, 0x40001A, 0x004104,
-	0x2EC986, 0x000007, 0x001210, 0x40003A,
-	0x004104, 0x2F2286, 0x00004D, 0x0000CD,
-	0x004810, 0x20043A, 0x000882, 0x40001A,
-	0x004104, 0x2F3186, 0x000007, 0x004820,
-	0x005904, 0x300886, 0x000040, 0x0007E5,
-	0x200480, 0x2816A0, 0x3216E0, 0x3A16E0,
-	0x4216E0, 0x021260, 0x000040, 0x000032,
-	0x400075, 0x00007D, 0x07D574, 0x200512,
-	0x000082, 0x40001A, 0x004104, 0x2FE186,
-	0x000007, 0x037206, 0x640007, 0x060007,
-	0x0000E5, 0x000020, 0x000040, 0x000A65,
-	0x000020, 0x020040, 0x020040, 0x000040,
-	0x000165, 0x000042, 0x70000A, 0x007104,
-	0x30A286, 0x000007, 0x018206, 0x640007,
-	0x050000, 0x007020, 0x000040, 0x037206,
-	0x640007, 0x000007, 0x00306D, 0x028860,
-	0x029060, 0x08000A, 0x028860, 0x008040,
-	0x100012, 0x00100D, 0x009184, 0x314186,
-	0x000E0D, 0x009184, 0x325186, 0x000007,
-	0x300007, 0x001020, 0x003B6D, 0x008040,
-	0x000080, 0x08001A, 0x000904, 0x316186,
-	0x000007, 0x001220, 0x000DED, 0x008040,
-	0x008042, 0x10000A, 0x40000D, 0x109544,
-	0x000007, 0x001020, 0x000DED, 0x008040,
-	0x008042, 0x20040A, 0x000082, 0x08001A,
-	0x000904, 0x31F186, 0x000007, 0x003B6D,
-	0x008042, 0x08000A, 0x000E15, 0x010984,
-	0x329B86, 0x600007, 0x08001A, 0x000C15,
-	0x010984, 0x328386, 0x000020, 0x1A0007,
-	0x0002ED, 0x008040, 0x620007, 0x00306D,
-	0x028042, 0x0A804A, 0x000820, 0x0A804A,
-	0x000606, 0x10804A, 0x000007, 0x282512,
-	0x001F32, 0x05D2F4, 0x54D104, 0x00735C,
-	0x000786, 0x000007, 0x0C0007, 0x0A0007,
-	0x1C0007, 0x003465, 0x020040, 0x004820,
-	0x025060, 0x40000A, 0x024060, 0x000040,
-	0x454944, 0x000007, 0x004020, 0x003AE5,
-	0x000040, 0x0028E5, 0x000042, 0x48000A,
-	0x004904, 0x386886, 0x002C65, 0x000042,
-	0x40000A, 0x0000D5, 0x454104, 0x000007,
-	0x000655, 0x054504, 0x34F286, 0x0001D5,
-	0x054504, 0x34F086, 0x002B65, 0x000042,
-	0x003AE5, 0x50004A, 0x40000A, 0x45C3D4,
-	0x000007, 0x454504, 0x000007, 0x0000CD,
-	0x444944, 0x000007, 0x454504, 0x000007,
-	0x00014D, 0x554944, 0x000007, 0x045144,
-	0x34E986, 0x002C65, 0x000042, 0x48000A,
-	0x4CD104, 0x000007, 0x04C144, 0x34F386,
-	0x000007, 0x160007, 0x002CE5, 0x040042,
-	0x40000A, 0x004020, 0x000040, 0x002965,
-	0x000042, 0x40000A, 0x004104, 0x356086,
-	0x000007, 0x002402, 0x36A206, 0x005C02,
-	0x0025E5, 0x000042, 0x40000A, 0x004274,
-	0x002AE5, 0x000042, 0x40000A, 0x004274,
-	0x500112, 0x0029E5, 0x000042, 0x40000A,
-	0x004234, 0x454104, 0x000007, 0x004020,
-	0x000040, 0x003EE5, 0x000020, 0x000040,
-	0x002DE5, 0x400152, 0x50000A, 0x045144,
-	0x364A86, 0x0000C5, 0x003EE5, 0x004020,
-	0x000040, 0x002BE5, 0x000042, 0x40000A,
-	0x404254, 0x000007, 0x002AE5, 0x004020,
-	0x000040, 0x500132, 0x040134, 0x005674,
-	0x0029E5, 0x020042, 0x42000A, 0x000042,
-	0x50000A, 0x05417C, 0x0028E5, 0x000042,
-	0x48000A, 0x0000C5, 0x4CC144, 0x371086,
-	0x0026E5, 0x0027E5, 0x020042, 0x40004A,
-	0x50000A, 0x00423C, 0x00567C, 0x0028E5,
-	0x004820, 0x000040, 0x281D12, 0x282512,
-	0x001F72, 0x002965, 0x000042, 0x40000A,
-	0x004104, 0x37AA86, 0x0E0007, 0x160007,
-	0x1E0007, 0x003EE5, 0x000042, 0x40000A,
-	0x004104, 0x37E886, 0x002D65, 0x000042,
-	0x28340A, 0x003465, 0x020042, 0x42004A,
-	0x004020, 0x4A004A, 0x50004A, 0x05D2F4,
-	0x54D104, 0x00735C, 0x385186, 0x000007,
-	0x000606, 0x080007, 0x0C0007, 0x080007,
-	0x0A0007, 0x0001E5, 0x020045, 0x004020,
-	0x000060, 0x000365, 0x000040, 0x002E65,
-	0x001A20, 0x0A1A60, 0x000040, 0x003465,
-	0x020042, 0x42004A, 0x004020, 0x4A004A,
-	0x000606, 0x50004A, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000
-};
-
-// --------------------------------------------
-//  DS-1E Controller InstructionRAM Code
-//	1999/06/21
-//	Buf441 slot is Enabled.
-// --------------------------------------------
-// 04/09?@creat
-// 04/12  stop nise fix
-// 06/21?@WorkingOff timming
-static unsigned long int	CntrlInst1E[] __initdata = {
-	0x000007, 0x240007, 0x0C0007, 0x1C0007,
-	0x060007, 0x700002, 0x000020, 0x030040,
-	0x007104, 0x004286, 0x030040, 0x000F0D,
-	0x000810, 0x20043A, 0x000282, 0x00020D,
-	0x000810, 0x20043A, 0x001282, 0x200E82,
-	0x00800D, 0x000810, 0x20043A, 0x001A82,
-	0x03460D, 0x000810, 0x10043A, 0x02EC0D,
-	0x000810, 0x18043A, 0x00010D, 0x020015,
-	0x0000FD, 0x000020, 0x038860, 0x039060,
-	0x038060, 0x038040, 0x038040, 0x038040,
-	0x018040, 0x000A7D, 0x038040, 0x038040,
-	0x018040, 0x200402, 0x000882, 0x08001A,
-	0x000904, 0x017186, 0x000007, 0x260007,
-	0x400007, 0x000007, 0x03258D, 0x000810,
-	0x18043A, 0x260007, 0x284402, 0x00087D,
-	0x018042, 0x00160A, 0x05A206, 0x000007,
-	0x440007, 0x00230D, 0x000810, 0x08043A,
-	0x22FA06, 0x000007, 0x0007FD, 0x018042,
-	0x08000A, 0x000904, 0x02AB86, 0x000195,
-	0x090D04, 0x000007, 0x000820, 0x0000F5,
-	0x000B7D, 0x01F060, 0x0000FD, 0x033A06,
-	0x018040, 0x000A7D, 0x038042, 0x13804A,
-	0x18000A, 0x001820, 0x059060, 0x058860,
-	0x018040, 0x0000FD, 0x018042, 0x70000A,
-	0x000115, 0x071144, 0x033B86, 0x030000,
-	0x007020, 0x036206, 0x018040, 0x00360D,
-	0x000810, 0x08043A, 0x232206, 0x000007,
-	0x02EC0D, 0x000810, 0x18043A, 0x019A06,
-	0x000007, 0x240007, 0x000F8D, 0x000810,
-	0x00163A, 0x002402, 0x005C02, 0x0028FD,
-	0x000020, 0x018040, 0x08000D, 0x000815,
-	0x510984, 0x000007, 0x00004D, 0x000E5D,
-	0x000E02, 0x00430D, 0x000810, 0x08043A,
-	0x2E1206, 0x000007, 0x00008D, 0x000924,
-	0x000F02, 0x00470D, 0x000810, 0x08043A,
-	0x2E1206, 0x000007, 0x480480, 0x001210,
-	0x28043A, 0x00778D, 0x000810, 0x280C3A,
-	0x00068D, 0x000810, 0x28143A, 0x284402,
-	0x03258D, 0x000810, 0x18043A, 0x07FF8D,
-	0x000820, 0x0002FD, 0x018040, 0x260007,
-	0x200007, 0x0002FD, 0x018042, 0x08000A,
-	0x000904, 0x051286, 0x000007, 0x240007,
-	0x02EC0D, 0x000810, 0x18043A, 0x00387D,
-	0x018042, 0x08000A, 0x001015, 0x010984,
-	0x019B86, 0x000007, 0x01B206, 0x000007,
-	0x0008FD, 0x018042, 0x18000A, 0x001904,
-	0x22B886, 0x280007, 0x001810, 0x28043A,
-	0x280C02, 0x00000D, 0x000810, 0x28143A,
-	0x08808D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00020D, 0x189904, 0x000007,
-	0x00402D, 0x0000BD, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x065A86, 0x000007,
-	0x000100, 0x000A20, 0x00047D, 0x018040,
-	0x018042, 0x20000A, 0x003015, 0x012144,
-	0x036186, 0x000007, 0x002104, 0x036186,
-	0x000007, 0x000F8D, 0x000810, 0x280C3A,
-	0x023944, 0x07C986, 0x000007, 0x001810,
-	0x28043A, 0x08810D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x002810, 0x78003A,
-	0x00788D, 0x000810, 0x08043A, 0x2A1206,
-	0x000007, 0x00400D, 0x001015, 0x189904,
-	0x292904, 0x393904, 0x000007, 0x070206,
-	0x000007, 0x0004F5, 0x00007D, 0x000020,
-	0x00008D, 0x010860, 0x018040, 0x00047D,
-	0x038042, 0x21804A, 0x18000A, 0x021944,
-	0x229086, 0x000007, 0x004075, 0x71F104,
-	0x000007, 0x010042, 0x28000A, 0x002904,
-	0x225886, 0x000007, 0x003C0D, 0x30A904,
-	0x000007, 0x00077D, 0x018042, 0x08000A,
-	0x000904, 0x08DA86, 0x00057D, 0x002820,
-	0x03B060, 0x08F206, 0x018040, 0x003020,
-	0x03A860, 0x018040, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x08FA86, 0x000007,
-	0x00057D, 0x018042, 0x28040A, 0x000E8D,
-	0x000810, 0x280C3A, 0x00000D, 0x000810,
-	0x28143A, 0x09000D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x003DFD, 0x000020,
-	0x018040, 0x00107D, 0x009D8D, 0x000810,
-	0x08043A, 0x2A1206, 0x000007, 0x000815,
-	0x08001A, 0x010984, 0x0A5186, 0x00137D,
-	0x200500, 0x280F20, 0x338F60, 0x3B8F60,
-	0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
-	0x038A60, 0x018040, 0x00107D, 0x018042,
-	0x08000A, 0x000215, 0x010984, 0x3A8186,
-	0x000007, 0x007FBD, 0x383DC4, 0x000007,
-	0x001A7D, 0x001375, 0x018042, 0x09004A,
-	0x10000A, 0x0B8D04, 0x139504, 0x000007,
-	0x000820, 0x019060, 0x001104, 0x225886,
-	0x010040, 0x0017FD, 0x018042, 0x08000A,
-	0x000904, 0x225A86, 0x000007, 0x00197D,
-	0x038042, 0x09804A, 0x10000A, 0x000924,
-	0x001664, 0x0011FD, 0x038042, 0x2B804A,
-	0x19804A, 0x00008D, 0x218944, 0x000007,
-	0x002244, 0x0C1986, 0x000007, 0x001A64,
-	0x002A24, 0x00197D, 0x080102, 0x100122,
-	0x000820, 0x039060, 0x018040, 0x003DFD,
-	0x00008D, 0x000820, 0x018040, 0x001375,
-	0x001A7D, 0x010042, 0x09804A, 0x10000A,
-	0x00021D, 0x0189E4, 0x2992E4, 0x309144,
-	0x000007, 0x00060D, 0x000A15, 0x000C1D,
-	0x001025, 0x00A9E4, 0x012BE4, 0x000464,
-	0x01B3E4, 0x0232E4, 0x000464, 0x000464,
-	0x000464, 0x000464, 0x00040D, 0x08B1C4,
-	0x000007, 0x000820, 0x000BF5, 0x030040,
-	0x00197D, 0x038042, 0x09804A, 0x000A24,
-	0x08000A, 0x080E64, 0x000007, 0x100122,
-	0x000820, 0x031060, 0x010040, 0x0064AC,
-	0x00027D, 0x000020, 0x018040, 0x00107D,
-	0x018042, 0x0011FD, 0x3B804A, 0x09804A,
-	0x20000A, 0x000095, 0x1A1144, 0x00A144,
-	0x0E5886, 0x00040D, 0x00B984, 0x0E5986,
-	0x0018FD, 0x018042, 0x0010FD, 0x09804A,
-	0x28000A, 0x000095, 0x010924, 0x002A64,
-	0x0E4986, 0x000007, 0x002904, 0x0E5A86,
-	0x000007, 0x0E6206, 0x080002, 0x00008D,
-	0x00387D, 0x000820, 0x018040, 0x00127D,
-	0x018042, 0x10000A, 0x003904, 0x0F0986,
-	0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986,
-	0x000025, 0x0FB206, 0x00002D, 0x000015,
-	0x00082D, 0x02E00D, 0x000820, 0x0FFA06,
-	0x00000D, 0x7F8035, 0x00B984, 0x0FA986,
-	0x400025, 0x00008D, 0x110944, 0x000007,
-	0x00018D, 0x109504, 0x000007, 0x009164,
-	0x000424, 0x000424, 0x000424, 0x100102,
-	0x280002, 0x02DF0D, 0x000820, 0x0FFA06,
-	0x00018D, 0x00042D, 0x00008D, 0x109504,
-	0x000007, 0x00020D, 0x109184, 0x000007,
-	0x02DF8D, 0x000820, 0x00008D, 0x0038FD,
-	0x018040, 0x003BFD, 0x001020, 0x03A860,
-	0x000815, 0x313184, 0x212184, 0x000007,
-	0x03B060, 0x03A060, 0x018040, 0x0022FD,
-	0x000095, 0x010924, 0x000424, 0x000424,
-	0x001264, 0x100102, 0x000820, 0x039060,
-	0x018040, 0x001924, 0x010F0D, 0x00397D,
-	0x000820, 0x058040, 0x038042, 0x09844A,
-	0x000606, 0x08040A, 0x000424, 0x000424,
-	0x00117D, 0x018042, 0x08000A, 0x000A24,
-	0x280502, 0x280C02, 0x09800D, 0x000820,
-	0x0002FD, 0x018040, 0x200007, 0x0022FD,
-	0x018042, 0x08000A, 0x000095, 0x280DC4,
-	0x011924, 0x00197D, 0x018042, 0x0011FD,
-	0x09804A, 0x10000A, 0x0000B5, 0x113144,
-	0x0A8D04, 0x000007, 0x080A44, 0x129504,
-	0x000007, 0x0023FD, 0x001020, 0x038040,
-	0x101244, 0x000007, 0x000820, 0x039060,
-	0x018040, 0x0002FD, 0x018042, 0x08000A,
-	0x000904, 0x123286, 0x000007, 0x003BFD,
-	0x000100, 0x000A10, 0x0B807A, 0x13804A,
-	0x090984, 0x000007, 0x000095, 0x013D04,
-	0x12B886, 0x10000A, 0x100002, 0x090984,
-	0x000007, 0x038042, 0x11804A, 0x090D04,
-	0x000007, 0x10000A, 0x090D84, 0x000007,
-	0x00257D, 0x000820, 0x018040, 0x00010D,
-	0x000810, 0x28143A, 0x00127D, 0x018042,
-	0x20000A, 0x00197D, 0x018042, 0x00117D,
-	0x31804A, 0x10000A, 0x003124, 0x013B8D,
-	0x00397D, 0x000820, 0x058040, 0x038042,
-	0x09844A, 0x000606, 0x08040A, 0x300102,
-	0x003124, 0x000424, 0x000424, 0x001224,
-	0x280502, 0x001A4C, 0x143986, 0x700002,
-	0x00002D, 0x030000, 0x00387D, 0x018042,
-	0x10000A, 0x146206, 0x002124, 0x0000AD,
-	0x100002, 0x00010D, 0x000924, 0x006B24,
-	0x014A0D, 0x00397D, 0x000820, 0x058040,
-	0x038042, 0x09844A, 0x000606, 0x08040A,
-	0x003264, 0x00008D, 0x000A24, 0x001020,
-	0x00227D, 0x018040, 0x014F8D, 0x000810,
-	0x08043A, 0x2B5A06, 0x000007, 0x002820,
-	0x00207D, 0x018040, 0x00117D, 0x038042,
-	0x13804A, 0x33800A, 0x00387D, 0x018042,
-	0x08000A, 0x000904, 0x177286, 0x000007,
-	0x00008D, 0x030964, 0x015B0D, 0x00397D,
-	0x000820, 0x058040, 0x038042, 0x09844A,
-	0x000606, 0x08040A, 0x380102, 0x000424,
-	0x000424, 0x001224, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x15DA86, 0x000007,
-	0x280502, 0x001A4C, 0x177186, 0x000007,
-	0x032164, 0x00632C, 0x003DFD, 0x018042,
-	0x08000A, 0x000095, 0x090904, 0x000007,
-	0x000820, 0x001A4C, 0x169986, 0x018040,
-	0x030000, 0x16B206, 0x002124, 0x00010D,
-	0x000924, 0x006B24, 0x016F0D, 0x00397D,
-	0x000820, 0x058040, 0x038042, 0x09844A,
-	0x000606, 0x08040A, 0x003A64, 0x000095,
-	0x001224, 0x0002FD, 0x018042, 0x08000A,
-	0x000904, 0x171286, 0x000007, 0x01760D,
-	0x000810, 0x08043A, 0x2B5A06, 0x000007,
-	0x160A06, 0x000007, 0x007020, 0x08010A,
-	0x10012A, 0x0020FD, 0x038860, 0x039060,
-	0x018040, 0x00227D, 0x018042, 0x003DFD,
-	0x08000A, 0x31844A, 0x000904, 0x181086,
-	0x18008B, 0x00008D, 0x189904, 0x00312C,
-	0x18E206, 0x000007, 0x00324C, 0x186B86,
-	0x000007, 0x001904, 0x186886, 0x000007,
-	0x000095, 0x199144, 0x00222C, 0x003124,
-	0x00636C, 0x000E3D, 0x001375, 0x000BFD,
-	0x010042, 0x09804A, 0x10000A, 0x038AEC,
-	0x0393EC, 0x00224C, 0x18E186, 0x000007,
-	0x00008D, 0x189904, 0x00226C, 0x00322C,
-	0x30050A, 0x301DAB, 0x002083, 0x0018FD,
-	0x018042, 0x08000A, 0x018924, 0x300502,
-	0x001083, 0x001875, 0x010042, 0x10000A,
-	0x00008D, 0x010924, 0x001375, 0x330542,
-	0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB,
-	0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B,
-	0x006083, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x19B286, 0x000007, 0x001E2D,
-	0x0005FD, 0x018042, 0x08000A, 0x028924,
-	0x280502, 0x00060D, 0x000810, 0x280C3A,
-	0x00008D, 0x000810, 0x28143A, 0x0A808D,
-	0x000820, 0x0002F5, 0x010040, 0x220007,
-	0x001275, 0x030042, 0x21004A, 0x00008D,
-	0x1A0944, 0x000007, 0x01AB8D, 0x000810,
-	0x08043A, 0x2CAA06, 0x000007, 0x0001F5,
-	0x030042, 0x0D004A, 0x10000A, 0x089144,
-	0x000007, 0x000820, 0x010040, 0x0025F5,
-	0x0A3144, 0x000007, 0x000820, 0x032860,
-	0x030040, 0x00217D, 0x038042, 0x0B804A,
-	0x10000A, 0x000820, 0x031060, 0x030040,
-	0x00008D, 0x000124, 0x00012C, 0x000E64,
-	0x001A64, 0x00636C, 0x08010A, 0x10012A,
-	0x000820, 0x031060, 0x030040, 0x0020FD,
-	0x018042, 0x08000A, 0x00227D, 0x018042,
-	0x10000A, 0x000820, 0x031060, 0x030040,
-	0x00197D, 0x018042, 0x08000A, 0x0022FD,
-	0x038042, 0x10000A, 0x000820, 0x031060,
-	0x030040, 0x090D04, 0x000007, 0x000820,
-	0x030040, 0x038042, 0x0B804A, 0x10000A,
-	0x000820, 0x031060, 0x030040, 0x038042,
-	0x13804A, 0x19804A, 0x110D04, 0x198D04,
-	0x000007, 0x08000A, 0x001020, 0x031860,
-	0x030860, 0x030040, 0x00008D, 0x0B0944,
-	0x000007, 0x000820, 0x010040, 0x0005F5,
-	0x030042, 0x08000A, 0x000820, 0x010040,
-	0x0000F5, 0x010042, 0x08000A, 0x000904,
-	0x1D9886, 0x001E75, 0x030042, 0x01044A,
-	0x000C0A, 0x1DAA06, 0x000007, 0x000402,
-	0x000C02, 0x00177D, 0x001AF5, 0x018042,
-	0x03144A, 0x031C4A, 0x03244A, 0x032C4A,
-	0x03344A, 0x033C4A, 0x03444A, 0x004C0A,
-	0x00043D, 0x0013F5, 0x001AFD, 0x030042,
-	0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
-	0x089144, 0x19A144, 0x0389E4, 0x0399EC,
-	0x005502, 0x005D0A, 0x030042, 0x0B004A,
-	0x1B804A, 0x13804A, 0x20000A, 0x089144,
-	0x19A144, 0x0389E4, 0x0399EC, 0x006502,
-	0x006D0A, 0x030042, 0x0B004A, 0x19004A,
-	0x2B804A, 0x13804A, 0x21804A, 0x30000A,
-	0x089144, 0x19A144, 0x2AB144, 0x0389E4,
-	0x0399EC, 0x007502, 0x007D0A, 0x03A9E4,
-	0x000702, 0x00107D, 0x000415, 0x018042,
-	0x08000A, 0x0109E4, 0x000F02, 0x002AF5,
-	0x0019FD, 0x010042, 0x09804A, 0x10000A,
-	0x000934, 0x001674, 0x0029F5, 0x010042,
-	0x10000A, 0x00917C, 0x002075, 0x010042,
-	0x08000A, 0x000904, 0x200A86, 0x0026F5,
-	0x0027F5, 0x030042, 0x09004A, 0x10000A,
-	0x000A3C, 0x00167C, 0x001A75, 0x000BFD,
-	0x010042, 0x51804A, 0x48000A, 0x160007,
-	0x001075, 0x010042, 0x282C0A, 0x281D12,
-	0x282512, 0x001F32, 0x1E0007, 0x0E0007,
-	0x001975, 0x010042, 0x002DF5, 0x0D004A,
-	0x10000A, 0x009144, 0x20EA86, 0x010042,
-	0x28340A, 0x000E5D, 0x00008D, 0x000375,
-	0x000820, 0x010040, 0x05D2F4, 0x54D104,
-	0x00735C, 0x218B86, 0x000007, 0x0C0007,
-	0x080007, 0x0A0007, 0x02178D, 0x000810,
-	0x08043A, 0x34B206, 0x000007, 0x219206,
-	0x000007, 0x080007, 0x002275, 0x010042,
-	0x20000A, 0x002104, 0x225886, 0x001E2D,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x21CA86, 0x000007, 0x002010, 0x30043A,
-	0x00057D, 0x0180C3, 0x08000A, 0x028924,
-	0x280502, 0x280C02, 0x0A810D, 0x000820,
-	0x0002F5, 0x010040, 0x220007, 0x0004FD,
-	0x018042, 0x70000A, 0x030000, 0x007020,
-	0x07FA06, 0x018040, 0x022B8D, 0x000810,
-	0x08043A, 0x2CAA06, 0x000007, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x22C286,
-	0x000007, 0x020206, 0x000007, 0x000875,
-	0x0009FD, 0x00010D, 0x234206, 0x000295,
-	0x000B75, 0x00097D, 0x00000D, 0x000515,
-	0x010042, 0x18000A, 0x001904, 0x2A0086,
-	0x0006F5, 0x001020, 0x010040, 0x0004F5,
-	0x000820, 0x010040, 0x000775, 0x010042,
-	0x09804A, 0x10000A, 0x001124, 0x000904,
-	0x23F286, 0x000815, 0x080102, 0x101204,
-	0x241206, 0x000575, 0x081204, 0x000007,
-	0x100102, 0x000575, 0x000425, 0x021124,
-	0x100102, 0x000820, 0x031060, 0x010040,
-	0x001924, 0x2A0086, 0x00008D, 0x000464,
-	0x009D04, 0x291086, 0x180102, 0x000575,
-	0x010042, 0x28040A, 0x00018D, 0x000924,
-	0x280D02, 0x00000D, 0x000924, 0x281502,
-	0x10000D, 0x000820, 0x0002F5, 0x010040,
-	0x200007, 0x001175, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x24FA86, 0x000007,
-	0x000100, 0x080B20, 0x130B60, 0x1B0B60,
-	0x030A60, 0x010040, 0x050042, 0x3D004A,
-	0x35004A, 0x2D004A, 0x20000A, 0x0006F5,
-	0x010042, 0x28140A, 0x0004F5, 0x010042,
-	0x08000A, 0x000315, 0x010D04, 0x260286,
-	0x004015, 0x000095, 0x010D04, 0x25F086,
-	0x100022, 0x10002A, 0x261A06, 0x000007,
-	0x333104, 0x2AA904, 0x000007, 0x032124,
-	0x280502, 0x284402, 0x001124, 0x400102,
-	0x000424, 0x000424, 0x003224, 0x00292C,
-	0x00636C, 0x277386, 0x000007, 0x02B164,
-	0x000464, 0x000464, 0x00008D, 0x000A64,
-	0x280D02, 0x10008D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x00008D, 0x38B904,
-	0x000007, 0x03296C, 0x30010A, 0x0002F5,
-	0x010042, 0x08000A, 0x000904, 0x270286,
-	0x000007, 0x00212C, 0x28050A, 0x00316C,
-	0x00046C, 0x00046C, 0x28450A, 0x001124,
-	0x006B64, 0x100102, 0x00008D, 0x01096C,
-	0x280D0A, 0x10010D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x004124, 0x000424,
-	0x000424, 0x003224, 0x300102, 0x032944,
-	0x27FA86, 0x000007, 0x300002, 0x0004F5,
-	0x010042, 0x08000A, 0x000315, 0x010D04,
-	0x284086, 0x003124, 0x000464, 0x300102,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x284A86, 0x000007, 0x284402, 0x003124,
-	0x300502, 0x003924, 0x300583, 0x000883,
-	0x0005F5, 0x010042, 0x28040A, 0x00008D,
-	0x008124, 0x280D02, 0x00008D, 0x008124,
-	0x281502, 0x10018D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x001025, 0x000575,
-	0x030042, 0x09004A, 0x10000A, 0x0A0904,
-	0x121104, 0x000007, 0x001020, 0x050860,
-	0x050040, 0x0006FD, 0x018042, 0x09004A,
-	0x10000A, 0x0000A5, 0x0A0904, 0x121104,
-	0x000007, 0x000820, 0x019060, 0x010040,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x29CA86, 0x000007, 0x244206, 0x000007,
-	0x000606, 0x000007, 0x0002F5, 0x010042,
-	0x08000A, 0x000904, 0x2A1A86, 0x000007,
-	0x000100, 0x080B20, 0x138B60, 0x1B8B60,
-	0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60,
-	0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60,
-	0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60,
-	0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60,
-	0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60,
-	0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
-	0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60,
-	0x038A60, 0x000606, 0x018040, 0x00008D,
-	0x000A64, 0x280D02, 0x000A24, 0x00027D,
-	0x018042, 0x10000A, 0x001224, 0x0003FD,
-	0x018042, 0x08000A, 0x000904, 0x2C0A86,
-	0x000007, 0x00018D, 0x000A24, 0x000464,
-	0x000464, 0x080102, 0x000924, 0x000424,
-	0x000424, 0x100102, 0x02000D, 0x009144,
-	0x2C6186, 0x000007, 0x0001FD, 0x018042,
-	0x08000A, 0x000A44, 0x2C4386, 0x018042,
-	0x0A000D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00027D, 0x001020, 0x000606,
-	0x018040, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x2CB286, 0x000007, 0x00037D,
-	0x018042, 0x08000A, 0x000904, 0x2CE286,
-	0x000007, 0x000075, 0x002E7D, 0x010042,
-	0x0B804A, 0x000020, 0x000904, 0x000686,
-	0x010040, 0x31844A, 0x30048B, 0x000883,
-	0x00008D, 0x000810, 0x28143A, 0x00008D,
-	0x000810, 0x280C3A, 0x000675, 0x010042,
-	0x08000A, 0x003815, 0x010924, 0x280502,
-	0x0B000D, 0x000820, 0x0002F5, 0x010040,
-	0x000606, 0x220007, 0x000464, 0x000464,
-	0x000606, 0x000007, 0x000134, 0x007F8D,
-	0x00093C, 0x281D12, 0x282512, 0x001F32,
-	0x0E0007, 0x00010D, 0x00037D, 0x000820,
-	0x018040, 0x05D2F4, 0x000007, 0x080007,
-	0x00037D, 0x018042, 0x08000A, 0x000904,
-	0x2E8A86, 0x000007, 0x000606, 0x000007,
-	0x000007, 0x000012, 0x100007, 0x320007,
-	0x600007, 0x460007, 0x100080, 0x48001A,
-	0x004904, 0x2EF186, 0x000007, 0x001210,
-	0x58003A, 0x000145, 0x5C5D04, 0x000007,
-	0x000080, 0x48001A, 0x004904, 0x2F4186,
-	0x000007, 0x001210, 0x50003A, 0x005904,
-	0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5,
-	0x7FFF7D, 0x07D524, 0x004224, 0x500102,
-	0x200502, 0x000082, 0x40001A, 0x004104,
-	0x2FC986, 0x000007, 0x003865, 0x40001A,
-	0x004020, 0x00104D, 0x04C184, 0x31AB86,
-	0x000040, 0x040007, 0x000165, 0x000145,
-	0x004020, 0x000040, 0x000765, 0x080080,
-	0x40001A, 0x004104, 0x305986, 0x000007,
-	0x001210, 0x40003A, 0x004104, 0x30B286,
-	0x00004D, 0x0000CD, 0x004810, 0x20043A,
-	0x000882, 0x40001A, 0x004104, 0x30C186,
-	0x000007, 0x004820, 0x005904, 0x319886,
-	0x000040, 0x0007E5, 0x200480, 0x2816A0,
-	0x3216E0, 0x3A16E0, 0x4216E0, 0x021260,
-	0x000040, 0x000032, 0x400075, 0x00007D,
-	0x07D574, 0x200512, 0x000082, 0x40001A,
-	0x004104, 0x317186, 0x000007, 0x038A06,
-	0x640007, 0x0000E5, 0x000020, 0x000040,
-	0x000A65, 0x000020, 0x020040, 0x020040,
-	0x000040, 0x000165, 0x000042, 0x70000A,
-	0x007104, 0x323286, 0x000007, 0x060007,
-	0x019A06, 0x640007, 0x050000, 0x007020,
-	0x000040, 0x038A06, 0x640007, 0x000007,
-	0x00306D, 0x028860, 0x029060, 0x08000A,
-	0x028860, 0x008040, 0x100012, 0x00100D,
-	0x009184, 0x32D186, 0x000E0D, 0x009184,
-	0x33E186, 0x000007, 0x300007, 0x001020,
-	0x003B6D, 0x008040, 0x000080, 0x08001A,
-	0x000904, 0x32F186, 0x000007, 0x001220,
-	0x000DED, 0x008040, 0x008042, 0x10000A,
-	0x40000D, 0x109544, 0x000007, 0x001020,
-	0x000DED, 0x008040, 0x008042, 0x20040A,
-	0x000082, 0x08001A, 0x000904, 0x338186,
-	0x000007, 0x003B6D, 0x008042, 0x08000A,
-	0x000E15, 0x010984, 0x342B86, 0x600007,
-	0x08001A, 0x000C15, 0x010984, 0x341386,
-	0x000020, 0x1A0007, 0x0002ED, 0x008040,
-	0x620007, 0x00306D, 0x028042, 0x0A804A,
-	0x000820, 0x0A804A, 0x000606, 0x10804A,
-	0x000007, 0x282512, 0x001F32, 0x05D2F4,
-	0x54D104, 0x00735C, 0x000786, 0x000007,
-	0x0C0007, 0x0A0007, 0x1C0007, 0x003465,
-	0x020040, 0x004820, 0x025060, 0x40000A,
-	0x024060, 0x000040, 0x454944, 0x000007,
-	0x004020, 0x003AE5, 0x000040, 0x0028E5,
-	0x000042, 0x48000A, 0x004904, 0x39F886,
-	0x002C65, 0x000042, 0x40000A, 0x0000D5,
-	0x454104, 0x000007, 0x000655, 0x054504,
-	0x368286, 0x0001D5, 0x054504, 0x368086,
-	0x002B65, 0x000042, 0x003AE5, 0x50004A,
-	0x40000A, 0x45C3D4, 0x000007, 0x454504,
-	0x000007, 0x0000CD, 0x444944, 0x000007,
-	0x454504, 0x000007, 0x00014D, 0x554944,
-	0x000007, 0x045144, 0x367986, 0x002C65,
-	0x000042, 0x48000A, 0x4CD104, 0x000007,
-	0x04C144, 0x368386, 0x000007, 0x160007,
-	0x002CE5, 0x040042, 0x40000A, 0x004020,
-	0x000040, 0x002965, 0x000042, 0x40000A,
-	0x004104, 0x36F086, 0x000007, 0x002402,
-	0x383206, 0x005C02, 0x0025E5, 0x000042,
-	0x40000A, 0x004274, 0x002AE5, 0x000042,
-	0x40000A, 0x004274, 0x500112, 0x0029E5,
-	0x000042, 0x40000A, 0x004234, 0x454104,
-	0x000007, 0x004020, 0x000040, 0x003EE5,
-	0x000020, 0x000040, 0x002DE5, 0x400152,
-	0x50000A, 0x045144, 0x37DA86, 0x0000C5,
-	0x003EE5, 0x004020, 0x000040, 0x002BE5,
-	0x000042, 0x40000A, 0x404254, 0x000007,
-	0x002AE5, 0x004020, 0x000040, 0x500132,
-	0x040134, 0x005674, 0x0029E5, 0x020042,
-	0x42000A, 0x000042, 0x50000A, 0x05417C,
-	0x0028E5, 0x000042, 0x48000A, 0x0000C5,
-	0x4CC144, 0x38A086, 0x0026E5, 0x0027E5,
-	0x020042, 0x40004A, 0x50000A, 0x00423C,
-	0x00567C, 0x0028E5, 0x004820, 0x000040,
-	0x281D12, 0x282512, 0x001F72, 0x002965,
-	0x000042, 0x40000A, 0x004104, 0x393A86,
-	0x0E0007, 0x160007, 0x1E0007, 0x003EE5,
-	0x000042, 0x40000A, 0x004104, 0x397886,
-	0x002D65, 0x000042, 0x28340A, 0x003465,
-	0x020042, 0x42004A, 0x004020, 0x4A004A,
-	0x50004A, 0x05D2F4, 0x54D104, 0x00735C,
-	0x39E186, 0x000007, 0x000606, 0x080007,
-	0x0C0007, 0x080007, 0x0A0007, 0x0001E5,
-	0x020045, 0x004020, 0x000060, 0x000365,
-	0x000040, 0x002E65, 0x001A20, 0x0A1A60,
-	0x000040, 0x003465, 0x020042, 0x42004A,
-	0x004020, 0x4A004A, 0x000606, 0x50004A,
-	0x0017FD, 0x018042, 0x08000A, 0x000904,
-	0x225A86, 0x000007, 0x00107D, 0x018042,
-	0x0011FD, 0x33804A, 0x19804A, 0x20000A,
-	0x000095, 0x2A1144, 0x01A144, 0x3B9086,
-	0x00040D, 0x00B184, 0x3B9186, 0x0018FD,
-	0x018042, 0x0010FD, 0x09804A, 0x38000A,
-	0x000095, 0x010924, 0x003A64, 0x3B8186,
-	0x000007, 0x003904, 0x3B9286, 0x000007,
-	0x3B9A06, 0x00000D, 0x00008D, 0x000820,
-	0x00387D, 0x018040, 0x700002, 0x00117D,
-	0x018042, 0x00197D, 0x29804A, 0x30000A,
-	0x380002, 0x003124, 0x000424, 0x000424,
-	0x002A24, 0x280502, 0x00068D, 0x000810,
-	0x28143A, 0x00750D, 0x00B124, 0x002264,
-	0x3D0386, 0x284402, 0x000810, 0x280C3A,
-	0x0B800D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00758D, 0x00B124, 0x100102,
-	0x012144, 0x3E4986, 0x001810, 0x10003A,
-	0x00387D, 0x018042, 0x08000A, 0x000904,
-	0x3E4886, 0x030000, 0x3E4A06, 0x0000BD,
-	0x00008D, 0x023164, 0x000A64, 0x280D02,
-	0x0B808D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00387D, 0x018042, 0x08000A,
-	0x000904, 0x3E3286, 0x030000, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x3D8286,
-	0x000007, 0x002810, 0x28043A, 0x00750D,
-	0x030924, 0x002264, 0x280D02, 0x02316C,
-	0x28450A, 0x0B810D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x00008D, 0x000A24,
-	0x3E4A06, 0x100102, 0x001810, 0x10003A,
-	0x0000BD, 0x003810, 0x30043A, 0x00187D,
-	0x018042, 0x0018FD, 0x09804A, 0x20000A,
-	0x0000AD, 0x028924, 0x07212C, 0x001010,
-	0x300583, 0x300D8B, 0x3014BB, 0x301C83,
-	0x002083, 0x00137D, 0x038042, 0x33844A,
-	0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB,
-	0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083,
-	0x001E0D, 0x0005FD, 0x018042, 0x20000A,
-	0x020924, 0x00068D, 0x00A96C, 0x00009D,
-	0x0002FD, 0x018042, 0x08000A, 0x000904,
-	0x3F6A86, 0x000007, 0x280502, 0x280D0A,
-	0x284402, 0x001810, 0x28143A, 0x0C008D,
-	0x000820, 0x0002FD, 0x018040, 0x220007,
-	0x003904, 0x225886, 0x001E0D, 0x00057D,
-	0x018042, 0x20000A, 0x020924, 0x0000A5,
-	0x0002FD, 0x018042, 0x08000A, 0x000904,
-	0x402A86, 0x000007, 0x280502, 0x280C02,
-	0x002010, 0x28143A, 0x0C010D, 0x000820,
-	0x0002FD, 0x018040, 0x225A06, 0x220007,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000
-};
-
-#endif	//_HWMCODE_
-
-
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/sound/Hwmcode.h linux-2.4.27-pre3/drivers/sound/Hwmcode.h
--- linux-2.4.26/drivers/sound/Hwmcode.h	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.27-pre3/drivers/sound/Hwmcode.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,804 +0,0 @@
-//=============================================================================
-// Copyright (c) 1997	Yamaha Corporation.	All Rights Reserved.
-//
-//	Title:
-//		hwmcode.c
-//	Desc:
-//		micro-code for CTRL & DSP
-//	HISTORY:
-//		April 03, 1997:		1st try by M. Mukojima
-//=============================================================================
-#define	YDSXG_DSPLENGTH				0x0080
-#define	YDSXG_CTRLLENGTH			0x3000
-
-
-static unsigned long int	gdwDSPCode[YDSXG_DSPLENGTH >> 2] = {
-	0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
-	0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
-	0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
-	0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000
-};
-
-
-// --------------------------------------------
-//  DS-1E Controller InstructionRAM Code
-//	1999/06/21
-//	Buf441 slot is Enabled.
-// --------------------------------------------
-// 04/09?@creat
-// 04/12  stop nise fix
-// 06/21?@WorkingOff timming
-static unsigned long	gdwCtrl1eCode[YDSXG_CTRLLENGTH >> 2] = {
-	0x000007, 0x240007, 0x0C0007, 0x1C0007,
-	0x060007, 0x700002, 0x000020, 0x030040,
-	0x007104, 0x004286, 0x030040, 0x000F0D,
-	0x000810, 0x20043A, 0x000282, 0x00020D,
-	0x000810, 0x20043A, 0x001282, 0x200E82,
-	0x00800D, 0x000810, 0x20043A, 0x001A82,
-	0x03460D, 0x000810, 0x10043A, 0x02EC0D,
-	0x000810, 0x18043A, 0x00010D, 0x020015,
-	0x0000FD, 0x000020, 0x038860, 0x039060,
-	0x038060, 0x038040, 0x038040, 0x038040,
-	0x018040, 0x000A7D, 0x038040, 0x038040,
-	0x018040, 0x200402, 0x000882, 0x08001A,
-	0x000904, 0x017186, 0x000007, 0x260007,
-	0x400007, 0x000007, 0x03258D, 0x000810,
-	0x18043A, 0x260007, 0x284402, 0x00087D,
-	0x018042, 0x00160A, 0x05A206, 0x000007,
-	0x440007, 0x00230D, 0x000810, 0x08043A,
-	0x22FA06, 0x000007, 0x0007FD, 0x018042,
-	0x08000A, 0x000904, 0x02AB86, 0x000195,
-	0x090D04, 0x000007, 0x000820, 0x0000F5,
-	0x000B7D, 0x01F060, 0x0000FD, 0x033A06,
-	0x018040, 0x000A7D, 0x038042, 0x13804A,
-	0x18000A, 0x001820, 0x059060, 0x058860,
-	0x018040, 0x0000FD, 0x018042, 0x70000A,
-	0x000115, 0x071144, 0x033B86, 0x030000,
-	0x007020, 0x036206, 0x018040, 0x00360D,
-	0x000810, 0x08043A, 0x232206, 0x000007,
-	0x02EC0D, 0x000810, 0x18043A, 0x019A06,
-	0x000007, 0x240007, 0x000F8D, 0x000810,
-	0x00163A, 0x002402, 0x005C02, 0x0028FD,
-	0x000020, 0x018040, 0x08000D, 0x000815,
-	0x510984, 0x000007, 0x00004D, 0x000E5D,
-	0x000E02, 0x00430D, 0x000810, 0x08043A,
-	0x2E1206, 0x000007, 0x00008D, 0x000924,
-	0x000F02, 0x00470D, 0x000810, 0x08043A,
-	0x2E1206, 0x000007, 0x480480, 0x001210,
-	0x28043A, 0x00778D, 0x000810, 0x280C3A,
-	0x00068D, 0x000810, 0x28143A, 0x284402,
-	0x03258D, 0x000810, 0x18043A, 0x07FF8D,
-	0x000820, 0x0002FD, 0x018040, 0x260007,
-	0x200007, 0x0002FD, 0x018042, 0x08000A,
-	0x000904, 0x051286, 0x000007, 0x240007,
-	0x02EC0D, 0x000810, 0x18043A, 0x00387D,
-	0x018042, 0x08000A, 0x001015, 0x010984,
-	0x019B86, 0x000007, 0x01B206, 0x000007,
-	0x0008FD, 0x018042, 0x18000A, 0x001904,
-	0x22B886, 0x280007, 0x001810, 0x28043A,
-	0x280C02, 0x00000D, 0x000810, 0x28143A,
-	0x08808D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00020D, 0x189904, 0x000007,
-	0x00402D, 0x0000BD, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x065A86, 0x000007,
-	0x000100, 0x000A20, 0x00047D, 0x018040,
-	0x018042, 0x20000A, 0x003015, 0x012144,
-	0x036186, 0x000007, 0x002104, 0x036186,
-	0x000007, 0x000F8D, 0x000810, 0x280C3A,
-	0x023944, 0x07C986, 0x000007, 0x001810,
-	0x28043A, 0x08810D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x002810, 0x78003A,
-	0x00788D, 0x000810, 0x08043A, 0x2A1206,
-	0x000007, 0x00400D, 0x001015, 0x189904,
-	0x292904, 0x393904, 0x000007, 0x070206,
-	0x000007, 0x0004F5, 0x00007D, 0x000020,
-	0x00008D, 0x010860, 0x018040, 0x00047D,
-	0x038042, 0x21804A, 0x18000A, 0x021944,
-	0x229086, 0x000007, 0x004075, 0x71F104,
-	0x000007, 0x010042, 0x28000A, 0x002904,
-	0x225886, 0x000007, 0x003C0D, 0x30A904,
-	0x000007, 0x00077D, 0x018042, 0x08000A,
-	0x000904, 0x08DA86, 0x00057D, 0x002820,
-	0x03B060, 0x08F206, 0x018040, 0x003020,
-	0x03A860, 0x018040, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x08FA86, 0x000007,
-	0x00057D, 0x018042, 0x28040A, 0x000E8D,
-	0x000810, 0x280C3A, 0x00000D, 0x000810,
-	0x28143A, 0x09000D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x003DFD, 0x000020,
-	0x018040, 0x00107D, 0x009D8D, 0x000810,
-	0x08043A, 0x2A1206, 0x000007, 0x000815,
-	0x08001A, 0x010984, 0x0A5186, 0x00137D,
-	0x200500, 0x280F20, 0x338F60, 0x3B8F60,
-	0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
-	0x038A60, 0x018040, 0x00107D, 0x018042,
-	0x08000A, 0x000215, 0x010984, 0x3A8186,
-	0x000007, 0x007FBD, 0x383DC4, 0x000007,
-	0x001A7D, 0x001375, 0x018042, 0x09004A,
-	0x10000A, 0x0B8D04, 0x139504, 0x000007,
-	0x000820, 0x019060, 0x001104, 0x225886,
-	0x010040, 0x0017FD, 0x018042, 0x08000A,
-	0x000904, 0x225A86, 0x000007, 0x00197D,
-	0x038042, 0x09804A, 0x10000A, 0x000924,
-	0x001664, 0x0011FD, 0x038042, 0x2B804A,
-	0x19804A, 0x00008D, 0x218944, 0x000007,
-	0x002244, 0x0C1986, 0x000007, 0x001A64,
-	0x002A24, 0x00197D, 0x080102, 0x100122,
-	0x000820, 0x039060, 0x018040, 0x003DFD,
-	0x00008D, 0x000820, 0x018040, 0x001375,
-	0x001A7D, 0x010042, 0x09804A, 0x10000A,
-	0x00021D, 0x0189E4, 0x2992E4, 0x309144,
-	0x000007, 0x00060D, 0x000A15, 0x000C1D,
-	0x001025, 0x00A9E4, 0x012BE4, 0x000464,
-	0x01B3E4, 0x0232E4, 0x000464, 0x000464,
-	0x000464, 0x000464, 0x00040D, 0x08B1C4,
-	0x000007, 0x000820, 0x000BF5, 0x030040,
-	0x00197D, 0x038042, 0x09804A, 0x000A24,
-	0x08000A, 0x080E64, 0x000007, 0x100122,
-	0x000820, 0x031060, 0x010040, 0x0064AC,
-	0x00027D, 0x000020, 0x018040, 0x00107D,
-	0x018042, 0x0011FD, 0x3B804A, 0x09804A,
-	0x20000A, 0x000095, 0x1A1144, 0x00A144,
-	0x0E5886, 0x00040D, 0x00B984, 0x0E5986,
-	0x0018FD, 0x018042, 0x0010FD, 0x09804A,
-	0x28000A, 0x000095, 0x010924, 0x002A64,
-	0x0E4986, 0x000007, 0x002904, 0x0E5A86,
-	0x000007, 0x0E6206, 0x080002, 0x00008D,
-	0x00387D, 0x000820, 0x018040, 0x00127D,
-	0x018042, 0x10000A, 0x003904, 0x0F0986,
-	0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986,
-	0x000025, 0x0FB206, 0x00002D, 0x000015,
-	0x00082D, 0x02E00D, 0x000820, 0x0FFA06,
-	0x00000D, 0x7F8035, 0x00B984, 0x0FA986,
-	0x400025, 0x00008D, 0x110944, 0x000007,
-	0x00018D, 0x109504, 0x000007, 0x009164,
-	0x000424, 0x000424, 0x000424, 0x100102,
-	0x280002, 0x02DF0D, 0x000820, 0x0FFA06,
-	0x00018D, 0x00042D, 0x00008D, 0x109504,
-	0x000007, 0x00020D, 0x109184, 0x000007,
-	0x02DF8D, 0x000820, 0x00008D, 0x0038FD,
-	0x018040, 0x003BFD, 0x001020, 0x03A860,
-	0x000815, 0x313184, 0x212184, 0x000007,
-	0x03B060, 0x03A060, 0x018040, 0x0022FD,
-	0x000095, 0x010924, 0x000424, 0x000424,
-	0x001264, 0x100102, 0x000820, 0x039060,
-	0x018040, 0x001924, 0x010F0D, 0x00397D,
-	0x000820, 0x058040, 0x038042, 0x09844A,
-	0x000606, 0x08040A, 0x000424, 0x000424,
-	0x00117D, 0x018042, 0x08000A, 0x000A24,
-	0x280502, 0x280C02, 0x09800D, 0x000820,
-	0x0002FD, 0x018040, 0x200007, 0x0022FD,
-	0x018042, 0x08000A, 0x000095, 0x280DC4,
-	0x011924, 0x00197D, 0x018042, 0x0011FD,
-	0x09804A, 0x10000A, 0x0000B5, 0x113144,
-	0x0A8D04, 0x000007, 0x080A44, 0x129504,
-	0x000007, 0x0023FD, 0x001020, 0x038040,
-	0x101244, 0x000007, 0x000820, 0x039060,
-	0x018040, 0x0002FD, 0x018042, 0x08000A,
-	0x000904, 0x123286, 0x000007, 0x003BFD,
-	0x000100, 0x000A10, 0x0B807A, 0x13804A,
-	0x090984, 0x000007, 0x000095, 0x013D04,
-	0x12B886, 0x10000A, 0x100002, 0x090984,
-	0x000007, 0x038042, 0x11804A, 0x090D04,
-	0x000007, 0x10000A, 0x090D84, 0x000007,
-	0x00257D, 0x000820, 0x018040, 0x00010D,
-	0x000810, 0x28143A, 0x00127D, 0x018042,
-	0x20000A, 0x00197D, 0x018042, 0x00117D,
-	0x31804A, 0x10000A, 0x003124, 0x013B8D,
-	0x00397D, 0x000820, 0x058040, 0x038042,
-	0x09844A, 0x000606, 0x08040A, 0x300102,
-	0x003124, 0x000424, 0x000424, 0x001224,
-	0x280502, 0x001A4C, 0x143986, 0x700002,
-	0x00002D, 0x030000, 0x00387D, 0x018042,
-	0x10000A, 0x146206, 0x002124, 0x0000AD,
-	0x100002, 0x00010D, 0x000924, 0x006B24,
-	0x014A0D, 0x00397D, 0x000820, 0x058040,
-	0x038042, 0x09844A, 0x000606, 0x08040A,
-	0x003264, 0x00008D, 0x000A24, 0x001020,
-	0x00227D, 0x018040, 0x014F8D, 0x000810,
-	0x08043A, 0x2B5A06, 0x000007, 0x002820,
-	0x00207D, 0x018040, 0x00117D, 0x038042,
-	0x13804A, 0x33800A, 0x00387D, 0x018042,
-	0x08000A, 0x000904, 0x177286, 0x000007,
-	0x00008D, 0x030964, 0x015B0D, 0x00397D,
-	0x000820, 0x058040, 0x038042, 0x09844A,
-	0x000606, 0x08040A, 0x380102, 0x000424,
-	0x000424, 0x001224, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x15DA86, 0x000007,
-	0x280502, 0x001A4C, 0x177186, 0x000007,
-	0x032164, 0x00632C, 0x003DFD, 0x018042,
-	0x08000A, 0x000095, 0x090904, 0x000007,
-	0x000820, 0x001A4C, 0x169986, 0x018040,
-	0x030000, 0x16B206, 0x002124, 0x00010D,
-	0x000924, 0x006B24, 0x016F0D, 0x00397D,
-	0x000820, 0x058040, 0x038042, 0x09844A,
-	0x000606, 0x08040A, 0x003A64, 0x000095,
-	0x001224, 0x0002FD, 0x018042, 0x08000A,
-	0x000904, 0x171286, 0x000007, 0x01760D,
-	0x000810, 0x08043A, 0x2B5A06, 0x000007,
-	0x160A06, 0x000007, 0x007020, 0x08010A,
-	0x10012A, 0x0020FD, 0x038860, 0x039060,
-	0x018040, 0x00227D, 0x018042, 0x003DFD,
-	0x08000A, 0x31844A, 0x000904, 0x181086,
-	0x18008B, 0x00008D, 0x189904, 0x00312C,
-	0x18E206, 0x000007, 0x00324C, 0x186B86,
-	0x000007, 0x001904, 0x186886, 0x000007,
-	0x000095, 0x199144, 0x00222C, 0x003124,
-	0x00636C, 0x000E3D, 0x001375, 0x000BFD,
-	0x010042, 0x09804A, 0x10000A, 0x038AEC,
-	0x0393EC, 0x00224C, 0x18E186, 0x000007,
-	0x00008D, 0x189904, 0x00226C, 0x00322C,
-	0x30050A, 0x301DAB, 0x002083, 0x0018FD,
-	0x018042, 0x08000A, 0x018924, 0x300502,
-	0x001083, 0x001875, 0x010042, 0x10000A,
-	0x00008D, 0x010924, 0x001375, 0x330542,
-	0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB,
-	0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B,
-	0x006083, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x19B286, 0x000007, 0x001E2D,
-	0x0005FD, 0x018042, 0x08000A, 0x028924,
-	0x280502, 0x00060D, 0x000810, 0x280C3A,
-	0x00008D, 0x000810, 0x28143A, 0x0A808D,
-	0x000820, 0x0002F5, 0x010040, 0x220007,
-	0x001275, 0x030042, 0x21004A, 0x00008D,
-	0x1A0944, 0x000007, 0x01AB8D, 0x000810,
-	0x08043A, 0x2CAA06, 0x000007, 0x0001F5,
-	0x030042, 0x0D004A, 0x10000A, 0x089144,
-	0x000007, 0x000820, 0x010040, 0x0025F5,
-	0x0A3144, 0x000007, 0x000820, 0x032860,
-	0x030040, 0x00217D, 0x038042, 0x0B804A,
-	0x10000A, 0x000820, 0x031060, 0x030040,
-	0x00008D, 0x000124, 0x00012C, 0x000E64,
-	0x001A64, 0x00636C, 0x08010A, 0x10012A,
-	0x000820, 0x031060, 0x030040, 0x0020FD,
-	0x018042, 0x08000A, 0x00227D, 0x018042,
-	0x10000A, 0x000820, 0x031060, 0x030040,
-	0x00197D, 0x018042, 0x08000A, 0x0022FD,
-	0x038042, 0x10000A, 0x000820, 0x031060,
-	0x030040, 0x090D04, 0x000007, 0x000820,
-	0x030040, 0x038042, 0x0B804A, 0x10000A,
-	0x000820, 0x031060, 0x030040, 0x038042,
-	0x13804A, 0x19804A, 0x110D04, 0x198D04,
-	0x000007, 0x08000A, 0x001020, 0x031860,
-	0x030860, 0x030040, 0x00008D, 0x0B0944,
-	0x000007, 0x000820, 0x010040, 0x0005F5,
-	0x030042, 0x08000A, 0x000820, 0x010040,
-	0x0000F5, 0x010042, 0x08000A, 0x000904,
-	0x1D9886, 0x001E75, 0x030042, 0x01044A,
-	0x000C0A, 0x1DAA06, 0x000007, 0x000402,
-	0x000C02, 0x00177D, 0x001AF5, 0x018042,
-	0x03144A, 0x031C4A, 0x03244A, 0x032C4A,
-	0x03344A, 0x033C4A, 0x03444A, 0x004C0A,
-	0x00043D, 0x0013F5, 0x001AFD, 0x030042,
-	0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
-	0x089144, 0x19A144, 0x0389E4, 0x0399EC,
-	0x005502, 0x005D0A, 0x030042, 0x0B004A,
-	0x1B804A, 0x13804A, 0x20000A, 0x089144,
-	0x19A144, 0x0389E4, 0x0399EC, 0x006502,
-	0x006D0A, 0x030042, 0x0B004A, 0x19004A,
-	0x2B804A, 0x13804A, 0x21804A, 0x30000A,
-	0x089144, 0x19A144, 0x2AB144, 0x0389E4,
-	0x0399EC, 0x007502, 0x007D0A, 0x03A9E4,
-	0x000702, 0x00107D, 0x000415, 0x018042,
-	0x08000A, 0x0109E4, 0x000F02, 0x002AF5,
-	0x0019FD, 0x010042, 0x09804A, 0x10000A,
-	0x000934, 0x001674, 0x0029F5, 0x010042,
-	0x10000A, 0x00917C, 0x002075, 0x010042,
-	0x08000A, 0x000904, 0x200A86, 0x0026F5,
-	0x0027F5, 0x030042, 0x09004A, 0x10000A,
-	0x000A3C, 0x00167C, 0x001A75, 0x000BFD,
-	0x010042, 0x51804A, 0x48000A, 0x160007,
-	0x001075, 0x010042, 0x282C0A, 0x281D12,
-	0x282512, 0x001F32, 0x1E0007, 0x0E0007,
-	0x001975, 0x010042, 0x002DF5, 0x0D004A,
-	0x10000A, 0x009144, 0x20EA86, 0x010042,
-	0x28340A, 0x000E5D, 0x00008D, 0x000375,
-	0x000820, 0x010040, 0x05D2F4, 0x54D104,
-	0x00735C, 0x218B86, 0x000007, 0x0C0007,
-	0x080007, 0x0A0007, 0x02178D, 0x000810,
-	0x08043A, 0x34B206, 0x000007, 0x219206,
-	0x000007, 0x080007, 0x002275, 0x010042,
-	0x20000A, 0x002104, 0x225886, 0x001E2D,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x21CA86, 0x000007, 0x002010, 0x30043A,
-	0x00057D, 0x0180C3, 0x08000A, 0x028924,
-	0x280502, 0x280C02, 0x0A810D, 0x000820,
-	0x0002F5, 0x010040, 0x220007, 0x0004FD,
-	0x018042, 0x70000A, 0x030000, 0x007020,
-	0x07FA06, 0x018040, 0x022B8D, 0x000810,
-	0x08043A, 0x2CAA06, 0x000007, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x22C286,
-	0x000007, 0x020206, 0x000007, 0x000875,
-	0x0009FD, 0x00010D, 0x234206, 0x000295,
-	0x000B75, 0x00097D, 0x00000D, 0x000515,
-	0x010042, 0x18000A, 0x001904, 0x2A0086,
-	0x0006F5, 0x001020, 0x010040, 0x0004F5,
-	0x000820, 0x010040, 0x000775, 0x010042,
-	0x09804A, 0x10000A, 0x001124, 0x000904,
-	0x23F286, 0x000815, 0x080102, 0x101204,
-	0x241206, 0x000575, 0x081204, 0x000007,
-	0x100102, 0x000575, 0x000425, 0x021124,
-	0x100102, 0x000820, 0x031060, 0x010040,
-	0x001924, 0x2A0086, 0x00008D, 0x000464,
-	0x009D04, 0x291086, 0x180102, 0x000575,
-	0x010042, 0x28040A, 0x00018D, 0x000924,
-	0x280D02, 0x00000D, 0x000924, 0x281502,
-	0x10000D, 0x000820, 0x0002F5, 0x010040,
-	0x200007, 0x001175, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x24FA86, 0x000007,
-	0x000100, 0x080B20, 0x130B60, 0x1B0B60,
-	0x030A60, 0x010040, 0x050042, 0x3D004A,
-	0x35004A, 0x2D004A, 0x20000A, 0x0006F5,
-	0x010042, 0x28140A, 0x0004F5, 0x010042,
-	0x08000A, 0x000315, 0x010D04, 0x260286,
-	0x004015, 0x000095, 0x010D04, 0x25F086,
-	0x100022, 0x10002A, 0x261A06, 0x000007,
-	0x333104, 0x2AA904, 0x000007, 0x032124,
-	0x280502, 0x284402, 0x001124, 0x400102,
-	0x000424, 0x000424, 0x003224, 0x00292C,
-	0x00636C, 0x277386, 0x000007, 0x02B164,
-	0x000464, 0x000464, 0x00008D, 0x000A64,
-	0x280D02, 0x10008D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x00008D, 0x38B904,
-	0x000007, 0x03296C, 0x30010A, 0x0002F5,
-	0x010042, 0x08000A, 0x000904, 0x270286,
-	0x000007, 0x00212C, 0x28050A, 0x00316C,
-	0x00046C, 0x00046C, 0x28450A, 0x001124,
-	0x006B64, 0x100102, 0x00008D, 0x01096C,
-	0x280D0A, 0x10010D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x004124, 0x000424,
-	0x000424, 0x003224, 0x300102, 0x032944,
-	0x27FA86, 0x000007, 0x300002, 0x0004F5,
-	0x010042, 0x08000A, 0x000315, 0x010D04,
-	0x284086, 0x003124, 0x000464, 0x300102,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x284A86, 0x000007, 0x284402, 0x003124,
-	0x300502, 0x003924, 0x300583, 0x000883,
-	0x0005F5, 0x010042, 0x28040A, 0x00008D,
-	0x008124, 0x280D02, 0x00008D, 0x008124,
-	0x281502, 0x10018D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x001025, 0x000575,
-	0x030042, 0x09004A, 0x10000A, 0x0A0904,
-	0x121104, 0x000007, 0x001020, 0x050860,
-	0x050040, 0x0006FD, 0x018042, 0x09004A,
-	0x10000A, 0x0000A5, 0x0A0904, 0x121104,
-	0x000007, 0x000820, 0x019060, 0x010040,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x29CA86, 0x000007, 0x244206, 0x000007,
-	0x000606, 0x000007, 0x0002F5, 0x010042,
-	0x08000A, 0x000904, 0x2A1A86, 0x000007,
-	0x000100, 0x080B20, 0x138B60, 0x1B8B60,
-	0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60,
-	0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60,
-	0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60,
-	0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60,
-	0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60,
-	0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
-	0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60,
-	0x038A60, 0x000606, 0x018040, 0x00008D,
-	0x000A64, 0x280D02, 0x000A24, 0x00027D,
-	0x018042, 0x10000A, 0x001224, 0x0003FD,
-	0x018042, 0x08000A, 0x000904, 0x2C0A86,
-	0x000007, 0x00018D, 0x000A24, 0x000464,
-	0x000464, 0x080102, 0x000924, 0x000424,
-	0x000424, 0x100102, 0x02000D, 0x009144,
-	0x2C6186, 0x000007, 0x0001FD, 0x018042,
-	0x08000A, 0x000A44, 0x2C4386, 0x018042,
-	0x0A000D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00027D, 0x001020, 0x000606,
-	0x018040, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x2CB286, 0x000007, 0x00037D,
-	0x018042, 0x08000A, 0x000904, 0x2CE286,
-	0x000007, 0x000075, 0x002E7D, 0x010042,
-	0x0B804A, 0x000020, 0x000904, 0x000686,
-	0x010040, 0x31844A, 0x30048B, 0x000883,
-	0x00008D, 0x000810, 0x28143A, 0x00008D,
-	0x000810, 0x280C3A, 0x000675, 0x010042,
-	0x08000A, 0x003815, 0x010924, 0x280502,
-	0x0B000D, 0x000820, 0x0002F5, 0x010040,
-	0x000606, 0x220007, 0x000464, 0x000464,
-	0x000606, 0x000007, 0x000134, 0x007F8D,
-	0x00093C, 0x281D12, 0x282512, 0x001F32,
-	0x0E0007, 0x00010D, 0x00037D, 0x000820,
-	0x018040, 0x05D2F4, 0x000007, 0x080007,
-	0x00037D, 0x018042, 0x08000A, 0x000904,
-	0x2E8A86, 0x000007, 0x000606, 0x000007,
-	0x000007, 0x000012, 0x100007, 0x320007,
-	0x600007, 0x460007, 0x100080, 0x48001A,
-	0x004904, 0x2EF186, 0x000007, 0x001210,
-	0x58003A, 0x000145, 0x5C5D04, 0x000007,
-	0x000080, 0x48001A, 0x004904, 0x2F4186,
-	0x000007, 0x001210, 0x50003A, 0x005904,
-	0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5,
-	0x7FFF7D, 0x07D524, 0x004224, 0x500102,
-	0x200502, 0x000082, 0x40001A, 0x004104,
-	0x2FC986, 0x000007, 0x003865, 0x40001A,
-	0x004020, 0x00104D, 0x04C184, 0x31AB86,
-	0x000040, 0x040007, 0x000165, 0x000145,
-	0x004020, 0x000040, 0x000765, 0x080080,
-	0x40001A, 0x004104, 0x305986, 0x000007,
-	0x001210, 0x40003A, 0x004104, 0x30B286,
-	0x00004D, 0x0000CD, 0x004810, 0x20043A,
-	0x000882, 0x40001A, 0x004104, 0x30C186,
-	0x000007, 0x004820, 0x005904, 0x319886,
-	0x000040, 0x0007E5, 0x200480, 0x2816A0,
-	0x3216E0, 0x3A16E0, 0x4216E0, 0x021260,
-	0x000040, 0x000032, 0x400075, 0x00007D,
-	0x07D574, 0x200512, 0x000082, 0x40001A,
-	0x004104, 0x317186, 0x000007, 0x038A06,
-	0x640007, 0x0000E5, 0x000020, 0x000040,
-	0x000A65, 0x000020, 0x020040, 0x020040,
-	0x000040, 0x000165, 0x000042, 0x70000A,
-	0x007104, 0x323286, 0x000007, 0x060007,
-	0x019A06, 0x640007, 0x050000, 0x007020,
-	0x000040, 0x038A06, 0x640007, 0x000007,
-	0x00306D, 0x028860, 0x029060, 0x08000A,
-	0x028860, 0x008040, 0x100012, 0x00100D,
-	0x009184, 0x32D186, 0x000E0D, 0x009184,
-	0x33E186, 0x000007, 0x300007, 0x001020,
-	0x003B6D, 0x008040, 0x000080, 0x08001A,
-	0x000904, 0x32F186, 0x000007, 0x001220,
-	0x000DED, 0x008040, 0x008042, 0x10000A,
-	0x40000D, 0x109544, 0x000007, 0x001020,
-	0x000DED, 0x008040, 0x008042, 0x20040A,
-	0x000082, 0x08001A, 0x000904, 0x338186,
-	0x000007, 0x003B6D, 0x008042, 0x08000A,
-	0x000E15, 0x010984, 0x342B86, 0x600007,
-	0x08001A, 0x000C15, 0x010984, 0x341386,
-	0x000020, 0x1A0007, 0x0002ED, 0x008040,
-	0x620007, 0x00306D, 0x028042, 0x0A804A,
-	0x000820, 0x0A804A, 0x000606, 0x10804A,
-	0x000007, 0x282512, 0x001F32, 0x05D2F4,
-	0x54D104, 0x00735C, 0x000786, 0x000007,
-	0x0C0007, 0x0A0007, 0x1C0007, 0x003465,
-	0x020040, 0x004820, 0x025060, 0x40000A,
-	0x024060, 0x000040, 0x454944, 0x000007,
-	0x004020, 0x003AE5, 0x000040, 0x0028E5,
-	0x000042, 0x48000A, 0x004904, 0x39F886,
-	0x002C65, 0x000042, 0x40000A, 0x0000D5,
-	0x454104, 0x000007, 0x000655, 0x054504,
-	0x368286, 0x0001D5, 0x054504, 0x368086,
-	0x002B65, 0x000042, 0x003AE5, 0x50004A,
-	0x40000A, 0x45C3D4, 0x000007, 0x454504,
-	0x000007, 0x0000CD, 0x444944, 0x000007,
-	0x454504, 0x000007, 0x00014D, 0x554944,
-	0x000007, 0x045144, 0x367986, 0x002C65,
-	0x000042, 0x48000A, 0x4CD104, 0x000007,
-	0x04C144, 0x368386, 0x000007, 0x160007,
-	0x002CE5, 0x040042, 0x40000A, 0x004020,
-	0x000040, 0x002965, 0x000042, 0x40000A,
-	0x004104, 0x36F086, 0x000007, 0x002402,
-	0x383206, 0x005C02, 0x0025E5, 0x000042,
-	0x40000A, 0x004274, 0x002AE5, 0x000042,
-	0x40000A, 0x004274, 0x500112, 0x0029E5,
-	0x000042, 0x40000A, 0x004234, 0x454104,
-	0x000007, 0x004020, 0x000040, 0x003EE5,
-	0x000020, 0x000040, 0x002DE5, 0x400152,
-	0x50000A, 0x045144, 0x37DA86, 0x0000C5,
-	0x003EE5, 0x004020, 0x000040, 0x002BE5,
-	0x000042, 0x40000A, 0x404254, 0x000007,
-	0x002AE5, 0x004020, 0x000040, 0x500132,
-	0x040134, 0x005674, 0x0029E5, 0x020042,
-	0x42000A, 0x000042, 0x50000A, 0x05417C,
-	0x0028E5, 0x000042, 0x48000A, 0x0000C5,
-	0x4CC144, 0x38A086, 0x0026E5, 0x0027E5,
-	0x020042, 0x40004A, 0x50000A, 0x00423C,
-	0x00567C, 0x0028E5, 0x004820, 0x000040,
-	0x281D12, 0x282512, 0x001F72, 0x002965,
-	0x000042, 0x40000A, 0x004104, 0x393A86,
-	0x0E0007, 0x160007, 0x1E0007, 0x003EE5,
-	0x000042, 0x40000A, 0x004104, 0x397886,
-	0x002D65, 0x000042, 0x28340A, 0x003465,
-	0x020042, 0x42004A, 0x004020, 0x4A004A,
-	0x50004A, 0x05D2F4, 0x54D104, 0x00735C,
-	0x39E186, 0x000007, 0x000606, 0x080007,
-	0x0C0007, 0x080007, 0x0A0007, 0x0001E5,
-	0x020045, 0x004020, 0x000060, 0x000365,
-	0x000040, 0x002E65, 0x001A20, 0x0A1A60,
-	0x000040, 0x003465, 0x020042, 0x42004A,
-	0x004020, 0x4A004A, 0x000606, 0x50004A,
-	0x0017FD, 0x018042, 0x08000A, 0x000904,
-	0x225A86, 0x000007, 0x00107D, 0x018042,
-	0x0011FD, 0x33804A, 0x19804A, 0x20000A,
-	0x000095, 0x2A1144, 0x01A144, 0x3B9086,
-	0x00040D, 0x00B184, 0x3B9186, 0x0018FD,
-	0x018042, 0x0010FD, 0x09804A, 0x38000A,
-	0x000095, 0x010924, 0x003A64, 0x3B8186,
-	0x000007, 0x003904, 0x3B9286, 0x000007,
-	0x3B9A06, 0x00000D, 0x00008D, 0x000820,
-	0x00387D, 0x018040, 0x700002, 0x00117D,
-	0x018042, 0x00197D, 0x29804A, 0x30000A,
-	0x380002, 0x003124, 0x000424, 0x000424,
-	0x002A24, 0x280502, 0x00068D, 0x000810,
-	0x28143A, 0x00750D, 0x00B124, 0x002264,
-	0x3D0386, 0x284402, 0x000810, 0x280C3A,
-	0x0B800D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00758D, 0x00B124, 0x100102,
-	0x012144, 0x3E4986, 0x001810, 0x10003A,
-	0x00387D, 0x018042, 0x08000A, 0x000904,
-	0x3E4886, 0x030000, 0x3E4A06, 0x0000BD,
-	0x00008D, 0x023164, 0x000A64, 0x280D02,
-	0x0B808D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00387D, 0x018042, 0x08000A,
-	0x000904, 0x3E3286, 0x030000, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x3D8286,
-	0x000007, 0x002810, 0x28043A, 0x00750D,
-	0x030924, 0x002264, 0x280D02, 0x02316C,
-	0x28450A, 0x0B810D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x00008D, 0x000A24,
-	0x3E4A06, 0x100102, 0x001810, 0x10003A,
-	0x0000BD, 0x003810, 0x30043A, 0x00187D,
-	0x018042, 0x0018FD, 0x09804A, 0x20000A,
-	0x0000AD, 0x028924, 0x07212C, 0x001010,
-	0x300583, 0x300D8B, 0x3014BB, 0x301C83,
-	0x002083, 0x00137D, 0x038042, 0x33844A,
-	0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB,
-	0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083,
-	0x001E0D, 0x0005FD, 0x018042, 0x20000A,
-	0x020924, 0x00068D, 0x00A96C, 0x00009D,
-	0x0002FD, 0x018042, 0x08000A, 0x000904,
-	0x3F6A86, 0x000007, 0x280502, 0x280D0A,
-	0x284402, 0x001810, 0x28143A, 0x0C008D,
-	0x000820, 0x0002FD, 0x018040, 0x220007,
-	0x003904, 0x225886, 0x001E0D, 0x00057D,
-	0x018042, 0x20000A, 0x020924, 0x0000A5,
-	0x0002FD, 0x018042, 0x08000A, 0x000904,
-	0x402A86, 0x000007, 0x280502, 0x280C02,
-	0x002010, 0x28143A, 0x0C010D, 0x000820,
-	0x0002FD, 0x018040, 0x225A06, 0x220007,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000
-};
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/sound/ad1848.c linux-2.4.27-pre3/drivers/sound/ad1848.c
--- linux-2.4.26/drivers/sound/ad1848.c	2003-06-13 14:51:36.000000000 +0000
+++ linux-2.4.27-pre3/drivers/sound/ad1848.c	2004-05-18 16:53:50.000000000 +0000
@@ -636,6 +636,7 @@ static void ad1848_mixer_reset(ad1848_in
 			devc->supported_devices = MODE3_MIXER_DEVICES;
 			break;
 		case MD_4232:
+		case MD_4235:
 		case MD_4236:
 			devc->supported_devices = MODE3_MIXER_DEVICES;
 			break;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/sound/i810_audio.c linux-2.4.27-pre3/drivers/sound/i810_audio.c
--- linux-2.4.26/drivers/sound/i810_audio.c	2004-04-14 13:05:32.000000000 +0000
+++ linux-2.4.27-pre3/drivers/sound/i810_audio.c	2004-05-18 16:54:29.000000000 +0000
@@ -99,9 +99,12 @@
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
+#include <linux/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
+#define DRIVER_VERSION "1.00"
+
 #ifndef PCI_DEVICE_ID_INTEL_82801
 #define PCI_DEVICE_ID_INTEL_82801	0x2415
 #endif
@@ -148,6 +151,9 @@
 #define PCI_DEVICE_ID_AMD_8111_AC97	0x746d
 #endif
 
+#define MODULOP2(a, b) ((a) & ((b) - 1))
+#define MASKP2(a, b) ((a) & ~((b) - 1))
+
 static int ftsodell;
 static int strict_clocking;
 static unsigned int clocking;
@@ -209,6 +215,7 @@ struct i810_channel 
 
 #define ENUM_ENGINE(PRE,DIG) 									\
 enum {												\
+	PRE##_BASE =	0x##DIG##0,		/* Base Address */				\
 	PRE##_BDBAR =	0x##DIG##0,		/* Buffer Descriptor list Base Address */	\
 	PRE##_CIV =	0x##DIG##4,		/* Current Index Value */			\
 	PRE##_LVI =	0x##DIG##5,		/* Last Valid Index */				\
@@ -256,8 +263,6 @@ enum {
 #define INT_GPI		(1<<0)
 #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
 
-#define DRIVER_VERSION "0.24"
-
 /* magic numbers to protect our data structures */
 #define I810_CARD_MAGIC		0x5072696E /* "Prin" */
 #define I810_STATE_MAGIC	0x63657373 /* "cess" */
@@ -491,8 +496,12 @@ struct i810_card {
 /* extract register offset from codec struct */
 #define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
 
+#define GET_CIV(port) MODULOP2(inb((port) + OFF_CIV), SG_LEN)
+#define GET_LVI(port) MODULOP2(inb((port) + OFF_LVI), SG_LEN)
+
 /* set LVI from CIV */
-#define CIV_TO_LVI(port, off) outb((inb(port+OFF_CIV)+off) & 31, port+OFF_LVI)
+#define CIV_TO_LVI(port, off) \
+	outb(MODULOP2(GET_CIV((port)) + (off), SG_LEN), (port) + OFF_LVI)
 
 static struct i810_card *devs = NULL;
 
@@ -762,7 +771,7 @@ static inline unsigned i810_get_dma_addr
 		port_picb = port + OFF_PICB;
 
 	do {
-		civ = inb(port+OFF_CIV) & 31;
+		civ = GET_CIV(port);
 		offset = inw(port_picb);
 		/* Must have a delay here! */ 
 		if(offset == 0)
@@ -782,7 +791,7 @@ static inline unsigned i810_get_dma_addr
 		 * that we won't have to worry about the chip still being
 		 * out of sync with reality ;-)
 		 */
-	} while (civ != (inb(port+OFF_CIV) & 31) || offset != inw(port_picb));
+	} while (civ != GET_CIV(port) || offset != inw(port_picb));
 		 
 	return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
 		% dmabuf->dmasize);
@@ -992,6 +1001,7 @@ static int prog_dmabuf(struct i810_state
 	dmabuf->numfrag = SG_LEN;
 	dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag;
 	dmabuf->fragsamples = dmabuf->fragsize >> 1;
+	dmabuf->fragshift = ffs(dmabuf->fragsize) - 1;
 	dmabuf->userfragsize = dmabuf->ossfragsize;
 	dmabuf->userfrags = dmabuf->dmasize/dmabuf->ossfragsize;
 
@@ -999,16 +1009,12 @@ static int prog_dmabuf(struct i810_state
 
 	if(dmabuf->ossmaxfrags == 4) {
 		fragint = 8;
-		dmabuf->fragshift = 2;
 	} else if (dmabuf->ossmaxfrags == 8) {
 		fragint = 4;
-		dmabuf->fragshift = 3;
 	} else if (dmabuf->ossmaxfrags == 16) {
 		fragint = 2;
-		dmabuf->fragshift = 4;
 	} else {
 		fragint = 1;
-		dmabuf->fragshift = 5;
 	}
 	/*
 	 *	Now set up the ring 
@@ -1072,41 +1078,41 @@ static void __i810_update_lvi(struct i81
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	int x, port;
-	
+	int trigger;
+	int count, fragsize;
+	void (*start)(struct i810_state *);
+
+	count = dmabuf->count;
 	port = state->card->iobase;
-	if(rec)
+	if (rec) {
 		port += dmabuf->read_channel->port;
-	else
+		trigger = PCM_ENABLE_INPUT;
+		start = __start_adc;
+		count = dmabuf->dmasize - count;
+	} else {
 		port += dmabuf->write_channel->port;
+		trigger = PCM_ENABLE_OUTPUT;
+		start = __start_dac;
+	}
+
+	/* Do not process partial fragments. */
+	fragsize = dmabuf->fragsize;
+	if (count < fragsize)
+		return;
 
-	/* if we are currently stopped, then our CIV is actually set to our
-	 * *last* sg segment and we are ready to wrap to the next.  However,
-	 * if we set our LVI to the last sg segment, then it won't wrap to
-	 * the next sg segment, it won't even get a start.  So, instead, when
-	 * we are stopped, we set both the LVI value and also we increment
-	 * the CIV value to the next sg segment to be played so that when
-	 * we call start_{dac,adc}, things will operate properly
-	 */
 	if (!dmabuf->enable && dmabuf->ready) {
-		if(rec && dmabuf->count < dmabuf->dmasize &&
-		   (dmabuf->trigger & PCM_ENABLE_INPUT))
-		{
-			CIV_TO_LVI(port, 1);
-			__start_adc(state);
-			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
-		} else if (!rec && dmabuf->count &&
-			   (dmabuf->trigger & PCM_ENABLE_OUTPUT))
-		{
-			CIV_TO_LVI(port, 1);
-			__start_dac(state);
-			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
-		}
+		if (!(dmabuf->trigger & trigger))
+			return;
+
+		start(state);
+		while (!(inb(port + OFF_CR) & ((1<<4) | (1<<2))))
+			;
 	}
 
-	/* swptr - 1 is the tail of our transfer */
-	x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
-	x /= dmabuf->fragsize;
-	outb(x, port+OFF_LVI);
+	/* MASKP2(swptr, fragsize) - 1 is the tail of our transfer */
+	x = MODULOP2(MASKP2(dmabuf->swptr, fragsize) - 1, dmabuf->dmasize);
+	x >>= dmabuf->fragshift;
+	outb(x, port + OFF_LVI);
 }
 
 static void i810_update_lvi(struct i810_state *state, int rec)
@@ -1126,13 +1132,17 @@ static void i810_update_ptr(struct i810_
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned hwptr;
+	unsigned fragmask, dmamask;
 	int diff;
 
-	/* error handling and process wake up for DAC */
+	fragmask = MASKP2(~0, dmabuf->fragsize);
+	dmamask = MODULOP2(~0, dmabuf->dmasize);
+
+	/* error handling and process wake up for ADC */
 	if (dmabuf->enable == ADC_RUNNING) {
 		/* update hardware pointer */
-		hwptr = i810_get_dma_addr(state, 1);
-		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+		hwptr = i810_get_dma_addr(state, 1) & fragmask;
+		diff = (hwptr - dmabuf->hwptr) & dmamask;
 #if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
 		printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
 #endif
@@ -1144,20 +1154,20 @@ static void i810_update_ptr(struct i810_
 			/* this is normal for the end of a read */
 			/* only give an error if we went past the */
 			/* last valid sg entry */
-			if((inb(state->card->iobase + PI_CIV) & 31) !=
-			   (inb(state->card->iobase + PI_LVI) & 31)) {
+			if (GET_CIV(state->card->iobase + PI_BASE) !=
+			    GET_LVI(state->card->iobase + PI_BASE)) {
 				printk(KERN_WARNING "i810_audio: DMA overrun on read\n");
 				dmabuf->error++;
 			}
 		}
-		if (dmabuf->count > dmabuf->userfragsize)
+		if (diff)
 			wake_up(&dmabuf->wait);
 	}
 	/* error handling and process wake up for DAC */
 	if (dmabuf->enable == DAC_RUNNING) {
 		/* update hardware pointer */
-		hwptr = i810_get_dma_addr(state, 0);
-		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+		hwptr = i810_get_dma_addr(state, 0) & fragmask;
+		diff = (hwptr - dmabuf->hwptr) & dmamask;
 #if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
 		printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
 #endif
@@ -1169,18 +1179,18 @@ static void i810_update_ptr(struct i810_
 			/* this is normal for the end of a write */
 			/* only give an error if we went past the */
 			/* last valid sg entry */
-			if((inb(state->card->iobase + PO_CIV) & 31) !=
-			   (inb(state->card->iobase + PO_LVI) & 31)) {
+			if (GET_CIV(state->card->iobase + PO_BASE) !=
+			    GET_LVI(state->card->iobase + PO_BASE)) {
 				printk(KERN_WARNING "i810_audio: DMA overrun on write\n");
 				printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
 					"count %d\n",
-					inb(state->card->iobase + PO_CIV) & 31,
-					inb(state->card->iobase + PO_LVI) & 31,
+					GET_CIV(state->card->iobase + PO_BASE),
+					GET_LVI(state->card->iobase + PO_BASE),
 					dmabuf->hwptr, dmabuf->count);
 				dmabuf->error++;
 			}
 		}
-		if (dmabuf->count < (dmabuf->dmasize-dmabuf->userfragsize))
+		if (diff)
 			wake_up(&dmabuf->wait);
 	}
 }
@@ -1197,7 +1207,6 @@ static inline int i810_get_free_write_sp
 		dmabuf->swptr = dmabuf->hwptr;
 	}
 	free = dmabuf->dmasize - dmabuf->count;
-	free -= (dmabuf->hwptr % dmabuf->fragsize);
 	if(free < 0)
 		return(0);
 	return(free);
@@ -1215,12 +1224,27 @@ static inline int i810_get_available_rea
 		dmabuf->swptr = dmabuf->hwptr;
 	}
 	avail = dmabuf->count;
-	avail -= (dmabuf->hwptr % dmabuf->fragsize);
 	if(avail < 0)
 		return(0);
 	return(avail);
 }
 
+static inline void fill_partial_frag(struct dmabuf *dmabuf)
+{
+	unsigned fragsize;
+	unsigned swptr, len;
+
+	fragsize = dmabuf->fragsize;
+	swptr = dmabuf->swptr;
+	len = fragsize - MODULOP2(dmabuf->swptr, fragsize);
+	if (len == fragsize)
+		return;
+
+	memset(dmabuf->rawbuf + swptr, '\0', len);
+	dmabuf->swptr = MODULOP2(swptr + len, dmabuf->dmasize);
+	dmabuf->count += len;
+}
+
 static int drain_dac(struct i810_state *state, int signals_allowed)
 {
 	DECLARE_WAITQUEUE(wait, current);
@@ -1235,30 +1259,28 @@ static int drain_dac(struct i810_state *
 		stop_dac(state);
 		return 0;
 	}
+
+	spin_lock_irqsave(&state->card->lock, flags);
+
+	fill_partial_frag(dmabuf);
+
+	/* 
+	 * This will make sure that our LVI is correct, that our
+	 * pointer is updated, and that the DAC is running.  We
+	 * have to force the setting of dmabuf->trigger to avoid
+	 * any possible deadlocks.
+	 */
+	dmabuf->trigger = PCM_ENABLE_OUTPUT;
+	__i810_update_lvi(state, 0);
+
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
 	add_wait_queue(&dmabuf->wait, &wait);
 	for (;;) {
 
 		spin_lock_irqsave(&state->card->lock, flags);
 		i810_update_ptr(state);
 		count = dmabuf->count;
-		spin_unlock_irqrestore(&state->card->lock, flags);
-
-		if (count <= 0)
-			break;
-
-		/* 
-		 * This will make sure that our LVI is correct, that our
-		 * pointer is updated, and that the DAC is running.  We
-		 * have to force the setting of dmabuf->trigger to avoid
-		 * any possible deadlocks.
-		 */
-		if(!dmabuf->enable) {
-			dmabuf->trigger = PCM_ENABLE_OUTPUT;
-			i810_update_lvi(state,0);
-		}
-                if (signal_pending(current) && signals_allowed) {
-                        break;
-                }
 
 		/* It seems that we have to set the current state to
 		 * TASK_INTERRUPTIBLE every time to make the process
@@ -1269,7 +1291,17 @@ static int drain_dac(struct i810_state *
 		 * instead of actually sleeping and waiting for an
 		 * interrupt to wake us up!
 		 */
-		set_current_state(TASK_INTERRUPTIBLE);
+		__set_current_state(signals_allowed ?
+				    TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		if (count <= 0)
+			break;
+
+                if (signal_pending(current) && signals_allowed) {
+                        break;
+                }
+
 		/*
 		 * set the timeout to significantly longer than it *should*
 		 * take for the DAC to drain the DMA buffer
@@ -1350,11 +1382,10 @@ static void i810_channel_interrupt(struc
 			if(status & DMA_INT_DCH)
 				printk("DCH -");
 #endif
-			if(dmabuf->enable & DAC_RUNNING)
-				count = dmabuf->count;
-			else
-				count = dmabuf->dmasize - dmabuf->count;
-			if(count > 0) {
+			count = dmabuf->count;
+			if(dmabuf->enable & ADC_RUNNING)
+				count = dmabuf->dmasize - count;
+			if (count >= (int)dmabuf->fragsize) {
 				outb(inb(port+OFF_CR) | 1, port+OFF_CR);
 #ifdef DEBUG_INTERRUPTS
 				printk(" CONTINUE ");
@@ -1417,6 +1448,7 @@ static ssize_t i810_read(struct file *fi
 	unsigned long flags;
 	unsigned int swptr;
 	int cnt;
+	int pending;
         DECLARE_WAITQUEUE(waita, current);
 
 #ifdef DEBUG2
@@ -1442,6 +1474,8 @@ static ssize_t i810_read(struct file *fi
 		return -EFAULT;
 	ret = 0;
 
+	pending = 0;
+
         add_wait_queue(&dmabuf->wait, &waita);
 	while (count > 0) {
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -1455,8 +1489,8 @@ static ssize_t i810_read(struct file *fi
                         }
                         continue;
                 }
-		swptr = dmabuf->swptr;
 		cnt = i810_get_available_read_data(state);
+		swptr = dmabuf->swptr;
 		// this is to make the copy_to_user simpler below
 		if(cnt > (dmabuf->dmasize - swptr))
 			cnt = dmabuf->dmasize - swptr;
@@ -1464,15 +1498,6 @@ static ssize_t i810_read(struct file *fi
 
 		if (cnt > count)
 			cnt = count;
-		/* Lop off the last two bits to force the code to always
-		 * write in full samples.  This keeps software that sets
-		 * O_NONBLOCK but doesn't check the return value of the
-		 * write call from getting things out of state where they
-		 * think a full 4 byte sample was written when really only
-		 * a portion was, resulting in odd sound and stereo
-		 * hysteresis.
-		 */
-		cnt &= ~0x3;
 		if (cnt <= 0) {
 			unsigned long tmo;
 			/*
@@ -1526,7 +1551,7 @@ static ssize_t i810_read(struct file *fi
 			goto done;
 		}
 
-		swptr = (swptr + cnt) % dmabuf->dmasize;
+		swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
 
 		spin_lock_irqsave(&card->lock, flags);
 
@@ -1535,7 +1560,7 @@ static ssize_t i810_read(struct file *fi
                         continue;
                 }
 		dmabuf->swptr = swptr;
-		dmabuf->count -= cnt;
+		pending = dmabuf->count -= cnt;
 		spin_unlock_irqrestore(&card->lock, flags);
 
 		count -= cnt;
@@ -1543,7 +1568,9 @@ static ssize_t i810_read(struct file *fi
 		ret += cnt;
 	}
  done:
-	i810_update_lvi(state,1);
+	pending = dmabuf->dmasize - pending;
+	if (dmabuf->enable || pending >= dmabuf->userfragsize)
+		i810_update_lvi(state, 1);
         set_current_state(TASK_RUNNING);
         remove_wait_queue(&dmabuf->wait, &waita);
 
@@ -1560,7 +1587,8 @@ static ssize_t i810_write(struct file *f
 	ssize_t ret;
 	unsigned long flags;
 	unsigned int swptr = 0;
-	int cnt, x;
+	int pending;
+	int cnt;
         DECLARE_WAITQUEUE(waita, current);
 
 #ifdef DEBUG2
@@ -1585,6 +1613,8 @@ static ssize_t i810_write(struct file *f
 		return -EFAULT;
 	ret = 0;
 
+	pending = 0;
+
         add_wait_queue(&dmabuf->wait, &waita);
 	while (count > 0) {
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -1599,8 +1629,8 @@ static ssize_t i810_write(struct file *f
                         continue;
                 }
 
-		swptr = dmabuf->swptr;
 		cnt = i810_get_free_write_space(state);
+		swptr = dmabuf->swptr;
 		/* Bound the maximum size to how much we can copy to the
 		 * dma buffer before we hit the end.  If we have more to
 		 * copy then it will get done in a second pass of this
@@ -1615,15 +1645,6 @@ static ssize_t i810_write(struct file *f
 #endif
 		if (cnt > count)
 			cnt = count;
-		/* Lop off the last two bits to force the code to always
-		 * write in full samples.  This keeps software that sets
-		 * O_NONBLOCK but doesn't check the return value of the
-		 * write call from getting things out of state where they
-		 * think a full 4 byte sample was written when really only
-		 * a portion was, resulting in odd sound and stereo
-		 * hysteresis.
-		 */
-		cnt &= ~0x3;
 		if (cnt <= 0) {
 			unsigned long tmo;
 			// There is data waiting to be played
@@ -1668,7 +1689,7 @@ static ssize_t i810_write(struct file *f
 			goto ret;
 		}
 
-		swptr = (swptr + cnt) % dmabuf->dmasize;
+		swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
 
 		spin_lock_irqsave(&state->card->lock, flags);
                 if (PM_SUSPENDED(card)) {
@@ -1677,19 +1698,16 @@ static ssize_t i810_write(struct file *f
                 }
 
 		dmabuf->swptr = swptr;
-		dmabuf->count += cnt;
+		pending = dmabuf->count += cnt;
 
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 	}
-	if (swptr % dmabuf->fragsize) {
-		x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
-		memset(dmabuf->rawbuf + swptr, '\0', x);
-	}
 ret:
-	i810_update_lvi(state,0);
+	if (dmabuf->enable || pending >= dmabuf->userfragsize)
+		i810_update_lvi(state, 0);
         set_current_state(TASK_RUNNING);
         remove_wait_queue(&dmabuf->wait, &waita);
 
@@ -2179,6 +2197,13 @@ static int i810_ioctl(struct inode *inod
 #if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
 #endif
+		/* silently ignore invalid PCM_ENABLE_xxx bits,
+		 * like the other drivers do
+		 */
+		if (!(file->f_mode & FMODE_READ ))
+			val &= ~PCM_ENABLE_INPUT;
+		if (!(file->f_mode & FMODE_WRITE ))
+			val &= ~PCM_ENABLE_OUTPUT;
 		if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
 			stop_adc(state);
 		}
@@ -2186,7 +2211,7 @@ static int i810_ioctl(struct inode *inod
 			stop_dac(state);
 		}
 		dmabuf->trigger = val;
-		if((file->f_mode & FMODE_WRITE) && (val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
+		if((val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
 			if (!dmabuf->write_channel) {
 				dmabuf->ready = 0;
 				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
@@ -2202,12 +2227,12 @@ static int i810_ioctl(struct inode *inod
 				dmabuf->swptr = dmabuf->hwptr;
 				dmabuf->count = i810_get_free_write_space(state);
 				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
-				__i810_update_lvi(state, 0);
 				spin_unlock_irqrestore(&state->card->lock, flags);
-			} else
-				start_dac(state);
+			}
+			i810_update_lvi(state, 0);
+			start_dac(state);
 		}
-		if((file->f_mode & FMODE_READ) && (val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
+		if((val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
 			if (!dmabuf->read_channel) {
 				dmabuf->ready = 0;
 				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
@@ -2471,7 +2496,7 @@ found_virt:
 	if(file->f_mode & FMODE_READ) {
 		if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) {
 			kfree (card->states[i]);
-			card->states[i] = NULL;;
+			card->states[i] = NULL;
 			return -EBUSY;
 		}
 		dmabuf->trigger |= PCM_ENABLE_INPUT;
@@ -2483,7 +2508,7 @@ found_virt:
 			if(file->f_mode & FMODE_READ)
 				card->free_pcm_channel(card,dmabuf->read_channel->num);
 			kfree (card->states[i]);
-			card->states[i] = NULL;;
+			card->states[i] = NULL;
 			return -EBUSY;
 		}
 		/* Initialize to 8kHz?  What if we don't support 8kHz? */
@@ -2819,7 +2844,7 @@ static int i810_ac97_power_up_bus(struct
 	return 1;
 }
 
-static int __init i810_ac97_init(struct i810_card *card)
+static int __devinit i810_ac97_init(struct i810_card *card)
 {
 	int num_ac97 = 0;
 	int ac97_id;
@@ -3024,7 +3049,7 @@ static int __init i810_ac97_init(struct 
 	return num_ac97;
 }
 
-static void __init i810_configure_clocking (void)
+static void __devinit i810_configure_clocking (void)
 {
 	struct i810_card *card;
 	struct i810_state *state;
@@ -3065,15 +3090,14 @@ static void __init i810_configure_clocki
 			goto config_out;
 		}
 		dmabuf->count = dmabuf->dmasize;
-		CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, 31);
-		save_flags(flags);
-		cli();
+		CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, -1);
+		local_irq_save(flags);
 		start_dac(state);
 		offset = i810_get_dma_addr(state, 0);
 		mdelay(50);
 		new_offset = i810_get_dma_addr(state, 0);
 		stop_dac(state);
-		restore_flags(flags);
+		local_irq_restore(flags);
 		i = new_offset - offset;
 #ifdef DEBUG_INTERRUPTS
 		printk("i810_audio: %d bytes in 50 milliseconds\n", i);
@@ -3097,7 +3121,7 @@ config_out_nodmabuf:
 /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
    until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
    
-static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
+static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
 {
 	struct i810_card *card;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/usb/hiddev.c linux-2.4.27-pre3/drivers/usb/hiddev.c
--- linux-2.4.26/drivers/usb/hiddev.c	2004-04-14 13:05:32.000000000 +0000
+++ linux-2.4.27-pre3/drivers/usb/hiddev.c	2004-05-18 16:52:51.000000000 +0000
@@ -433,7 +433,9 @@ static int hiddev_ioctl(struct inode *in
 		dinfo.product = dev->descriptor.idProduct;
 		dinfo.version = dev->descriptor.bcdDevice;
 		dinfo.num_applications = hid->maxapplication;
-		return copy_to_user((void *) arg, &dinfo, sizeof(dinfo));
+		if (copy_to_user((void *) arg, &dinfo, sizeof(dinfo)))
+			return -EFAULT;
+		return 0;
 
 	case HIDIOCGFLAG:
 		return put_user(list->flags, (int *) arg);
@@ -522,7 +524,9 @@ static int hiddev_ioctl(struct inode *in
 
 		rinfo.num_fields = report->maxfield;
 
-		return copy_to_user((void *) arg, &rinfo, sizeof(rinfo));
+		if (copy_to_user((void *) arg, &rinfo, sizeof(rinfo)))
+			return -EFAULT;
+		return 0;
 
 	case HIDIOCGFIELDINFO:
 		if (copy_from_user(&finfo, (void *) arg, sizeof(finfo)))
@@ -552,7 +556,9 @@ static int hiddev_ioctl(struct inode *in
 		finfo.unit_exponent = field->unit_exponent;
 		finfo.unit = field->unit;
 
-		return copy_to_user((void *) arg, &finfo, sizeof(finfo));
+		if (copy_to_user((void *) arg, &finfo, sizeof(finfo)))
+			return -EFAULT;
+		return 0;
 
 	case HIDIOCGUCODE:
 		if (copy_from_user(uref, (void *) arg, sizeof(*uref)))
@@ -572,7 +578,9 @@ static int hiddev_ioctl(struct inode *in
 
 		uref->usage_code = field->usage[uref->usage_index].hid;
 
-		return copy_to_user((void *) arg, uref, sizeof(*uref));
+		if (copy_to_user((void *) arg, uref, sizeof(*uref)))
+			return -EFAULT;
+		return 0;
 
 	case HIDIOCGUSAGE:
 	case HIDIOCSUSAGE:
@@ -656,7 +664,9 @@ static int hiddev_ioctl(struct inode *in
 		cinfo.usage = hid->collection[cinfo.index].usage;
 		cinfo.level = hid->collection[cinfo.index].level;
 
-		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+		if (copy_to_user((void *) arg, &cinfo, sizeof(cinfo)))
+			return -EFAULT;
+		return 0;
 
 	default:
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/usb/printer.c linux-2.4.27-pre3/drivers/usb/printer.c
--- linux-2.4.26/drivers/usb/printer.c	2004-04-14 13:05:33.000000000 +0000
+++ linux-2.4.27-pre3/drivers/usb/printer.c	2004-05-18 16:51:42.000000000 +0000
@@ -222,6 +222,7 @@ static int usblp_select_alts(struct usbl
 static int usblp_set_protocol(struct usblp *usblp, int protocol);
 static int usblp_cache_device_id_string(struct usblp *usblp);
 
+static DECLARE_MUTEX(usblp_sem);	/* locks the existence of usblp's. */
 
 /*
  * Functions for usblp control messages.
@@ -332,7 +333,7 @@ static int usblp_open(struct inode *inod
 	if (minor < 0 || minor >= USBLP_MINORS)
 		return -ENODEV;
 
-	lock_kernel();
+	down (&usblp_sem);
 	usblp  = usblp_table[minor];
 
 	retval = -ENODEV;
@@ -374,7 +375,7 @@ static int usblp_open(struct inode *inod
 		}
 	}
 out:
-	unlock_kernel();
+	up (&usblp_sem);
 	return retval;
 }
 
@@ -404,15 +405,13 @@ static int usblp_release(struct inode *i
 {
 	struct usblp *usblp = file->private_data;
 
-	down (&usblp->sem);
-	lock_kernel();
+	down (&usblp_sem);
 	usblp->used = 0;
 	if (usblp->present) {
 		usblp_unlink_urbs(usblp);
-		up(&usblp->sem);
 	} else 		/* finish cleanup from disconnect */
 		usblp_cleanup (usblp);
-	unlock_kernel();
+	up (&usblp_sem);
 	return 0;
 }
 
@@ -1112,17 +1111,16 @@ static void usblp_disconnect(struct usb_
 		BUG ();
 	}
 
+	down (&usblp_sem);
 	down (&usblp->sem);
-	lock_kernel();
 	usblp->present = 0;
 
 	usblp_unlink_urbs(usblp);
+	up (&usblp->sem);
 
 	if (!usblp->used)
 		usblp_cleanup (usblp);
-	else 	/* cleanup later, on release */
-		up (&usblp->sem);
-	unlock_kernel();
+	up (&usblp_sem);
 }
 
 static struct usb_device_id usblp_ids [] = {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/usb/speedtch.c linux-2.4.27-pre3/drivers/usb/speedtch.c
--- linux-2.4.26/drivers/usb/speedtch.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.27-pre3/drivers/usb/speedtch.c	2004-05-18 16:52:32.000000000 +0000
@@ -83,6 +83,10 @@
 #define VERBOSE_DEBUG
 */
 
+#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
+#	define DEBUG
+#endif
+
 #include <linux/usb.h>
 
 #ifdef DEBUG
@@ -101,8 +105,8 @@ static int udsl_print_packet (const unsi
 #endif
 
 #define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
-#define DRIVER_DESC	"Alcatel SpeedTouch USB driver"
-#define DRIVER_VERSION	"1.7"
+#define DRIVER_VERSION	"1.8"
+#define DRIVER_DESC	"Alcatel SpeedTouch USB driver version " DRIVER_VERSION
 
 static const char udsl_driver_name [] = "speedtch";
 
@@ -294,6 +298,19 @@ static struct usb_driver udsl_usb_driver
 };
 
 
+/***********
+**  misc  **
+***********/
+
+static inline void udsl_pop (struct atm_vcc *vcc, struct sk_buff *skb)
+{
+	if (vcc->pop)
+		vcc->pop (vcc, skb);
+	else
+		dev_kfree_skb (skb);
+}
+
+
 /*************
 **  decode  **
 *************/
@@ -717,10 +734,7 @@ made_progress:
 	if (!UDSL_SKB (skb)->num_cells) {
 		struct atm_vcc *vcc = UDSL_SKB (skb)->atm_data.vcc;
 
-		if (vcc->pop)
-			vcc->pop (vcc, skb);
-		else
-			dev_kfree_skb (skb);
+		udsl_pop (vcc, skb);
 		instance->current_skb = NULL;
 
 		atomic_inc (&vcc->stats->tx);
@@ -739,10 +753,7 @@ static void udsl_cancel_send (struct uds
 		if (UDSL_SKB (skb)->atm_data.vcc == vcc) {
 			dbg ("udsl_cancel_send: popping skb 0x%p", skb);
 			__skb_unlink (skb, &instance->sndqueue);
-			if (vcc->pop)
-				vcc->pop (vcc, skb);
-			else
-				dev_kfree_skb (skb);
+			udsl_pop (vcc, skb);
 		}
 	spin_unlock_irq (&instance->sndqueue.lock);
 
@@ -750,10 +761,7 @@ static void udsl_cancel_send (struct uds
 	if ((skb = instance->current_skb) && (UDSL_SKB (skb)->atm_data.vcc == vcc)) {
 		dbg ("udsl_cancel_send: popping current skb (0x%p)", skb);
 		instance->current_skb = NULL;
-		if (vcc->pop)
-			vcc->pop (vcc, skb);
-		else
-			dev_kfree_skb (skb);
+		udsl_pop (vcc, skb);
 	}
 	tasklet_enable (&instance->send_tasklet);
 	dbg ("udsl_cancel_send done");
@@ -762,22 +770,26 @@ static void udsl_cancel_send (struct uds
 static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
 {
 	struct udsl_instance_data *instance = vcc->dev->dev_data;
+	int err;
 
 	vdbg ("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len);
 
 	if (!instance || !instance->usb_dev) {
 		dbg ("udsl_atm_send: NULL data!");
-		return -ENODEV;
+		err = -ENODEV;
+		goto fail;
 	}
 
 	if (vcc->qos.aal != ATM_AAL5) {
 		dbg ("udsl_atm_send: unsupported ATM type %d!", vcc->qos.aal);
-		return -EINVAL;
+		err = -EINVAL;
+		goto fail;
 	}
 
 	if (skb->len > ATM_MAX_AAL5_PDU) {
 		dbg ("udsl_atm_send: packet too long (%d vs %d)!", skb->len, ATM_MAX_AAL5_PDU);
-		return -EINVAL;
+		err = -EINVAL;
+		goto fail;
 	}
 
 	PACKETDEBUG (skb->data, skb->len);
@@ -787,6 +799,10 @@ static int udsl_atm_send (struct atm_vcc
 	tasklet_schedule (&instance->send_tasklet);
 
 	return 0;
+
+fail:
+	udsl_pop (vcc, skb);
+	return err;
 }
 
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/usb/storage/scsiglue.c linux-2.4.27-pre3/drivers/usb/storage/scsiglue.c
--- linux-2.4.26/drivers/usb/storage/scsiglue.c	2004-04-14 13:05:35.000000000 +0000
+++ linux-2.4.27-pre3/drivers/usb/storage/scsiglue.c	2004-05-18 16:53:17.000000000 +0000
@@ -218,7 +218,14 @@ static int device_reset( Scsi_Cmnd *srb 
 	US_DEBUGP("device_reset() called\n" );
 
 	spin_unlock_irq(&io_request_lock);
+	down(&(us->dev_semaphore));
+	if (!us->pusb_dev) {
+		up(&(us->dev_semaphore));
+		spin_lock_irq(&io_request_lock);
+		return SUCCESS;
+	}
 	rc = us->transport_reset(us);
+	up(&(us->dev_semaphore));
 	spin_lock_irq(&io_request_lock);
 	return rc;
 }
@@ -235,27 +242,44 @@ static int bus_reset( Scsi_Cmnd *srb )
 	/* we use the usb_reset_device() function to handle this for us */
 	US_DEBUGP("bus_reset() called\n");
 
+	spin_unlock_irq(&io_request_lock);
+
+	down(&(us->dev_semaphore));
+
 	/* if the device has been removed, this worked */
 	if (!us->pusb_dev) {
 		US_DEBUGP("-- device removed already\n");
+		up(&(us->dev_semaphore));
+		spin_lock_irq(&io_request_lock);
 		return SUCCESS;
 	}
 
-	spin_unlock_irq(&io_request_lock);
+	/* The USB subsystem doesn't handle synchronisation between
+	 * a device's several drivers. Therefore we reset only devices
+	 * with just one interface, which we of course own. */
+	if (us->pusb_dev->actconfig->bNumInterfaces != 1) {
+		printk(KERN_NOTICE "usb-storage: "
+		    "Refusing to reset a multi-interface device\n");
+		up(&(us->dev_semaphore));
+		spin_lock_irq(&io_request_lock);
+		/* XXX Don't just return success, make sure current cmd fails */
+		return SUCCESS;
+	}
 
 	/* release the IRQ, if we have one */
-	down(&(us->irq_urb_sem));
 	if (us->irq_urb) {
 		US_DEBUGP("-- releasing irq URB\n");
 		result = usb_unlink_urb(us->irq_urb);
 		US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
 	}
-	up(&(us->irq_urb_sem));
 
 	/* attempt to reset the port */
 	if (usb_reset_device(us->pusb_dev) < 0) {
-		spin_lock_irq(&io_request_lock);
-		return FAILED;
+		/*
+		 * Do not return errors, or else the error handler might
+		 * invoke host_reset, which is not implemented.
+		 */
+		goto bail_out;
 	}
 
 	/* FIXME: This needs to lock out driver probing while it's working
@@ -286,17 +310,18 @@ static int bus_reset( Scsi_Cmnd *srb )
 		up(&intf->driver->serialize);
 	}
 
+bail_out:
 	/* re-allocate the IRQ URB and submit it to restore connectivity
 	 * for CBI devices
 	 */
 	if (us->protocol == US_PR_CBI) {
-		down(&(us->irq_urb_sem));
 		us->irq_urb->dev = us->pusb_dev;
 		result = usb_submit_urb(us->irq_urb);
 		US_DEBUGP("usb_submit_urb() returns %d\n", result);
-		up(&(us->irq_urb_sem));
 	}
-	
+
+	up(&(us->dev_semaphore));
+
 	spin_lock_irq(&io_request_lock);
 
 	US_DEBUGP("bus_reset() complete\n");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/usb/storage/unusual_devs.h linux-2.4.27-pre3/drivers/usb/storage/unusual_devs.h
--- linux-2.4.26/drivers/usb/storage/unusual_devs.h	2004-04-14 13:05:35.000000000 +0000
+++ linux-2.4.27-pre3/drivers/usb/storage/unusual_devs.h	2004-05-18 16:54:31.000000000 +0000
@@ -669,7 +669,7 @@ UNUSUAL_DEV(  0x097a, 0x0001, 0x0000, 0x
 UNUSUAL_DEV(  0x0a16, 0x8888, 0x0100, 0x0100,
 		"IBM",
 		"IBM USB Memory Key",
-		US_SC_SCSI, US_PR_BULK, NULL,
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 
 /* This Pentax still camera is not conformant
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/usb/storage/usb.c linux-2.4.27-pre3/drivers/usb/storage/usb.c
--- linux-2.4.26/drivers/usb/storage/usb.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/drivers/usb/storage/usb.c	2004-05-18 16:52:04.000000000 +0000
@@ -501,6 +501,9 @@ static int usb_stor_control_thread(void 
  * strucuture is current.  This includes the ep_int field, which gives us
  * the endpoint for the interrupt.
  * Returns non-zero on failure, zero on success
+ *
+ * ss->dev_semaphore is expected taken, except for a newly minted,
+ * unregistered device.
  */ 
 static int usb_stor_allocate_irq(struct us_data *ss)
 {
@@ -510,13 +513,9 @@ static int usb_stor_allocate_irq(struct 
 
 	US_DEBUGP("Allocating IRQ for CBI transport\n");
 
-	/* lock access to the data structure */
-	down(&(ss->irq_urb_sem));
-
 	/* allocate the URB */
 	ss->irq_urb = usb_alloc_urb(0);
 	if (!ss->irq_urb) {
-		up(&(ss->irq_urb_sem));
 		US_DEBUGP("couldn't allocate interrupt URB");
 		return 1;
 	}
@@ -537,12 +536,9 @@ static int usb_stor_allocate_irq(struct 
 	US_DEBUGP("usb_submit_urb() returns %d\n", result);
 	if (result) {
 		usb_free_urb(ss->irq_urb);
-		up(&(ss->irq_urb_sem));
 		return 2;
 	}
 
-	/* unlock the data structure and return success */
-	up(&(ss->irq_urb_sem));
 	return 0;
 }
 
@@ -772,7 +768,6 @@ static void * storage_probe(struct usb_d
 		init_completion(&(ss->notify));
 		init_MUTEX_LOCKED(&(ss->ip_waitq));
 		spin_lock_init(&(ss->queue_exclusion));
-		init_MUTEX(&(ss->irq_urb_sem));
 		init_MUTEX(&(ss->current_urb_sem));
 		init_MUTEX(&(ss->dev_semaphore));
 
@@ -1063,7 +1058,6 @@ static void storage_disconnect(struct us
 	down(&(ss->dev_semaphore));
 
 	/* release the IRQ, if we have one */
-	down(&(ss->irq_urb_sem));
 	if (ss->irq_urb) {
 		US_DEBUGP("-- releasing irq URB\n");
 		result = usb_unlink_urb(ss->irq_urb);
@@ -1071,7 +1065,6 @@ static void storage_disconnect(struct us
 		usb_free_urb(ss->irq_urb);
 		ss->irq_urb = NULL;
 	}
-	up(&(ss->irq_urb_sem));
 
 	/* free up the main URB for this device */
 	US_DEBUGP("-- releasing main URB\n");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/usb/storage/usb.h linux-2.4.27-pre3/drivers/usb/storage/usb.h
--- linux-2.4.26/drivers/usb/storage/usb.h	2003-08-25 11:44:42.000000000 +0000
+++ linux-2.4.27-pre3/drivers/usb/storage/usb.h	2004-05-18 16:53:59.000000000 +0000
@@ -116,7 +116,7 @@ struct us_data {
 	struct us_data		*next;		 /* next device */
 
 	/* the device we're working with */
-	struct semaphore	dev_semaphore;	 /* protect pusb_dev */
+	struct semaphore	dev_semaphore;	 /* protect many things */
 	struct usb_device	*pusb_dev;	 /* this usb_device */
 
 	unsigned int		flags;		 /* from filter initially */
@@ -162,7 +162,6 @@ struct us_data {
 	atomic_t		ip_wanted[1];	 /* is an IRQ expected?	 */
 
 	/* interrupt communications data */
-	struct semaphore	irq_urb_sem;	 /* to protect irq_urb	 */
 	struct urb		*irq_urb;	 /* for USB int requests */
 	unsigned char		irqbuf[2];	 /* buffer for USB IRQ	 */
 	unsigned char		irqdata[2];	 /* data from USB IRQ	 */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/usb/tiglusb.c linux-2.4.27-pre3/drivers/usb/tiglusb.c
--- linux-2.4.26/drivers/usb/tiglusb.c	2003-06-13 14:51:37.000000000 +0000
+++ linux-2.4.27-pre3/drivers/usb/tiglusb.c	2004-05-18 16:54:01.000000000 +0000
@@ -3,7 +3,7 @@
  * tiglusb -- Texas Instruments' USB GraphLink (aka SilverLink) driver.
  * Target: Texas Instruments graphing calculators (http://lpg.ticalc.org).
  *
- * Copyright (C) 2001-2002:
+ * Copyright (C) 2001-2004:
  *   Romain Lievin <roms@lpg.ticalc.org>
  *   Julien BLACHE <jb@technologeek.org>
  * under the terms of the GNU General Public License.
@@ -14,11 +14,14 @@
  * and the website at:  http://lpg.ticalc.org/prj_usb/
  * for more info.
  *
+ * History:
  *   1.0x, Romain & Julien: initial submit.
  *   1.03, Greg Kroah: modifications.
  *   1.04, Julien: clean-up & fixes; Romain: 2.4 backport.
  *   1.05, Randy Dunlap: bug fix with the timeout parameter (divide-by-zero).
  *   1.06, Romain: synched with 2.5, version/firmware changed (confusing).
+ *   1.07, Romain: fixed bad use of usb_clear_halt (invalid argument);
+ *          timeout argument checked in ioctl + clean-up.
  */
 
 #include <linux/module.h>
@@ -38,8 +41,8 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "1.06"
-#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org> & Julien Blache <jb@jblache.org>"
+#define DRIVER_VERSION "1.07"
+#define DRIVER_AUTHOR  "Romain Lievin <roms@tilp.info> & Julien Blache <jb@jblache.org>"
 #define DRIVER_DESC    "TI-GRAPH LINK USB (aka SilverLink) driver"
 #define DRIVER_LICENSE "GPL"
 
@@ -74,15 +77,15 @@ clear_pipes (struct usb_device *dev)
 {
 	unsigned int pipe;
 
-	pipe = usb_sndbulkpipe (dev, 1);
-	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
-		err ("clear_pipe (r), request failed");
+	pipe = usb_sndbulkpipe (dev, 2);
+	if (usb_clear_halt (dev, pipe)) {
+		err ("clear_pipe (w), request failed");
 		return -1;
 	}
 
-	pipe = usb_sndbulkpipe (dev, 2);
-	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
-		err ("clear_pipe (w), request failed");
+	pipe = usb_rcvbulkpipe (dev, 1);
+	if (usb_clear_halt (dev, pipe)) {
+		err ("clear_pipe (r), request failed");
 		return -1;
 	}
 
@@ -181,15 +184,14 @@ tiglusb_read (struct file *filp, char *b
 	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
 			       &bytes_read, HZ * 10 / timeout);
 	if (result == -ETIMEDOUT) {	/* NAK */
-		ret = result;
-		if (!bytes_read) {
+		if (!bytes_read)
 			dbg ("quirk !");
-		}
 		warn ("tiglusb_read, NAK received.");
+		ret = result;
 		goto out;
 	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
 		warn ("clear_halt request to remove STALL condition.");
-		if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+		if (usb_clear_halt (s->dev, pipe))
 			err ("clear_halt, request failed");
 		clear_device (s->dev);
 		ret = result;
@@ -244,7 +246,7 @@ tiglusb_write (struct file *filp, const 
 		goto out;
 	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
 		warn ("clear_halt request to remove STALL condition.");
-		if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+		if (usb_clear_halt (s->dev, pipe))
 			err ("clear_halt, request failed");
 		clear_device (s->dev);
 		ret = result;
@@ -284,15 +286,16 @@ tiglusb_ioctl (struct inode *inode, stru
 
 	switch (cmd) {
 	case IOCTL_TIUSB_TIMEOUT:
-		timeout = arg;	// timeout value in tenth of seconds
+		if (arg > 0)
+			timeout = (int)arg;
+		else
+			ret = -EINVAL;
 		break;
 	case IOCTL_TIUSB_RESET_DEVICE:
-		dbg ("IOCTL_TIGLUSB_RESET_DEVICE");
 		if (clear_device (s->dev))
 			ret = -EIO;
 		break;
 	case IOCTL_TIUSB_RESET_PIPES:
-		dbg ("IOCTL_TIGLUSB_RESET_PIPES");
 		if (clear_pipes (s->dev))
 			ret = -EIO;
 		break;
@@ -430,7 +433,7 @@ static struct usb_driver tiglusb_driver 
 
 #ifndef MODULE
 /*
- * You can use 'tiusb=timeout'
+ * You can use 'tiusb=timeout' to set timeout.
  */
 static int __init
 tiglusb_setup (char *str)
@@ -440,10 +443,11 @@ tiglusb_setup (char *str)
 	str = get_options (str, ARRAY_SIZE (ints), ints);
 
 	if (ints[0] > 0) {
-		timeout = ints[1];
+		if (ints[1] > 0)
+			timeout = ints[1];
+		else
+			info ("tiglusb: wrong timeout value (0), using default value.");
 	}
-	if (!timeout)
-		timeout = TIMAXTIME;
 
 	return 1;
 }
@@ -466,8 +470,6 @@ tiglusb_init (void)
 		init_waitqueue_head (&s->wait);
 		init_waitqueue_head (&s->remove_ok);
 	}
-	if (timeout <= 0)
-               timeout = TIMAXTIME;
 
 	/* register device */
 	if (register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
@@ -487,12 +489,6 @@ tiglusb_init (void)
 
 	info (DRIVER_DESC ", version " DRIVER_VERSION);
 
-       if (timeout <= 0)
-               timeout = TIMAXTIME;
-
-	if (!timeout)
-		timeout = TIMAXTIME;
-
 	return 0;
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/video/riva/accel.c linux-2.4.27-pre3/drivers/video/riva/accel.c
--- linux-2.4.26/drivers/video/riva/accel.c	2003-06-13 14:51:37.000000000 +0000
+++ linux-2.4.27-pre3/drivers/video/riva/accel.c	2004-05-18 16:55:37.000000000 +0000
@@ -300,8 +300,8 @@ static void fbcon_riva16_clear(struct vc
 
 static inline void convert_bgcolor_16(u32 *col)
 {
-	*col = ((*col & 0x00007C00) << 9)
-             | ((*col & 0x000003E0) << 6)
+	*col = ((*col & 0x0000F800) << 8)
+             | ((*col & 0x000007E0) << 5)
              | ((*col & 0x0000001F) << 3)
              |          0xFF000000;
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/video/riva/fbdev.c linux-2.4.27-pre3/drivers/video/riva/fbdev.c
--- linux-2.4.26/drivers/video/riva/fbdev.c	2003-06-13 14:51:37.000000000 +0000
+++ linux-2.4.27-pre3/drivers/video/riva/fbdev.c	2004-05-18 16:54:16.000000000 +0000
@@ -952,7 +952,7 @@ static void riva_load_video_mode(struct 
 	newmode.crtc[0x12] = Set8Bits (vDisplay);
 	newmode.crtc[0x13] = ((width / 8) * ((bpp + 1) / 8)) & 0xFF;
 	newmode.crtc[0x15] = Set8Bits (vBlankStart);
-	newmode.crtc[0x16] = Set8Bits (vBlankEnd);
+	newmode.crtc[0x16] = Set8Bits (vBlankEnd + 1);
 
 	newmode.ext.bpp = bpp;
 	newmode.ext.width = width;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/buffer.c linux-2.4.27-pre3/fs/buffer.c
--- linux-2.4.26/fs/buffer.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/fs/buffer.c	2004-05-18 16:53:42.000000000 +0000
@@ -2836,7 +2836,7 @@ void show_buffers(void)
 				       buf_types[nlist], found, tmp);
 		}
 		printk("%9s: %d buffers, %lu kbyte, %d used (last=%d), "
-		       "%d locked, %d dirty %d delay\n",
+		       "%d locked, %d dirty, %d delay\n",
 		       buf_types[nlist], found, size_buffers_type[nlist]>>10,
 		       used, lastused, locked, dirty, delalloc);
 	}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/devpts/inode.c linux-2.4.27-pre3/fs/devpts/inode.c
--- linux-2.4.26/fs/devpts/inode.c	2001-10-25 07:02:26.000000000 +0000
+++ linux-2.4.27-pre3/fs/devpts/inode.c	2004-05-18 16:51:55.000000000 +0000
@@ -137,12 +137,12 @@ struct super_block *devpts_read_super(st
 
 	if ( devpts_parse_options(data,sbi) && !silent) {
 		printk("devpts: called with bogus options\n");
-		goto fail_free;
+		goto fail_inode;
 	}
 
 	inode = new_inode(s);
 	if (!inode)
-		goto fail_free;
+		goto fail_inode;
 	inode->i_ino = 1;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = 0;
@@ -164,6 +164,8 @@ struct super_block *devpts_read_super(st
 	
 	printk("devpts: get root dentry failed\n");
 	iput(inode);
+fail_inode:
+	kfree(sbi->inodes);
 fail_free:
 	kfree(sbi);
 fail:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/dquot.c linux-2.4.27-pre3/fs/dquot.c
--- linux-2.4.26/fs/dquot.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/fs/dquot.c	2004-05-18 16:54:11.000000000 +0000
@@ -397,6 +397,10 @@ restart:
 			wait_on_dquot(dquot);
 		if (dquot_dirty(dquot))
 			sb->dq_op->write_dquot(dquot);
+		/* Move the inuse_list head pointer to just after the
+		 * current dquot, so that we'll restart the list walk
+		 * after this point on the next pass. */
+		list_move(&inuse_list, &dquot->dq_inuse);
 		dqput(dquot);
 		goto restart;
 	}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/ext2/super.c linux-2.4.27-pre3/fs/ext2/super.c
--- linux-2.4.26/fs/ext2/super.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.27-pre3/fs/ext2/super.c	2004-05-18 16:54:01.000000000 +0000
@@ -427,7 +427,7 @@ struct super_block * ext2_read_super (st
 	unsigned short resuid = EXT2_DEF_RESUID;
 	unsigned short resgid = EXT2_DEF_RESGID;
 	unsigned long block;
-	unsigned long logic_sb_block = 1;
+	unsigned long logic_sb_block;
 	unsigned long offset = 0;
 	kdev_t dev = sb->s_dev;
 	int blocksize = BLOCK_SIZE;
@@ -465,6 +465,8 @@ struct super_block * ext2_read_super (st
 	if (blocksize != BLOCK_SIZE) {
 		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
 		offset = (sb_block*BLOCK_SIZE) % blocksize;
+	} else {
+		logic_sb_block = sb_block;
 	}
 
 	if (!(bh = sb_bread(sb, logic_sb_block))) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/jfs/jfs_debug.c linux-2.4.27-pre3/fs/jfs/jfs_debug.c
--- linux-2.4.26/fs/jfs/jfs_debug.c	2003-06-13 14:51:37.000000000 +0000
+++ linux-2.4.27-pre3/fs/jfs/jfs_debug.c	2004-05-18 16:55:08.000000000 +0000
@@ -1,6 +1,6 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
- *   Portions Copyright (c) Christoph Hellwig, 2001-2002
+ *   Copyright (C) International Business Machines Corp., 2000-2004
+ *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   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
@@ -147,7 +147,7 @@ void jfs_proc_clean(void)
 	if (base) {
 		for (i = 0; i < NPROCENT; i++)
 			remove_proc_entry(Entries[i].name, base);
-		remove_proc_entry("jfs", base);
+		remove_proc_entry("jfs", proc_root_fs);
 	}
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/jfs/jfs_dtree.c linux-2.4.27-pre3/fs/jfs/jfs_dtree.c
--- linux-2.4.26/fs/jfs/jfs_dtree.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/jfs/jfs_dtree.c	2004-05-18 16:54:37.000000000 +0000
@@ -177,8 +177,8 @@ static int ciCompare(struct component_na
 static void dtGetKey(dtpage_t * p, int i, struct component_name * key,
 		     int flag);
 
-static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
-			       int ri, struct component_name * key, int flag);
+static int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
+			      int ri, struct component_name * key, int flag);
 
 static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
 			  ddata_t * data, struct dt_lock **);
@@ -342,7 +342,6 @@ static u32 add_index(tid_t tid, struct i
 	struct metapage *mp;
 	s64 offset;
 	uint page_offset;
-	int rc;
 	struct tlock *tlck;
 	s64 xaddr;
 
@@ -396,11 +395,11 @@ static u32 add_index(tid_t tid, struct i
 		 * Allocate the first block & add it to the xtree
 		 */
 		xaddr = 0;
-		if ((rc =
-		     xtInsert(tid, ip, 0, 0, sbi->nbperpage,
-			      &xaddr, 0))) {
+		if (xtInsert(tid, ip, 0, 0, sbi->nbperpage, &xaddr, 0)) {
 			jfs_warn("add_index: xtInsert failed!");
-			return -EPERM;
+			memcpy(&jfs_ip->i_dirtable, temp_table,
+			       sizeof (temp_table));
+			goto clean_up;
 		}
 		ip->i_size = PSIZE;
 		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
@@ -408,7 +407,9 @@ static u32 add_index(tid_t tid, struct i
 		if ((mp = get_index_page(ip, 0)) == 0) {
 			jfs_err("add_index: get_metapage failed!");
 			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
-			return -EPERM;
+			memcpy(&jfs_ip->i_dirtable, temp_table,
+			       sizeof (temp_table));
+			goto clean_up;
 		}
 		tlck = txLock(tid, ip, mp, tlckDATA);
 		llck = (struct linelock *) & tlck->lock;
@@ -438,12 +439,9 @@ static u32 add_index(tid_t tid, struct i
 		 * This will be the beginning of a new page
 		 */
 		xaddr = 0;
-		if ((rc =
-		     xtInsert(tid, ip, 0, blkno, sbi->nbperpage,
-			      &xaddr, 0))) {
+		if (xtInsert(tid, ip, 0, blkno, sbi->nbperpage, &xaddr, 0)) {
 			jfs_warn("add_index: xtInsert failed!");
-			jfs_ip->next_index--;
-			return -EPERM;
+			goto clean_up;
 		}
 		ip->i_size += PSIZE;
 		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
@@ -457,7 +455,7 @@ static u32 add_index(tid_t tid, struct i
 
 	if (mp == 0) {
 		jfs_err("add_index: get/read_metapage failed!");
-		return -EPERM;
+		goto clean_up;
 	}
 
 	lock_index(tid, ip, mp, index);
@@ -472,6 +470,12 @@ static u32 add_index(tid_t tid, struct i
 	release_metapage(mp);
 
 	return index;
+
+      clean_up:
+
+	jfs_ip->next_index--;
+
+	return 0;
 }
 
 /*
@@ -982,7 +986,9 @@ static int dtSplitUp(tid_t tid,
 		split->pxdlist = &pxdlist;
 		rc = dtSplitRoot(tid, ip, split, &rmp);
 
-		DT_PUTPAGE(rmp);
+		if (!rc)
+			DT_PUTPAGE(rmp);
+
 		DT_PUTPAGE(smp);
 
 		goto freeKeyName;
@@ -1150,9 +1156,16 @@ static int dtSplitUp(tid_t tid,
 			if ((sp->header.flag & BT_ROOT && skip > 1) ||
 			    sp->header.prev != 0 || skip > 1) {
 				/* compute uppercase router prefix key */
-				ciGetLeafPrefixKey(lp,
-						   lp->header.nextindex - 1,
-						   rp, 0, &key, sbi->mntflag);
+				rc = ciGetLeafPrefixKey(lp,
+							lp->header.nextindex-1,
+							rp, 0, &key,
+							sbi->mntflag);
+				if (rc) {
+					DT_PUTPAGE(lmp);
+					DT_PUTPAGE(rmp);
+					DT_PUTPAGE(smp);
+					goto splitOut;
+				}
 			} else {
 				/* next to leftmost entry of
 				   lowest internal level */
@@ -1876,6 +1889,9 @@ static int dtSplitRoot(tid_t tid,
 	xlen = lengthPXD(pxd);
 	xsize = xlen << JFS_SBI(sb)->l2bsize;
 	rmp = get_metapage(ip, rbn, xsize, 1);
+	if (!rmp)
+		return -EIO;
+
 	rp = rmp->data;
 
 	BT_MARK_DIRTY(rmp, ip);
@@ -3708,18 +3724,28 @@ static int ciCompare(struct component_na
  *	     from two adjacent leaf entries
  *	     across page boundary
  *
- * return:
- *	Number of prefix bytes needed to distinguish b from a.
+ * return: non-zero on error
+ *	
  */
-static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
+static int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
 			       int ri, struct component_name * key, int flag)
 {
 	int klen, namlen;
 	wchar_t *pl, *pr, *kname;
-	wchar_t lname[JFS_NAME_MAX + 1];
-	struct component_name lkey = { 0, lname };
-	wchar_t rname[JFS_NAME_MAX + 1];
-	struct component_name rkey = { 0, rname };
+	struct component_name lkey;
+	struct component_name rkey;
+
+	lkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
+					GFP_KERNEL);
+	if (lkey.name == NULL)
+		return -ENOSPC;
+
+	rkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
+					GFP_KERNEL);
+	if (rkey.name == NULL) {
+		kfree(lkey.name);
+		return -ENOSPC;
+	}
 
 	/* get left and right key */
 	dtGetKey(lp, li, &lkey, flag);
@@ -3744,7 +3770,7 @@ static void ciGetLeafPrefixKey(dtpage_t 
 		*kname = *pr;
 		if (*pl != *pr) {
 			key->namlen = klen + 1;
-			return;
+			goto free_names;
 		}
 	}
 
@@ -3755,7 +3781,10 @@ static void ciGetLeafPrefixKey(dtpage_t 
 	} else			/* l->namelen == r->namelen */
 		key->namlen = klen;
 
-	return;
+free_names:
+	kfree(lkey.name);
+	kfree(rkey.name);
+	return 0;
 }
 
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/jfs/jfs_metapage.c linux-2.4.27-pre3/fs/jfs/jfs_metapage.c
--- linux-2.4.26/fs/jfs/jfs_metapage.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/jfs/jfs_metapage.c	2004-05-18 16:54:17.000000000 +0000
@@ -284,33 +284,36 @@ struct metapage *__get_metapage(struct i
 	else
 		mapping = inode->i_mapping;
 
-	spin_lock(&meta_lock);
-
 	hash_ptr = meta_hash(mapping, lblock);
-
+again:
+	spin_lock(&meta_lock);
 	mp = search_hash(hash_ptr, mapping, lblock);
 	if (mp) {
 	      page_found:
+		mp->count++;
+		lock_metapage(mp);
+		spin_unlock(&meta_lock);
+		if (test_bit(META_stale, &mp->flag)) {
+			release_metapage(mp);
+			goto again;
+		}
 		if (test_bit(META_discard, &mp->flag)) {
 			if (!new) {
-				spin_unlock(&meta_lock);
 				jfs_error(inode->i_sb,
 					  "__get_metapage: using a "
 					  "discarded metapage");
+				release_metapage(mp);
 				return NULL;
 			}
 			clear_bit(META_discard, &mp->flag);
 		}
-		mp->count++;
 		jfs_info("__get_metapage: found 0x%p, in hash", mp);
 		if (mp->logical_size != size) {
-			spin_unlock(&meta_lock);
 			jfs_error(inode->i_sb,
 				  "__get_metapage: mp->logical_size != size");
+			release_metapage(mp);
 			return NULL;
 		}
-		lock_metapage(mp);
-		spin_unlock(&meta_lock);
 	} else {
 		l2bsize = inode->i_blkbits;
 		l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
@@ -498,46 +501,57 @@ void release_metapage(struct metapage * 
 	if (--mp->count || atomic_read(&mp->nohomeok)) {
 		unlock_metapage(mp);
 		spin_unlock(&meta_lock);
-	} else {
-		remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
-		spin_unlock(&meta_lock);
-
-		if (mp->page) {
-			kunmap(mp->page);
-			mp->data = 0;
-			if (test_bit(META_dirty, &mp->flag))
-				__write_metapage(mp);
-			if (test_bit(META_sync, &mp->flag)) {
-				sync_metapage(mp);
-				clear_bit(META_sync, &mp->flag);
-			}
-
-			if (test_bit(META_discard, &mp->flag)) {
-				lock_page(mp->page);
-				block_flushpage(mp->page, 0);
-				UnlockPage(mp->page);
-			}
+		return;
+	}
 
-			page_cache_release(mp->page);
-			INCREMENT(mpStat.pagefree);
+	if (mp->page) {
+		/* Releasing spinlock, we have to check mp->count later */
+		set_bit(META_stale, &mp->flag);
+		spin_unlock(&meta_lock);
+		kunmap(mp->page);
+		mp->data = 0;
+		if (test_bit(META_dirty, &mp->flag))
+			__write_metapage(mp);
+		if (test_bit(META_sync, &mp->flag)) {
+			sync_metapage(mp);
+			clear_bit(META_sync, &mp->flag);
 		}
 
-		if (mp->lsn) {
-			/*
-			 * Remove metapage from logsynclist.
-			 */
-			log = mp->log;
-			LOGSYNC_LOCK(log);
-			mp->log = 0;
-			mp->lsn = 0;
-			mp->clsn = 0;
-			log->count--;
-			list_del(&mp->synclist);
-			LOGSYNC_UNLOCK(log);
+		if (test_bit(META_discard, &mp->flag)) {
+			lock_page(mp->page);
+			block_flushpage(mp->page, 0);
+			UnlockPage(mp->page);
 		}
 
-		free_metapage(mp);
+		page_cache_release(mp->page);
+		mp->page = NULL;
+		INCREMENT(mpStat.pagefree);
+		spin_lock(&meta_lock);
+	}
+
+	if (mp->lsn) {
+		/*
+		 * Remove metapage from logsynclist.
+		 */
+		log = mp->log;
+		LOGSYNC_LOCK(log);
+		mp->log = 0;
+		mp->lsn = 0;
+		mp->clsn = 0;
+		log->count--;
+		list_del(&mp->synclist);
+		LOGSYNC_UNLOCK(log);
+	}
+	if (mp->count) {
+		/* Someone else is trying to get this metpage */
+		unlock_metapage(mp);
+		spin_unlock(&meta_lock);
+		return;
 	}
+	remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
+	spin_unlock(&meta_lock);
+
+	free_metapage(mp);
 }
 
 void __invalidate_metapages(struct inode *ip, s64 addr, int len)
@@ -557,9 +571,20 @@ void __invalidate_metapages(struct inode
 	for (lblock = addr; lblock < addr + len;
 	     lblock += 1 << l2BlocksPerPage) {
 		hash_ptr = meta_hash(mapping, lblock);
+again:
 		spin_lock(&meta_lock);
 		mp = search_hash(hash_ptr, mapping, lblock);
 		if (mp) {
+			if (test_bit(META_stale, &mp->flag)) {
+				/* Racing with release_metapage */
+				mp->count++;
+				lock_metapage(mp);
+				spin_unlock(&meta_lock);
+				/* racing release_metapage should be done now */
+				release_metapage(mp);
+				goto again;
+			}
+
 			set_bit(META_discard, &mp->flag);
 			spin_unlock(&meta_lock);
 		} else {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/jfs/jfs_metapage.h linux-2.4.27-pre3/fs/jfs/jfs_metapage.h
--- linux-2.4.26/fs/jfs/jfs_metapage.h	2003-06-13 14:51:37.000000000 +0000
+++ linux-2.4.27-pre3/fs/jfs/jfs_metapage.h	2004-05-18 16:52:25.000000000 +0000
@@ -64,6 +64,7 @@ struct metapage {
 #define META_sync	4
 #define META_discard	5
 #define META_forced	6
+#define META_stale	7
 
 #define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag)
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/jfs/jfs_txnmgr.c linux-2.4.27-pre3/fs/jfs/jfs_txnmgr.c
--- linux-2.4.26/fs/jfs/jfs_txnmgr.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/jfs/jfs_txnmgr.c	2004-05-18 16:52:02.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *   Copyright (C) International Business Machines Corp., 2000-2003
+ *   Copyright (C) International Business Machines Corp., 2000-2004
  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -175,7 +175,6 @@ static void dtLog(struct jfs_log * log, 
 		struct tlock * tlck);
 static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
 		struct tlock * tlck);
-static void txAbortCommit(struct commit * cd);
 static void txAllocPMap(struct inode *ip, struct maplock * maplock,
 		struct tblock * tblk);
 static void txForce(struct tblock * tblk);
@@ -1295,7 +1294,7 @@ int txCommit(tid_t tid,		/* transaction 
 
       out:
 	if (rc != 0)
-		txAbortCommit(&cd);
+		txAbort(tid, 1);
 
       TheEnd:
 	jfs_info("txCommit: tid = %d, returning %d", tid, rc);
@@ -2633,64 +2632,6 @@ void txAbort(tid_t tid, int dirty)
 	return;
 }
 
-
-/*
- *      txAbortCommit()
- *
- * function: abort commit.
- *
- * frees tlocks of transaction; line-locks and segment locks for all
- * segments in comdata structure. frees malloc storage
- * sets state of file-system to FM_MDIRTY in super-block.
- * log age of page-frames in memory for which caller has
- * are reset to 0 (to avoid logwarap).
- */
-static void txAbortCommit(struct commit * cd)
-{
-	struct tblock *tblk;
-	tid_t tid;
-	lid_t lid, next;
-	struct metapage *mp;
-
-	jfs_warn("txAbortCommit: cd:0x%p", cd);
-
-	/*
-	 * free tlocks of the transaction
-	 */
-	tid = cd->tid;
-	tblk = tid_to_tblock(tid);
-	for (lid = tblk->next; lid; lid = next) {
-		next = lid_to_tlock(lid)->next;
-
-		mp = lid_to_tlock(lid)->mp;
-		if (mp) {
-			mp->lid = 0;
-
-			/*
-			 * reset lsn of page to avoid logwarap;
-			 */
-			if (mp->xflag & COMMIT_PAGE)
-				LogSyncRelease(mp);
-		}
-
-		/* insert tlock at head of freelist */
-		TXN_LOCK();
-		txLockFree(lid);
-		TXN_UNLOCK();
-	}
-
-	tblk->next = tblk->last = 0;
-
-	/* free the transaction block */
-	txEnd(tid);
-
-	/*
-	 * mark filesystem dirty
-	 */
-	jfs_error(cd->sb, "txAbortCommit");
-}
-
-
 /*
  *      txLazyCommit(void)
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/jfs/namei.c linux-2.4.27-pre3/fs/jfs/namei.c
--- linux-2.4.26/fs/jfs/namei.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/jfs/namei.c	2004-05-18 16:51:36.000000000 +0000
@@ -784,14 +784,14 @@ static int jfs_link(struct dentry *old_d
 		goto out;
 
 	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
-		goto out;
+		goto free_dname;
 
 	/*
 	 * create entry for new link in parent directory
 	 */
 	ino = ip->i_ino;
 	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
-		goto out;
+		goto free_dname;
 
 	/* update object inode */
 	ip->i_nlink++;		/* for new link */
@@ -804,6 +804,9 @@ static int jfs_link(struct dentry *old_d
 	iplist[1] = dir;
 	rc = txCommit(tid, 2, &iplist[0], 0);
 
+      free_dname:
+	free_UCSname(&dname);
+
       out:
 	txEnd(tid);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/proc/base.c linux-2.4.27-pre3/fs/proc/base.c
--- linux-2.4.26/fs/proc/base.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.27-pre3/fs/proc/base.c	2004-05-18 16:53:52.000000000 +0000
@@ -883,8 +883,8 @@ static struct dentry *proc_lookupfd(stru
 	return NULL;
 
 out_unlock2:
-	put_files_struct(files);
 	read_unlock(&files->file_lock);
+	put_files_struct(files);
 out_unlock:
 	iput(inode);
 out:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/reiserfs/journal.c linux-2.4.27-pre3/fs/reiserfs/journal.c
--- linux-2.4.26/fs/reiserfs/journal.c	2003-08-25 11:44:43.000000000 +0000
+++ linux-2.4.27-pre3/fs/reiserfs/journal.c	2004-05-18 16:53:47.000000000 +0000
@@ -198,6 +198,9 @@ static int set_bit_in_list_bitmap(struct
 static void cleanup_bitmap_list(struct super_block *p_s_sb,
                                 struct reiserfs_list_bitmap *jb) {
   int i;
+  if (jb->bitmaps == NULL)
+	return ;
+
   for (i = 0 ; i < SB_BMAP_NR(p_s_sb) ; i++) {
     if (jb->bitmaps[i]) {
       free_bitmap_node(p_s_sb, jb->bitmaps[i]) ;
@@ -2064,8 +2067,11 @@ int journal_init(struct super_block *p_s
     INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;
     INIT_LIST_HEAD (&SB_JOURNAL(p_s_sb)->j_prealloc_list);
 
-    reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap, 
-				   SB_BMAP_NR(p_s_sb)) ;
+    if (reiserfs_allocate_list_bitmaps(p_s_sb,
+				       SB_JOURNAL(p_s_sb)->j_list_bitmap, 
+				       SB_BMAP_NR(p_s_sb)))
+	goto free_and_return ;
+
     allocate_bitmap_nodes(p_s_sb) ;
 
     /* reserved for journal area support */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/kmem.h linux-2.4.27-pre3/fs/xfs/linux/kmem.h
--- linux-2.4.26/fs/xfs/linux/kmem.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/kmem.h	2004-05-18 16:54:28.000000000 +0000
@@ -49,14 +49,18 @@ typedef unsigned long xfs_pflags_t;
 #define PFLAGS_TEST_NOIO()              (current->flags & PF_NOIO)
 #define PFLAGS_TEST_FSTRANS()           (current->flags & PF_FSTRANS)
 
-#define PFLAGS_SET_NOIO(STATEP) do {    \
-	*(STATEP) = current->flags;     \
-        current->flags |= PF_NOIO;      \
+#define PFLAGS_SET_NOIO() do {		\
+	current->flags |= PF_NOIO;	\
 } while (0)
 
-#define PFLAGS_SET_FSTRANS(STATEP) do { \
-	*(STATEP) = current->flags;     \
-        current->flags |= PF_FSTRANS;   \
+#define PFLAGS_CLEAR_NOIO() do {	\
+	current->flags &= ~PF_NOIO;	\
+} while (0)
+
+/* these could be nested, so we save state */
+#define PFLAGS_SET_FSTRANS(STATEP) do {	\
+	*(STATEP) = current->flags;	\
+	current->flags |= PF_FSTRANS;	\
 } while (0)
 
 #define PFLAGS_CLEAR_FSTRANS(STATEP) do { \
@@ -64,14 +68,15 @@ typedef unsigned long xfs_pflags_t;
 	current->flags &= ~PF_FSTRANS;	\
 } while (0)
 
-
-#define PFLAGS_RESTORE(STATEP) do {     \
-	current->flags = *(STATEP);     \
+/* Restore the PF_FSTRANS state to what was saved in STATEP */
+#define PFLAGS_RESTORE_FSTRANS(STATEP) do {     		\
+	current->flags = ((current->flags & ~PF_FSTRANS) |	\
+			  (*(STATEP) & PF_FSTRANS));		\
 } while (0)
 
 #define PFLAGS_DUP(OSTATEP, NSTATEP) do { \
 	*(NSTATEP) = *(OSTATEP);	\
-} while (0);
+} while (0)
 
 static __inline unsigned int kmem_flags_convert(int flags)
 {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/xfs_aops.c linux-2.4.27-pre3/fs/xfs/linux/xfs_aops.c
--- linux-2.4.26/fs/xfs/linux/xfs_aops.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/xfs_aops.c	2004-05-18 16:55:17.000000000 +0000
@@ -108,7 +108,7 @@ linvfs_unwritten_done(
 	struct buffer_head	*bh,
 	int			uptodate)
 {
-	page_buf_t		*pb = (page_buf_t *)bh->b_private;
+	xfs_buf_t		*pb = (xfs_buf_t *)bh->b_private;
 
 	ASSERT(buffer_unwritten(bh));
 	bh->b_end_io = NULL;
@@ -241,9 +241,9 @@ xfs_map_at_offset(
 STATIC struct page *
 xfs_probe_unwritten_page(
 	struct address_space	*mapping,
-	unsigned long		index,
+	pgoff_t			index,
 	xfs_iomap_t		*iomapp,
-	page_buf_t		*pb,
+	xfs_buf_t		*pb,
 	unsigned long		max_offset,
 	unsigned long		*fsbs,
 	unsigned int            bbits)
@@ -289,7 +289,7 @@ xfs_probe_unwritten_page(
 STATIC unsigned int
 xfs_probe_unmapped_page(
 	struct address_space	*mapping,
-	unsigned long		index,
+	pgoff_t			index,
 	unsigned int		pg_offset)
 {
 	struct page		*page;
@@ -326,8 +326,8 @@ xfs_probe_unmapped_cluster(
 	struct buffer_head	*bh,
 	struct buffer_head	*head)
 {
-	unsigned long		tindex, tlast, tloff;
-	unsigned int		len, total = 0;
+	pgoff_t			tindex, tlast, tloff;
+	unsigned int		pg_offset, len, total = 0;
 	struct address_space	*mapping = inode->i_mapping;
 
 	/* First sum forwards in this page */
@@ -352,9 +352,9 @@ xfs_probe_unmapped_cluster(
 			total += len;
 		}
 		if (tindex == tlast &&
-		    (tloff = i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) {
+		    (pg_offset = i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) {
 			total += xfs_probe_unmapped_page(mapping,
-							tindex, tloff);
+							tindex, pg_offset);
 		}
 	}
 	return total;
@@ -368,7 +368,7 @@ xfs_probe_unmapped_cluster(
 STATIC struct page *
 xfs_probe_delalloc_page(
 	struct inode		*inode,
-	unsigned long		index)
+	pgoff_t			index)
 {
 	struct page		*page;
 
@@ -412,7 +412,7 @@ xfs_map_unwritten(
 {
 	struct buffer_head	*bh = curr;
 	xfs_iomap_t		*tmp;
-	page_buf_t		*pb;
+	xfs_buf_t		*pb;
 	loff_t			offset, size;
 	unsigned long		nblocks = 0;
 
@@ -464,8 +464,9 @@ xfs_map_unwritten(
 	 */
 	if (bh == head) {
 		struct address_space	*mapping = inode->i_mapping;
-		unsigned long		tindex, tloff, tlast, bs;
-		unsigned int		bbits = inode->i_blkbits;
+		pgoff_t			tindex, tloff, tlast;
+		unsigned long		bs;
+		unsigned int		pg_offset, bbits = inode->i_blkbits;
 		struct page		*page;
 
 		tlast = i_size_read(inode) >> PAGE_CACHE_SHIFT;
@@ -489,10 +490,10 @@ xfs_map_unwritten(
 		}
 
 		if (tindex == tlast &&
-		    (tloff = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)))) {
+		    (pg_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)))) {
 			page = xfs_probe_unwritten_page(mapping,
 							tindex, iomapp, pb,
-							tloff, &bs, bbits);
+							pg_offset, &bs, bbits);
 			if (page) {
 				nblocks += bs;
 				atomic_add(bs, &pb->pb_io_remaining);
@@ -567,7 +568,8 @@ xfs_convert_page(
 {
 	struct buffer_head	*bh_arr[MAX_BUF_PER_PAGE], *bh, *head;
 	xfs_iomap_t		*mp = iomapp, *tmp;
-	unsigned long		end, offset, end_index;
+	unsigned long		end, offset;
+	pgoff_t			end_index;
 	int			i = 0, index = 0;
 	int			bbits = inode->i_blkbits;
 
@@ -634,12 +636,12 @@ xfs_convert_page(
 STATIC void
 xfs_cluster_write(
 	struct inode		*inode,
-	unsigned long		tindex,
+	pgoff_t			tindex,
 	xfs_iomap_t		*iomapp,
 	int			startio,
 	int			all_bh)
 {
-	unsigned long		tlast;
+	pgoff_t			tlast;
 	struct page		*page;
 
 	tlast = (iomapp->iomap_offset + iomapp->iomap_bsize) >> PAGE_CACHE_SHIFT;
@@ -1036,7 +1038,6 @@ linvfs_writepage(
 	int			need_trans;
 	int			delalloc, unmapped, unwritten;
 	struct inode		*inode = page->mapping->host;
-	xfs_pflags_t		pflags;
 
 	xfs_page_trace(XFS_WRITEPAGE_ENTER, inode, page, 0);
 
@@ -1080,10 +1081,10 @@ linvfs_writepage(
 	 * to real space and flush out to disk.
 	 */
 	if (need_trans)
-		PFLAGS_SET_NOIO(&pflags);
+		PFLAGS_SET_NOIO();
 	error = xfs_page_state_convert(inode, page, 1, unmapped);
 	if (need_trans)
-		PFLAGS_RESTORE(&pflags);
+		PFLAGS_CLEAR_NOIO();
 	if (error == -EAGAIN)
 		goto out_fail;
 
@@ -1181,7 +1182,7 @@ linvfs_direct_IO(
 {
 	struct page		**maplist;
 	size_t			page_offset;
-	page_buf_t		*pb;
+	xfs_buf_t		*pb;
 	xfs_iomap_t		iomap;
 	int			error = 0;
 	int			pb_flags, map_flags, pg_index = 0;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/xfs_buf.c linux-2.4.27-pre3/fs/xfs/linux/xfs_buf.c
--- linux-2.4.26/fs/xfs/linux/xfs_buf.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/xfs_buf.c	2004-05-18 16:51:33.000000000 +0000
@@ -31,14 +31,10 @@
  */
 
 /*
- *	page_buf.c
- *
- *	The page_buf module provides an abstract buffer cache model on top of
- *	the Linux page cache.  Cached metadata blocks for a file system are
- *	hashed to the inode for the block device.  The page_buf module
- *	assembles buffer (page_buf_t) objects on demand to aggregate such
- *	cached pages for I/O.
- *
+ *	The xfs_buf.c code provides an abstract buffer cache model on top
+ *	of the Linux page cache.  Cached metadata blocks for a file system
+ *	are hashed to the inode for the block device.  xfs_buf.c assembles
+ *	buffers (xfs_buf_t) on demand to aggregate such cached pages for I/O.
  *
  *      Written by Steve Lord, Jim Mostek, Russell Cattelan
  *		    and Rajagopal Ananthanarayanan ("ananth") at SGI.
@@ -93,6 +89,10 @@
 # endif
 #endif
 
+#ifndef VM_MAP
+#define VM_MAP	VM_ALLOC
+#endif
+
 /*
  * File wide globals
  */
@@ -119,8 +119,8 @@ struct buffer_head		*pb_resv_bh = NULL;	
 int				pb_resv_bh_cnt = 0;	/* # of bh available */
 
 STATIC void pagebuf_daemon_wakeup(void);
-STATIC void _pagebuf_ioapply(page_buf_t *);
-STATIC void pagebuf_delwri_queue(page_buf_t *, int);
+STATIC void _pagebuf_ioapply(xfs_buf_t *);
+STATIC void pagebuf_delwri_queue(xfs_buf_t *, int);
 STATIC void pagebuf_runall_queues(struct list_head[]);
 
 /*
@@ -130,7 +130,7 @@ STATIC void pagebuf_runall_queues(struct
 #ifdef PAGEBUF_TRACE
 void
 pagebuf_trace(
-	page_buf_t	*pb,
+	xfs_buf_t	*pb,
 	char		*id,
 	void		*data,
 	void		*ra)
@@ -217,8 +217,6 @@ _bhash(
  * Mapping of multi-page buffers into contiguous virtual space
  */
 
-STATIC void *pagebuf_mapout_locked(page_buf_t *);
-
 typedef struct a_list {
 	void		*vm_addr;
 	struct a_list	*next;
@@ -277,8 +275,8 @@ purge_addresses(void)
 
 STATIC void
 _pagebuf_initialize(
-	page_buf_t		*pb,
-	pb_target_t		*target,
+	xfs_buf_t		*pb,
+	xfs_buftarg_t		*target,
 	loff_t			range_base,
 	size_t			range_length,
 	page_buf_flags_t	flags)
@@ -288,7 +286,7 @@ _pagebuf_initialize(
 	 */
 	flags &= ~(PBF_LOCK|PBF_MAPPED|PBF_DONT_BLOCK|PBF_READ_AHEAD);
 
-	memset(pb, 0, sizeof(page_buf_t));
+	memset(pb, 0, sizeof(xfs_buf_t));
 	atomic_set(&pb->pb_hold, 1);
 	init_MUTEX_LOCKED(&pb->pb_iodonesema);
 	INIT_LIST_HEAD(&pb->pb_list);
@@ -299,12 +297,12 @@ _pagebuf_initialize(
 	pb->pb_file_offset = range_base;
 	/*
 	 * Set buffer_length and count_desired to the same value initially.
-	 * IO routines should use count_desired, which will be the same in
+	 * I/O routines should use count_desired, which will be the same in
 	 * most cases but may be reset (e.g. XFS recovery).
 	 */
 	pb->pb_buffer_length = pb->pb_count_desired = range_length;
 	pb->pb_flags = flags | PBF_NONE;
-	pb->pb_bn = PAGE_BUF_DADDR_NULL;
+	pb->pb_bn = XFS_BUF_DADDR_NULL;
 	atomic_set(&pb->pb_pin_count, 0);
 	init_waitqueue_head(&pb->pb_waiters);
 
@@ -318,7 +316,7 @@ _pagebuf_initialize(
  */
 STATIC int
 _pagebuf_get_pages(
-	page_buf_t		*pb,
+	xfs_buf_t		*pb,
 	int			page_count,
 	page_buf_flags_t	flags)
 {
@@ -340,201 +338,165 @@ _pagebuf_get_pages(
 }
 
 /*
- * Walk a pagebuf releasing all the pages contained within it.
+ *	Frees pb_pages if it was malloced.
  */
-STATIC inline void
-_pagebuf_freepages(
-	page_buf_t		*pb)
+STATIC void
+_pagebuf_free_pages(
+	xfs_buf_t	*bp)
 {
-	int			buf_index;
-
-	for (buf_index = 0; buf_index < pb->pb_page_count; buf_index++) {
-		struct page	*page = pb->pb_pages[buf_index];
-
-		if (page) {
-			pb->pb_pages[buf_index] = NULL;
-			page_cache_release(page);
-		}
+	if (bp->pb_pages != bp->pb_page_array) {
+		kmem_free(bp->pb_pages,
+			  bp->pb_page_count * sizeof(struct page *));
 	}
 }
 
 /*
- *	pagebuf_free
+ *	Releases the specified buffer.
  *
- *	pagebuf_free releases the specified buffer.  The modification
- *	state of any associated pages is left unchanged.
+ * 	The modification state of any associated pages is left unchanged.
+ * 	The buffer most not be on any hash - use pagebuf_rele instead for
+ * 	hashed and refcounted buffers
  */
 void
 pagebuf_free(
-	page_buf_t		*pb)
+	xfs_buf_t		*bp)
 {
-	PB_TRACE(pb, "free", 0);
-	
-	ASSERT(list_empty(&pb->pb_hash_list));
-
-	/* release any virtual mapping */ ;
-	if (pb->pb_flags & _PBF_ADDR_ALLOCATED) {
-		void *vaddr = pagebuf_mapout_locked(pb);
-		if (vaddr) {
-			free_address(vaddr);
-		}
-	}
+	PB_TRACE(bp, "free", 0);
 
-	if (pb->pb_flags & _PBF_MEM_ALLOCATED) {
-		if (pb->pb_pages) {
-			/* release the pages in the address list */
-			if ((pb->pb_pages[0]) &&
-			    (pb->pb_flags & _PBF_MEM_SLAB)) {
-				kfree(pb->pb_addr);
-			} else {
-				_pagebuf_freepages(pb);
-			}
-			if (pb->pb_pages != pb->pb_page_array)
-				kfree(pb->pb_pages);
-			pb->pb_pages = NULL;
-		}
-		pb->pb_flags &= ~(_PBF_MEM_ALLOCATED|_PBF_MEM_SLAB);
+	ASSERT(list_empty(&bp->pb_hash_list));
+
+	if (bp->pb_flags & _PBF_PAGE_CACHE) {
+		uint		i;
+
+		if ((bp->pb_flags & PBF_MAPPED) && (bp->pb_page_count > 1))
+			free_address(bp->pb_addr - bp->pb_offset);
+
+		for (i = 0; i < bp->pb_page_count; i++)
+			page_cache_release(bp->pb_pages[i]);
+		_pagebuf_free_pages(bp);
+	} else if (bp->pb_flags & _PBF_KMEM_ALLOC) {
+		 /*
+		  * XXX(hch): bp->pb_count_desired might be incorrect (see
+		  * pagebuf_associate_memory for details), but fortunately
+		  * the Linux version of kmem_free ignores the len argument..
+		  */
+		kmem_free(bp->pb_addr, bp->pb_count_desired);
+		_pagebuf_free_pages(bp);
 	}
 
-	pagebuf_deallocate(pb);
+	pagebuf_deallocate(bp);
 }
 
 /*
- *	_pagebuf_lookup_pages
- *
- *	_pagebuf_lookup_pages finds all pages which match the buffer
- *	in question and the range of file offsets supplied,
- *	and builds the page list for the buffer, if the
- *	page list is not already formed or if not all of the pages are
- *	already in the list. Invalid pages (pages which have not yet been
- *	read in from disk) are assigned for any pages which are not found.
+ *	Finds all pages for buffer in question and builds it's page list.
  */
 STATIC int
 _pagebuf_lookup_pages(
-	page_buf_t		*pb,
-	struct address_space	*aspace,
-	page_buf_flags_t	flags)
+	xfs_buf_t		*bp,
+	uint			flags)
 {
-	loff_t			next_buffer_offset;
-	unsigned long		page_count, pi, index;
-	struct page		*page;
+	struct address_space	*mapping = bp->pb_target->pbr_mapping;
+	size_t			blocksize = bp->pb_target->pbr_bsize;
 	int			gfp_mask = pb_to_gfp(flags);
-	int			all_mapped, good_pages, rval, retries;
-	size_t			blocksize;
-
-	next_buffer_offset = pb->pb_file_offset + pb->pb_buffer_length;
-	good_pages = page_count = (page_buf_btoc(next_buffer_offset) -
-				   page_buf_btoct(pb->pb_file_offset));
-
-	if (pb->pb_flags & _PBF_ALL_PAGES_MAPPED) {
-		/* Bring pages forward in cache */
-		for (pi = 0; pi < page_count; pi++) {
-			mark_page_accessed(pb->pb_pages[pi]);
-		}
-		if ((flags & PBF_MAPPED) && !(pb->pb_flags & PBF_MAPPED)) {
-			all_mapped = 1;
-			rval = 0;
-			goto mapit;
-		}
-		return 0;
-	}
+	unsigned short		page_count, i;
+	pgoff_t			first;
+	loff_t			end;
+	int			error;
 
-	/* Ensure pb_pages field has been initialised */
-	rval = _pagebuf_get_pages(pb, page_count, flags);
-	if (rval)
-		return rval;
+	end = bp->pb_file_offset + bp->pb_buffer_length;
+	page_count = page_buf_btoc(end) - page_buf_btoct(bp->pb_file_offset);
 
-	all_mapped = 1;
-	blocksize = pb->pb_target->pbr_bsize;
+	error = _pagebuf_get_pages(bp, page_count, flags);
+	if (unlikely(error))
+		return error;
+
+	first = bp->pb_file_offset >> PAGE_CACHE_SHIFT;
+
+	for (i = 0; i < bp->pb_page_count; i++) {
+		struct page	*page;
+		uint		retries = 0;
+
+	      retry:
+		page = find_or_create_page(mapping, first + i, gfp_mask);
+		if (unlikely(page == NULL)) {
+			if (flags & PBF_READ_AHEAD)
+				return -ENOMEM;
 
-	/* Enter the pages in the page list */
-	index = (pb->pb_file_offset - pb->pb_offset) >> PAGE_CACHE_SHIFT;
-	for (pi = 0; pi < page_count; pi++, index++) {
-		if (pb->pb_pages[pi] == 0) {
-			retries = 0;
-		      retry:
-			page = find_or_create_page(aspace, index, gfp_mask);
-			if (!page) {
-				if (flags & PBF_READ_AHEAD)
-					return -ENOMEM;
-				/*
-				 * This could deadlock.  But until all the
-				 * XFS lowlevel code is revamped to handle
-				 * buffer allocation failures we can't do
-				 * much.
-				 */
-				if (!(++retries % 100)) {
-					printk(KERN_ERR
-					       "possibly deadlocking in %s\n",
-					       __FUNCTION__);
-				}
-				XFS_STATS_INC(pb_page_retries);
-				pagebuf_daemon_wakeup();
-				current->state = TASK_UNINTERRUPTIBLE;
-				schedule_timeout(10);
-				goto retry;
+			/*
+			 * This could deadlock.
+			 *
+			 * But until all the XFS lowlevel code is revamped to
+			 * handle buffer allocation failures we can't do much.
+			 */
+			if (!(++retries % 100)) {
+				printk(KERN_ERR "possibly deadlocking in %s\n",
+						__FUNCTION__);
 			}
-			XFS_STATS_INC(pb_page_found);
-			mark_page_accessed(page);
-			pb->pb_pages[pi] = page;
-		} else {
-			page = pb->pb_pages[pi];
-			lock_page(page);
+
+			XFS_STATS_INC(pb_page_retries);
+			pagebuf_daemon_wakeup();
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(10);
+			goto retry;
 		}
 
-		/* If we need to do I/O on a page record the fact */
+		XFS_STATS_INC(pb_page_found);
+
+		/* if we need to do I/O on a page record the fact */
 		if (!Page_Uptodate(page)) {
-			good_pages--;
-			if ((blocksize == PAGE_CACHE_SIZE) &&
-			    (flags & PBF_READ))
-				pb->pb_locked = 1;
+			page_count--;
+			if (blocksize == PAGE_CACHE_SIZE && (flags & PBF_READ))
+				bp->pb_locked = 1;
 		}
-	}
 
-	if (!pb->pb_locked) {
-		for (pi = 0; pi < page_count; pi++) {
-			if (pb->pb_pages[pi])
-				unlock_page(pb->pb_pages[pi]);
-		}
+		bp->pb_pages[i] = page;
 	}
 
-	pb->pb_flags |= _PBF_PAGECACHE;
-mapit:
-	pb->pb_flags |= _PBF_MEM_ALLOCATED;
-	if (all_mapped) {
-		pb->pb_flags |= _PBF_ALL_PAGES_MAPPED;
-
-		/* A single page buffer is always mappable */
-		if (page_count == 1) {
-			pb->pb_addr = (caddr_t)
-				page_address(pb->pb_pages[0]) + pb->pb_offset;
-			pb->pb_flags |= PBF_MAPPED;
-		} else if (flags & PBF_MAPPED) {
-			if (as_list_len > 64)
-				purge_addresses();
-			pb->pb_addr = vmap(pb->pb_pages, page_count,
-					VM_ALLOC, PAGE_KERNEL);
-			if (pb->pb_addr == NULL)
-				return -ENOMEM;
-			pb->pb_addr += pb->pb_offset;
-			pb->pb_flags |= PBF_MAPPED | _PBF_ADDR_ALLOCATED;
-		}
-	}
-	/* If some pages were found with data in them
-	 * we are not in PBF_NONE state.
-	 */
-	if (good_pages != 0) {
-		pb->pb_flags &= ~(PBF_NONE);
-		if (good_pages != page_count) {
-			pb->pb_flags |= PBF_PARTIAL;
-		}
+	if (!bp->pb_locked) {
+		for (i = 0; i < bp->pb_page_count; i++)
+			unlock_page(bp->pb_pages[i]);
 	}
 
-	PB_TRACE(pb, "lookup_pages", (long)good_pages);
+	bp->pb_flags |= _PBF_PAGE_CACHE;
 
-	return rval;
+	if (page_count) {
+		/* if we have any uptodate pages, mark that in the buffer */
+		bp->pb_flags &= ~PBF_NONE;
+
+		/* if some pages aren't uptodate, mark that in the buffer */
+		if (page_count != bp->pb_page_count)
+			bp->pb_flags |= PBF_PARTIAL;
+	}
+
+	PB_TRACE(bp, "lookup_pages", (long)page_count);
+	return error;
 }
 
+/*
+ *	Map buffer into kernel address-space if nessecary.
+ */
+STATIC int
+_pagebuf_map_pages(
+	xfs_buf_t		*bp,
+	uint			flags)
+{
+	/* A single page buffer is always mappable */
+	if (bp->pb_page_count == 1) {
+		bp->pb_addr = page_address(bp->pb_pages[0]) + bp->pb_offset;
+		bp->pb_flags |= PBF_MAPPED;
+	} else if (flags & PBF_MAPPED) {
+		if (as_list_len > 64)
+			purge_addresses();
+		bp->pb_addr = vmap(bp->pb_pages, bp->pb_page_count,
+				VM_MAP, PAGE_KERNEL);
+		if (unlikely(bp->pb_addr == NULL))
+			return -ENOMEM;
+		bp->pb_addr += bp->pb_offset;
+		bp->pb_flags |= PBF_MAPPED;
+	}
+
+	return 0;
+}
 
 /*
  *	Pre-allocation of a pool of buffer heads for use in
@@ -660,20 +622,19 @@ _pagebuf_free_bh(
  *	which may imply that this call will block until those buffers
  *	are unlocked.  No I/O is implied by this call.
  */
-STATIC page_buf_t *
+STATIC xfs_buf_t *
 _pagebuf_find(				/* find buffer for block	*/
-	pb_target_t		*target,/* target for block		*/
+	xfs_buftarg_t		*target,/* target for block		*/
 	loff_t			ioff,	/* starting offset of range	*/
 	size_t			isize,	/* length of range		*/
 	page_buf_flags_t	flags,	/* PBF_TRYLOCK			*/
-	page_buf_t		*new_pb)/* newly allocated buffer	*/
+	xfs_buf_t		*new_pb)/* newly allocated buffer	*/
 {
 	loff_t			range_base;
 	size_t			range_length;
 	int			hval;
 	pb_hash_t		*h;
-	struct list_head	*p;
-	page_buf_t		*pb;
+	xfs_buf_t		*pb, *n;
 	int			not_locked;
 
 	range_base = (ioff << BBSHIFT);
@@ -689,9 +650,8 @@ _pagebuf_find(				/* find buffer for blo
 	h = &pbhash[hval];
 
 	spin_lock(&h->pb_hash_lock);
-	list_for_each(p, &h->pb_hash) {
-		pb = list_entry(p, page_buf_t, pb_hash_list);
 
+	list_for_each_entry_safe(pb, n, &h->pb_hash, pb_hash_list) {
 		if (pb->pb_target == target &&
 		    pb->pb_file_offset == range_base &&
 		    pb->pb_buffer_length == range_length) {
@@ -749,11 +709,7 @@ found:
 	}
 
 	if (pb->pb_flags & PBF_STALE)
-		pb->pb_flags &= PBF_MAPPED | \
-				_PBF_ALL_PAGES_MAPPED | \
-				_PBF_ADDR_ALLOCATED | \
-				_PBF_MEM_ALLOCATED | \
-				_PBF_MEM_SLAB;
+		pb->pb_flags &= PBF_MAPPED;
 	PB_TRACE(pb, "got_lock", 0);
 	XFS_STATS_INC(pb_get_locked);
 	return (pb);
@@ -770,10 +726,10 @@ found:
  *	pages are present in the buffer, not all of every page may be
  *	valid.
  */
-page_buf_t *
+xfs_buf_t *
 pagebuf_find(				/* find buffer for block	*/
 					/* if the block is in memory	*/
-	pb_target_t		*target,/* target for block		*/
+	xfs_buftarg_t		*target,/* target for block		*/
 	loff_t			ioff,	/* starting offset of range	*/
 	size_t			isize,	/* length of range		*/
 	page_buf_flags_t	flags)	/* PBF_TRYLOCK			*/
@@ -790,37 +746,48 @@ pagebuf_find(				/* find buffer for bloc
  *	although backing storage may not be.  If PBF_READ is set in
  *	flags, pagebuf_iostart is called also.
  */
-page_buf_t *
+xfs_buf_t *
 pagebuf_get(				/* allocate a buffer		*/
-	pb_target_t		*target,/* target for buffer		*/
+	xfs_buftarg_t		*target,/* target for buffer		*/
 	loff_t			ioff,	/* starting offset of range	*/
 	size_t			isize,	/* length of range		*/
 	page_buf_flags_t	flags)	/* PBF_TRYLOCK			*/
 {
-	page_buf_t		*pb, *new_pb;
-	int			error;
+	xfs_buf_t		*pb, *new_pb;
+	int			error = 0, i;
 
 	new_pb = pagebuf_allocate(flags);
 	if (unlikely(!new_pb))
-		return (NULL);
+		return NULL;
 
 	pb = _pagebuf_find(target, ioff, isize, flags, new_pb);
-	if (pb != new_pb) {
+	if (pb == new_pb) {
+		error = _pagebuf_lookup_pages(pb, flags);
+		if (unlikely(error)) {
+			printk(KERN_WARNING
+			       "pagebuf_get: failed to lookup pages\n");
+			goto no_buffer;
+		}
+	} else {
 		pagebuf_deallocate(new_pb);
-		if (unlikely(!pb))
-			return (NULL);
+		if (unlikely(pb == NULL))
+			return NULL;
 	}
 
-	XFS_STATS_INC(pb_get);
+	for (i = 0; i < pb->pb_page_count; i++)
+		mark_page_accessed(pb->pb_pages[i]);
 
-	/* fill in any missing pages */
-	error = _pagebuf_lookup_pages(pb, pb->pb_target->pbr_mapping, flags);
-	if (unlikely(error)) {
-		printk(KERN_WARNING
-			"pagebuf_get: warning, failed to lookup pages\n");
-		goto no_buffer;
+	if (!(pb->pb_flags & PBF_MAPPED)) {
+		error = _pagebuf_map_pages(pb, flags);
+		if (unlikely(error)) {
+			printk(KERN_WARNING
+			       "pagebuf_get: failed to map pages\n");
+			goto no_buffer;
+		}
 	}
 
+	XFS_STATS_INC(pb_get);
+
 	/*
 	 * Always fill in the block number now, the mapped cases can do
 	 * their own overlay of this later.
@@ -861,14 +828,14 @@ no_buffer:
 /*
  * Create a skeletal pagebuf (no pages associated with it).
  */
-page_buf_t *
+xfs_buf_t *
 pagebuf_lookup(
-	struct pb_target	*target,
+	xfs_buftarg_t		*target,
 	loff_t			ioff,
 	size_t			isize,
 	page_buf_flags_t	flags)
 {
-	page_buf_t		*pb;
+	xfs_buf_t		*pb;
 
 	flags |= _PBF_PRIVATE_BH;
 	pb = pagebuf_allocate(flags);
@@ -884,7 +851,7 @@ pagebuf_lookup(
  */
 void
 pagebuf_readahead(
-	pb_target_t		*target,
+	xfs_buftarg_t		*target,
 	loff_t			ioff,
 	size_t			isize,
 	page_buf_flags_t	flags)
@@ -893,12 +860,12 @@ pagebuf_readahead(
 	pagebuf_get(target, ioff, isize, flags);
 }
 
-page_buf_t *
+xfs_buf_t *
 pagebuf_get_empty(
 	size_t			len,
-	pb_target_t		*target)
+	xfs_buftarg_t		*target)
 {
-	page_buf_t		*pb;
+	xfs_buf_t		*pb;
 
 	pb = pagebuf_allocate(0);
 	if (pb)
@@ -920,7 +887,7 @@ mem_to_page(
 
 int
 pagebuf_associate_memory(
-	page_buf_t		*pb,
+	xfs_buf_t		*pb,
 	void			*mem,
 	size_t			len)
 {
@@ -937,9 +904,9 @@ pagebuf_associate_memory(
 		page_count++;
 
 	/* Free any previous set of page pointers */
-	if (pb->pb_pages && (pb->pb_pages != pb->pb_page_array)) {
-		kfree(pb->pb_pages);
-	}
+	if (pb->pb_pages)
+		_pagebuf_free_pages(pb);
+
 	pb->pb_pages = NULL;
 	pb->pb_addr = mem;
 
@@ -969,55 +936,55 @@ pagebuf_associate_memory(
 	return 0;
 }
 
-page_buf_t *
+xfs_buf_t *
 pagebuf_get_no_daddr(
 	size_t			len,
-	pb_target_t		*target)
+	xfs_buftarg_t		*target)
 {
-	int			rval;
-	void			*rmem = NULL;
-	page_buf_flags_t	flags = PBF_FORCEIO;
-	page_buf_t		*pb;
-	size_t			tlen = 0;
+	size_t			malloc_len = len;
+	xfs_buf_t		*bp;
+	void			*data;
+	int			error;
 
 	if (unlikely(len > 0x20000))
-		return NULL;
-
-	pb = pagebuf_allocate(flags);
-	if (!pb)
-		return NULL;
+		goto fail;
 
-	_pagebuf_initialize(pb, target, 0, len, flags);
-
-	do {
-		if (tlen == 0) {
-			tlen = len; /* first time */
-		} else {
-			kfree(rmem); /* free the mem from the previous try */
-			tlen <<= 1; /* double the size and try again */
-		}
-		if ((rmem = kmalloc(tlen, GFP_KERNEL)) == 0) {
-			pagebuf_free(pb);
-			return NULL;
-		}
-	} while ((size_t)rmem != ((size_t)rmem & ~target->pbr_smask));
-
-	if ((rval = pagebuf_associate_memory(pb, rmem, len)) != 0) {
-		kfree(rmem);
-		pagebuf_free(pb);
-		return NULL;
-	}
-	/* otherwise pagebuf_free just ignores it */
-	pb->pb_flags |= (_PBF_MEM_ALLOCATED | _PBF_MEM_SLAB);
-	PB_CLEAR_OWNER(pb);
-	up(&pb->pb_sema);	/* Return unlocked pagebuf */
-
-	PB_TRACE(pb, "no_daddr", rmem);
-
-	return pb;
+	bp = pagebuf_allocate(0);
+	if (unlikely(bp == NULL))
+		goto fail;
+	_pagebuf_initialize(bp, target, 0, len, PBF_FORCEIO);
+
+ try_again:
+	data = kmem_alloc(malloc_len, KM_SLEEP);
+	if (unlikely(data == NULL))
+		goto fail_free_buf;
+
+	/* check whether alignment matches.. */
+	if ((__psunsigned_t)data !=
+	    ((__psunsigned_t)data & ~target->pbr_smask)) {
+		/* .. else double the size and try again */
+		kmem_free(data, malloc_len);
+		malloc_len <<= 1;
+		goto try_again;
+	}
+
+	error = pagebuf_associate_memory(bp, data, len);
+	if (error)
+		goto fail_free_mem;
+	bp->pb_flags |= _PBF_KMEM_ALLOC;
+
+	pagebuf_unlock(bp);
+
+	PB_TRACE(bp, "no_daddr", data);
+	return bp;
+ fail_free_mem:
+	kmem_free(data, malloc_len);
+ fail_free_buf:
+	pagebuf_free(bp);
+ fail:
+	return NULL;
 }
 
-
 /*
  *	pagebuf_hold
  *
@@ -1028,7 +995,7 @@ pagebuf_get_no_daddr(
  */
 void
 pagebuf_hold(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	atomic_inc(&pb->pb_hold);
 	PB_TRACE(pb, "hold", 0);
@@ -1042,7 +1009,7 @@ pagebuf_hold(
  */
 void
 pagebuf_rele(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	pb_hash_t		*hash = pb_hash(pb);
 
@@ -1071,7 +1038,7 @@ pagebuf_rele(
 		if (do_free) {
 			list_del_init(&pb->pb_hash_list);
 			spin_unlock(&hash->pb_hash_lock);
-			pagebuf_free(pb);
+			xfs_buf_free(pb);
 		} else {
 			spin_unlock(&hash->pb_hash_lock);
 		}
@@ -1101,7 +1068,7 @@ pagebuf_rele(
 int
 pagebuf_cond_lock(			/* lock buffer, if not locked	*/
 					/* returns -EBUSY if locked)	*/
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	int			locked;
 
@@ -1120,7 +1087,7 @@ pagebuf_cond_lock(			/* lock buffer, if 
  */
 int
 pagebuf_lock_value(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	return(atomic_read(&pb->pb_sema.count));
 }
@@ -1135,7 +1102,7 @@ pagebuf_lock_value(
  */
 int
 pagebuf_lock(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	PB_TRACE(pb, "lock", 0);
 	if (atomic_read(&pb->pb_io_remaining))
@@ -1155,7 +1122,7 @@ pagebuf_lock(
  */
 void
 pagebuf_unlock(				/* unlock buffer		*/
-	page_buf_t		*pb)	/* buffer to unlock		*/
+	xfs_buf_t		*pb)	/* buffer to unlock		*/
 {
 	PB_CLEAR_OWNER(pb);
 	up(&pb->pb_sema);
@@ -1183,7 +1150,7 @@ pagebuf_unlock(				/* unlock buffer		*/
  */
 void
 pagebuf_pin(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	atomic_inc(&pb->pb_pin_count);
 	PB_TRACE(pb, "pin", (long)pb->pb_pin_count.counter);
@@ -1198,7 +1165,7 @@ pagebuf_pin(
  */
 void
 pagebuf_unpin(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	if (atomic_dec_and_test(&pb->pb_pin_count)) {
 		wake_up_all(&pb->pb_waiters);
@@ -1208,7 +1175,7 @@ pagebuf_unpin(
 
 int
 pagebuf_ispin(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	return atomic_read(&pb->pb_pin_count);
 }
@@ -1222,7 +1189,7 @@ pagebuf_ispin(
  */
 static inline void
 _pagebuf_wait_unpin(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	DECLARE_WAITQUEUE	(wait, current);
 
@@ -1258,23 +1225,17 @@ void
 pagebuf_iodone_sched(
 	void			*v)
 {
-	page_buf_t		*pb = (page_buf_t *)v;
+	xfs_buf_t		*bp = (xfs_buf_t *)v;
 
-	if (pb->pb_iodone) {
-		(*(pb->pb_iodone)) (pb);
-		return;
-	}
-
-	if (pb->pb_flags & PBF_ASYNC) {
-		if (!pb->pb_relse)
-			pagebuf_unlock(pb);
-		pagebuf_rele(pb);
-	}
+	if (bp->pb_iodone)
+		(*(bp->pb_iodone))(bp);
+	else if (bp->pb_flags & PBF_ASYNC)
+		xfs_buf_relse(bp);
 }
 
 void
 pagebuf_iodone(
-	page_buf_t		*pb,
+	xfs_buf_t		*pb,
 	int			dataio,
 	int			schedule)
 {
@@ -1312,10 +1273,11 @@ pagebuf_iodone(
  */
 void
 pagebuf_ioerror(			/* mark/clear buffer error flag */
-	page_buf_t		*pb,	/* buffer to mark		*/
-	unsigned int		error)	/* error to store (0 if none)	*/
+	xfs_buf_t		*pb,	/* buffer to mark		*/
+	int			error)	/* error to store (0 if none)	*/
 {
-	pb->pb_error = error;
+	ASSERT(error >= 0 && error <= 0xffff);
+	pb->pb_error = (unsigned short)error;
 	PB_TRACE(pb, "ioerror", (unsigned long)error);
 }
 
@@ -1333,7 +1295,7 @@ pagebuf_ioerror(			/* mark/clear buffer 
  */
 int
 pagebuf_iostart(			/* start I/O on a buffer	  */
-	page_buf_t		*pb,	/* buffer to start		  */
+	xfs_buf_t		*pb,	/* buffer to start		  */
 	page_buf_flags_t	flags)	/* PBF_LOCK, PBF_ASYNC, PBF_READ, */
 					/* PBF_WRITE, PBF_DELWRI,	  */
 					/* PBF_DONT_BLOCK		  */
@@ -1350,11 +1312,11 @@ pagebuf_iostart(			/* start I/O on a buf
 	}
 
 	pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC | PBF_DELWRI | \
-			PBF_READ_AHEAD | PBF_RUN_QUEUES);
+			PBF_READ_AHEAD | _PBF_RUN_QUEUES);
 	pb->pb_flags |= flags & (PBF_READ | PBF_WRITE | PBF_ASYNC | \
-			PBF_READ_AHEAD | PBF_RUN_QUEUES);
+			PBF_READ_AHEAD | _PBF_RUN_QUEUES);
 
-	BUG_ON(pb->pb_bn == PAGE_BUF_DADDR_NULL);
+	BUG_ON(pb->pb_bn == XFS_BUF_DADDR_NULL);
 
 	/* For writes allow an alternate strategy routine to precede
 	 * the actual I/O request (which may not be issued at all in
@@ -1381,19 +1343,19 @@ pagebuf_iostart(			/* start I/O on a buf
 
 STATIC __inline__ int
 _pagebuf_iolocked(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	ASSERT(pb->pb_flags & (PBF_READ|PBF_WRITE));
 	if (pb->pb_target->pbr_bsize < PAGE_CACHE_SIZE)
 		return pb->pb_locked;
 	if (pb->pb_flags & PBF_READ)
 		return pb->pb_locked;
-	return (pb->pb_flags & _PBF_PAGECACHE);
+	return (pb->pb_flags & _PBF_PAGE_CACHE);
 }
 
 STATIC void
 _pagebuf_iodone(
-	page_buf_t		*pb,
+	xfs_buf_t		*pb,
 	int			schedule)
 {
 	int			i;
@@ -1415,7 +1377,7 @@ _end_io_pagebuf(
 	int			fullpage)
 {
 	struct page		*page = bh->b_page;
-	page_buf_t		*pb = (page_buf_t *)bh->b_private;
+	xfs_buf_t		*pb = (xfs_buf_t *)bh->b_private;
 
 	mark_buffer_uptodate(bh, uptodate);
 	put_bh(bh);
@@ -1470,6 +1432,75 @@ _pagebuf_end_io_partial_pages(
 	_end_io_pagebuf(bh, uptodate, 0);
 }
 
+/*
+ *	Handling of buftargs.
+ */
+
+void
+xfs_free_buftarg(
+	xfs_buftarg_t		*btp,
+	int			external)
+{
+	xfs_flush_buftarg(btp, 1);
+	if (external)
+		xfs_blkdev_put(btp->pbr_bdev);
+	kmem_free(btp, sizeof(*btp));
+}
+
+void
+xfs_incore_relse(
+	xfs_buftarg_t		*btp,
+	int			delwri_only,
+	int			wait)
+{
+	destroy_buffers(btp->pbr_kdev);
+	truncate_inode_pages(btp->pbr_mapping, 0LL);
+}
+
+void
+xfs_setsize_buftarg(
+	xfs_buftarg_t		*btp,
+	unsigned int		blocksize,
+	unsigned int		sectorsize)
+{
+	btp->pbr_bsize = blocksize;
+	btp->pbr_sshift = ffs(sectorsize) - 1;
+	btp->pbr_smask = sectorsize - 1;
+
+	if (set_blocksize(btp->pbr_kdev, sectorsize)) {
+		printk(KERN_WARNING
+			"XFS: Cannot set_blocksize to %u on device 0x%x\n",
+			sectorsize, kdev_t_to_nr(btp->pbr_kdev));
+	}
+}
+
+xfs_buftarg_t *
+xfs_alloc_buftarg(
+	struct block_device	*bdev)
+{
+	xfs_buftarg_t		*btp;
+
+	btp = kmem_zalloc(sizeof(*btp), KM_SLEEP);
+
+	btp->pbr_dev =  bdev->bd_dev;
+	btp->pbr_kdev = to_kdev_t(btp->pbr_dev);
+	btp->pbr_bdev = bdev;
+	btp->pbr_mapping = bdev->bd_inode->i_mapping;
+	xfs_setsize_buftarg(btp, PAGE_CACHE_SIZE,
+			    get_hardsect_size(btp->pbr_kdev));
+
+	switch (MAJOR(btp->pbr_dev)) {
+	case MD_MAJOR:
+	case EVMS_MAJOR:
+		btp->pbr_flags = PBR_ALIGNED_ONLY;
+		break;
+	case LVM_BLK_MAJOR:
+		btp->pbr_flags = PBR_SECTOR_ONLY;
+		break;
+	}
+
+	return btp;
+}
 
 /*
  * Initiate I/O on part of a page we are interested in
@@ -1477,9 +1508,9 @@ _pagebuf_end_io_partial_pages(
 STATIC int
 _pagebuf_page_io(
 	struct page		*page,	/* Page structure we are dealing with */
-	pb_target_t		*pbr,	/* device parameters (bsz, ssz, dev) */
-	page_buf_t		*pb,	/* pagebuf holding it, can be NULL */
-	page_buf_daddr_t	bn,	/* starting block number */
+	xfs_buftarg_t		*pbr,	/* device parameters (bsz, ssz, dev) */
+	xfs_buf_t		*pb,	/* pagebuf holding it, can be NULL */
+	xfs_daddr_t		bn,	/* starting block number */
 	size_t			pg_offset,	/* starting offset in page */
 	size_t			pg_length,	/* count of data to process */
 	int			rw,	/* read/write operation */
@@ -1630,15 +1661,15 @@ request:
 
 STATIC void
 _pagebuf_page_apply(
-	page_buf_t		*pb,
+	xfs_buf_t		*pb,
 	loff_t			offset,
 	struct page		*page,
 	size_t			pg_offset,
 	size_t			pg_length,
 	int			last)
 {
-	page_buf_daddr_t	bn = pb->pb_bn;
-	pb_target_t		*pbr = pb->pb_target;
+	xfs_daddr_t		bn = pb->pb_bn;
+	xfs_buftarg_t		*pbr = pb->pb_target;
 	loff_t			pb_offset;
 	int			status, locking;
 
@@ -1674,26 +1705,11 @@ _pagebuf_page_apply(
 }
 
 /*
- *	pagebuf_iorequest
- *
- *	pagebuf_iorequest is the core I/O request routine.
- *	It assumes that the buffer is well-formed and
- *	mapped and ready for physical I/O, unlike
- *	pagebuf_iostart() and pagebuf_iophysio().  Those
- *	routines call the pagebuf_ioinitiate routine to start I/O,
- *	if it is present, or else call pagebuf_iorequest()
- *	directly if the pagebuf_ioinitiate routine is not present.
- *
- *	This function will be responsible for ensuring access to the
- *	pages is restricted whilst I/O is in progress - for locking
- *	pagebufs the pagebuf lock is the mediator, for non-locking
- *	pagebufs the pages will be locked. In the locking case we
- *	need to use the pagebuf lock as multiple meta-data buffers
- *	will reference the same page.
+ *	pagebuf_iorequest -- the core I/O request routine.
  */
 int
 pagebuf_iorequest(			/* start real I/O		*/
-	page_buf_t		*pb)	/* buffer to convey to device	*/
+	xfs_buf_t		*pb)	/* buffer to convey to device	*/
 {
 	PB_TRACE(pb, "iorequest", 0);
 
@@ -1729,7 +1745,7 @@ pagebuf_iorequest(			/* start real I/O		
  */
 int
 pagebuf_iowait(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	PB_TRACE(pb, "iowait", 0);
 	if (atomic_read(&pb->pb_io_remaining))
@@ -1741,28 +1757,9 @@ pagebuf_iowait(
 	return pb->pb_error;
 }
 
-STATIC void *
-pagebuf_mapout_locked(
-	page_buf_t		*pb)
-{
-	void			*old_addr = NULL;
-
-	if (pb->pb_flags & PBF_MAPPED) {
-		if (pb->pb_flags & _PBF_ADDR_ALLOCATED)
-			old_addr = pb->pb_addr - pb->pb_offset;
-		pb->pb_addr = NULL;
-		pb->pb_flags &= ~(PBF_MAPPED | _PBF_ADDR_ALLOCATED);
-	}
-
-	return old_addr;	/* Caller must free the address space,
-				 * we are under a spin lock, probably
-				 * not safe to do vfree here
-				 */
-}
-
 caddr_t
 pagebuf_offset(
-	page_buf_t		*pb,
+	xfs_buf_t		*pb,
 	size_t			offset)
 {
 	struct page		*page;
@@ -1780,7 +1777,7 @@ pagebuf_offset(
  */
 void
 pagebuf_iomove(
-	page_buf_t		*pb,	/* buffer to process		*/
+	xfs_buf_t		*pb,	/* buffer to process		*/
 	size_t			boff,	/* starting buffer offset	*/
 	size_t			bsize,	/* length to copy		*/
 	caddr_t			data,	/* data address			*/
@@ -1817,11 +1814,11 @@ pagebuf_iomove(
 /*
  *	_pagebuf_ioapply
  *
- *	Applies _pagebuf_page_apply to each page of the page_buf_t.
+ *	Applies _pagebuf_page_apply to each page of the xfs_buf_t.
  */
 STATIC void
 _pagebuf_ioapply(			/* apply function to pages	*/
-	page_buf_t		*pb)	/* buffer to examine		*/
+	xfs_buf_t		*pb)	/* buffer to examine		*/
 {
 	int			index;
 	loff_t			buffer_offset = pb->pb_file_offset;
@@ -1866,8 +1863,8 @@ _pagebuf_ioapply(			/* apply function to
 	 * Run the block device task queue here, while we have
 	 * a hold on the pagebuf (important to have that hold).
 	 */
-	if (pb->pb_flags & PBF_RUN_QUEUES) {
-		pb->pb_flags &= ~PBF_RUN_QUEUES;
+	if (pb->pb_flags & _PBF_RUN_QUEUES) {
+		pb->pb_flags &= ~_PBF_RUN_QUEUES;
 		if (atomic_read(&pb->pb_io_remaining) > 1)
 			blk_run_queues();
 	}
@@ -1875,7 +1872,7 @@ _pagebuf_ioapply(			/* apply function to
 
 
 /*
- * Pagebuf delayed write buffer handling
+ * Delayed write buffer list handling
  */
 
 STATIC LIST_HEAD(pbd_delwrite_queue);
@@ -1883,21 +1880,22 @@ STATIC spinlock_t pbd_delwrite_lock = SP
 
 STATIC void
 pagebuf_delwri_queue(
-	page_buf_t		*pb,
+	xfs_buf_t		*pb,
 	int			unlock)
 {
 	PB_TRACE(pb, "delwri_q", (long)unlock);
+	ASSERT(pb->pb_flags & PBF_DELWRI);
+
 	spin_lock(&pbd_delwrite_lock);
 	/* If already in the queue, dequeue and place at tail */
 	if (!list_empty(&pb->pb_list)) {
-		if (unlock) {
+		if (unlock)
 			atomic_dec(&pb->pb_hold);
-		}
 		list_del(&pb->pb_list);
 	}
 
 	list_add_tail(&pb->pb_list, &pbd_delwrite_queue);
-	pb->pb_flushtime = jiffies + xfs_age_buffer;
+	pb->pb_queuetime = jiffies;
 	spin_unlock(&pbd_delwrite_lock);
 
 	if (unlock)
@@ -1906,9 +1904,11 @@ pagebuf_delwri_queue(
 
 void
 pagebuf_delwri_dequeue(
-	page_buf_t		*pb)
+	xfs_buf_t		*pb)
 {
 	PB_TRACE(pb, "delwri_uq", 0);
+	ASSERT(pb->pb_flags & PBF_DELWRI);
+
 	spin_lock(&pbd_delwrite_lock);
 	list_del_init(&pb->pb_list);
 	pb->pb_flags &= ~PBF_DELWRI;
@@ -2027,9 +2027,9 @@ STATIC int
 pagebuf_daemon(
 	void			*data)
 {
+	struct list_head	tmp;
+	xfs_buf_t		*pb, *n;
 	int			count;
-	page_buf_t		*pb;
-	struct list_head	*curr, *next, tmp;
 
 	/*  Set up the thread  */
 	daemonize();
@@ -2053,18 +2053,17 @@ pagebuf_daemon(
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(xfs_flush_interval);
 
-		spin_lock(&pbd_delwrite_lock);
-
 		count = 0;
-		list_for_each_safe(curr, next, &pbd_delwrite_queue) {
-			pb = list_entry(curr, page_buf_t, pb_list);
-
+		spin_lock(&pbd_delwrite_lock);
+		list_for_each_entry_safe(pb, n, &pbd_delwrite_queue, pb_list) {
 			PB_TRACE(pb, "walkq1", (long)pagebuf_ispin(pb));
+			ASSERT(pb->pb_flags & PBF_DELWRI);
 
-			if ((pb->pb_flags & PBF_DELWRI) &&
-			     !pagebuf_ispin(pb) && !pagebuf_cond_lock(pb)) {
+			if (!pagebuf_ispin(pb) && !pagebuf_cond_lock(pb)) {
 				if (!force_flush &&
-				    time_before(jiffies, pb->pb_flushtime)) {
+				    time_before(jiffies,
+						pb->pb_queuetime +
+						xfs_age_buffer)) {
 					pagebuf_unlock(pb);
 					break;
 				}
@@ -2075,12 +2074,11 @@ pagebuf_daemon(
 				count++;
 			}
 		}
-
 		spin_unlock(&pbd_delwrite_lock);
+
 		while (!list_empty(&tmp)) {
-			pb = list_entry(tmp.next, page_buf_t, pb_list);
+			pb = list_entry(tmp.next, xfs_buf_t, pb_list);
 			list_del_init(&pb->pb_list);
-
 			pagebuf_iostrategy(pb);
 		}
 
@@ -2095,35 +2093,32 @@ pagebuf_daemon(
 	complete_and_exit(&pagebuf_daemon_done, 0);
 }
 
-void
-pagebuf_delwri_flush(
-	pb_target_t		*target,
-	u_long			flags,
-	int			*pinptr)
+/*
+ * Go through all incore buffers, and release buffers if they belong to
+ * the given device. This is used in filesystem error handling to
+ * preserve the consistency of its metadata.
+ */
+int
+xfs_flush_buftarg(
+	xfs_buftarg_t		*target,
+	int			wait)
 {
-	page_buf_t		*pb;
-	struct list_head	*curr, *next, tmp;
+	struct list_head	tmp;
+	xfs_buf_t		*pb, *n;
 	int			pincount = 0;
 	int			flush_cnt = 0;
 
 	pagebuf_runall_queues(pagebuf_dataiodone_tq);
 	pagebuf_runall_queues(pagebuf_logiodone_tq);
 
-	spin_lock(&pbd_delwrite_lock);
 	INIT_LIST_HEAD(&tmp);
+	spin_lock(&pbd_delwrite_lock);
+	list_for_each_entry_safe(pb, n, &pbd_delwrite_queue, pb_list) {
 
-	list_for_each_safe(curr, next, &pbd_delwrite_queue) {
-		pb = list_entry(curr, page_buf_t, pb_list);
-
-		/*
-		 * Skip other targets, markers and in progress buffers
-		 */
-
-		if ((pb->pb_flags == 0) || (pb->pb_target != target) ||
-		    !(pb->pb_flags & PBF_DELWRI)) {
+		if (pb->pb_target != target)
 			continue;
-		}
 
+		ASSERT(pb->pb_flags & PBF_DELWRI);
 		PB_TRACE(pb, "walkq2", (long)pagebuf_ispin(pb));
 		if (pagebuf_ispin(pb)) {
 			pincount++;
@@ -2133,20 +2128,18 @@ pagebuf_delwri_flush(
 		pb->pb_flags &= ~PBF_DELWRI;
 		pb->pb_flags |= PBF_WRITE;
 		list_move(&pb->pb_list, &tmp);
-
 	}
-	
-	/* ok found all the items that can be worked on 
-	 * drop the lock and process the private list */
 	spin_unlock(&pbd_delwrite_lock);
-	
-	list_for_each_safe(curr, next, &tmp) {
-		pb = list_entry(curr, page_buf_t, pb_list);
-		
-		if (flags & PBDF_WAIT)
+
+	/*
+	 * Dropped the delayed write list lock, now walk the temporary list
+	 */
+	list_for_each_entry_safe(pb, n, &tmp, pb_list) {
+
+		if (wait)
 			pb->pb_flags &= ~PBF_ASYNC;
 		else
-			list_del_init(curr);
+			list_del_init(&pb->pb_list);
 
 		pagebuf_lock(pb);
 		pagebuf_iostrategy(pb);
@@ -2159,22 +2152,19 @@ pagebuf_delwri_flush(
 
 	blk_run_queues();
 
-	/* must run list the second time even if PBDF_WAIT isn't
-	 * to reset all the pb_list pointers 
+	/*
+	 * Remaining list items must be flushed before returning
 	 */
 	while (!list_empty(&tmp)) {
-		pb = list_entry(tmp.next, page_buf_t, pb_list);
+		pb = list_entry(tmp.next, xfs_buf_t, pb_list);
 
 		list_del_init(&pb->pb_list);
 		
-		pagebuf_iowait(pb);
-		if (!pb->pb_relse)
-			pagebuf_unlock(pb);
-		pagebuf_rele(pb);
+		xfs_iowait(pb);
+		xfs_buf_relse(pb);
 	}
 
-	if (pinptr)
-		*pinptr = pincount;
+	return pincount;
 }
 
 STATIC int
@@ -2258,7 +2248,7 @@ pagebuf_init(void)
 {
 	int			i;
 
-	pagebuf_cache = kmem_cache_create("page_buf_t", sizeof(page_buf_t), 0,
+	pagebuf_cache = kmem_cache_create("xfs_buf_t", sizeof(xfs_buf_t), 0,
 			SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if (pagebuf_cache == NULL) {
 		printk("pagebuf: couldn't init pagebuf cache\n");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/xfs_buf.h linux-2.4.27-pre3/fs/xfs/linux/xfs_buf.h
--- linux-2.4.26/fs/xfs/linux/xfs_buf.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/xfs_buf.h	2004-05-18 16:54:43.000000000 +0000
@@ -61,10 +61,7 @@
  *	Base types
  */
 
-/* daddr must be signed since -1 is used for bmaps that are not yet allocated */
-typedef loff_t page_buf_daddr_t;
-
-#define PAGE_BUF_DADDR_NULL ((page_buf_daddr_t) (-1LL))
+#define XFS_BUF_DADDR_NULL ((xfs_daddr_t) (-1LL))
 
 #define page_buf_ctob(pp)	((pp) * PAGE_CACHE_SIZE)
 #define page_buf_btoc(dd)	(((dd) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
@@ -86,29 +83,24 @@ typedef enum page_buf_flags_e {		/* pb_f
 	PBF_ASYNC = (1 << 4),   /* initiator will not wait for completion  */
 	PBF_NONE = (1 << 5),    /* buffer not read at all                  */
 	PBF_DELWRI = (1 << 6),  /* buffer has dirty pages                  */
-	PBF_STALE = (1 << 10),	/* buffer has been staled, do not find it  */
-	PBF_FS_MANAGED = (1 << 11), /* filesystem controls freeing memory  */
-	PBF_FS_DATAIOD = (1 << 12), /* schedule IO completion on fs datad  */
+	PBF_STALE = (1 << 7),	/* buffer has been staled, do not find it  */
+	PBF_FS_MANAGED = (1 << 8),  /* filesystem controls freeing memory  */
+	PBF_FS_DATAIOD = (1 << 9),  /* schedule IO completion on fs datad  */
+	PBF_FORCEIO = (1 << 10),    /* ignore any cache state		   */
+	PBF_FLUSH = (1 << 11),	    /* flush disk write cache		   */
+	PBF_READ_AHEAD = (1 << 12), /* asynchronous read-ahead		   */
+	PBF_DIRECTIO = (1 << 13),   /* used for a direct IO mapping	   */
 
 	/* flags used only as arguments to access routines */
-	PBF_LOCK = (1 << 13),	/* lock requested			   */
-	PBF_TRYLOCK = (1 << 14), /* lock requested, but do not wait	   */
-	PBF_DONT_BLOCK = (1 << 15), /* do not block in current thread	   */
+	PBF_LOCK = (1 << 14),       /* lock requested			   */
+	PBF_TRYLOCK = (1 << 15),    /* lock requested, but do not wait	   */
+	PBF_DONT_BLOCK = (1 << 16), /* do not block in current thread	   */
 
 	/* flags used only internally */
-	_PBF_PAGECACHE = (1 << 16),	/* backed by pagecache		   */
-	_PBF_PRIVATE_BH = (1 << 17), /* do not use public buffer heads	   */
-	_PBF_ALL_PAGES_MAPPED = (1 << 18), /* all pages in range mapped	   */
-	_PBF_ADDR_ALLOCATED = (1 << 19), /* pb_addr space was allocated	   */
-	_PBF_MEM_ALLOCATED = (1 << 20), /* underlying pages are allocated  */
-	_PBF_MEM_SLAB = (1 << 21), /* underlying pages are slab allocated  */
-
-	PBF_FORCEIO = (1 << 22), /* ignore any cache state		   */
-	PBF_FLUSH = (1 << 23),	/* flush disk write cache		   */
-	PBF_READ_AHEAD = (1 << 24), /* asynchronous read-ahead		   */
-	PBF_RUN_QUEUES = (1 << 25), /* run block device task queue	   */
-	PBF_DIRECTIO = (1 << 26), /* used for a direct IO mapping	   */
-
+	_PBF_PAGE_CACHE = (1 << 17),/* backed by pagecache		   */
+	_PBF_KMEM_ALLOC = (1 << 18),/* backed by kmem_alloc()		   */
+	_PBF_RUN_QUEUES = (1 << 19),/* run block device task queue	   */
+	_PBF_PRIVATE_BH = (1 << 20),/* do not use public buffer heads	   */
 } page_buf_flags_t;
 
 #define PBF_UPDATE (PBF_READ | PBF_WRITE)
@@ -118,7 +110,7 @@ typedef enum page_buf_flags_e {		/* pb_f
 #define PBR_SECTOR_ONLY	1	/* only use sector size buffer heads */
 #define PBR_ALIGNED_ONLY 2	/* only use aligned I/O */
 
-typedef struct pb_target {
+typedef struct xfs_buftarg {
 	int			pbr_flags;
 	dev_t			pbr_dev;
 	kdev_t			pbr_kdev;
@@ -127,44 +119,42 @@ typedef struct pb_target {
 	unsigned int		pbr_bsize;
 	unsigned int		pbr_sshift;
 	size_t			pbr_smask;
-} pb_target_t;
+} xfs_buftarg_t;
 
 /*
- *	page_buf_t:  Buffer structure for page cache-based buffers
+ *	xfs_buf_t:  Buffer structure for page cache-based buffers
  *
  * This buffer structure is used by the page cache buffer management routines
- * to refer to an assembly of pages forming a logical buffer.  The actual
- * I/O is performed with buffer_head or bio structures, as required by drivers,
- * for drivers which do not understand this structure.  The buffer structure is
- * used on temporary basis only, and discarded when released.
- *
- * The real data storage is recorded in the page cache.  Metadata is
- * hashed to the inode for the block device on which the file system resides.
- * File data is hashed to the inode for the file.  Pages which are only
- * partially filled with data have bits set in their block_map entry
- * to indicate which disk blocks in the page are not valid.
+ * to refer to an assembly of pages forming a logical buffer.  The actual I/O
+ * is performed with buffer_head structures, as required by drivers.
+ * 
+ * The buffer structure is used on temporary basis only, and discarded when
+ * released.  The real data storage is recorded in the page cache.  Metadata is
+ * hashed to the block device on which the file system resides.
  */
 
-struct page_buf_s;
-typedef void (*page_buf_iodone_t)(struct page_buf_s *);
-			/* call-back function on I/O completion */
-typedef void (*page_buf_relse_t)(struct page_buf_s *);
-			/* call-back function on I/O completion */
-typedef int (*page_buf_bdstrat_t)(struct page_buf_s *);
+struct xfs_buf;
+
+/* call-back function on I/O completion */
+typedef void (*page_buf_iodone_t)(struct xfs_buf *);
+/* call-back function on I/O completion */
+typedef void (*page_buf_relse_t)(struct xfs_buf *);
+/* pre-write function */
+typedef int (*page_buf_bdstrat_t)(struct xfs_buf *);
 
 #define PB_PAGES	4
 
-typedef struct page_buf_s {
+typedef struct xfs_buf {
 	struct semaphore	pb_sema;	/* semaphore for lockables  */
-	unsigned long		pb_flushtime;	/* time to flush pagebuf    */
+	unsigned long		pb_queuetime;	/* time buffer was queued   */
 	atomic_t		pb_pin_count;	/* pin count		    */
 	wait_queue_head_t	pb_waiters;	/* unpin waiters	    */
 	struct list_head	pb_list;
 	page_buf_flags_t	pb_flags;	/* status flags */
 	struct list_head	pb_hash_list;
-	struct pb_target	*pb_target;	/* logical object */
+	xfs_buftarg_t		*pb_target;	/* logical object */
 	atomic_t		pb_hold;	/* reference count */
-	page_buf_daddr_t	pb_bn;		/* block number for I/O */
+	xfs_daddr_t		pb_bn;		/* block number for I/O */
 	loff_t			pb_file_offset;	/* offset in file */
 	size_t			pb_buffer_length; /* size of buffer in bytes */
 	size_t			pb_count_desired; /* desired transfer size */
@@ -188,52 +178,52 @@ typedef struct page_buf_s {
 #ifdef PAGEBUF_LOCK_TRACKING
 	int			pb_last_holder;
 #endif
-} page_buf_t;
+} xfs_buf_t;
 
 
 /* Finding and Reading Buffers */
 
-extern page_buf_t *pagebuf_find(	/* find buffer for block if	*/
+extern xfs_buf_t *pagebuf_find(	/* find buffer for block if	*/
 					/* the block is in memory	*/
-		struct pb_target *,	/* inode for block		*/
+		xfs_buftarg_t *,	/* inode for block		*/
 		loff_t,			/* starting offset of range	*/
 		size_t,			/* length of range		*/
 		page_buf_flags_t);	/* PBF_LOCK			*/
 
-extern page_buf_t *pagebuf_get(		/* allocate a buffer		*/
-		struct pb_target *,	/* inode for buffer		*/
+extern xfs_buf_t *pagebuf_get(		/* allocate a buffer		*/
+		xfs_buftarg_t *,	/* inode for buffer		*/
 		loff_t,			/* starting offset of range     */
 		size_t,			/* length of range              */
 		page_buf_flags_t);	/* PBF_LOCK, PBF_READ,		*/
 					/* PBF_ASYNC			*/
 
-extern page_buf_t *pagebuf_lookup(
-		struct pb_target *,
+extern xfs_buf_t *pagebuf_lookup(
+		xfs_buftarg_t *,
 		loff_t,			/* starting offset of range	*/
 		size_t,			/* length of range		*/
 		page_buf_flags_t);	/* PBF_READ, PBF_WRITE,		*/
 					/* PBF_FORCEIO, 		*/
 
-extern page_buf_t *pagebuf_get_empty(	/* allocate pagebuf struct with	*/
+extern xfs_buf_t *pagebuf_get_empty(	/* allocate pagebuf struct with	*/
 					/*  no memory or disk address	*/
 		size_t len,
-		struct pb_target *);	/* mount point "fake" inode	*/
+		xfs_buftarg_t *);	/* mount point "fake" inode	*/
 
-extern page_buf_t *pagebuf_get_no_daddr(/* allocate pagebuf struct	*/
+extern xfs_buf_t *pagebuf_get_no_daddr(/* allocate pagebuf struct	*/
 					/* without disk address		*/
 		size_t len,
-		struct pb_target *);	/* mount point "fake" inode	*/
+		xfs_buftarg_t *);	/* mount point "fake" inode	*/
 
 extern int pagebuf_associate_memory(
-		page_buf_t *,
+		xfs_buf_t *,
 		void *,
 		size_t);
 
 extern void pagebuf_hold(		/* increment reference count	*/
-		page_buf_t *);		/* buffer to hold		*/
+		xfs_buf_t *);		/* buffer to hold		*/
 
 extern void pagebuf_readahead(		/* read ahead into cache	*/
-		struct pb_target  *,	/* target for buffer (or NULL)	*/
+		xfs_buftarg_t  *,	/* target for buffer (or NULL)	*/
 		loff_t,			/* starting offset of range     */
 		size_t,			/* length of range              */
 		page_buf_flags_t);	/* additional read flags	*/
@@ -241,63 +231,63 @@ extern void pagebuf_readahead(		/* read 
 /* Releasing Buffers */
 
 extern void pagebuf_free(		/* deallocate a buffer		*/
-		page_buf_t *);		/* buffer to deallocate		*/
+		xfs_buf_t *);		/* buffer to deallocate		*/
 
 extern void pagebuf_rele(		/* release hold on a buffer	*/
-		page_buf_t *);		/* buffer to release		*/
+		xfs_buf_t *);		/* buffer to release		*/
 
 /* Locking and Unlocking Buffers */
 
 extern int pagebuf_cond_lock(		/* lock buffer, if not locked	*/
 					/* (returns -EBUSY if locked)	*/
-		page_buf_t *);		/* buffer to lock		*/
+		xfs_buf_t *);		/* buffer to lock		*/
 
 extern int pagebuf_lock_value(		/* return count on lock		*/
-		page_buf_t *);          /* buffer to check              */
+		xfs_buf_t *);          /* buffer to check              */
 
 extern int pagebuf_lock(		/* lock buffer                  */
-		page_buf_t *);          /* buffer to lock               */
+		xfs_buf_t *);          /* buffer to lock               */
 
 extern void pagebuf_unlock(		/* unlock buffer		*/
-		page_buf_t *);		/* buffer to unlock		*/
+		xfs_buf_t *);		/* buffer to unlock		*/
 
 /* Buffer Read and Write Routines */
 
 extern void pagebuf_iodone(		/* mark buffer I/O complete	*/
-		page_buf_t *,		/* buffer to mark		*/
+		xfs_buf_t *,		/* buffer to mark		*/
 		int,			/* use data/log helper thread.	*/
 		int);			/* run completion locally, or in
 					 * a helper thread.		*/
 
 extern void pagebuf_ioerror(		/* mark buffer in error	(or not) */
-		page_buf_t *,		/* buffer to mark		*/
-		unsigned int);		/* error to store (0 if none)	*/
+		xfs_buf_t *,		/* buffer to mark		*/
+		int);			/* error to store (0 if none)	*/
 
 extern int pagebuf_iostart(		/* start I/O on a buffer	*/
-		page_buf_t *,		/* buffer to start		*/
+		xfs_buf_t *,		/* buffer to start		*/
 		page_buf_flags_t);	/* PBF_LOCK, PBF_ASYNC,		*/
 					/* PBF_READ, PBF_WRITE,		*/
 					/* PBF_DELWRI			*/
 
 extern int pagebuf_iorequest(		/* start real I/O		*/
-		page_buf_t *);		/* buffer to convey to device	*/
+		xfs_buf_t *);		/* buffer to convey to device	*/
 
 extern int pagebuf_iowait(		/* wait for buffer I/O done	*/
-		page_buf_t *);		/* buffer to wait on		*/
+		xfs_buf_t *);		/* buffer to wait on		*/
 
 extern void pagebuf_iomove(		/* move data in/out of pagebuf	*/
-		page_buf_t *,		/* buffer to manipulate		*/
+		xfs_buf_t *,		/* buffer to manipulate		*/
 		size_t,			/* starting buffer offset	*/
 		size_t,			/* length in buffer		*/
 		caddr_t,		/* data pointer			*/
 		page_buf_rw_t);		/* direction			*/
 
-static inline int pagebuf_iostrategy(page_buf_t *pb)
+static inline int pagebuf_iostrategy(xfs_buf_t *pb)
 {
 	return pb->pb_strat ? pb->pb_strat(pb) : pagebuf_iorequest(pb);
 }
 
-static inline int pagebuf_geterror(page_buf_t *pb)
+static inline int pagebuf_geterror(xfs_buf_t *pb)
 {
 	return pb ? pb->pb_error : ENOMEM;
 }
@@ -305,30 +295,23 @@ static inline int pagebuf_geterror(page_
 /* Buffer Utility Routines */
 
 extern caddr_t pagebuf_offset(		/* pointer at offset in buffer	*/
-		page_buf_t *,		/* buffer to offset into	*/
+		xfs_buf_t *,		/* buffer to offset into	*/
 		size_t);		/* offset			*/
 
 /* Pinning Buffer Storage in Memory */
 
 extern void pagebuf_pin(		/* pin buffer in memory		*/
-		page_buf_t *);		/* buffer to pin		*/
+		xfs_buf_t *);		/* buffer to pin		*/
 
 extern void pagebuf_unpin(		/* unpin buffered data		*/
-		page_buf_t *);		/* buffer to unpin		*/
+		xfs_buf_t *);		/* buffer to unpin		*/
 
 extern int pagebuf_ispin(		/* check if buffer is pinned	*/
-		page_buf_t *);		/* buffer to check		*/
+		xfs_buf_t *);		/* buffer to check		*/
 
 /* Delayed Write Buffer Routines */
 
-#define PBDF_WAIT    0x01
-extern void pagebuf_delwri_flush(
-		pb_target_t *,
-		unsigned long,
-		int *);
-
-extern void pagebuf_delwri_dequeue(
-		page_buf_t *);
+extern void pagebuf_delwri_dequeue(xfs_buf_t *);
 
 /* Buffer Daemon Setup Routines */
 
@@ -339,7 +322,7 @@ extern void pagebuf_terminate(void);
 #ifdef PAGEBUF_TRACE
 extern ktrace_t *pagebuf_trace_buf;
 extern void pagebuf_trace(
-		page_buf_t *,		/* buffer being traced		*/
+		xfs_buf_t *,		/* buffer being traced		*/
 		char *,			/* description of operation	*/
 		void *,			/* arbitrary diagnostic value	*/
 		void *);		/* return address		*/
@@ -424,7 +407,7 @@ BUFFER_FNS(Delay, delay)
 #define XFS_BUF_MANAGE		PBF_FS_MANAGED
 #define XFS_BUF_UNMANAGE(x)	((x)->pb_flags &= ~PBF_FS_MANAGED)
 
-static inline void xfs_buf_undelay(page_buf_t *pb)
+static inline void xfs_buf_undelay(xfs_buf_t *pb)
 {
 	if (pb->pb_flags & PBF_DELWRI) {
 		if (pb->pb_list.next != &pb->pb_list) {
@@ -478,12 +461,6 @@ static inline void xfs_buf_undelay(page_
 
 #define XFS_BUF_BP_ISMAPPED(bp)	 1
 
-typedef struct page_buf_s xfs_buf_t;
-#define xfs_buf page_buf_s
-
-typedef struct pb_target xfs_buftarg_t;
-#define xfs_buftarg pb_target
-
 #define XFS_BUF_DATAIO(x)	((x)->pb_flags |= PBF_FS_DATAIOD)
 #define XFS_BUF_UNDATAIO(x)	((x)->pb_flags &= ~PBF_FS_DATAIOD)
 
@@ -516,7 +493,7 @@ typedef struct pb_target xfs_buftarg_t;
 
 #define XFS_BUF_PTR(bp)		(xfs_caddr_t)((bp)->pb_addr)
 
-extern inline xfs_caddr_t xfs_buf_offset(page_buf_t *bp, size_t offset)
+extern inline xfs_caddr_t xfs_buf_offset(xfs_buf_t *bp, size_t offset)
 {
 	if (bp->pb_flags & PBF_MAPPED)
 		return XFS_BUF_PTR(bp) + offset;
@@ -527,7 +504,7 @@ extern inline xfs_caddr_t xfs_buf_offset
 				pagebuf_associate_memory(bp, val, count)
 #define XFS_BUF_ADDR(bp)	((bp)->pb_bn)
 #define XFS_BUF_SET_ADDR(bp, blk)		\
-			((bp)->pb_bn = (page_buf_daddr_t)(blk))
+			((bp)->pb_bn = (xfs_daddr_t)(blk))
 #define XFS_BUF_OFFSET(bp)	((bp)->pb_file_offset)
 #define XFS_BUF_SET_OFFSET(bp, off)		\
 			((bp)->pb_file_offset = (off))
@@ -572,15 +549,15 @@ extern inline xfs_caddr_t xfs_buf_offset
 #define xfs_buf_get_flags(target, blkno, len, flags) \
 		pagebuf_get((target), (blkno), (len), (flags))
 
-static inline int	xfs_bawrite(void *mp, page_buf_t *bp)
+static inline int	xfs_bawrite(void *mp, xfs_buf_t *bp)
 {
 	bp->pb_fspriv3 = mp;
 	bp->pb_strat = xfs_bdstrat_cb;
 	xfs_buf_undelay(bp);
-	return pagebuf_iostart(bp, PBF_WRITE | PBF_ASYNC | PBF_RUN_QUEUES);
+	return pagebuf_iostart(bp, PBF_WRITE | PBF_ASYNC | _PBF_RUN_QUEUES);
 }
 
-static inline void	xfs_buf_relse(page_buf_t *bp)
+static inline void	xfs_buf_relse(xfs_buf_t *bp)
 {
 	if (!bp->pb_relse)
 		pagebuf_unlock(bp);
@@ -608,13 +585,13 @@ static inline void	xfs_buf_relse(page_bu
 	    pagebuf_iomove((pb), (off), (len), NULL, PBRW_ZERO)
 
 
-static inline int	XFS_bwrite(page_buf_t *pb)
+static inline int	XFS_bwrite(xfs_buf_t *pb)
 {
 	int	iowait = (pb->pb_flags & PBF_ASYNC) == 0;
 	int	error = 0;
 
 	if (!iowait)
-		pb->pb_flags |= PBF_RUN_QUEUES;
+		pb->pb_flags |= _PBF_RUN_QUEUES;
 
 	xfs_buf_undelay(pb);
 	pagebuf_iostrategy(pb);
@@ -628,7 +605,7 @@ static inline int	XFS_bwrite(page_buf_t 
 #define XFS_bdwrite(pb)		     \
 	    pagebuf_iostart(pb, PBF_DELWRI | PBF_ASYNC)
 
-static inline int xfs_bdwrite(void *mp, page_buf_t *bp)
+static inline int xfs_bdwrite(void *mp, xfs_buf_t *bp)
 {
 	bp->pb_strat = xfs_bdstrat_cb;
 	bp->pb_fspriv3 = mp;
@@ -640,21 +617,6 @@ static inline int xfs_bdwrite(void *mp, 
 
 #define xfs_iowait(pb)	pagebuf_iowait(pb)
 
-
-/*
- * Go through all incore buffers, and release buffers
- * if they belong to the given device. This is used in
- * filesystem error handling to preserve the consistency
- * of its metadata.
- */
-
-#define xfs_binval(buftarg)	xfs_flush_buftarg(buftarg)
-
-#define XFS_bflush(buftarg)	xfs_flush_buftarg(buftarg)
-
-#define xfs_incore_relse(buftarg,delwri_only,wait)	\
-	xfs_relse_buftarg(buftarg)
-
 #define xfs_baread(target, rablkno, ralen)  \
 	pagebuf_readahead((target), (rablkno), (ralen), PBF_DONT_BLOCK)
 
@@ -662,4 +624,23 @@ static inline int xfs_bdwrite(void *mp, 
 #define xfs_buf_get_noaddr(len, target)	pagebuf_get_no_daddr((len), (target))
 #define xfs_buf_free(bp)		pagebuf_free(bp)
 
+ /*
+  *	Handling of buftargs.
+  */
+ 
+extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *);
+extern void xfs_free_buftarg(xfs_buftarg_t *, int);
+extern void xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
+extern void xfs_incore_relse(xfs_buftarg_t *, int, int);
+extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
+
+#define xfs_getsize_buftarg(buftarg) \
+	block_size((buftarg)->pbr_kdev)
+#define xfs_readonly_buftarg(buftarg) \
+	is_read_only((buftarg)->pbr_kdev)
+#define xfs_binval(buftarg) \
+	xfs_flush_buftarg(buftarg, 1)
+#define XFS_bflush(buftarg) \
+	xfs_flush_buftarg(buftarg, 1)
+
 #endif	/* __XFS_BUF_H__ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/xfs_file.c linux-2.4.27-pre3/fs/xfs/linux/xfs_file.c
--- linux-2.4.26/fs/xfs/linux/xfs_file.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/xfs_file.c	2004-05-18 16:52:01.000000000 +0000
@@ -68,7 +68,7 @@ __linvfs_read(
 {
 	struct inode	*inode = file->f_dentry->d_inode;
 	vnode_t		*vp = LINVFS_GET_VP(inode);
-	size_t		rval;
+	ssize_t		rval;
 
 	if (unlikely(file->f_flags & O_DIRECT)) {
 		ioflags |= IO_ISDIRECT;
@@ -213,6 +213,10 @@ linvfs_fsync(
 	int		error;
 	int		flags = FSYNC_WAIT;
 
+	error = fsync_inode_data_buffers(inode);
+	if (error)
+		return error;
+
 	if (datasync)
 		flags |= FSYNC_DATA;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/xfs_iops.c linux-2.4.27-pre3/fs/xfs/linux/xfs_iops.c
--- linux-2.4.26/fs/xfs/linux/xfs_iops.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/xfs_iops.c	2004-05-18 16:53:22.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 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
@@ -521,18 +521,12 @@ linvfs_setattr(
 	}
 
 	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET))
-		flags = ATTR_UTIME;
+		flags |= ATTR_UTIME;
 
 	VOP_SETATTR(vp, &vattr, flags, NULL, error);
 	if (error)
-		return(-error);	/* Positive error up from XFS */
-	if (ia_valid & ATTR_SIZE) {
-		error = vmtruncate(inode, attr->ia_size);
-	}
-
-	if (!error) {
-		vn_revalidate(vp);
-	}
+		return -error;
+	vn_revalidate(vp);
 	return error;
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/xfs_linux.h linux-2.4.27-pre3/fs/xfs/linux/xfs_linux.h
--- linux-2.4.26/fs/xfs/linux/xfs_linux.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/xfs_linux.h	2004-05-18 16:54:17.000000000 +0000
@@ -63,6 +63,7 @@
 
 #include <linux/mm.h>
 #include <linux/kernel.h>
+#include <linux/blkdev.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/file.h>
@@ -236,6 +237,10 @@ BUFFER_FNS(Unwritten, unwritten)
 #define DEFAULT_PROJID	0
 #define dfltprid	DEFAULT_PROJID
 
+#ifndef pgoff_t		/* 2.6 compat */
+#define pgoff_t		unsigned long
+#endif
+
 #define MAXPATHLEN	1024
 
 #define MIN(a,b)	(min(a,b))
@@ -258,13 +263,10 @@ BUFFER_FNS(Unwritten, unwritten)
 
 #define XFS_DEV_TO_KDEVT(dev)	mk_kdev(XFS_DEV_MAJOR(dev),XFS_DEV_MINOR(dev))
 
+#define xfs_stack_trace()	dump_stack()
 
-/* Produce a kernel stack trace */
-
-static inline void xfs_stack_trace(void)
-{
-	dump_stack();
-}
+#define xfs_itruncate_data(ip, off)	\
+	(-vmtruncate(LINVFS_GET_IP(XFS_ITOV(ip)), (off)))
 
 
 /* Move the kernel do_div definition off to one side */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/xfs_lrw.h linux-2.4.27-pre3/fs/xfs/linux/xfs_lrw.h
--- linux-2.4.26/fs/xfs/linux/xfs_lrw.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/xfs_lrw.h	2004-05-18 16:53:37.000000000 +0000
@@ -38,7 +38,7 @@ struct xfs_mount;
 struct xfs_iocore;
 struct xfs_inode;
 struct xfs_bmbt_irec;
-struct page_buf_s;
+struct xfs_buf;
 struct xfs_iomap;
 
 #if defined(XFS_RW_TRACE)
@@ -89,8 +89,8 @@ extern void xfs_inval_cached_trace(struc
 
 extern int xfs_bmap(struct bhv_desc *, xfs_off_t, ssize_t, int,
 			struct xfs_iomap *, int *);
-extern int xfsbdstrat(struct xfs_mount *, struct page_buf_s *);
-extern int xfs_bdstrat_cb(struct page_buf_s *);
+extern int xfsbdstrat(struct xfs_mount *, struct xfs_buf *);
+extern int xfs_bdstrat_cb(struct xfs_buf *);
 
 extern int xfs_zero_eof(struct vnode *, struct xfs_iocore *, xfs_off_t,
 				xfs_fsize_t, xfs_fsize_t);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/xfs_super.c linux-2.4.27-pre3/fs/xfs/linux/xfs_super.c
--- linux-2.4.26/fs/xfs/linux/xfs_super.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/xfs_super.c	2004-05-18 16:54:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 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
@@ -67,7 +67,6 @@
 #include "xfs_utils.h"
 #include "xfs_version.h"
 
-#include <linux/blkdev.h>
 #include <linux/init.h>
 
 STATIC struct quotactl_ops linvfs_qops;
@@ -319,88 +318,6 @@ xfs_blkdev_put(
 		blkdev_put(bdev, BDEV_FS);
 }
 
-void
-xfs_flush_buftarg(
-	xfs_buftarg_t		*btp)
-{
-	pagebuf_delwri_flush(btp, PBDF_WAIT, NULL);
-}
-
-void
-xfs_free_buftarg(
-	xfs_buftarg_t		*btp)
-{
-	xfs_flush_buftarg(btp);
-	kmem_free(btp, sizeof(*btp));
-}
-
-int
-xfs_readonly_buftarg(
-	xfs_buftarg_t		*btp)
-{
-	return is_read_only(btp->pbr_kdev);
-}
-
-void
-xfs_relse_buftarg(
-	xfs_buftarg_t		*btp)
-{
-	destroy_buffers(btp->pbr_kdev);
-	truncate_inode_pages(btp->pbr_mapping, 0LL);
-}
-
-unsigned int
-xfs_getsize_buftarg(
-	xfs_buftarg_t		*btp)
-{
-	return block_size(btp->pbr_kdev);
-}
-
-void
-xfs_setsize_buftarg(
-	xfs_buftarg_t		*btp,
-	unsigned int		blocksize,
-	unsigned int		sectorsize)
-{
-	btp->pbr_bsize = blocksize;
-	btp->pbr_sshift = ffs(sectorsize) - 1;
-	btp->pbr_smask = sectorsize - 1;
-
-	if (set_blocksize(btp->pbr_kdev, sectorsize)) {
-		printk(KERN_WARNING
-			"XFS: Cannot set_blocksize to %u on device 0x%x\n",
-			sectorsize, kdev_t_to_nr(btp->pbr_kdev));
-	}
-}
-
-xfs_buftarg_t *
-xfs_alloc_buftarg(
-	struct block_device	*bdev)
-{
-	xfs_buftarg_t		*btp;
-
-	btp = kmem_zalloc(sizeof(*btp), KM_SLEEP);
-
-	btp->pbr_dev =  bdev->bd_dev;
-	btp->pbr_kdev = to_kdev_t(btp->pbr_dev);
-	btp->pbr_bdev = bdev;
-	btp->pbr_mapping = bdev->bd_inode->i_mapping;
-	xfs_setsize_buftarg(btp, PAGE_CACHE_SIZE,
-			    get_hardsect_size(btp->pbr_kdev));
-
-	switch (MAJOR(btp->pbr_dev)) {
-	case MD_MAJOR:
-	case EVMS_MAJOR:
-		btp->pbr_flags = PBR_ALIGNED_ONLY;
-		break;
-	case LVM_BLK_MAJOR:
-		btp->pbr_flags = PBR_SECTOR_ONLY;
-		break;
-	}
-
-	return btp;
-}
-
 STATIC struct inode *
 linvfs_alloc_inode(
 	struct super_block	*sb)
@@ -501,7 +418,8 @@ linvfs_clear_inode(
 #define SYNCD_FLAGS	(SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR|SYNC_REFCACHE)
 
 STATIC int
-syncd(void *arg)
+xfssyncd(
+	void			*arg)
 {
 	vfs_t			*vfsp = (vfs_t *) arg;
 	int			error;
@@ -537,11 +455,12 @@ syncd(void *arg)
 }
 
 STATIC int
-linvfs_start_syncd(vfs_t *vfsp)
+linvfs_start_syncd(
+	vfs_t			*vfsp)
 {
-	int pid;
+	int			pid;
 
-	pid = kernel_thread(syncd, (void *) vfsp,
+	pid = kernel_thread(xfssyncd, (void *) vfsp,
 			CLONE_VM | CLONE_FS | CLONE_FILES);
 	if (pid < 0)
 		return pid;
@@ -550,7 +469,8 @@ linvfs_start_syncd(vfs_t *vfsp)
 }
 
 STATIC void
-linvfs_stop_syncd(vfs_t *vfsp)
+linvfs_stop_syncd(
+	vfs_t			*vfsp)
 {
 	vfsp->vfs_flag |= VFS_UMOUNT;
 	wmb();
@@ -603,6 +523,7 @@ linvfs_sync_super(
 	int		error;
 
 	VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_WAIT, NULL, error);
+	sb->s_dirt = 0;
 	return -error;
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/linux/xfs_super.h linux-2.4.27-pre3/fs/xfs/linux/xfs_super.h
--- linux-2.4.26/fs/xfs/linux/xfs_super.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/linux/xfs_super.h	2004-05-18 16:52:50.000000000 +0000
@@ -112,7 +112,7 @@ extern void xfs_qm_exit(void);
 
 struct xfs_inode;
 struct xfs_mount;
-struct pb_target;
+struct xfs_buftarg;
 struct block_device;
 
 extern __uint64_t xfs_max_file_offset(unsigned int);
@@ -127,14 +127,6 @@ extern int  xfs_blkdev_get(struct xfs_mo
 				struct block_device **);
 extern void xfs_blkdev_put(struct block_device *);
 
-extern struct pb_target *xfs_alloc_buftarg(struct block_device *);
-extern void xfs_relse_buftarg(struct pb_target *);
-extern void xfs_free_buftarg(struct pb_target *);
-extern void xfs_flush_buftarg(struct pb_target *);
-extern int xfs_readonly_buftarg(struct pb_target *);
-extern void xfs_setsize_buftarg(struct pb_target *, unsigned int, unsigned int);
-extern unsigned int xfs_getsize_buftarg(struct pb_target *);
-
 /* matching a 2.6 kernel export, thus no xfs_ prefix */
 extern struct dentry *d_alloc_anon(struct inode *inode);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_acl.c linux-2.4.27-pre3/fs/xfs/xfs_acl.c
--- linux-2.4.26/fs/xfs/xfs_acl.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_acl.c	2004-05-18 16:52:37.000000000 +0000
@@ -111,7 +111,7 @@ posix_acl_xattr_to_xfs(
 		return EINVAL;
 
 	if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
-		return EINVAL;
+		return EOPNOTSUPP;
 
 	memset(dest, 0, sizeof(xfs_acl_t));
 	dest->acl_cnt = posix_acl_xattr_count(size);
@@ -340,7 +340,6 @@ xfs_acl_vset(
 		xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
 	}
 
-
 out:
 	VN_RELE(vp);
 	_ACL_FREE(xfs_acl);
@@ -354,13 +353,15 @@ xfs_acl_iaccess(
 	cred_t		*cr)
 {
 	xfs_acl_t	*acl;
-	int		error;
+	int		rval;
 
 	if (!(_ACL_ALLOC(acl)))
 		return -1;
 
 	/* If the file has no ACL return -1. */
-	if (xfs_attr_fetch(ip, SGI_ACL_FILE, (char *)acl, sizeof(xfs_acl_t))) {
+	rval = sizeof(xfs_acl_t);
+	if (xfs_attr_fetch(ip, SGI_ACL_FILE, SGI_ACL_FILE_SIZE,
+			(char *)acl, &rval, ATTR_ROOT | ATTR_KERNACCESS, cr)) {
 		_ACL_FREE(acl);
 		return -1;
 	}
@@ -375,9 +376,9 @@ xfs_acl_iaccess(
 	/* Synchronize ACL with mode bits */
 	xfs_acl_sync_mode(ip->i_d.di_mode, acl);
 
-	error = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr);
+	rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr);
 	_ACL_FREE(acl);
-	return error;
+	return rval;
 }
 
 STATIC int
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_attr.c linux-2.4.27-pre3/fs/xfs/xfs_attr.c
--- linux-2.4.26/fs/xfs/xfs_attr.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_attr.c	2004-05-18 16:53:45.000000000 +0000
@@ -115,20 +115,12 @@ ktrace_t *xfs_attr_trace_buf;
  * Overall external interface routines.
  *========================================================================*/
 
-/*ARGSUSED*/
-STATIC int
-xfs_attr_get_int(xfs_inode_t *ip, char *name, char *value, int *valuelenp,
-	     int flags, int lock, struct cred *cred)
+int
+xfs_attr_fetch(xfs_inode_t *ip, char *name, int namelen,
+	       char *value, int *valuelenp, int flags, struct cred *cred)
 {
 	xfs_da_args_t   args;
 	int             error;
-	int             namelen;
-
-	ASSERT(MAXNAMELEN-1 <= 0xff);	/* length is stored in uint8 */
-	namelen = strlen(name);
-	if (namelen >= MAXNAMELEN)
-		return(EFAULT);		/* match IRIX behaviour */
-	XFS_STATS_INC(xs_attr_get);
 
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return(EIO);
@@ -138,12 +130,11 @@ xfs_attr_get_int(xfs_inode_t *ip, char *
 	     ip->i_d.di_anextents == 0))
 		return(ENOATTR);
 
-	if (lock) {
+	if (!(flags & ATTR_KERNACCESS)) {
 		xfs_ilock(ip, XFS_ILOCK_SHARED);
-		/*
-		 * Do we answer them, or ignore them?
-		 */
-		if ((error = xfs_iaccess(ip, S_IRUSR, cred))) {
+
+		if (!(flags & ATTR_SECURE) &&
+		    ((error = xfs_iaccess(ip, S_IRUSR, cred)))) {
 			xfs_iunlock(ip, XFS_ILOCK_SHARED);
 			return(XFS_ERROR(error));
 		}
@@ -161,7 +152,6 @@ xfs_attr_get_int(xfs_inode_t *ip, char *
 	args.hashval = xfs_da_hashname(args.name, args.namelen);
 	args.dp = ip;
 	args.whichfork = XFS_ATTR_FORK;
-	args.trans = NULL;
 
 	/*
 	 * Decide on what work routines to call based on the inode size.
@@ -178,7 +168,7 @@ xfs_attr_get_int(xfs_inode_t *ip, char *
 		error = xfs_attr_node_get(&args);
 	}
 
-	if (lock)
+	if (!(flags & ATTR_KERNACCESS))
 		xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
 	/*
@@ -192,20 +182,21 @@ xfs_attr_get_int(xfs_inode_t *ip, char *
 }
 
 int
-xfs_attr_fetch(xfs_inode_t *ip, char *name, char *value, int valuelen)
-{
-	return xfs_attr_get_int(ip, name, value, &valuelen, ATTR_ROOT, 0, NULL);
-}
-
-int
 xfs_attr_get(bhv_desc_t *bdp, char *name, char *value, int *valuelenp,
 	     int flags, struct cred *cred)
 {
 	xfs_inode_t	*ip = XFS_BHVTOI(bdp);
+	int		namelen;
+
+	XFS_STATS_INC(xs_attr_get);
 
 	if (!name)
 		return(EINVAL);
-	return xfs_attr_get_int(ip, name, value, valuelenp, flags, 1, cred);
+	namelen = strlen(name);
+	if (namelen >= MAXNAMELEN)
+		return(EFAULT);		/* match IRIX behaviour */
+
+	return xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred);
 }
 
 /*ARGSUSED*/
@@ -224,22 +215,20 @@ xfs_attr_set(bhv_desc_t *bdp, char *name
 	int             rsvd = (flags & ATTR_ROOT) != 0;
 	int             namelen;
 
-	ASSERT(MAXNAMELEN-1 <= 0xff); /* length is stored in uint8 */
 	namelen = strlen(name);
 	if (namelen >= MAXNAMELEN)
-		return EFAULT; /* match irix behaviour */
+		return EFAULT;		/* match IRIX behaviour */
 
 	XFS_STATS_INC(xs_attr_set);
-	/*
-	 * Do we answer them, or ignore them?
-	 */
+
 	dp = XFS_BHVTOI(bdp);
 	mp = dp->i_mount;
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return (EIO);
 
 	xfs_ilock(dp, XFS_ILOCK_SHARED);
-	if ((error = xfs_iaccess(dp, S_IWUSR, cred))) {
+	if (!(flags & ATTR_SECURE) &&
+	     (error = xfs_iaccess(dp, S_IWUSR, cred))) {
 		xfs_iunlock(dp, XFS_ILOCK_SHARED);
 		return(XFS_ERROR(error));
 	}
@@ -489,16 +478,14 @@ xfs_attr_remove(bhv_desc_t *bdp, char *n
 
 	XFS_STATS_INC(xs_attr_remove);
 
-	/*
-	 * Do we answer them, or ignore them?
-	 */
 	dp = XFS_BHVTOI(bdp);
 	mp = dp->i_mount;
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return (EIO);
 
 	xfs_ilock(dp, XFS_ILOCK_SHARED);
-	if ((error = xfs_iaccess(dp, S_IWUSR, cred))) {
+	if (!(flags & ATTR_SECURE) &&
+	     (error = xfs_iaccess(dp, S_IWUSR, cred))) {
 		xfs_iunlock(dp, XFS_ILOCK_SHARED);
 		return(XFS_ERROR(error));
 	} else if (XFS_IFORK_Q(dp) == 0 ||
@@ -683,11 +670,10 @@ xfs_attr_list(bhv_desc_t *bdp, char *buf
 
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return (EIO);
-	/*
-	 * Do they have permission?
-	 */
+
 	xfs_ilock(dp, XFS_ILOCK_SHARED);
-	if ((error = xfs_iaccess(dp, S_IRUSR, cred))) {
+	if (!(flags & ATTR_SECURE) &&
+	     (error = xfs_iaccess(dp, S_IRUSR, cred))) {
 		xfs_iunlock(dp, XFS_ILOCK_SHARED);
 		return(XFS_ERROR(error));
 	}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_attr.h linux-2.4.27-pre3/fs/xfs/xfs_attr.h
--- linux-2.4.26/fs/xfs/xfs_attr.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_attr.h	2004-05-18 16:55:17.000000000 +0000
@@ -92,6 +92,7 @@ extern int attr_generic_list(struct vnod
 #define ATTR_REPLACE	0x0020	/* pure set: fail if attr does not exist */
 #define ATTR_SYSTEM	0x0100	/* use attrs in system (pseudo) namespace */
 
+#define ATTR_KERNACCESS	0x0400	/* [kernel] iaccess, inode held io-locked */
 #define ATTR_KERNOTIME	0x1000	/* [kernel] don't update inode timestamps */
 #define ATTR_KERNOVAL	0x2000	/* [kernel] get attr size only, not value */
 #define ATTR_KERNAMELS	0x4000	/* [kernel] list attr names (simple list) */
@@ -186,6 +187,7 @@ int xfs_attr_inactive(struct xfs_inode *
 int xfs_attr_node_get(struct xfs_da_args *);
 int xfs_attr_leaf_get(struct xfs_da_args *);
 int xfs_attr_shortform_getvalue(struct xfs_da_args *);
-int xfs_attr_fetch(struct xfs_inode *, char *, char *, int);
+int xfs_attr_fetch(struct xfs_inode *, char *, int,
+			char *, int *, int, struct cred *);
 
 #endif	/* __XFS_ATTR_H__ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_dir2_node.c linux-2.4.27-pre3/fs/xfs/xfs_dir2_node.c
--- linux-2.4.26/fs/xfs/xfs_dir2_node.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_dir2_node.c	2004-05-18 16:51:31.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 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
@@ -224,12 +224,21 @@ xfs_dir2_leafn_add(
 	mp = dp->i_mount;
 	tp = args->trans;
 	leaf = bp->data;
+
+	/*
+	 * Quick check just to make sure we are not going to index
+	 * into other peoples memory
+	 */
+	if (index < 0)
+		return XFS_ERROR(EFSCORRUPTED);
+
 	/*
 	 * If there are already the maximum number of leaf entries in
 	 * the block, if there are no stale entries it won't fit.
 	 * Caller will do a split.  If there are stale entries we'll do
 	 * a compact.
 	 */
+
 	if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == XFS_DIR2_MAX_LEAF_ENTS(mp)) {
 		if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT))
 			return XFS_ERROR(ENOSPC);
@@ -828,12 +837,24 @@ xfs_dir2_leafn_rebalance(
 		state->inleaf = !swap;
 	else
 		state->inleaf =
-			swap ^ (args->hashval < INT_GET(leaf2->ents[0].hashval, ARCH_CONVERT));
+			swap ^ (blk1->index <= INT_GET(leaf1->hdr.count, ARCH_CONVERT));
 	/*
 	 * Adjust the expected index for insertion.
 	 */
 	if (!state->inleaf)
 		blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT);
+	
+	/* 
+	 * Finally sanity check just to make sure we are not returning a negative index 
+	 */
+	if(blk2->index < 0) {
+		state->inleaf = 1;
+		blk2->index = 0;
+		cmn_err(CE_ALERT,
+			"xfs_dir2_leafn_rebalance: picked the wrong leaf? reverting orignal leaf: "
+			"blk1->index %d\n",
+			blk1->index);
+	}
 }
 
 /*
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_iomap.c linux-2.4.27-pre3/fs/xfs/xfs_iomap.c
--- linux-2.4.26/fs/xfs/xfs_iomap.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_iomap.c	2004-05-18 16:51:25.000000000 +0000
@@ -591,10 +591,11 @@ retry:
 	firstblock = NULLFSBLOCK;
 
 	/*
-	 * roundup the allocation request to m_dalign boundary if file size
-	 * is greater that 512K and we are allocating past the allocation eof
+	 * Roundup the allocation request to a stripe unit (m_dalign) boundary
+	 * if the file size is >= stripe unit size, and we are allocating past
+	 * the allocation eof.
 	 */
-	if (mp->m_dalign && (isize >= mp->m_dalign) && aeof) {
+	if (mp->m_dalign && (isize >= XFS_FSB_TO_B(mp, mp->m_dalign)) && aeof) {
 		int eof;
 		xfs_fileoff_t new_last_fsb;
 		new_last_fsb = roundup_64(last_fsb, mp->m_dalign);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_macros.c linux-2.4.27-pre3/fs/xfs/xfs_macros.c
--- linux-2.4.26/fs/xfs/xfs_macros.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_macros.c	2004-05-18 16:55:21.000000000 +0000
@@ -2234,3 +2234,12 @@ xlog_grant_sub_space(xlog_t *log, int by
 	XLOG_GRANT_SUB_SPACE(log, bytes, type);
 }
 #endif
+
+#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASMOREBITS)
+int
+xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_HASMOREBITS(sbp);
+}
+#endif
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_mount.c linux-2.4.27-pre3/fs/xfs/xfs_mount.c
--- linux-2.4.26/fs/xfs/xfs_mount.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_mount.c	2004-05-18 16:54:17.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 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
@@ -117,6 +117,7 @@ static struct {
     { offsetof(xfs_sb_t, sb_logsectlog), 0 },
     { offsetof(xfs_sb_t, sb_logsectsize),0 },
     { offsetof(xfs_sb_t, sb_logsunit),	 0 },
+    { offsetof(xfs_sb_t, sb_features2),	 0 },
     { sizeof(xfs_sb_t),			 0 }
 };
 
@@ -1130,22 +1131,11 @@ xfs_unmountfs(xfs_mount_t *mp, struct cr
 void
 xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr)
 {
-	int		have_logdev = (mp->m_logdev_targp != mp->m_ddev_targp);
-
-	if (mp->m_ddev_targp) {
-		xfs_free_buftarg(mp->m_ddev_targp);
-		mp->m_ddev_targp = NULL;
-	}
-	if (mp->m_rtdev_targp) {
-		xfs_blkdev_put(mp->m_rtdev_targp->pbr_bdev);
-		xfs_free_buftarg(mp->m_rtdev_targp);
-		mp->m_rtdev_targp = NULL;
-	}
-	if (mp->m_logdev_targp && have_logdev) {
-		xfs_blkdev_put(mp->m_logdev_targp->pbr_bdev);
-		xfs_free_buftarg(mp->m_logdev_targp);
-		mp->m_logdev_targp = NULL;
-	}
+	if (mp->m_logdev_targp != mp->m_ddev_targp)
+		xfs_free_buftarg(mp->m_logdev_targp, 1);
+	if (mp->m_rtdev_targp)
+		xfs_free_buftarg(mp->m_rtdev_targp, 1);
+	xfs_free_buftarg(mp->m_ddev_targp, 0);
 }
 
 int
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_sb.h linux-2.4.27-pre3/fs/xfs/xfs_sb.h
--- linux-2.4.26/fs/xfs/xfs_sb.h	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_sb.h	2004-05-18 16:53:52.000000000 +0000
@@ -60,6 +60,7 @@ struct xfs_mount;
 #define XFS_SB_VERSION_SECTORBIT	0x0800
 #define	XFS_SB_VERSION_EXTFLGBIT	0x1000
 #define	XFS_SB_VERSION_DIRV2BIT		0x2000
+#define	XFS_SB_VERSION_MOREBITSBIT	0x8000
 #define	XFS_SB_VERSION_OKSASHFBITS	\
 	(XFS_SB_VERSION_EXTFLGBIT | \
 	 XFS_SB_VERSION_DIRV2BIT)
@@ -80,17 +81,46 @@ struct xfs_mount;
 	(XFS_SB_VERSION_NUMBITS | \
 	 XFS_SB_VERSION_OKREALFBITS | \
 	 XFS_SB_VERSION_OKSASHFBITS)
-#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2,na,sflag)	\
-	(((ia) || (dia) || (extflag) || (dirv2) || (na) || (sflag)) ? \
+#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2,na,sflag,morebits)	\
+	(((ia) || (dia) || (extflag) || (dirv2) || (na) || (sflag) || \
+	  (morebits)) ? \
 		(XFS_SB_VERSION_4 | \
 		 ((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) | \
 		 ((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) | \
 		 ((extflag) ? XFS_SB_VERSION_EXTFLGBIT : 0) | \
 		 ((dirv2) ? XFS_SB_VERSION_DIRV2BIT : 0) | \
 		 ((na) ? XFS_SB_VERSION_LOGV2BIT : 0) | \
-		 ((sflag) ? XFS_SB_VERSION_SECTORBIT : 0)) : \
+		 ((sflag) ? XFS_SB_VERSION_SECTORBIT : 0) | \
+		 ((morebits) ? XFS_SB_VERSION_MOREBITSBIT : 0)) : \
 		XFS_SB_VERSION_1)
 
+/*
+ * There are two words to hold XFS "feature" bits: the original
+ * word, sb_versionnum, and sb_features2.  Whenever a bit is set in
+ * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set.
+ *
+ * These defines represent bits in sb_features2.
+ */
+#define XFS_SB_VERSION2_REALFBITS	0x00ffffff	/* Mask: features */
+#define XFS_SB_VERSION2_RESERVED1BIT	0x00000001
+#define XFS_SB_VERSION2_SASHFBITS	0xff000000	/* Mask: features that
+							   require changing
+							   PROM and SASH */
+
+#define	XFS_SB_VERSION2_OKREALFBITS	\
+	(0)
+#define	XFS_SB_VERSION2_OKSASHFBITS	\
+	(0)
+#define XFS_SB_VERSION2_OKREALBITS	\
+	(XFS_SB_VERSION2_OKREALFBITS |	\
+	 XFS_SB_VERSION2_OKSASHFBITS )
+
+/*
+ * mkfs macro to set up sb_features2 word
+ */
+#define	XFS_SB_VERSION2_MKFS(xyz)	\
+	((xyz) ? 0 : 0)
+
 typedef struct xfs_sb
 {
 	__uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */
@@ -146,6 +176,7 @@ typedef struct xfs_sb
 	__uint8_t	sb_logsectlog;	/* log2 of the log sector size */
 	__uint16_t	sb_logsectsize;	/* sector size for the log, bytes */
 	__uint32_t	sb_logsunit;	/* stripe unit size for the log */
+	__uint32_t	sb_features2;	/* additonal feature bits */
 } xfs_sb_t;
 
 /*
@@ -164,6 +195,7 @@ typedef enum {
 	XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
 	XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
 	XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
+	XFS_SBS_FEATURES2,
 	XFS_SBS_FIELDCOUNT
 } xfs_sb_field_t;
 
@@ -217,8 +249,11 @@ int xfs_sb_good_version(xfs_sb_t *sbp);
 #define	XFS_SB_GOOD_VERSION_INT(sbp)	\
 	((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \
 	  ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \
-	 ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
-	  !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS)
+	   ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+	    !(((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) && \
+	      ((sbp)->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && \
+	      ((sbp)->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS))
+
 #ifdef __KERNEL__
 #define	XFS_SB_GOOD_VERSION(sbp)	\
 	(XFS_SB_GOOD_VERSION_INT(sbp) && \
@@ -453,6 +488,25 @@ int xfs_sb_version_hassector(xfs_sb_t *s
 	((sbp)->sb_versionnum & XFS_SB_VERSION_SECTORBIT))
 #endif
 
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASMOREBITSBIT)
+int xfs_sb_version_hasmorebits(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASMOREBITS(sbp)	xfs_sb_version_hasmorebits(sbp)
+#else
+#define XFS_SB_VERSION_HASMOREBITS(sbp)	\
+	((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+	 ((sbp)->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT))
+#endif
+
+/*
+ * sb_features2 bit version macros.
+ *
+ * For example, for a bit defined as XFS_SB_VERSION2_YBIT, has a macro:
+ *
+ * SB_VERSION_HASYBIT(xfs_sb_t *sbp)
+ *	((XFS_SB_VERSION_HASMOREBITS(sbp) &&
+ *	 ((sbp)->sb_versionnum & XFS_SB_VERSION2_YBIT)
+ */
+
 /*
  * end of superblock version macros
  */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_trans.c linux-2.4.27-pre3/fs/xfs/xfs_trans.c
--- linux-2.4.26/fs/xfs/xfs_trans.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_trans.c	2004-05-18 16:53:43.000000000 +0000
@@ -250,7 +250,7 @@ xfs_trans_reserve(
 		error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
 					  -blocks, rsvd);
 		if (error != 0) {
-                        PFLAGS_RESTORE(&tp->t_pflags);
+                        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 			return (XFS_ERROR(ENOSPC));
 		}
 		tp->t_blk_res += blocks;
@@ -323,7 +323,7 @@ undo_blocks:
 		tp->t_blk_res = 0;
 	}
 
-        PFLAGS_RESTORE(&tp->t_pflags);
+        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 
 	return (error);
 }
@@ -734,7 +734,7 @@ shut_us_down:
 			if (commit_lsn == -1 && !shutdown)
 				shutdown = XFS_ERROR(EIO);
 		}
-                PFLAGS_RESTORE(&tp->t_pflags);
+                PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 		xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);
 		xfs_trans_free_busy(tp);
 		xfs_trans_free(tp);
@@ -823,7 +823,7 @@ shut_us_down:
 	 * had pinned, clean up, free trans structure, and return error.
 	 */
 	if (error || commit_lsn == -1) {
-                PFLAGS_RESTORE(&tp->t_pflags);
+                PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 		xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
 		return XFS_ERROR(EIO);
 	}
@@ -862,7 +862,7 @@ shut_us_down:
 	error = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb));
 
 	/* mark this thread as no longer being in a transaction */
-        PFLAGS_RESTORE(&tp->t_pflags);
+        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 
 	/*
 	 * Once all the items of the transaction have been copied
@@ -1100,7 +1100,7 @@ xfs_trans_cancel(
 	}
 
 	/* mark this thread as no longer being in a transaction */
-        PFLAGS_RESTORE(&tp->t_pflags);
+        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 
 	xfs_trans_free_items(tp, flags);
 	xfs_trans_free_busy(tp);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_vfsops.c linux-2.4.27-pre3/fs/xfs/xfs_vfsops.c
--- linux-2.4.26/fs/xfs/xfs_vfsops.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_vfsops.c	2004-05-18 16:53:54.000000000 +0000
@@ -213,9 +213,9 @@ xfs_cleanup(void)
  */
 STATIC int
 xfs_start_flags(
+	struct vfs		*vfs,
 	struct xfs_mount_args	*ap,
-	struct xfs_mount	*mp,
-	int			ronly)
+	struct xfs_mount	*mp)
 {
 	/* Values are in BBs */
 	if ((ap->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) {
@@ -305,7 +305,7 @@ xfs_start_flags(
 	 * no recovery flag requires a read-only mount
 	 */
 	if (ap->flags & XFSMNT_NORECOVERY) {
-		if (!ronly) {
+		if (!(vfs->vfs_flag & VFS_RDONLY)) {
 			cmn_err(CE_WARN,
 	"XFS: tried to mount a FS read-write without recovery!");
 			return XFS_ERROR(EINVAL);
@@ -327,10 +327,12 @@ xfs_start_flags(
  */
 STATIC int
 xfs_finish_flags(
+	struct vfs		*vfs,
 	struct xfs_mount_args	*ap,
-	struct xfs_mount	*mp,
-	int			ronly)
+	struct xfs_mount	*mp)
 {
+	int			ronly = (vfs->vfs_flag & VFS_RDONLY);
+
 	/* Fail a mount where the logbuf is smaller then the log stripe */
 	if (XFS_SB_VERSION_HASLOGV2(&mp->m_sb)) {
 		if ((ap->logbufsize == -1) &&
@@ -420,7 +422,6 @@ xfs_mount(
 	struct bhv_desc		*p;
 	struct xfs_mount	*mp = XFS_BHVTOM(bhvp);
 	struct block_device	*ddev, *logdev, *rtdev;
-	int			ronly = (vfsp->vfs_flag & VFS_RDONLY);
 	int			flags = 0, error;
 
 	ddev = vfsp->vfs_super->s_bdev;
@@ -472,13 +473,13 @@ xfs_mount(
 	/*
 	 * Setup flags based on mount(2) options and then the superblock
 	 */
-	error = xfs_start_flags(args, mp, ronly);
+	error = xfs_start_flags(vfsp, args, mp);
 	if (error)
 		goto error;
 	error = xfs_readsb(mp);
 	if (error)
 		goto error;
-	error = xfs_finish_flags(args, mp, ronly);
+	error = xfs_finish_flags(vfsp, args, mp);
 	if (error) {
 		xfs_freesb(mp);
 		goto error;
@@ -624,7 +625,7 @@ xfs_mntupdate(
 
 	if (*flags & MS_RDONLY) {
 		xfs_refcache_purge_mp(mp);
-		pagebuf_delwri_flush(mp->m_ddev_targp, 0, NULL);
+		xfs_flush_buftarg(mp->m_ddev_targp, 0);
 		xfs_finish_reclaim_all(mp, 0);
 
 		/* This loop must run at least twice.
@@ -636,9 +637,11 @@ xfs_mntupdate(
 		 */ 
 		do {
 			VFS_SYNC(vfsp, REMOUNT_READONLY_FLAGS, NULL, error);
-			pagebuf_delwri_flush(mp->m_ddev_targp, PBDF_WAIT,
-								&pincount);
-			if(0 == pincount) { delay(50); count++; }
+			pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
+			if (!pincount) {
+				delay(50);
+				count++;
+			}
 		} while (count < 2);
 
 		/* Ok now write out an unmount record */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/fs/xfs/xfs_vnodeops.c linux-2.4.27-pre3/fs/xfs/xfs_vnodeops.c
--- linux-2.4.26/fs/xfs/xfs_vnodeops.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/fs/xfs/xfs_vnodeops.c	2004-05-18 16:53:57.000000000 +0000
@@ -680,18 +680,12 @@ xfs_setattr(
 	 * once it is a part of the transaction.
 	 */
 	if (mask & XFS_AT_SIZE) {
-		if (vap->va_size > ip->i_d.di_size) {
+		code = 0;
+		if (vap->va_size > ip->i_d.di_size)
 			code = xfs_igrow_start(ip, vap->va_size, credp);
-			xfs_iunlock(ip, XFS_ILOCK_EXCL);
-		} else if (vap->va_size <= ip->i_d.di_size) {
-			xfs_iunlock(ip, XFS_ILOCK_EXCL);
-			xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
-					    (xfs_fsize_t)vap->va_size);
-			code = 0;
-		} else {
-			xfs_iunlock(ip, XFS_ILOCK_EXCL);
-			code = 0;
-		}
+		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+		if (!code)
+			code = xfs_itruncate_data(ip, vap->va_size);
 		if (code) {
 			ASSERT(tp == NULL);
 			lock_flags &= ~XFS_ILOCK_EXCL;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-i386/acpi.h linux-2.4.27-pre3/include/asm-i386/acpi.h
--- linux-2.4.26/include/asm-i386/acpi.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-i386/acpi.h	2004-05-18 16:51:11.000000000 +0000
@@ -99,33 +99,43 @@ __acpi_release_global_lock (unsigned int
         :"=r"(n_hi), "=r"(n_lo)     \
         :"0"(n_hi), "1"(n_lo))
 
+#ifdef CONFIG_ACPI_PCI
+extern int acpi_noirq;
+extern int acpi_pci_disabled;
+static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
+static inline void acpi_disable_pci(void) 
+{
+	acpi_pci_disabled = 1; 
+	acpi_noirq_set();
+}
+extern int acpi_irq_balance_set(char *str);
+#else
+static inline void acpi_noirq_set(void) { }
+static inline void acpi_disable_pci(void) { acpi_noirq_set(); }
+static inline int acpi_irq_balance_set(char *str) { return 0; }
+#endif
 
 #ifdef CONFIG_ACPI_BOOT 
 extern int acpi_lapic;
 extern int acpi_ioapic;
-extern int acpi_noirq;
 extern int acpi_strict;
 extern int acpi_disabled;
 extern int acpi_ht;
-static inline void disable_acpi(void) { acpi_disabled = 1; acpi_ht = 0; }
+static inline void disable_acpi(void) 
+{ 
+	acpi_disabled = 1;
+	acpi_ht = 0;
+	acpi_disable_pci();
+}
 
 /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
 #define FIX_ACPI_PAGES 4
 
 #else	/* !CONFIG_ACPI_BOOT */
-#  define acpi_lapic 0
-#  define acpi_ioapic 0
-
+#define acpi_lapic 0
+#define acpi_ioapic 0
 #endif	/* !CONFIG_ACPI_BOOT */
 
-#ifdef CONFIG_ACPI_PCI
-static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
-extern int acpi_irq_balance_set(char *str);
-#else
-static inline void acpi_noirq_set(void) { }
-static inline int acpi_irq_balance_set(char *str) { return 0; }
-#endif
-
 #ifdef CONFIG_ACPI_SLEEP
 
 extern unsigned long saved_eip;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-i386/smpboot.h linux-2.4.27-pre3/include/asm-i386/smpboot.h
--- linux-2.4.26/include/asm-i386/smpboot.h	2003-08-25 11:44:43.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-i386/smpboot.h	2004-05-18 16:55:08.000000000 +0000
@@ -73,11 +73,18 @@ extern unsigned char raw_phys_apicid[NR_
  */
 static inline int cpu_present_to_apicid(int mps_cpu)
 {
-	if (clustered_apic_mode == CLUSTERED_APIC_XAPIC)
-		return raw_phys_apicid[mps_cpu];
-	if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ)
-		return (mps_cpu/4)*16 + (1<<(mps_cpu%4));
-	return mps_cpu;
+	switch (clustered_apic_mode) {
+		case CLUSTERED_APIC_XAPIC:
+			if (mps_cpu >= NR_CPUS)
+				return BAD_APICID;
+			else
+				return raw_phys_apicid[mps_cpu];
+		case CLUSTERED_APIC_NUMAQ:
+			return (mps_cpu & ~0x3) << 2 | 1 << (mps_cpu & 0x3);
+		case CLUSTERED_APIC_NONE:
+		default:
+			return mps_cpu;
+	}
 }
 
 static inline unsigned long apicid_to_phys_cpu_present(int apicid)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-ia64/acpi.h linux-2.4.27-pre3/include/asm-ia64/acpi.h
--- linux-2.4.26/include/asm-ia64/acpi.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-ia64/acpi.h	2004-05-18 16:55:08.000000000 +0000
@@ -97,7 +97,8 @@
 	} while (0)
 
 #define acpi_disabled 0	/* ACPI always enabled */
-#define acpi_strict 1	/* no ACPI workarounds */
+#define acpi_pci_disabled 0 /* ACPI PCI always enabled on IA64 */
+#define acpi_strict 1	/* no ACPI spec workarounds on IA64 */
 static inline void disable_acpi(void) { }
 
 const char *acpi_get_sysname (void);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-ia64/ia32.h linux-2.4.27-pre3/include/asm-ia64/ia32.h
--- linux-2.4.26/include/asm-ia64/ia32.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-ia64/ia32.h	2004-05-18 16:55:21.000000000 +0000
@@ -377,7 +377,6 @@ struct old_linux32_dirent {
 #define IA32_TSS_OFFSET		(IA32_PAGE_OFFSET + PAGE_SIZE)
 #define IA32_LDT_OFFSET		(IA32_PAGE_OFFSET + 2*PAGE_SIZE)
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE	IA32_PAGE_SIZE
 
 /*
@@ -395,20 +394,6 @@ void ia64_elf32_init(struct pt_regs *reg
 #define elf_addr_t	u32
 #define elf_caddr_t	u32
 
-/* ELF register definitions.  This is needed for core dump support.  */
-
-#define ELF_NGREG	128			/* XXX fix me */
-#define ELF_NFPREG	128			/* XXX fix me */
-
-typedef unsigned long elf_greg_t;
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-typedef struct {
-	unsigned long w0;
-	unsigned long w1;
-} elf_fpreg_t;
-typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-
 /* This macro yields a bitmask that programs can use to figure out
    what instruction set this CPU supports.  */
 #define ELF_HWCAP	0
@@ -558,6 +543,23 @@ extern void ia32_load_segment_descriptor
 	asm volatile ("ldf.fill f6=[%2];; stfe [%1]=f6" : "=f"(f6): "r"(dst),  "r"(src) : "memory"); \
 	} while(0)
 
+struct user_regs_struct32 {
+	__u32 ebx, ecx, edx, esi, edi, ebp, eax;
+	unsigned short ds, __ds, es, __es;
+	unsigned short fs, __fs, gs, __gs;
+	__u32 orig_eax, eip;
+	unsigned short cs, __cs;
+	__u32 eflags, esp;
+	unsigned short ss, __ss;
+};
+
+/* Prototypes for use in elfcore32.h */
+int save_ia32_fpstate (struct task_struct *tsk, 
+                       struct ia32_user_i387_struct *save);
+
+int save_ia32_fpxstate (struct task_struct *tsk, 
+			struct ia32_user_fxsr_struct *save);
+
 #endif /* !CONFIG_IA32_SUPPORT */
 
 #endif /* _ASM_IA64_IA32_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-m68k/motorola_pgalloc.h linux-2.4.27-pre3/include/asm-m68k/motorola_pgalloc.h
--- linux-2.4.26/include/asm-m68k/motorola_pgalloc.h	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-m68k/motorola_pgalloc.h	2004-05-18 16:55:38.000000000 +0000
@@ -231,20 +231,24 @@ static inline void flush_tlb_all(void)
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
-	if (mm == current->mm)
+	if (mm == current->active_mm)
 		__flush_tlb();
 }
 
 static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 {
-	if (vma->vm_mm == current->mm)
+	if (vma->vm_mm == current->active_mm) {
+		mm_segment_t old_fs = get_fs();
+		set_fs(USER_DS);
 		__flush_tlb_one(addr);
+		set_fs(old_fs);
+	}
 }
 
 static inline void flush_tlb_range(struct mm_struct *mm,
 				   unsigned long start, unsigned long end)
 {
-	if (mm == current->mm)
+	if (mm == current->active_mm)
 		__flush_tlb();
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sh64/cayman.h linux-2.4.27-pre3/include/asm-sh64/cayman.h
--- linux-2.4.26/include/asm-sh64/cayman.h	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sh64/cayman.h	2004-05-18 16:53:47.000000000 +0000
@@ -13,7 +13,7 @@
  */
 
 
-/* Setup for the SMSC FDC37C935 */
+/* Setup for the SMSC FDC37C935 / LAN91C100FD */
 #define SMSC_IRQ         IRQ_IRL1
 
 /* Setup for PCI Bus 2, which transmits interrupts via the EPLD */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sh64/io.h linux-2.4.27-pre3/include/asm-sh64/io.h
--- linux-2.4.26/include/asm-sh64/io.h	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sh64/io.h	2004-05-18 16:52:18.000000000 +0000
@@ -107,6 +107,13 @@ void outl(unsigned long value, unsigned 
 
 #ifdef __KERNEL__
 
+#ifdef CONFIG_SH_CAYMAN
+extern unsigned long smsc_superio_virt;
+#endif
+#ifdef CONFIG_PCI
+extern unsigned long pciio_virt;
+#endif
+
 #define IO_SPACE_LIMIT 0xffffffff
 
 /*
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sh64/keyboard.h linux-2.4.27-pre3/include/asm-sh64/keyboard.h
--- linux-2.4.26/include/asm-sh64/keyboard.h	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sh64/keyboard.h	2004-05-18 16:52:26.000000000 +0000
@@ -19,7 +19,7 @@
 #include <asm/io.h>
 
 #ifdef CONFIG_SH_CAYMAN
-#define KEYBOARD_IRQ			(START_EXT_IRQS + 2) /* SMSC IRQ 1 */
+#define KEYBOARD_IRQ			(START_EXT_IRQS + 2) /* SMSC SuperIO IRQ 1 */
 #endif
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 
@@ -61,7 +61,7 @@ extern unsigned char pckbd_sysrq_xlate[1
  */
 
 #ifdef CONFIG_SH_CAYMAN
-#define AUX_IRQ (START_EXT_IRQS + 6) /* SMSC IRQ12 */
+#define AUX_IRQ (START_EXT_IRQS + 6) /* SMSC SuperIO IRQ12 */
 #endif
 
 #define aux_request_irq(hand, dev_id)					\
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sh64/processor.h linux-2.4.27-pre3/include/asm-sh64/processor.h
--- linux-2.4.26/include/asm-sh64/processor.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sh64/processor.h	2004-05-18 16:51:41.000000000 +0000
@@ -101,7 +101,7 @@ extern struct sh_cpuinfo boot_cpu_data;
  */
 #define SR_FD    0x00008000
 
-#ifdef ST_DEBUG
+#if defined(CONFIG_SH64_SR_WATCH)
 #define SR_MMU   0x84000000
 #else
 #define SR_MMU   0x80000000
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sh64/registers.h linux-2.4.27-pre3/include/asm-sh64/registers.h
--- linux-2.4.26/include/asm-sh64/registers.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sh64/registers.h	2004-05-18 16:51:39.000000000 +0000
@@ -115,7 +115,7 @@
 #define SR_HARMLESS	0x00000000500080f0	/* Write ignores for most */
 #define SR_ENABLE_FPU	0xffffffffffff7fff	/* AND with this */
 
-#ifdef ST_DEBUG
+#if defined (CONFIG_SH64_SR_WATCH)
 #define SR_ENABLE_MMU	0x0000000084000000	/* OR with this */
 #else
 #define SR_ENABLE_MMU	0x0000000080000000	/* OR with this */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sh64/unistd.h linux-2.4.27-pre3/include/asm-sh64/unistd.h
--- linux-2.4.26/include/asm-sh64/unistd.h	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sh64/unistd.h	2004-05-18 16:54:48.000000000 +0000
@@ -287,20 +287,31 @@ do { \
 type name(void) \
 { \
 register unsigned long __sc0 __asm__ ("r9") = ((0x10 << 16) | __NR_##name); \
-__asm__ __volatile__ ("trapa	%1" \
+__asm__ __volatile__ ("trapa	%1 !\t\t\t" #name "()"			    \
 	: "=r" (__sc0) 							    \
 	: "r" (__sc0) ); 						    \
 __syscall_return(type,__sc0); 						    \
 }
 
+	/*
+	 * The apparent spurious "dummy" assembler comment is *needed*,
+	 * as without it, the compiler treats the arg<n> variables
+	 * as no longer live just before the asm. The compiler can
+	 * then optimize the storage into any registers it wishes.
+	 * The additional dummy statement forces the compiler to put
+	 * the arguments into the correct registers before the TRAPA.
+	 */ 
 #define _syscall1(type,name,type1,arg1) \
 type name(type1 arg1) \
 { \
 register unsigned long __sc0 __asm__ ("r9") = ((0x11 << 16) | __NR_##name); \
 register unsigned long __sc2 __asm__ ("r2") = (unsigned long) arg1;	    \
-__asm__ __volatile__ ("trapa	%1" \
+__asm__ __volatile__ ("trapa	%1 !\t\t\t" #name "(%2)"		    \
 	: "=r" (__sc0) 							    \
 	: "r" (__sc0), "r" (__sc2));					    \
+__asm__ __volatile__ ("!dummy	%0 %1"				   	    \
+	:								    \
+	: "r" (__sc0), "r" (__sc2));					    \
 __syscall_return(type,__sc0); 						    \
 }
 
@@ -310,9 +321,12 @@ type name(type1 arg1,type2 arg2) \
 register unsigned long __sc0 __asm__ ("r9") = ((0x12 << 16) | __NR_##name); \
 register unsigned long __sc2 __asm__ ("r2") = (unsigned long) arg1;	    \
 register unsigned long __sc3 __asm__ ("r3") = (unsigned long) arg2;	    \
-__asm__ __volatile__ ("trapa	%1" \
+__asm__ __volatile__ ("trapa	%1 !\t\t\t" #name "(%2,%3)"		    \
 	: "=r" (__sc0) 							    \
 	: "r" (__sc0), "r" (__sc2), "r" (__sc3) );			    \
+__asm__ __volatile__ ("!dummy	%0 %1 %2"			   	    \
+	:								    \
+	: "r" (__sc0), "r" (__sc2), "r" (__sc3) );			    \
 __syscall_return(type,__sc0); 						    \
 }
 
@@ -323,9 +337,12 @@ register unsigned long __sc0 __asm__ ("r
 register unsigned long __sc2 __asm__ ("r2") = (unsigned long) arg1;	    \
 register unsigned long __sc3 __asm__ ("r3") = (unsigned long) arg2;	    \
 register unsigned long __sc4 __asm__ ("r4") = (unsigned long) arg3;	    \
-__asm__ __volatile__ ("trapa	%1" \
+__asm__ __volatile__ ("trapa	%1 !\t\t\t" #name "(%2,%3,%4)"		    \
 	: "=r" (__sc0) 							    \
 	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) );		    \
+__asm__ __volatile__ ("!dummy	%0 %1 %2 %3"			   	    \
+	:								    \
+	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) );	   	    \
 __syscall_return(type,__sc0); 						    \
 }
 
@@ -337,9 +354,12 @@ register unsigned long __sc2 __asm__ ("r
 register unsigned long __sc3 __asm__ ("r3") = (unsigned long) arg2;	    \
 register unsigned long __sc4 __asm__ ("r4") = (unsigned long) arg3;	    \
 register unsigned long __sc5 __asm__ ("r5") = (unsigned long) arg4;	    \
-__asm__ __volatile__ ("trapa	%1" \
+__asm__ __volatile__ ("trapa	%1 !\t\t\t" #name "(%2,%3,%4,%5)"	    \
 	: "=r" (__sc0) 							    \
 	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5) );\
+__asm__ __volatile__ ("!dummy	%0 %1 %2 %3 %4"			   	    \
+	:								    \
+	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5) );\
 __syscall_return(type,__sc0); 						    \
 }
 
@@ -352,9 +372,13 @@ register unsigned long __sc3 __asm__ ("r
 register unsigned long __sc4 __asm__ ("r4") = (unsigned long) arg3;	    \
 register unsigned long __sc5 __asm__ ("r5") = (unsigned long) arg4;	    \
 register unsigned long __sc6 __asm__ ("r6") = (unsigned long) arg5;	    \
-__asm__ __volatile__ ("trapa	%1" \
+__asm__ __volatile__ ("trapa	%1 !\t\t\t" #name "(%2,%3,%4,%5,%6)"	    \
 	: "=r" (__sc0) 							    \
-	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5), \
+	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5),  \
+	  "r" (__sc6));							    \
+__asm__ __volatile__ ("!dummy	%0 %1 %2 %3 %4 %5"		   	    \
+	:								    \
+	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5),  \
 	  "r" (__sc6));							    \
 __syscall_return(type,__sc0); 						    \
 }
@@ -369,9 +393,13 @@ register unsigned long __sc4 __asm__ ("r
 register unsigned long __sc5 __asm__ ("r5") = (unsigned long) arg4;	    \
 register unsigned long __sc6 __asm__ ("r6") = (unsigned long) arg5;	    \
 register unsigned long __sc7 __asm__ ("r7") = (unsigned long) arg6;	    \
-__asm__ __volatile__ ("trapa	%1" \
+__asm__ __volatile__ ("trapa	%1 !\t\t\t" #name "(%2,%3,%4,%5,%6,%7)"	    \
 	: "=r" (__sc0) 							    \
-	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5), \
+	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5),  \
+	  "r" (__sc6), "r" (__sc7));					    \
+__asm__ __volatile__ ("!dummy	%0 %1 %2 %3 %4 %5 %6"		   	    \
+	:								    \
+	: "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4), "r" (__sc5),  \
 	  "r" (__sc6), "r" (__sc7));					    \
 __syscall_return(type,__sc0); 						    \
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sparc64/mmu_context.h linux-2.4.27-pre3/include/asm-sparc64/mmu_context.h
--- linux-2.4.26/include/asm-sparc64/mmu_context.h	2001-08-28 14:09:44.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sparc64/mmu_context.h	2004-05-18 16:55:18.000000000 +0000
@@ -83,7 +83,8 @@ do { \
 	paddr = __pa((__mm)->pgd); \
 	pgd_cache = 0UL; \
 	if ((__tsk)->thread.flags & SPARC_FLAG_32BIT) \
-		pgd_cache = pgd_val((__mm)->pgd[0]) << 11UL; \
+		pgd_cache = \
+		   ((unsigned long)pgd_val((__mm)->pgd[0])) << 11UL; \
 	__asm__ __volatile__("wrpr	%%g0, 0x494, %%pstate\n\t" \
 			     "mov	%3, %%g4\n\t" \
 			     "mov	%0, %%g7\n\t" \
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sparc64/page.h linux-2.4.27-pre3/include/asm-sparc64/page.h
--- linux-2.4.26/include/asm-sparc64/page.h	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sparc64/page.h	2004-05-18 16:52:51.000000000 +0000
@@ -57,8 +57,8 @@ typedef struct { unsigned long iopgprot;
 
 #define pte_val(x)	((x).pte)
 #define iopte_val(x)	((x).iopte)
-#define pmd_val(x)      ((unsigned long)(x).pmd)
-#define pgd_val(x)	((unsigned long)(x).pgd)
+#define pmd_val(x)      ((x).pmd)
+#define pgd_val(x)	((x).pgd)
 #define ctxd_val(x)	((x).ctxd)
 #define pgprot_val(x)	((x).pgprot)
 #define iopgprot_val(x)	((x).iopgprot)
@@ -83,8 +83,8 @@ typedef unsigned long iopgprot_t;
 
 #define pte_val(x)	(x)
 #define iopte_val(x)	(x)
-#define pmd_val(x)      ((unsigned long)(x))
-#define pgd_val(x)	((unsigned long)(x))
+#define pmd_val(x)      (x)
+#define pgd_val(x)	(x)
 #define ctxd_val(x)	(x)
 #define pgprot_val(x)	(x)
 #define iopgprot_val(x)	(x)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sparc64/pgtable.h linux-2.4.27-pre3/include/asm-sparc64/pgtable.h
--- linux-2.4.26/include/asm-sparc64/pgtable.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sparc64/pgtable.h	2004-05-18 16:50:55.000000000 +0000
@@ -215,19 +215,21 @@ extern inline pte_t pte_modify(pte_t ori
 	(pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL))
 #define pgd_set(pgdp, pmdp)	\
 	(pgd_val(*(pgdp)) = (__pa((unsigned long) (pmdp)) >> 11UL))
-#define pmd_page(pmd)			((unsigned long) __va((pmd_val(pmd)<<11UL)))
-#define pgd_page(pgd)			((unsigned long) __va((pgd_val(pgd)<<11UL)))
+#define pmd_page(pmd)		\
+	((unsigned long) __va(((unsigned long)pmd_val(pmd))<<11UL))
+#define pgd_page(pgd)		\
+	((unsigned long) __va(((unsigned long)pgd_val(pgd))<<11UL))
 #define pte_none(pte) 			(!pte_val(pte))
 #define pte_present(pte)		(pte_val(pte) & _PAGE_PRESENT)
 #define pte_clear(pte)			(pte_val(*(pte)) = 0UL)
 #define pmd_none(pmd)			(!pmd_val(pmd))
 #define pmd_bad(pmd)			(0)
-#define pmd_present(pmd)		(pmd_val(pmd) != 0UL)
-#define pmd_clear(pmdp)			(pmd_val(*(pmdp)) = 0UL)
+#define pmd_present(pmd)		(pmd_val(pmd) != 0U)
+#define pmd_clear(pmdp)			(pmd_val(*(pmdp)) = 0U)
 #define pgd_none(pgd)			(!pgd_val(pgd))
 #define pgd_bad(pgd)			(0)
-#define pgd_present(pgd)		(pgd_val(pgd) != 0UL)
-#define pgd_clear(pgdp)			(pgd_val(*(pgdp)) = 0UL)
+#define pgd_present(pgd)		(pgd_val(pgd) != 0U)
+#define pgd_clear(pgdp)			(pgd_val(*(pgdp)) = 0U)
 
 /* The following only work if pte_present() is true.
  * Undefined behaviour if not..
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-sparc64/svr4.h linux-2.4.27-pre3/include/asm-sparc64/svr4.h
--- linux-2.4.26/include/asm-sparc64/svr4.h	1998-08-04 23:03:35.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-sparc64/svr4.h	2004-05-18 16:54:01.000000000 +0000
@@ -87,7 +87,7 @@ enum svr4_stack_flags {
 
 /* signal stack exection place, unsupported */
 typedef struct svr4_stack_t {
-        char *sp;
+        u32  sp;
         int  size;
         int  flags;
 } svr4_stack_t;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/asm-x86_64/acpi.h linux-2.4.27-pre3/include/asm-x86_64/acpi.h
--- linux-2.4.26/include/asm-x86_64/acpi.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/asm-x86_64/acpi.h	2004-05-18 16:54:04.000000000 +0000
@@ -91,39 +91,48 @@ __acpi_release_global_lock (unsigned int
         :"r"(d32),            \
         "0"(n_lo), "1"(n_hi))
 
-
 #define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \
     asm("shrl   $1,%2;"             \
         "rcrl   $1,%3;"             \
         :"=r"(n_hi), "=r"(n_lo)     \
         :"0"(n_hi), "1"(n_lo))
-
+#ifdef CONFIG_ACPI_PCI
+extern int acpi_noirq;
+extern int acpi_pci_disabled;
+static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
+static inline void acpi_disable_pci(void) 
+{
+	acpi_pci_disabled = 1; 
+	acpi_noirq_set();
+}
+extern int acpi_irq_balance_set(char *str);
+#else
+static inline void acpi_noirq_set(void) { }
+static inline void acpi_disable_pci(void) { acpi_noirq_set(); }
+static inline int acpi_irq_balance_set(char *str) { return 0; }
+#endif
 
 #ifdef CONFIG_ACPI_BOOT 
 extern int acpi_lapic;
 extern int acpi_ioapic;
-extern int acpi_noirq;
 extern int acpi_strict;
 extern int acpi_disabled;
 extern int acpi_ht;
-static inline void disable_acpi(void) { acpi_disabled = 1; acpi_ht = 0; }
+static inline void disable_acpi(void) 
+{ 
+	acpi_disabled = 1;
+	acpi_ht = 0;
+	acpi_disable_pci();
+}
 
 /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
 #define FIX_ACPI_PAGES 4
 
-#else	/* CONFIG_ACPI_BOOT */
-#  define acpi_lapic 0
-#  define acpi_ioapic 0
-
-#endif
+#else	/* !CONFIG_ACPI_BOOT */
+#define acpi_lapic 0
+#define acpi_ioapic 0
+#endif	/* !CONFIG_ACPI_BOOT */
 
-#ifdef CONFIG_ACPI_PCI
-static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
-extern int acpi_irq_balance_set(char *str);
-#else
-static inline void acpi_noirq_set(void) { }
-static inline int acpi_irq_balance_set(char *str) { return 0; }
-#endif
 
 #ifdef CONFIG_ACPI_SLEEP
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/acpi.h linux-2.4.27-pre3/include/linux/acpi.h
--- linux-2.4.26/include/linux/acpi.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/acpi.h	2004-05-18 16:50:48.000000000 +0000
@@ -319,6 +319,14 @@ struct acpi_table_ecdt {
 
 /* Table Handlers */
 
+/* PCI MMCONFIG */
+struct acpi_table_mcfg {
+	struct acpi_table_header	header;
+	u8				reserved[8];
+	u32				base_address;
+	u32				base_reserved;
+} __attribute__ ((packed));
+
 enum acpi_table_id {
 	ACPI_TABLE_UNKNOWN = 0,
 	ACPI_APIC,
@@ -338,6 +346,7 @@ enum acpi_table_id {
 	ACPI_SSDT,
 	ACPI_SPMI,
 	ACPI_HPET,
+	ACPI_MCFG,
 	ACPI_TABLE_COUNT
 };
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/ata.h linux-2.4.27-pre3/include/linux/ata.h
--- linux-2.4.26/include/linux/ata.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/ata.h	2004-05-18 16:51:36.000000000 +0000
@@ -0,0 +1,214 @@
+
+/*
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+ */
+
+#ifndef __LINUX_ATA_H__
+#define __LINUX_ATA_H__
+
+/* defines only for the constants which don't work well as enums */
+#define ATA_DMA_BOUNDARY	0xffffUL
+#define ATA_DMA_MASK		0xffffffffULL
+
+enum {
+	/* various global constants */
+	ATA_MAX_DEVICES		= 2,	/* per bus/port */
+	ATA_MAX_PRD		= 256,	/* we could make these 256/256 */
+	ATA_SECT_SIZE		= 512,
+	ATA_SECT_SIZE_MASK	= (ATA_SECT_SIZE - 1),
+	ATA_SECT_DWORDS		= ATA_SECT_SIZE / sizeof(u32),
+
+	ATA_ID_WORDS		= 256,
+	ATA_ID_PROD_OFS		= 27,
+	ATA_ID_SERNO_OFS	= 10,
+	ATA_ID_MAJOR_VER	= 80,
+	ATA_ID_PIO_MODES	= 64,
+	ATA_ID_UDMA_MODES	= 88,
+	ATA_ID_PIO4		= (1 << 1),
+
+	ATA_PCI_CTL_OFS		= 2,
+	ATA_SERNO_LEN		= 20,
+	ATA_UDMA0		= (1 << 0),
+	ATA_UDMA1		= ATA_UDMA0 | (1 << 1),
+	ATA_UDMA2		= ATA_UDMA1 | (1 << 2),
+	ATA_UDMA3		= ATA_UDMA2 | (1 << 3),
+	ATA_UDMA4		= ATA_UDMA3 | (1 << 4),
+	ATA_UDMA5		= ATA_UDMA4 | (1 << 5),
+	ATA_UDMA6		= ATA_UDMA5 | (1 << 6),
+	ATA_UDMA7		= ATA_UDMA6 | (1 << 7),
+	/* ATA_UDMA7 is just for completeness... doesn't exist (yet?).  */
+
+	ATA_UDMA_MASK_40C	= ATA_UDMA2,	/* udma0-2 */
+
+	/* DMA-related */
+	ATA_PRD_SZ		= 8,
+	ATA_PRD_TBL_SZ		= (ATA_MAX_PRD * ATA_PRD_SZ),
+	ATA_PRD_EOT		= (1 << 31),	/* end-of-table flag */
+
+	ATA_DMA_TABLE_OFS	= 4,
+	ATA_DMA_STATUS		= 2,
+	ATA_DMA_CMD		= 0,
+	ATA_DMA_WR		= (1 << 3),
+	ATA_DMA_START		= (1 << 0),
+	ATA_DMA_INTR		= (1 << 2),
+	ATA_DMA_ERR		= (1 << 1),
+	ATA_DMA_ACTIVE		= (1 << 0),
+
+	/* bits in ATA command block registers */
+	ATA_HOB			= (1 << 7),	/* LBA48 selector */
+	ATA_NIEN		= (1 << 1),	/* disable-irq flag */
+	ATA_LBA			= (1 << 6),	/* LBA28 selector */
+	ATA_DEV1		= (1 << 4),	/* Select Device 1 (slave) */
+	ATA_BUSY		= (1 << 7),	/* BSY status bit */
+	ATA_DEVICE_OBS		= (1 << 7) | (1 << 5), /* obs bits in dev reg */
+	ATA_DEVCTL_OBS		= (1 << 3),	/* obsolete bit in devctl reg */
+	ATA_DRQ			= (1 << 3),	/* data request i/o */
+	ATA_ERR			= (1 << 0),	/* have an error */
+	ATA_SRST		= (1 << 2),	/* software reset */
+	ATA_ABORTED		= (1 << 2),	/* command aborted */
+
+	/* ATA command block registers */
+	ATA_REG_DATA		= 0x00,
+	ATA_REG_ERR		= 0x01,
+	ATA_REG_NSECT		= 0x02,
+	ATA_REG_LBAL		= 0x03,
+	ATA_REG_LBAM		= 0x04,
+	ATA_REG_LBAH		= 0x05,
+	ATA_REG_DEVICE		= 0x06,
+	ATA_REG_STATUS		= 0x07,
+
+	ATA_REG_FEATURE		= ATA_REG_ERR, /* and their aliases */
+	ATA_REG_CMD		= ATA_REG_STATUS,
+	ATA_REG_BYTEL		= ATA_REG_LBAM,
+	ATA_REG_BYTEH		= ATA_REG_LBAH,
+	ATA_REG_DEVSEL		= ATA_REG_DEVICE,
+	ATA_REG_IRQ		= ATA_REG_NSECT,
+
+	/* ATA device commands */
+	ATA_CMD_EDD		= 0x90,	/* execute device diagnostic */
+	ATA_CMD_FLUSH		= 0xE7,
+	ATA_CMD_FLUSH_EXT	= 0xEA,
+	ATA_CMD_ID_ATA		= 0xEC,
+	ATA_CMD_ID_ATAPI	= 0xA1,
+	ATA_CMD_READ		= 0xC8,
+	ATA_CMD_READ_EXT	= 0x25,
+	ATA_CMD_WRITE		= 0xCA,
+	ATA_CMD_WRITE_EXT	= 0x35,
+	ATA_CMD_PIO_READ	= 0x20,
+	ATA_CMD_PIO_READ_EXT	= 0x24,
+	ATA_CMD_PIO_WRITE	= 0x30,
+	ATA_CMD_PIO_WRITE_EXT	= 0x34,
+	ATA_CMD_SET_FEATURES	= 0xEF,
+	ATA_CMD_PACKET		= 0xA0,
+
+	/* SETFEATURES stuff */
+	SETFEATURES_XFER	= 0x03,
+	XFER_UDMA_7		= 0x47,
+	XFER_UDMA_6		= 0x46,
+	XFER_UDMA_5		= 0x45,
+	XFER_UDMA_4		= 0x44,
+	XFER_UDMA_3		= 0x43,
+	XFER_UDMA_2		= 0x42,
+	XFER_UDMA_1		= 0x41,
+	XFER_UDMA_0		= 0x40,
+	XFER_PIO_4		= 0x0C,
+	XFER_PIO_3		= 0x0B,
+
+	/* ATAPI stuff */
+	ATAPI_PKT_DMA		= (1 << 0),
+
+	/* cable types */
+	ATA_CBL_NONE		= 0,
+	ATA_CBL_PATA40		= 1,
+	ATA_CBL_PATA80		= 2,
+	ATA_CBL_PATA_UNK	= 3,
+	ATA_CBL_SATA		= 4,
+
+	/* SATA Status and Control Registers */
+	SCR_STATUS		= 0,
+	SCR_ERROR		= 1,
+	SCR_CONTROL		= 2,
+	SCR_ACTIVE		= 3,
+	SCR_NOTIFICATION	= 4,
+
+	/* struct ata_taskfile flags */
+	ATA_TFLAG_LBA48		= (1 << 0), /* enable 48-bit LBA and "HOB" */
+	ATA_TFLAG_ISADDR	= (1 << 1), /* enable r/w to nsect/lba regs */
+	ATA_TFLAG_DEVICE	= (1 << 2), /* enable r/w to device reg */
+	ATA_TFLAG_WRITE		= (1 << 3), /* data dir: host->dev==1 (write) */
+};
+
+enum ata_tf_protocols {
+	/* ATA taskfile protocols */
+	ATA_PROT_UNKNOWN,	/* unknown/invalid */
+	ATA_PROT_NODATA,	/* no data */
+	ATA_PROT_PIO,		/* PIO single sector */
+	ATA_PROT_PIO_MULT,	/* PIO multiple sector */
+	ATA_PROT_DMA,		/* DMA */
+	ATA_PROT_ATAPI,		/* packet command */
+	ATA_PROT_ATAPI_DMA,	/* packet command with special DMA sauce */
+};
+
+/* core structures */
+
+struct ata_prd {
+	u32			addr;
+	u32			flags_len;
+} __attribute__((packed));
+
+struct ata_taskfile {
+	unsigned long		flags;		/* ATA_TFLAG_xxx */
+	u8			protocol;	/* ATA_PROT_xxx */
+
+	u8			ctl;		/* control reg */
+
+	u8			hob_feature;	/* additional data */
+	u8			hob_nsect;	/* to support LBA48 */
+	u8			hob_lbal;
+	u8			hob_lbam;
+	u8			hob_lbah;
+
+	u8			feature;
+	u8			nsect;
+	u8			lbal;
+	u8			lbam;
+	u8			lbah;
+
+	u8			device;
+
+	u8			command;	/* IO operation */
+};
+
+#define ata_id_is_ata(dev)	(((dev)->id[0] & (1 << 15)) == 0)
+#define ata_id_wcache_enabled(dev) ((dev)->id[85] & (1 << 5))
+#define ata_id_has_lba48(dev)	((dev)->id[83] & (1 << 10))
+#define ata_id_has_wcache(dev)	((dev)->id[82] & (1 << 5))
+#define ata_id_has_lba(dev)	((dev)->id[49] & (1 << 8))
+#define ata_id_has_dma(dev)	((dev)->id[49] & (1 << 9))
+#define ata_id_u32(dev,n)	\
+	(((u32) (dev)->id[(n) + 1] << 16) | ((u32) (dev)->id[(n)]))
+#define ata_id_u64(dev,n)	\
+	( ((u64) dev->id[(n) + 3] << 48) |	\
+	  ((u64) dev->id[(n) + 2] << 32) |	\
+	  ((u64) dev->id[(n) + 1] << 16) |	\
+	  ((u64) dev->id[(n) + 0]) )
+
+#endif /* __LINUX_ATA_H__ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/atmdev.h linux-2.4.27-pre3/include/linux/atmdev.h
--- linux-2.4.26/include/linux/atmdev.h	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/atmdev.h	2004-05-18 16:54:41.000000000 +0000
@@ -411,9 +411,9 @@ void vcc_remove_socket(struct sock *sk);
  *
  */
 
-static inline int atm_guess_pdu2truesize(int pdu_size)
+static inline int atm_guess_pdu2truesize(int size)
 {
-	return ((pdu_size+15) & ~15) + sizeof(struct sk_buff);
+	return (SKB_DATA_ALIGN(size) + sizeof(struct skb_shared_info));
 }
 
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/compiler.h linux-2.4.27-pre3/include/linux/compiler.h
--- linux-2.4.26/include/linux/compiler.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/compiler.h	2004-05-18 16:53:55.000000000 +0000
@@ -14,7 +14,7 @@
 #define unlikely(x)	__builtin_expect((x),0)
 
 #if __GNUC__ > 3
-#define __attribute_used__	__attribute((__used__))
+#define __attribute_used__	__attribute__((__used__))
 #elif __GNUC__ == 3
 #if  __GNUC_MINOR__ >= 3
 # define __attribute_used__	__attribute__((__used__))
@@ -27,4 +27,15 @@
 #define __attribute_used__	/* not implemented */
 #endif /* __GNUC__ */
 
+#if __GNUC__ == 3
+#if __GNUC_MINOR__ >= 1
+# define inline         __inline__ __attribute__((always_inline))
+# define __inline__     __inline__ __attribute__((always_inline))
+# define __inline       __inline__ __attribute__((always_inline))
+#endif
+#endif
+
+/* no checker support, so we unconditionally define this as (null) */
+#define __user
+
 #endif /* __LINUX_COMPILER_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/crypto.h linux-2.4.27-pre3/include/linux/crypto.h
--- linux-2.4.26/include/linux/crypto.h	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/crypto.h	2004-05-18 16:52:30.000000000 +0000
@@ -22,6 +22,7 @@
 #include <linux/list.h>
 #include <linux/string.h>
 #include <asm/page.h>
+#include <asm/errno.h>
 
 /*
  * Algorithm masks and types.
@@ -76,6 +77,8 @@ struct digest_alg {
 	void (*dia_init)(void *ctx);
 	void (*dia_update)(void *ctx, const u8 *data, unsigned int len);
 	void (*dia_final)(void *ctx, u8 *out);
+	int (*dia_setkey)(void *ctx, const u8 *key,
+	                  unsigned int keylen, u32 *flags);
 };
 
 struct compress_alg {
@@ -157,6 +160,8 @@ struct digest_tfm {
 	void (*dit_final)(struct crypto_tfm *tfm, u8 *out);
 	void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg,
 	                   unsigned int nsg, u8 *out);
+	int (*dit_setkey)(struct crypto_tfm *tfm,
+	                  const u8 *key, unsigned int keylen);
 #ifdef CONFIG_CRYPTO_HMAC
 	void *dit_hmac_block;
 #endif
@@ -287,6 +292,15 @@ static inline void crypto_digest_digest(
 	tfm->crt_digest.dit_digest(tfm, sg, nsg, out);
 }
 
+static inline int crypto_digest_setkey(struct crypto_tfm *tfm,
+                                       const u8 *key, unsigned int keylen)
+{
+	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
+	if (tfm->crt_digest.dit_setkey == NULL)
+		return -ENOSYS;
+	return tfm->crt_digest.dit_setkey(tfm, key, keylen);
+}
+
 static inline int crypto_cipher_setkey(struct crypto_tfm *tfm,
                                        const u8 *key, unsigned int keylen)
 {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/icmpv6.h linux-2.4.27-pre3/include/linux/icmpv6.h
--- linux-2.4.26/include/linux/icmpv6.h	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/icmpv6.h	2004-05-18 16:52:03.000000000 +0000
@@ -95,8 +95,7 @@ struct icmp6hdr {
 #define MLD2_ALLOW_NEW_SOURCES	5
 #define MLD2_BLOCK_OLD_SOURCES	6
 
-/* this must be an IANA-assigned value; 206 for testing only */
-#define ICMPV6_MLD2_REPORT		206
+#define ICMPV6_MLD2_REPORT		143
 #define MLD2_ALL_MCR_INIT { { { 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,0x16 } } }
 
 /*
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/kernel.h linux-2.4.27-pre3/include/linux/kernel.h
--- linux-2.4.26/include/linux/kernel.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/kernel.h	2004-05-18 16:50:48.000000000 +0000
@@ -196,4 +196,11 @@ struct sysinfo {
 
 #define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
 
+#define WARN_ON(condition) do { \
+	if (unlikely((condition)!=0)) { \
+		printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
+		dump_stack(); \
+	} \
+} while (0)
+
 #endif /* _LINUX_KERNEL_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/libata.h linux-2.4.27-pre3/include/linux/libata.h
--- linux-2.4.26/include/linux/libata.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/libata.h	2004-05-18 16:54:30.000000000 +0000
@@ -0,0 +1,558 @@
+/*
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+ */
+
+#ifndef __LINUX_LIBATA_H__
+#define __LINUX_LIBATA_H__
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <linux/ata.h>
+#include <linux/tqueue.h>
+
+/*
+ * compile-time options
+ */
+#undef ATA_FORCE_PIO		/* do not configure or use DMA */
+#undef ATA_DEBUG		/* debugging output */
+#undef ATA_VERBOSE_DEBUG	/* yet more debugging output */
+#undef ATA_IRQ_TRAP		/* define to ack screaming irqs */
+#undef ATA_NDEBUG		/* define to disable quick runtime checks */
+#undef ATA_ENABLE_ATAPI		/* define to enable ATAPI support */
+#undef ATA_ENABLE_PATA		/* define to enable PATA support in some
+				 * low-level drivers */
+
+
+/* note: prints function name for you */
+#ifdef ATA_DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#ifdef ATA_VERBOSE_DEBUG
+#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define VPRINTK(fmt, args...)
+#endif	/* ATA_VERBOSE_DEBUG */
+#else
+#define DPRINTK(fmt, args...)
+#define VPRINTK(fmt, args...)
+#endif	/* ATA_DEBUG */
+
+#ifdef ATA_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+        if(unlikely(!(expr))) {                                   \
+        printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
+        #expr,__FILE__,__FUNCTION__,__LINE__);          \
+        }
+#endif
+
+/* defines only for the constants which don't work well as enums */
+#define ATA_TAG_POISON		0xfafbfcfdU
+
+enum {
+	/* various global constants */
+	LIBATA_MAX_PRD		= ATA_MAX_PRD / 2,
+	ATA_MAX_PORTS		= 8,
+	ATA_DEF_QUEUE		= 1,
+	ATA_MAX_QUEUE		= 1,
+	ATA_MAX_SECTORS		= 200,	/* FIXME */
+	ATA_MAX_BUS		= 2,
+	ATA_DEF_BUSY_WAIT	= 10000,
+	ATA_SHORT_PAUSE		= (HZ >> 6) + 1,
+
+	ATA_SHT_EMULATED	= 1,
+	ATA_SHT_NEW_EH_CODE	= 0, /* IORL hack, part one */
+	ATA_SHT_CMD_PER_LUN	= 1,
+	ATA_SHT_THIS_ID		= -1,
+	ATA_SHT_USE_CLUSTERING	= 0,
+
+	/* struct ata_device stuff */
+	ATA_DFLAG_LBA48		= (1 << 0), /* device supports LBA48 */
+	ATA_DFLAG_PIO		= (1 << 1), /* device currently in PIO mode */
+	ATA_DFLAG_MASTER	= (1 << 2), /* is device 0? */
+	ATA_DFLAG_WCACHE	= (1 << 3), /* has write cache we can
+					     * (hopefully) flush? */
+
+	ATA_DEV_UNKNOWN		= 0,	/* unknown device */
+	ATA_DEV_ATA		= 1,	/* ATA device */
+	ATA_DEV_ATA_UNSUP	= 2,	/* ATA device (unsupported) */
+	ATA_DEV_ATAPI		= 3,	/* ATAPI device */
+	ATA_DEV_ATAPI_UNSUP	= 4,	/* ATAPI device (unsupported) */
+	ATA_DEV_NONE		= 5,	/* no device */
+
+	/* struct ata_port flags */
+	ATA_FLAG_SLAVE_POSS	= (1 << 1), /* host supports slave dev */
+					    /* (doesn't imply presence) */
+	ATA_FLAG_PORT_DISABLED	= (1 << 2), /* port is disabled, ignore it */
+	ATA_FLAG_SATA		= (1 << 3),
+	ATA_FLAG_NO_LEGACY	= (1 << 4), /* no legacy mode check */
+	ATA_FLAG_SRST		= (1 << 5), /* use ATA SRST, not E.D.D. */
+	ATA_FLAG_MMIO		= (1 << 6), /* use MMIO, not PIO */
+	ATA_FLAG_SATA_RESET	= (1 << 7), /* use COMRESET */
+
+	ATA_QCFLAG_ACTIVE	= (1 << 1), /* cmd not yet ack'd to scsi lyer */
+	ATA_QCFLAG_DMA		= (1 << 2), /* data delivered via DMA */
+	ATA_QCFLAG_ATAPI	= (1 << 3), /* is ATAPI packet command? */
+	ATA_QCFLAG_SG		= (1 << 4), /* have s/g table? */
+	ATA_QCFLAG_POLL		= (1 << 5), /* polling, no interrupts */
+
+	/* various lengths of time */
+	ATA_TMOUT_EDD		= 5 * HZ,	/* hueristic */
+	ATA_TMOUT_PIO		= 30 * HZ,
+	ATA_TMOUT_BOOT		= 30 * HZ,	/* hueristic */
+	ATA_TMOUT_BOOT_QUICK	= 7 * HZ,	/* hueristic */
+	ATA_TMOUT_CDB		= 30 * HZ,
+	ATA_TMOUT_CDB_QUICK	= 5 * HZ,
+
+	/* ATA bus states */
+	BUS_UNKNOWN		= 0,
+	BUS_DMA			= 1,
+	BUS_IDLE		= 2,
+	BUS_NOINTR		= 3,
+	BUS_NODATA		= 4,
+	BUS_TIMER		= 5,
+	BUS_PIO			= 6,
+	BUS_EDD			= 7,
+	BUS_IDENTIFY		= 8,
+	BUS_PACKET		= 9,
+
+	/* thread states */
+	THR_UNKNOWN		= 0,
+	THR_PORT_RESET		= (THR_UNKNOWN + 1),
+	THR_AWAIT_DEATH		= (THR_PORT_RESET + 1),
+	THR_PROBE_FAILED	= (THR_AWAIT_DEATH + 1),
+	THR_IDLE		= (THR_PROBE_FAILED + 1),
+	THR_PROBE_SUCCESS	= (THR_IDLE + 1),
+	THR_PROBE_START		= (THR_PROBE_SUCCESS + 1),
+
+	/* SATA port states */
+	PORT_UNKNOWN		= 0,
+	PORT_ENABLED		= 1,
+	PORT_DISABLED		= 2,
+
+	/* ata_qc_cb_t flags - note uses above ATA_QCFLAG_xxx namespace,
+	 * but not numberspace
+	 */
+	ATA_QCFLAG_TIMEOUT	= (1 << 0),
+};
+
+enum pio_task_states {
+	PIO_ST_UNKNOWN,
+	PIO_ST_IDLE,
+	PIO_ST_POLL,
+	PIO_ST_TMOUT,
+	PIO_ST,
+	PIO_ST_LAST,
+	PIO_ST_LAST_POLL,
+	PIO_ST_ERR,
+};
+
+/* forward declarations */
+struct ata_port_operations;
+struct ata_port;
+struct ata_queued_cmd;
+
+/* typedefs */
+typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc, unsigned int flags);
+
+struct ata_ioports {
+	unsigned long		cmd_addr;
+	unsigned long		data_addr;
+	unsigned long		error_addr;
+	unsigned long		feature_addr;
+	unsigned long		nsect_addr;
+	unsigned long		lbal_addr;
+	unsigned long		lbam_addr;
+	unsigned long		lbah_addr;
+	unsigned long		device_addr;
+	unsigned long		status_addr;
+	unsigned long		command_addr;
+	unsigned long		altstatus_addr;
+	unsigned long		ctl_addr;
+	unsigned long		bmdma_addr;
+	unsigned long		scr_addr;
+};
+
+struct ata_probe_ent {
+	struct list_head	node;
+	struct pci_dev		*pdev;
+	struct ata_port_operations	*port_ops;
+	Scsi_Host_Template	*sht;
+	struct ata_ioports	port[ATA_MAX_PORTS];
+	unsigned int		n_ports;
+	unsigned int		pio_mask;
+	unsigned int		udma_mask;
+	unsigned int		legacy_mode;
+	unsigned long		irq;
+	unsigned int		irq_flags;
+	unsigned long		host_flags;
+	void			*mmio_base;
+	void			*private_data;
+};
+
+struct ata_host_set {
+	spinlock_t		lock;
+	struct pci_dev		*pdev;
+	unsigned long		irq;
+	void			*mmio_base;
+	unsigned int		n_ports;
+	void			*private_data;
+	struct ata_port *	ports[0];
+};
+
+struct ata_queued_cmd {
+	struct ata_port		*ap;
+	struct ata_device	*dev;
+
+	struct scsi_cmnd	*scsicmd;
+	void			(*scsidone)(struct scsi_cmnd *);
+
+	unsigned long		flags;		/* ATA_QCFLAG_xxx */
+	unsigned int		tag;
+	unsigned int		n_elem;
+	unsigned int		nsect;
+	unsigned int		cursect;
+	unsigned int		cursg;
+	unsigned int		cursg_ofs;
+	struct ata_taskfile	tf;
+	struct scatterlist	sgent;
+
+	struct scatterlist	*sg;
+
+	ata_qc_cb_t		callback;
+
+	struct completion	*waiting;
+
+	void			*private_data;
+};
+
+struct ata_host_stats {
+	unsigned long		unhandled_irq;
+	unsigned long		idle_irq;
+	unsigned long		rw_reqbuf;
+};
+
+struct ata_device {
+	u64			n_sectors;	/* size of device, if ATA */
+	unsigned long		flags;		/* ATA_DFLAG_xxx */
+	unsigned int		class;		/* ATA_DEV_xxx */
+	unsigned int		devno;		/* 0 or 1 */
+	u16			id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+	unsigned int		pio_mode;
+	unsigned int		udma_mode;
+
+	unsigned char		vendor[8];	/* space-padded, not ASCIIZ */
+	unsigned char		product[32];	/* WARNING: shorter than
+						 * ATAPI7 spec size, 40 ASCII
+						 * characters
+						 */
+
+	/* cache info about current transfer mode */
+	u8			xfer_protocol;	/* taskfile xfer protocol */
+	u8			read_cmd;	/* opcode to use on read */
+	u8			write_cmd;	/* opcode to use on write */
+};
+
+struct ata_port {
+	struct Scsi_Host	*host;	/* our co-allocated scsi host */
+	struct ata_port_operations	*ops;
+	unsigned long		flags;	/* ATA_FLAG_xxx */
+	unsigned int		id;	/* unique id req'd by scsi midlyr */
+	unsigned int		port_no; /* unique port #; from zero */
+
+	struct ata_prd		*prd;	 /* our SG list */
+	dma_addr_t		prd_dma; /* and its DMA mapping */
+
+	struct ata_ioports	ioaddr;	/* ATA cmd/ctl/dma register blocks */
+
+	u8			ctl;	/* cache of ATA control register */
+	u8			last_ctl;	/* Cache last written value */
+	unsigned int		bus_state;
+	unsigned int		port_state;
+	unsigned int		pio_mask;
+	unsigned int		udma_mask;
+	unsigned int		cbl;	/* cable type; ATA_CBL_xxx */
+
+	struct ata_device	device[ATA_MAX_DEVICES];
+
+	struct ata_queued_cmd	qcmd[ATA_MAX_QUEUE];
+	unsigned long		qactive;
+	unsigned int		active_tag;
+
+	struct ata_host_stats	stats;
+	struct ata_host_set	*host_set;
+
+	struct semaphore	probe_sem;
+
+	unsigned int		thr_state;
+
+	struct tq_struct	packet_task;
+
+	struct tq_struct	pio_task;
+	unsigned int		pio_task_state;
+	unsigned long		pio_task_timeout;
+
+	struct tq_struct	probe_task;
+
+	void			*private_data;
+};
+
+struct ata_port_operations {
+	void (*port_disable) (struct ata_port *);
+
+	void (*dev_config) (struct ata_port *, struct ata_device *);
+
+	void (*set_piomode) (struct ata_port *, struct ata_device *,
+			     unsigned int);
+	void (*set_udmamode) (struct ata_port *, struct ata_device *,
+			     unsigned int);
+
+	void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
+	void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
+
+	void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
+	u8   (*check_status)(struct ata_port *ap);
+
+	void (*phy_reset) (struct ata_port *ap);
+	void (*post_set_mode) (struct ata_port *ap);
+
+	void (*bmdma_start) (struct ata_queued_cmd *qc);
+	void (*fill_sg) (struct ata_queued_cmd *qc);
+	void (*eng_timeout) (struct ata_port *ap);
+
+	irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
+
+	u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
+	void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
+			   u32 val);
+
+	int (*port_start) (struct ata_port *ap);
+	void (*port_stop) (struct ata_port *ap);
+
+	void (*host_stop) (struct ata_host_set *host_set);
+};
+
+struct ata_port_info {
+	Scsi_Host_Template	*sht;
+	unsigned long		host_flags;
+	unsigned long		pio_mask;
+	unsigned long		udma_mask;
+	struct ata_port_operations	*port_ops;
+};
+
+struct pci_bits {
+	unsigned int		reg;	/* PCI config register to read */
+	unsigned int		width;	/* 1 (8 bit), 2 (16 bit), 4 (32 bit) */
+	unsigned long		mask;
+	unsigned long		val;
+};
+
+extern void ata_port_probe(struct ata_port *);
+extern void sata_phy_reset(struct ata_port *ap);
+extern void ata_bus_reset(struct ata_port *ap);
+extern void ata_port_disable(struct ata_port *);
+extern void ata_std_ports(struct ata_ioports *ioaddr);
+extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
+			     unsigned int n_ports);
+extern void ata_pci_remove_one (struct pci_dev *pdev);
+extern int ata_device_add(struct ata_probe_ent *ent);
+extern int ata_scsi_detect(Scsi_Host_Template *sht);
+extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+extern int ata_scsi_error(struct Scsi_Host *host);
+extern int ata_scsi_release(struct Scsi_Host *host);
+extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+/*
+ * Default driver ops implementations
+ */
+extern void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf);
+extern void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+extern void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf);
+extern void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+extern void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp);
+extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf);
+extern u8 ata_check_status_pio(struct ata_port *ap);
+extern u8 ata_check_status_mmio(struct ata_port *ap);
+extern void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf);
+extern void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+extern int ata_port_start (struct ata_port *ap);
+extern void ata_port_stop (struct ata_port *ap);
+extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+extern void ata_fill_sg(struct ata_queued_cmd *qc);
+extern void ata_bmdma_start_mmio (struct ata_queued_cmd *qc);
+extern void ata_bmdma_start_pio (struct ata_queued_cmd *qc);
+extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits);
+extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat, unsigned int done_late);
+extern void ata_eng_timeout(struct ata_port *ap);
+extern void ata_add_to_probe_list (struct ata_probe_ent *probe_ent);
+extern int ata_std_bios_param(Disk * disk, kdev_t dev, int *ip);
+
+
+static inline unsigned long msecs_to_jiffies(unsigned long msecs)
+{
+	return ((HZ * msecs + 999) / 1000);
+}
+
+static inline unsigned int ata_tag_valid(unsigned int tag)
+{
+	return (tag < ATA_MAX_QUEUE) ? 1 : 0;
+}
+
+static inline unsigned int ata_dev_present(struct ata_device *dev)
+{
+	return ((dev->class == ATA_DEV_ATA) ||
+		(dev->class == ATA_DEV_ATAPI));
+}
+
+static inline u8 ata_chk_err(struct ata_port *ap)
+{
+	if (ap->flags & ATA_FLAG_MMIO) {
+		return readb((void *) ap->ioaddr.error_addr);
+	}
+	return inb(ap->ioaddr.error_addr);
+}
+
+static inline u8 ata_chk_status(struct ata_port *ap)
+{
+	return ap->ops->check_status(ap);
+}
+
+static inline u8 ata_altstatus(struct ata_port *ap)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		return readb(ap->ioaddr.altstatus_addr);
+	return inb(ap->ioaddr.altstatus_addr);
+}
+
+static inline void ata_pause(struct ata_port *ap)
+{
+	ata_altstatus(ap);
+	ndelay(400);
+}
+
+static inline u8 ata_busy_wait(struct ata_port *ap, unsigned int bits,
+			       unsigned int max)
+{
+	u8 status;
+
+	do {
+		udelay(10);
+		status = ata_chk_status(ap);
+		max--;
+	} while ((status & bits) && (max > 0));
+
+	return status;
+}
+
+static inline u8 ata_wait_idle(struct ata_port *ap)
+{
+	u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+	if (status & (ATA_BUSY | ATA_DRQ)) {
+		unsigned long l = ap->ioaddr.status_addr;
+		printk(KERN_WARNING
+		       "ATA: abnormal status 0x%X on port 0x%lX\n",
+		       status, l);
+	}
+
+	return status;
+}
+
+static inline struct ata_queued_cmd *ata_qc_from_tag (struct ata_port *ap,
+						      unsigned int tag)
+{
+	if (likely(ata_tag_valid(tag)))
+		return &ap->qcmd[tag];
+	return NULL;
+}
+
+static inline void ata_tf_init(struct ata_port *ap, struct ata_taskfile *tf, unsigned int device)
+{
+	memset(tf, 0, sizeof(*tf));
+
+	tf->ctl = ap->ctl;
+	if (device == 0)
+		tf->device = ATA_DEVICE_OBS;
+	else
+		tf->device = ATA_DEVICE_OBS | ATA_DEV1;
+}
+
+static inline u8 ata_irq_on(struct ata_port *ap)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	ap->ctl &= ~ATA_NIEN;
+	ap->last_ctl = ap->ctl;
+
+	if (ap->flags & ATA_FLAG_MMIO)
+		writeb(ap->ctl, ioaddr->ctl_addr);
+	else
+		outb(ap->ctl, ioaddr->ctl_addr);
+	return ata_wait_idle(ap);
+}
+
+static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+{
+	unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+	u8 host_stat, post_stat, status;
+
+	status = ata_busy_wait(ap, bits, 1000);
+	if (status & bits)
+		DPRINTK("abnormal status 0x%X\n", status);
+
+	/* get controller status; clear intr, err bits */
+	if (ap->flags & ATA_FLAG_MMIO) {
+		void *mmio = (void *) ap->ioaddr.bmdma_addr;
+		host_stat = readb(mmio + ATA_DMA_STATUS);
+		writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+		       mmio + ATA_DMA_STATUS);
+
+		post_stat = readb(mmio + ATA_DMA_STATUS);
+	} else {
+		host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+		outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+		     ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+
+		post_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+	}
+
+	VPRINTK("irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
+		host_stat, post_stat, status);
+
+	return status;
+}
+
+static inline u32 scr_read(struct ata_port *ap, unsigned int reg)
+{
+	return ap->ops->scr_read(ap, reg);
+}
+
+static inline void scr_write(struct ata_port *ap, unsigned int reg, u32 val)
+{
+	ap->ops->scr_write(ap, reg, val);
+}
+
+static inline unsigned int sata_dev_present(struct ata_port *ap)
+{
+	return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0;
+}
+
+#endif /* __LINUX_LIBATA_H__ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/module.h linux-2.4.27-pre3/include/linux/module.h
--- linux-2.4.26/include/linux/module.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/module.h	2004-05-18 16:54:32.000000000 +0000
@@ -8,6 +8,7 @@
 #define _LINUX_MODULE_H
 
 #include <linux/config.h>
+#include <linux/compiler.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
 
@@ -284,7 +285,7 @@ static const struct gtype##_id * __modul
  */
  
 #define MODULE_LICENSE(license) 	\
-static const char __module_license[] __attribute__((section(".modinfo"))) =   \
+static const char __module_license[] __attribute_used__ __attribute__((section(".modinfo"))) =   \
 "license=" license
 
 /* Define the module variable, and usage macros.  */
@@ -296,10 +297,10 @@ extern struct module __this_module;
 #define MOD_IN_USE		__MOD_IN_USE(THIS_MODULE)
 
 #include <linux/version.h>
-static const char __module_kernel_version[] __attribute__((section(".modinfo"))) =
+static const char __module_kernel_version[] __attribute_used__ __attribute__((section(".modinfo"))) =
 "kernel_version=" UTS_RELEASE;
 #ifdef MODVERSIONS
-static const char __module_using_checksums[] __attribute__((section(".modinfo"))) =
+static const char __module_using_checksums[] __attribute_used__ __attribute__((section(".modinfo"))) =
 "using_checksums=1";
 #endif
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/netdevice.h linux-2.4.27-pre3/include/linux/netdevice.h
--- linux-2.4.26/include/linux/netdevice.h	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/netdevice.h	2004-05-18 16:55:09.000000000 +0000
@@ -43,13 +43,14 @@ struct divert_blk;
 struct vlan_group;
 struct ethtool_ops;
 
-					/* source back-compat hook */
+					/* source back-compat hooks */
 #define SET_ETHTOOL_OPS(netdev,ops) \
 	( (netdev)->ethtool_ops = (ops) )
 
 #define HAVE_ALLOC_NETDEV		/* feature macro: alloc_xxxdev
 					   functions are available. */
-#define HAVE_FREE_NETDEV
+#define HAVE_FREE_NETDEV		/* free_netdev() */
+#define HAVE_NETDEV_PRIV		/* netdev_priv() */
 
 #define NET_XMIT_SUCCESS	0
 #define NET_XMIT_DROP		1	/* skb dropped			*/
@@ -467,6 +468,10 @@ struct packet_type 
 	struct packet_type	*next;
 };
 
+static inline void *netdev_priv(struct net_device *dev)
+{
+	return dev->priv;
+}
 
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
@@ -732,6 +737,17 @@ enum {
 #define netif_msg_hw(p)		((p)->msg_enable & NETIF_MSG_HW)
 #define netif_msg_wol(p)	((p)->msg_enable & NETIF_MSG_WOL)
 
+static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits)
+{
+	/* use default */
+	if (debug_value < 0 || debug_value >= (sizeof(u32) * 8))
+		return default_msg_enable_bits;
+	if (debug_value == 0)	/* no output */
+		return 0;
+	/* set low N bits */
+	return (1 << debug_value) - 1;
+}
+
 /* Schedule rx intr now? */
 
 static inline int netif_rx_schedule_prep(struct net_device *dev)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/netfilter_ipv4/ip_conntrack_tftp.h linux-2.4.27-pre3/include/linux/netfilter_ipv4/ip_conntrack_tftp.h
--- linux-2.4.26/include/linux/netfilter_ipv4/ip_conntrack_tftp.h	2003-06-13 14:51:38.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/netfilter_ipv4/ip_conntrack_tftp.h	2004-05-18 16:52:34.000000000 +0000
@@ -9,5 +9,8 @@ struct tftphdr {
 
 #define TFTP_OPCODE_READ	1
 #define TFTP_OPCODE_WRITE	2
+#define TFTP_OPCODE_DATA	3
+#define TFTP_OPCODE_ACK		4
+#define TFTP_OPCODE_ERROR	5
 
 #endif /* _IP_CT_TFTP */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/pci.h linux-2.4.27-pre3/include/linux/pci.h
--- linux-2.4.26/include/linux/pci.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/pci.h	2004-05-18 16:53:11.000000000 +0000
@@ -197,6 +197,8 @@
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
 #define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_CAP_ID_SHPC	0x0C    /* PCI Standard Hot-Plug Controller */	
+#define  PCI_CAP_ID_EXP		0x10    /* PCI-EXPRESS */	
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
 #define PCI_CAP_SIZEOF		4
@@ -832,5 +834,7 @@ extern int pci_pci_problems;
 #define PCIPCI_VSFX		16
 #define PCIPCI_ALIMAGIK		32
 
+extern int pciehp_msi_quirk;
+
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/pci_ids.h linux-2.4.27-pre3/include/linux/pci_ids.h
--- linux-2.4.26/include/linux/pci_ids.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/pci_ids.h	2004-05-18 16:52:48.000000000 +0000
@@ -528,7 +528,6 @@
 #define PCI_DEVICE_ID_SI_6202		0x0002
 #define PCI_DEVICE_ID_SI_503		0x0008
 #define PCI_DEVICE_ID_SI_ACPI		0x0009
-#define PCI_DEVICE_ID_SI_180		0x0180
 #define PCI_DEVICE_ID_SI_5597_VGA	0x0200
 #define PCI_DEVICE_ID_SI_6205		0x0205
 #define PCI_DEVICE_ID_SI_501		0x0406
@@ -1269,6 +1268,8 @@
 
 #define PCI_VENDOR_ID_TOSHIBA		0x1179
 #define PCI_DEVICE_ID_TOSHIBA_PICCOLO	0x0102
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1	0x0103
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2	0x0105
 #define PCI_DEVICE_ID_TOSHIBA_601	0x0601
 #define PCI_DEVICE_ID_TOSHIBA_TOPIC95	0x060a
 #define PCI_DEVICE_ID_TOSHIBA_TOPIC97	0x060f
@@ -1691,6 +1692,8 @@
 #define PCI_DEVICE_ID_TIGON3_5901	0x170d
 #define PCI_DEVICE_ID_TIGON3_5901_2	0x170e
 #define PCI_DEVICE_ID_BCM4401		0x4401
+#define PCI_DEVICE_ID_BCM4401B0		0x4402
+#define PCI_DEVICE_ID_BCM4401B1		0x170c
 
 #define PCI_VENDOR_ID_ENE		0x1524
 #define PCI_DEVICE_ID_ENE_1211		0x1211
@@ -1907,6 +1910,7 @@
 #define PCI_DEVICE_ID_INTEL_ICH6_3	0x266e
 #define PCI_DEVICE_ID_INTEL_82850_HB	0x2530
 #define PCI_DEVICE_ID_INTEL_82845G_HB	0x2560
+#define PCI_DEVICE_ID_INTEL_SMCH	0x3590
 #define PCI_DEVICE_ID_INTEL_80310	0x530d
 #define PCI_DEVICE_ID_INTEL_82810_MC1	0x7120
 #define PCI_DEVICE_ID_INTEL_82810_IG1	0x7121
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/sched.h linux-2.4.27-pre3/include/linux/sched.h
--- linux-2.4.26/include/linux/sched.h	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/sched.h	2004-05-18 16:51:20.000000000 +0000
@@ -273,9 +273,9 @@ struct user_struct {
 };
 
 #define get_current_user() ({ 				\
-	struct user_struct *__user = current->user;	\
-	atomic_inc(&__user->__count);			\
-	__user; })
+	struct user_struct *__tmp_user = current->user;	\
+	atomic_inc(&__tmp_user->__count);		\
+	__tmp_user; })
 
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/sctp.h linux-2.4.27-pre3/include/linux/sctp.h
--- linux-2.4.26/include/linux/sctp.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/sctp.h	2004-05-18 16:53:25.000000000 +0000
@@ -1,5 +1,5 @@
 /* SCTP kernel reference Implementation
- * (C) Copyright IBM Corp. 2001, 2003
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001 Intel Corp.
@@ -93,6 +93,9 @@ typedef enum {
         SCTP_CID_ECN_CWR		= 13,
         SCTP_CID_SHUTDOWN_COMPLETE	= 14,
 
+	/* PR-SCTP Sec 3.2 */
+	SCTP_CID_FWD_TSN		= 0xC0,
+
 	/* Use hex, as defined in ADDIP sec. 3.1 */
 	SCTP_CID_ASCONF			= 0xC1,
 	SCTP_CID_ASCONF_ACK		= 0x80,
@@ -168,6 +171,9 @@ typedef enum {
 	SCTP_PARAM_SUPPORTED_ADDRESS_TYPES	= __constant_htons(12),
 	SCTP_PARAM_ECN_CAPABLE			= __constant_htons(0x8000),
 
+	/* PR-SCTP Sec 3.1 */
+	SCTP_PARAM_FWD_TSN_SUPPORT	= __constant_htons(0xc000),
+
 	/* Add-IP Extension. Section 3.2 */
 	SCTP_PARAM_ADD_IP		= __constant_htons(0xc001),
 	SCTP_PARAM_DEL_IP		= __constant_htons(0xc002),
@@ -472,9 +478,67 @@ typedef struct sctp_cwr_chunk {
 	sctp_cwrhdr_t cwr_hdr;
 } __attribute__((packed)) sctp_cwr_chunk_t;
 
-/*
- * ADDIP Section 3.1 New Chunk Types
+/* PR-SCTP
+ * 3.2 Forward Cumulative TSN Chunk Definition (FORWARD TSN)
+ *
+ * Forward Cumulative TSN chunk has 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
+ *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *      |   Type = 192  |  Flags = 0x00 |        Length = Variable      |
+ *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *      |                      New Cumulative TSN                       |
+ *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *      |         Stream-1              |       Stream Sequence-1       |
+ *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *      \                                                               /
+ *      /                                                               \
+ *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *      |         Stream-N              |       Stream Sequence-N       |
+ *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *      Chunk Flags:
+ *
+ *        Set to all zeros on transmit and ignored on receipt.
+ *
+ *      New Cumulative TSN: 32 bit u_int
+ *
+ *       This indicates the new cumulative TSN to the data receiver. Upon
+ *       the reception of this value, the data receiver MUST consider
+ *       any missing TSNs earlier than or equal to this value as received
+ *       and stop reporting them as gaps in any subsequent SACKs.
+ *
+ *      Stream-N: 16 bit u_int
+ *
+ *       This field holds a stream number that was skipped by this
+ *       FWD-TSN.
+ *
+ *      Stream Sequence-N: 16 bit u_int
+ *       This field holds the sequence number associated with the stream
+ *       that was skipped. The stream sequence field holds the largest stream
+ *       sequence number in this stream being skipped.  The receiver of
+ *       the FWD-TSN's can use the Stream-N and Stream Sequence-N fields
+ *       to enable delivery of any stranded TSN's that remain on the stream
+ *       re-ordering queues. This field MUST NOT report TSN's corresponding
+ *       to DATA chunk that are marked as unordered. For ordered DATA
+ *       chunks this field MUST be filled in.
  */
+struct sctp_fwdtsn_skip {
+	__u16 stream;
+	__u16 ssn;
+} __attribute__((packed));
+
+struct sctp_fwdtsn_hdr {
+	__u32 new_cum_tsn;
+	struct sctp_fwdtsn_skip skip[0];
+} __attribute((packed));
+
+struct sctp_fwdtsn_chunk {
+	struct sctp_chunkhdr chunk_hdr;
+	struct sctp_fwdtsn_hdr fwdtsn_hdr;
+} __attribute((packed));
+
 
 /* ADDIP
  * Section 3.1.1 Address Configuration Change Chunk (ASCONF)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/linux/sysctl.h linux-2.4.27-pre3/include/linux/sysctl.h
--- linux-2.4.26/include/linux/sysctl.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/linux/sysctl.h	2004-05-18 16:50:50.000000000 +0000
@@ -128,6 +128,7 @@ enum
 	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 */
+	KERN_SPARC_SCONS_PWROFF=64, /* int: serial console power-off halt */
 };
 
 
@@ -554,6 +555,7 @@ enum {
 	NET_SCTP_PRESERVE_ENABLE         = 11,
 	NET_SCTP_MAX_BURST               = 12,
 	NET_SCTP_ADDIP_ENABLE            = 13,
+	NET_SCTP_PRSCTP_ENABLE           = 14,
 };
 /* /proc/sys/net/khttpd/ */
 enum {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/net/sctp/command.h linux-2.4.27-pre3/include/net/sctp/command.h
--- linux-2.4.26/include/net/sctp/command.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/net/sctp/command.h	2004-05-18 16:54:35.000000000 +0000
@@ -1,5 +1,5 @@
 /* SCTP kernel reference Implementation
- * (C) Copyright IBM Corp. 2001, 2003
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (C) 1999-2001 Cisco, Motorola
  *
  * This file is part of the SCTP kernel reference Implementation
@@ -29,6 +29,7 @@
  * La Monte H.P. Yarroll <piggy@acm.org>
  * Karl Knutson <karl@athena.chicago.il.us>
  * Ardelle Fan <ardelle.fan@intel.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -90,6 +91,8 @@ typedef enum {
 	SCTP_CMD_RENEGE,         /* Renege data on an association. */
 	SCTP_CMD_SETUP_T4,	 /* ADDIP, setup T4 RTO timer parms. */
 	SCTP_CMD_PROCESS_OPERR,  /* Process an ERROR chunk. */
+	SCTP_CMD_REPORT_FWDTSN,	 /* Report new cumulative TSN Ack. */
+	SCTP_CMD_PROCESS_FWDTSN, /* Skips were reported, so process further. */
 	SCTP_CMD_LAST
 } sctp_verb_t;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/net/sctp/constants.h linux-2.4.27-pre3/include/net/sctp/constants.h
--- linux-2.4.26/include/net/sctp/constants.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/net/sctp/constants.h	2004-05-18 16:50:50.000000000 +0000
@@ -1,5 +1,5 @@
 /* SCTP kernel reference Implementation
- * (C) Copyright IBM Corp. 2001, 2003
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001 Intel Corp.
@@ -57,15 +57,6 @@ enum { SCTP_MAX_STREAM = 0xffff };
 enum { SCTP_DEFAULT_OUTSTREAMS = 10 };
 enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM };
 
-/* Define the amount of space to reserve for SCTP, IP, LL.
- * There is a little bit of waste that we are always allocating
- * for ipv6 headers, but this seems worth the simplicity.
- */
-
-#define SCTP_IP_OVERHEAD ((sizeof(struct sctphdr)\
-                          + sizeof(struct ipv6hdr)\
-                          + MAX_HEADER))
-
 /* Since CIDs are sparse, we need all four of the following
  * symbols.  CIDs are dense through SCTP_CID_BASE_MAX.
  */
@@ -77,6 +68,8 @@ enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX
 
 #define SCTP_NUM_ADDIP_CHUNK_TYPES	2
 
+#define SCTP_NUM_PRSCTP_CHUNK_TYPES	1
+
 /* These are the different flavours of event.  */
 typedef enum {
 
@@ -238,11 +231,6 @@ const char *sctp_pname(const sctp_subtyp
 /* This is a table of printable names of sctp_state_t's.  */
 extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[];
 
-/* SCTP reachability state for each address */
-#define SCTP_ADDR_NOHB			4
-#define SCTP_ADDR_REACHABLE		2
-#define SCTP_ADDR_NOT_REACHABLE		1
-
 /* Maximum chunk length considering padding requirements. */
 enum { SCTP_MAX_CHUNK_LEN = ((1<<16) - sizeof(__u32)) };
 
@@ -355,7 +343,6 @@ typedef enum {
 	SCTP_XMIT_OK,
 	SCTP_XMIT_PMTU_FULL,
 	SCTP_XMIT_RWND_FULL,
-	SCTP_XMIT_MUST_FRAG,
 	SCTP_XMIT_NAGLE_DELAY,
 } sctp_xmit_t;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/net/sctp/sctp.h linux-2.4.27-pre3/include/net/sctp/sctp.h
--- linux-2.4.26/include/net/sctp/sctp.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/net/sctp/sctp.h	2004-05-18 16:52:25.000000000 +0000
@@ -454,12 +454,15 @@ static inline __s32 sctp_jitter(__u32 rt
 static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu)
 {
 	int frag = pmtu;
-	frag -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
-	frag -= sizeof(struct sctp_sack_chunk);
+
+	frag -= sp->pf->af->net_header_len;
+	frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk);
 
 	if (sp->user_frag)
 		frag = min_t(int, frag, sp->user_frag);
 
+	frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN);
+
 	return frag;
 }
 
@@ -489,6 +492,14 @@ for (err = (sctp_errhdr_t *)((void *)chu
      err = (sctp_errhdr_t *)((void *)err + \
 	    WORD_ROUND(ntohs(err->length))))
 
+#define sctp_walk_fwdtsn(pos, chunk)\
+_sctp_walk_fwdtsn((pos), (chunk), ntohs((chunk)->chunk_hdr->length) - sizeof(struct sctp_fwdtsn_chunk))
+
+#define _sctp_walk_fwdtsn(pos, chunk, end)\
+for (pos = chunk->subh.fwdtsn_hdr->skip;\
+     (void *)pos <= (void *)chunk->subh.fwdtsn_hdr->skip + end - sizeof(struct sctp_fwdtsn_skip);\
+     pos++)
+
 /* Round an int up to the next multiple of 4.  */
 #define WORD_ROUND(s) (((s)+3)&~3)
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/net/sctp/sm.h linux-2.4.27-pre3/include/net/sctp/sm.h
--- linux-2.4.26/include/net/sctp/sm.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/net/sctp/sm.h	2004-05-18 16:52:30.000000000 +0000
@@ -1,5 +1,5 @@
 /* SCTP kernel reference Implementation
- * (C) Copyright IBM Corp. 2001, 2003
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001 Intel Corp.
@@ -141,6 +141,9 @@ sctp_state_fn_t sctp_sf_cookie_echoed_er
 sctp_state_fn_t sctp_sf_do_5_2_6_stale;
 sctp_state_fn_t sctp_sf_do_asconf;
 sctp_state_fn_t sctp_sf_do_asconf_ack;
+sctp_state_fn_t sctp_sf_do_9_2_reshutack;
+sctp_state_fn_t sctp_sf_eat_fwd_tsn;
+sctp_state_fn_t sctp_sf_eat_fwd_tsn_fast;
 
 /* Prototypes for primitive event state functions.  */
 sctp_state_fn_t sctp_sf_do_prm_asoc;
@@ -170,25 +173,6 @@ sctp_state_fn_t sctp_sf_do_6_3_3_rtx;
 sctp_state_fn_t sctp_sf_do_6_2_sack;
 sctp_state_fn_t sctp_sf_autoclose_timer_expire;
 
-
-/* These are state functions which are either obsolete or not in use yet.
- * If any of these functions needs to be revived, it should be renamed with
- * the "sctp_sf_xxx" prefix, and be moved to the above prototype groups.
- */
-
-/* Prototypes for chunk state functions.  Not in use. */
-sctp_state_fn_t sctp_sf_do_9_2_reshutack;
-sctp_state_fn_t sctp_sf_do_9_2_reshut;
-sctp_state_fn_t sctp_sf_do_9_2_shutack;
-
-/* Prototypes for timeout event state functions.  Not in use. */
-sctp_state_fn_t sctp_do_4_2_reinit;
-sctp_state_fn_t sctp_do_4_3_reecho;
-sctp_state_fn_t sctp_do_9_2_reshut;
-sctp_state_fn_t sctp_do_9_2_reshutack;
-sctp_state_fn_t sctp_do_8_3_hb_err;
-sctp_state_fn_t sctp_heartoff;
-
 /* Prototypes for utility support functions.  */
 __u8 sctp_get_chunk_type(struct sctp_chunk *chunk);
 const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t,
@@ -277,6 +261,9 @@ struct sctp_chunk *sctp_process_asconf(s
 				       struct sctp_chunk *asconf);
 int sctp_process_asconf_ack(struct sctp_association *asoc,
 			    struct sctp_chunk *asconf_ack);
+struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
+				    __u32 new_cum_tsn, size_t nstreams,
+				    struct sctp_fwdtsn_skip *skiplist);
 
 void sctp_chunk_assign_tsn(struct sctp_chunk *);
 void sctp_chunk_assign_ssn(struct sctp_chunk *);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/net/sctp/structs.h linux-2.4.27-pre3/include/net/sctp/structs.h
--- linux-2.4.26/include/net/sctp/structs.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/net/sctp/structs.h	2004-05-18 16:54:15.000000000 +0000
@@ -194,6 +194,9 @@ extern struct sctp_globals {
 	
 	/* Flag to indicate if addip is enabled. */
 	int addip_enable;
+
+	/* Flag to indicate if PR-SCTP is enabled. */
+	int prsctp_enable;
 } sctp_globals;
 
 #define sctp_rto_initial		(sctp_globals.rto_initial)
@@ -222,6 +225,7 @@ extern struct sctp_globals {
 #define sctp_local_addr_list		(sctp_globals.local_addr_list)
 #define sctp_local_addr_lock		(sctp_globals.local_addr_lock)
 #define sctp_addip_enable		(sctp_globals.addip_enable)
+#define sctp_prsctp_enable		(sctp_globals.prsctp_enable)
 
 /* SCTP Socket type: UDP or TCP style. */
 typedef enum {
@@ -317,6 +321,8 @@ struct sctp_cookie {
 	/* This holds the originating address of the INIT packet.  */
 	union sctp_addr peer_addr;
 
+	__u8 prsctp_capable;
+
 	/* This is a shim for my peer's INIT packet, followed by
 	 * a copy of the raw address list of the association.
 	 * The length of the raw address list is saved in the
@@ -413,6 +419,13 @@ static inline __u16 sctp_ssn_next(struct
 	return stream->ssn[id]++;
 }
 
+/* Skip over this ssn and all below. */
+static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id, 
+				 __u16 ssn)
+{
+	stream->ssn[id] = ssn+1;
+}
+              
 /*
  * Pointers to address related SCTP functions.
  * (i.e. things that depend on the address family.)
@@ -514,8 +527,8 @@ struct sctp_datamsg {
 	/* Did the messenge fail to send? */
 	int send_error;
 	char send_failed;
-	/* Control whether fragments from this message can expire. */
-	char can_expire;
+	/* Control whether chunks from this message can be abandoned. */
+	char can_abandon;
 };
 
 struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
@@ -527,8 +540,8 @@ void sctp_datamsg_hold(struct sctp_datam
 void sctp_datamsg_free(struct sctp_datamsg *);
 void sctp_datamsg_track(struct sctp_chunk *);
 void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *);
-void sctp_datamsg_fail(struct sctp_chunk *, int error);
-int sctp_datamsg_expires(struct sctp_chunk *);
+void sctp_chunk_fail(struct sctp_chunk *, int error);
+int sctp_chunk_abandoned(struct sctp_chunk *);
 
 
 /* RFC2960 1.4 Key Terms
@@ -583,6 +596,7 @@ struct sctp_chunk {
 		struct sctp_cwrhdr *ecn_cwr_hdr;
 		struct sctp_errhdr *err_hdr;
 		struct sctp_addiphdr *addip_hdr;
+		struct sctp_fwdtsn_hdr *fwdtsn_hdr;
 	} subh;
 
 	__u8 *chunk_end;
@@ -667,6 +681,9 @@ struct sctp_packet {
 
 	/* This contains the payload chunks.  */
 	struct sk_buff_head chunks;
+
+	/* This is the overhead of the sctp and ip headers. */
+	size_t overhead;
 	/* This is the total size of all chunks INCLUDING padding.  */
 	size_t size;
 
@@ -676,16 +693,6 @@ struct sctp_packet {
 	 */
 	struct sctp_transport *transport;
 
-	/* Allow a callback for getting a high priority chunk
-	 * bundled early into the packet (This is used for ECNE).
-	 */
-	sctp_packet_phandler_t *get_prepend_chunk;
-
-	/* This packet should advertise ECN capability to the network
-	 * via the ECT bit.
-	 */
-	char ecn_capable;
-
 	/* This packet contains a COOKIE-ECHO chunk. */
 	char has_cookie_echo;
 
@@ -698,29 +705,21 @@ struct sctp_packet {
 	int malloced;
 };
 
-typedef int (sctp_outq_thandler_t)(struct sctp_outq *, void *);
-typedef int (sctp_outq_ehandler_t)(struct sctp_outq *);
-typedef struct sctp_packet *(sctp_outq_ohandler_init_t)
-	(struct sctp_packet *,
-	 struct sctp_transport *,
-	 __u16 sport,
-	 __u16 dport);
-typedef struct sctp_packet *(sctp_outq_ohandler_config_t)
-	(struct sctp_packet *,
-	 __u32 vtag,
-	 int ecn_capable,
-	 sctp_packet_phandler_t *get_prepend_chunk);
-typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *,
-					       struct sctp_chunk *);
-typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *);
-
-sctp_outq_ohandler_init_t    sctp_packet_init;
-sctp_outq_ohandler_config_t  sctp_packet_config;
-sctp_outq_ohandler_t	     sctp_packet_append_chunk;
-sctp_outq_ohandler_t	     sctp_packet_transmit_chunk;
-sctp_outq_ohandler_force_t   sctp_packet_transmit;
+struct sctp_packet *sctp_packet_init(struct sctp_packet *,
+				     struct sctp_transport *,
+				     __u16 sport, __u16 dport);
+struct sctp_packet *sctp_packet_config(struct sctp_packet *, __u32 vtag, int);
+sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *,
+                                       struct sctp_chunk *);
+sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *,
+                                     struct sctp_chunk *);
+int sctp_packet_transmit(struct sctp_packet *);
 void sctp_packet_free(struct sctp_packet *);
 
+static inline int sctp_packet_empty(struct sctp_packet *packet)
+{
+	return (packet->size == packet->overhead);
+}
 
 /* This represents a remote transport address.
  * For local transport addresses, we just use union sctp_addr.
@@ -905,7 +904,7 @@ struct sctp_transport {
 		/* A flag which indicates the occurrence of a changeover */
 		char changeover_active;
 
-		/* A glag which indicates whether the change of primary is
+		/* A flag which indicates whether the change of primary is
 		 * the first switch to this destination address during an
 		 * active switch.
 		 */
@@ -1008,15 +1007,10 @@ struct sctp_outq {
 	 */
 	struct list_head retransmit;
 
-	/* Call these functions to send chunks down to the next lower
-	 * layer.  This is always sctp_packet, but we separate the two
-	 * structures to make testing simpler.
-	 */
-	sctp_outq_ohandler_init_t	*init_output;
-	sctp_outq_ohandler_config_t	*config_output;
-	sctp_outq_ohandler_t	*append_output;
-	sctp_outq_ohandler_t	*build_output;
-	sctp_outq_ohandler_force_t	*force_output;
+	/* Put chunks on this list to save them for FWD TSN processing as
+	 * they were abandoned.
+	 */
+	struct list_head abandoned;
 
 	/* How many unackd bytes do we have in-flight?	*/
 	__u32 outstanding_bytes;
@@ -1039,12 +1033,6 @@ int sctp_outq_tail(struct sctp_outq *, s
 int sctp_outq_flush(struct sctp_outq *, int);
 int sctp_outq_sack(struct sctp_outq *, struct sctp_sackhdr *);
 int sctp_outq_is_empty(const struct sctp_outq *);
-int sctp_outq_set_output_handlers(struct sctp_outq *,
-				  sctp_outq_ohandler_init_t init,
-				  sctp_outq_ohandler_config_t config,
-				  sctp_outq_ohandler_t append,
-				  sctp_outq_ohandler_t build,
-				  sctp_outq_ohandler_force_t force);
 void sctp_outq_restart(struct sctp_outq *);
 
 void sctp_retransmit(struct sctp_outq *, struct sctp_transport *,
@@ -1390,16 +1378,25 @@ struct sctp_association {
 		struct sctp_tsnmap tsn_map;
 		__u8 _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)];
 
-		/* Do we need to sack the peer? */
-		__u8	sack_needed;
+		/* Ack State   : This flag indicates if the next received
+		 *             : packet is to be responded to with a
+		 *             : SACK. This is initializedto 0.  When a packet
+		 *             : is received it is incremented. If this value
+		 *             : reaches 2 or more, a SACK is sent and the
+		 *             : value is reset to 0. Note: This is used only
+		 *             : when no DATA chunks are received out of
+		 *             : order.  When DATA chunks are out of order,
+		 *             : SACK's are not delayed (see Section 6).
+		 */
+		__u8    sack_needed;     /* Do we need to sack the peer? */
+
 		/* These are capabilities which our peer advertised.  */
 		__u8	ecn_capable;	 /* Can peer do ECN? */
 		__u8	ipv4_address;	 /* Peer understands IPv4 addresses? */
 		__u8	ipv6_address;	 /* Peer understands IPv6 addresses? */
 		__u8	hostname_address;/* Peer understands DNS addresses? */
-
-		/* Does peer support ADDIP? */
-		__u8    asconf_capable;
+		__u8    asconf_capable;  /* Does peer support ADDIP? */
+		__u8    prsctp_capable;  /* Can peer do PR-SCTP? */
 
 		/* This mask is used to disable sending the ASCONF chunk
 		 * with specified parameter to peer.
@@ -1492,6 +1489,9 @@ struct sctp_association {
 
 	__u32 ctsn_ack_point;
 
+	/* PR-SCTP Advanced.Peer.Ack.Point */
+	__u32 adv_peer_ack_point;
+
 	/* Highest TSN that is acknowledged by incoming SACKs. */
 	__u32 highest_sacked;
 
@@ -1532,19 +1532,7 @@ struct sctp_association {
 	/* The message size at which SCTP fragmentation will occur. */
 	__u32 frag_point;
 
-	/* Ack State   : This flag indicates if the next received
-	 *	       : packet is to be responded to with a
-	 *	       : SACK. This is initializedto 0.	 When a packet
-	 *	       : is received it is incremented. If this value
-	 *	       : reaches 2 or more, a SACK is sent and the
-	 *	       : value is reset to 0. Note: This is used only
-	 *	       : when no DATA chunks are received out of
-	 *	       : order.	 When DATA chunks are out of order,
-	 *	       : SACK's are not delayed (see Section 6).
-	 */
-	/* Do we need to send an ack?
-	 * When counters[SctpCounterAckState] is above 1 we do!
-	 */
+	/* Currently only one counter is used to count INIT errors. */
 	int counters[SCTP_NUMBER_COUNTERS];
 
 	/* Default send parameters. */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/net/sctp/tsnmap.h linux-2.4.27-pre3/include/net/sctp/tsnmap.h
--- linux-2.4.26/include/net/sctp/tsnmap.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/net/sctp/tsnmap.h	2004-05-18 16:54:30.000000000 +0000
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001-2003 International Business Machines, Corp.
  * Copyright (c) 2001 Intel Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
@@ -37,6 +37,7 @@
  *   Jon Grimm             <jgrimm@us.ibm.com>
  *   La Monte H.P. Yarroll <piggy@acm.org>
  *   Karl Knutson          <karl@athena.chicago.il.us>
+ *   Sridhar Samudrala     <sri@us.ibm.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -145,6 +146,9 @@ int sctp_tsnmap_check(const struct sctp_
 /* Mark this TSN as seen.  */
 void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
 
+/* Mark this TSN and all lower as seen. */
+void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
+
 /* Retrieve the Cumulative TSN ACK Point.  */
 static inline __u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map)
 {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/net/sctp/ulpevent.h linux-2.4.27-pre3/include/net/sctp/ulpevent.h
--- linux-2.4.26/include/net/sctp/ulpevent.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/net/sctp/ulpevent.h	2004-05-18 16:55:10.000000000 +0000
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001 International Business Machines, Corp.
  * Copyright (c) 2001 Intel Corp.
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
@@ -54,7 +54,13 @@
  * growing this structure as it is at the maximum limit now.
  */
 struct sctp_ulpevent {
-	struct sctp_sndrcvinfo sndrcvinfo;
+	struct sctp_association *asoc;
+	__u16 stream;
+	__u16 ssn;
+	__u16 flags;
+	__u32 ppid;
+	__u32 tsn;
+	__u32 cumtsn;
 	int msg_flags;
 	int iif;
 };
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/net/sctp/ulpqueue.h linux-2.4.27-pre3/include/net/sctp/ulpqueue.h
--- linux-2.4.26/include/net/sctp/ulpqueue.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.27-pre3/include/net/sctp/ulpqueue.h	2004-05-18 16:51:40.000000000 +0000
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001-2003 International Business Machines, Corp.
  * Copyright (c) 2001 Intel Corp.
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
@@ -38,6 +38,7 @@
  * Written or modified by:
  *   Jon Grimm             <jgrimm@us.ibm.com>
  *   La Monte H.P. Yarroll <piggy@acm.org>
+ *   Sridhar Samudrala     <sri@us.ibm.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -79,6 +80,9 @@ void sctp_ulpq_abort_pd(struct sctp_ulpq
 /* Clear the partial data delivery condition on this socket. */
 int sctp_clear_pd(struct sock *sk);
 
+/* Skip over an SSN. */
+void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn);
+
 #endif /* __sctp_ulpqueue_h__ */
 
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/include/net/sctp/user.h linux-2.4.27-pre3/include/net/sctp/user.h
--- linux-2.4.26/include/net/sctp/user.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.27-pre3/include/net/sctp/user.h	2004-05-18 16:53:01.000000000 +0000
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001-2003 International Business Machines, Corp.
  * Copyright (c) 2002 Intel Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
@@ -246,7 +246,7 @@ struct sctp_paddr_change {
  *   event that happened to the address.  They include:
  */
 enum sctp_spc_state {
-	SCTP_ADDR_REACHABLE,
+	SCTP_ADDR_AVAILABLE,
 	SCTP_ADDR_UNREACHABLE,
 	SCTP_ADDR_REMOVED,
 	SCTP_ADDR_ADDED,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/kernel/sysctl.c linux-2.4.27-pre3/kernel/sysctl.c
--- linux-2.4.26/kernel/sysctl.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.27-pre3/kernel/sysctl.c	2004-05-18 16:51:21.000000000 +0000
@@ -84,6 +84,7 @@ extern int exception_trace;
 #ifdef __sparc__
 extern char reboot_command [];
 extern int stop_a_enabled;
+extern int scons_pwroff;
 #endif
 
 #ifdef CONFIG_ARCH_S390
@@ -197,6 +198,8 @@ static ctl_table kern_table[] = {
 	 256, 0644, NULL, &proc_dostring, &sysctl_string },
 	{KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
 	 0644, NULL, &proc_dointvec},
+	{KERN_SPARC_SCONS_PWROFF, "scons-poweroff", &scons_pwroff, sizeof (int),
+	 0644, NULL, &proc_dointvec},
 #endif
 #ifdef CONFIG_PPC32
 	{KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/mm/page_alloc.c linux-2.4.27-pre3/mm/page_alloc.c
--- linux-2.4.26/mm/page_alloc.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/mm/page_alloc.c	2004-05-18 16:51:12.000000000 +0000
@@ -46,6 +46,36 @@ static int lower_zone_reserve_ratio[MAX_
 
 int vm_gfp_debug = 0;
 
+int free_dbg_count = 0;
+
+static void FASTCALL(__free_pages_ok (struct page *page, unsigned int order));
+
+static spinlock_t free_pages_ok_no_irq_lock = SPIN_LOCK_UNLOCKED;
+struct page * free_pages_ok_no_irq_head;
+
+static void do_free_pages_ok_no_irq(void * arg)
+{
+       struct page * page, * __page;
+
+       spin_lock_irq(&free_pages_ok_no_irq_lock);
+
+       page = free_pages_ok_no_irq_head;
+       free_pages_ok_no_irq_head = NULL;
+
+       spin_unlock_irq(&free_pages_ok_no_irq_lock);
+
+       while (page) {
+               __page = page;
+               page = page->next_hash;
+               __free_pages_ok(__page, __page->index);
+       }
+}
+
+static struct tq_struct free_pages_ok_no_irq_task = {
+       .routine        = do_free_pages_ok_no_irq,
+};
+
+
 /*
  * Temporary debugging check.
  */
@@ -81,7 +111,6 @@ int vm_gfp_debug = 0;
  * -- wli
  */
 
-static void FASTCALL(__free_pages_ok (struct page *page, unsigned int order));
 static void __free_pages_ok (struct page *page, unsigned int order)
 {
 	unsigned long index, page_idx, mask, flags;
@@ -94,8 +123,20 @@ static void __free_pages_ok (struct page
 	 * a reference to a page in order to pin it for io. -ben
 	 */
 	if (PageLRU(page)) {
-		if (unlikely(in_interrupt()))
-			BUG();
+		if (unlikely(in_interrupt()) || ((free_dbg_count++ % 10000) == 0)) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&free_pages_ok_no_irq_lock, flags);
+			page->next_hash = free_pages_ok_no_irq_head;
+			free_pages_ok_no_irq_head = page;
+			page->index = order;
+	
+			spin_unlock_irqrestore(&free_pages_ok_no_irq_lock, flags);
+	
+			schedule_task(&free_pages_ok_no_irq_task);
+			return;
+		}
+		
 		lru_cache_del(page);
 	}
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/Config.in linux-2.4.27-pre3/net/Config.in
--- linux-2.4.26/net/Config.in	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.27-pre3/net/Config.in	2004-05-18 16:51:58.000000000 +0000
@@ -99,7 +99,7 @@ endmenu
 
 mainmenu_option next_comment
 comment 'Network testing'
-tristate 'Packet Generator (USE WITH CAUTION)' CONFIG_NET_PKTGEN
+dep_tristate 'Packet Generator (USE WITH CAUTION)' CONFIG_NET_PKTGEN $CONFIG_PROC_FS
 endmenu
 
 endmenu
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/bluetooth/rfcomm/tty.c linux-2.4.27-pre3/net/bluetooth/rfcomm/tty.c
--- linux-2.4.26/net/bluetooth/rfcomm/tty.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/bluetooth/rfcomm/tty.c	2004-05-18 16:52:01.000000000 +0000
@@ -338,12 +338,14 @@ static int rfcomm_release_dev(unsigned l
 
 	BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
 
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
 	if (!(dev = rfcomm_dev_get(req.dev_id)))
 		return -ENODEV;
 
+	if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
+		rfcomm_dev_put(dev);
+		return -EPERM;
+	}
+
 	if (req.flags & (1 << RFCOMM_HANGUP_NOW))
 		rfcomm_dlc_close(dev->dlc, 0);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/ipv4/igmp.c linux-2.4.27-pre3/net/ipv4/igmp.c
--- linux-2.4.26/net/ipv4/igmp.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/ipv4/igmp.c	2004-05-18 16:55:19.000000000 +0000
@@ -2126,7 +2126,8 @@ int ip_mc_procinfo(char *buffer, char **
 			continue;
 
 #ifdef CONFIG_IP_MULTICAST
-		querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2";
+		querier = IGMP_V1_SEEN(in_dev) ? "V1" : IGMP_V2_SEEN(in_dev) ?
+			"V2" : "V3";
 #endif
 
 		len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n",
@@ -2137,7 +2138,9 @@ int ip_mc_procinfo(char *buffer, char **
 			len+=sprintf(buffer+len,
 				     "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
 				     im->multiaddr, im->users,
-				     im->tm_running, im->timer.expires-jiffies, im->reporter);
+				     im->tm_running, im->tm_running ?
+				     im->timer.expires-jiffies : 0,
+				     im->reporter);
 
 			pos=begin+len;
 			if(pos<offset)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/ipv4/ip_sockglue.c linux-2.4.27-pre3/net/ipv4/ip_sockglue.c
--- linux-2.4.26/net/ipv4/ip_sockglue.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/ipv4/ip_sockglue.c	2004-05-18 16:52:16.000000000 +0000
@@ -791,7 +791,7 @@ int ip_setsockopt(struct sock *sk, int l
 				goto mc_msf_out;
 			}
 			if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
-				err = EINVAL;
+				err = -EINVAL;
 				goto mc_msf_out;
 			}
 			msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/ipv4/netfilter/ip_conntrack_tftp.c linux-2.4.27-pre3/net/ipv4/netfilter/ip_conntrack_tftp.c
--- linux-2.4.26/net/ipv4/netfilter/ip_conntrack_tftp.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/net/ipv4/netfilter/ip_conntrack_tftp.c	2004-05-18 16:52:36.000000000 +0000
@@ -64,6 +64,13 @@ static int tftp_help(const struct iphdr 
 		DUMP_TUPLE(&exp.mask);
 		ip_conntrack_expect_related(ct, &exp);
 		break;
+	case TFTP_OPCODE_DATA:
+	case TFTP_OPCODE_ACK:
+		DEBUGP("Data/ACK opcode\n");
+		break;
+	case TFTP_OPCODE_ERROR:
+		DEBUGP("Error opcode\n");
+		break;
 	default:
 		DEBUGP("Unknown opcode\n");
 	}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/ipv4/netfilter/ipt_MASQUERADE.c linux-2.4.27-pre3/net/ipv4/netfilter/ipt_MASQUERADE.c
--- linux-2.4.26/net/ipv4/netfilter/ipt_MASQUERADE.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/ipv4/netfilter/ipt_MASQUERADE.c	2004-05-18 16:53:50.000000000 +0000
@@ -102,6 +102,7 @@ masquerade_target(struct sk_buff **pskb,
                 if (net_ratelimit())
                         printk("MASQUERADE:"
                                " Route sent us somewhere else.\n");
+			ip_rt_put(rt);
 		return NF_DROP;
 	}
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/ipv6/icmp.c linux-2.4.27-pre3/net/ipv6/icmp.c
--- linux-2.4.26/net/ipv6/icmp.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/ipv6/icmp.c	2004-05-18 16:52:16.000000000 +0000
@@ -595,6 +595,7 @@ int icmpv6_rcv(struct sk_buff *skb)
 		break;
 
 	case ICMPV6_MGM_REDUCTION:
+	case ICMPV6_MLD2_REPORT:
 		break;
 
 	default:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sched/sch_dsmark.c linux-2.4.27-pre3/net/sched/sch_dsmark.c
--- linux-2.4.26/net/sched/sch_dsmark.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.27-pre3/net/sched/sch_dsmark.c	2004-05-18 16:51:39.000000000 +0000
@@ -324,7 +324,8 @@ int dsmark_init(struct Qdisc *sch,struct
 	__u16 tmp;
 
 	DPRINTK("dsmark_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt);
-	if (rtattr_parse(tb,TCA_DSMARK_MAX,RTA_DATA(opt),RTA_PAYLOAD(opt)) < 0 ||
+	if (!opt ||
+	    rtattr_parse(tb,TCA_DSMARK_MAX,RTA_DATA(opt),RTA_PAYLOAD(opt)) < 0 ||
 	    !tb[TCA_DSMARK_INDICES-1] ||
 	    RTA_PAYLOAD(tb[TCA_DSMARK_INDICES-1]) < sizeof(__u16))
                 return -EINVAL;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/associola.c linux-2.4.27-pre3/net/sctp/associola.c
--- linux-2.4.26/net/sctp/associola.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/associola.c	2004-05-18 16:52:43.000000000 +0000
@@ -1,5 +1,5 @@
 /* SCTP kernel reference Implementation
- * (C) Copyright IBM Corp. 2001, 2003
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001 Intel Corp.
@@ -210,6 +210,7 @@ struct sctp_association *sctp_associatio
 	asoc->next_tsn = asoc->c.initial_tsn;
 
 	asoc->ctsn_ack_point = asoc->next_tsn - 1;
+	asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
 	asoc->highest_sacked = asoc->ctsn_ack_point;
 	asoc->last_cwr_tsn = asoc->ctsn_ack_point;
 	asoc->unack_data = 0;
@@ -261,12 +262,6 @@ struct sctp_association *sctp_associatio
 
 	/* Create an output queue.  */
 	sctp_outq_init(asoc, &asoc->outqueue);
-	sctp_outq_set_output_handlers(&asoc->outqueue,
-				      sctp_packet_init,
-				      sctp_packet_config,
-				      sctp_packet_append_chunk,
-				      sctp_packet_transmit_chunk,
-				      sctp_packet_transmit);
 
 	if (!sctp_ulpq_init(&asoc->ulpq, asoc))
 		goto fail_init;
@@ -478,10 +473,8 @@ struct sctp_transport *sctp_assoc_add_pe
 	/* The asoc->peer.port might not be meaningful yet, but
 	 * initialize the packet structure anyway.
 	 */
-	(asoc->outqueue.init_output)(&peer->packet,
-				     peer,
-				     asoc->base.bind_addr.port,
-				     asoc->peer.port);
+	sctp_packet_init(&peer->packet, peer, asoc->base.bind_addr.port,
+			 asoc->peer.port);
 
 	/* 7.2.1 Slow-Start
 	 *
@@ -611,7 +604,7 @@ void sctp_assoc_control_transport(struct
 	switch (command) {
 	case SCTP_TRANSPORT_UP:
 		transport->active = SCTP_ACTIVE;
-		spc_state = SCTP_ADDR_REACHABLE;
+		spc_state = SCTP_ADDR_AVAILABLE;
 		break;
 
 	case SCTP_TRANSPORT_DOWN:
@@ -958,6 +951,9 @@ void sctp_assoc_migrate(struct sctp_asso
 void sctp_assoc_update(struct sctp_association *asoc,
 		       struct sctp_association *new)
 {
+	struct sctp_transport *trans;
+	struct list_head *pos, *temp;
+
 	/* Copy in new parameters of peer. */
 	asoc->c = new->c;
 	asoc->peer.rwnd = new->peer.rwnd;
@@ -966,22 +962,22 @@ void sctp_assoc_update(struct sctp_assoc
 	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,
 			 asoc->peer.i.initial_tsn);
 
-	/* FIXME:
-	 *    Do we need to copy primary_path etc?
-	 *
-	 *    More explicitly, addresses may have been removed and
-	 *    this needs accounting for.
-	 */
+	/* Remove any peer addresses not present in the new association. */
+	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
+		trans = list_entry(pos, struct sctp_transport, transports);
+		if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr))
+			sctp_assoc_del_peer(asoc, &trans->ipaddr);
+	}
 
 	/* If the case is A (association restart), use
 	 * initial_tsn as next_tsn. If the case is B, use
 	 * current next_tsn in case data sent to peer
 	 * has been discarded and needs retransmission.
 	 */
-	if (sctp_state(asoc, ESTABLISHED)) {
-
+	if (asoc->state >= SCTP_STATE_ESTABLISHED) {
 		asoc->next_tsn = new->next_tsn;
 		asoc->ctsn_ack_point = new->ctsn_ack_point;
+		asoc->adv_peer_ack_point = new->adv_peer_ack_point;
 
 		/* Reinitialize SSN for both local streams
 		 * and peer's streams.
@@ -989,14 +985,23 @@ void sctp_assoc_update(struct sctp_assoc
 		sctp_ssnmap_clear(asoc->ssnmap);
 
 	} else {
+		/* Add any peer addresses from the new association. */
+		list_for_each(pos, &new->peer.transport_addr_list) {
+			trans = list_entry(pos, struct sctp_transport,
+					   transports);
+			if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr))
+				sctp_assoc_add_peer(asoc, &trans->ipaddr,
+						    GFP_ATOMIC);
+		}
+
 		asoc->ctsn_ack_point = asoc->next_tsn - 1;
+		asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
 		if (!asoc->ssnmap) {
 			/* Move the ssnmap. */
 			asoc->ssnmap = new->ssnmap;
 			new->ssnmap = NULL;
 		}
 	}
-
 }
 
 /* Update the retran path for sending a retransmitted packet.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/chunk.c linux-2.4.27-pre3/net/sctp/chunk.c
--- linux-2.4.26/net/sctp/chunk.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/chunk.c	2004-05-18 16:51:21.000000000 +0000
@@ -1,5 +1,5 @@
 /* SCTP kernel reference Implementation
- * Copyright (c) 2003 International Business Machines Corp.
+ * (C) Copyright IBM Corp. 2003, 2004
  *
  * This file is part of the SCTP kernel reference Implementation
  *
@@ -31,6 +31,7 @@
  *
  * Written or modified by:
  *    Jon Grimm             <jgrimm@us.ibm.com>
+ *    Sridhar Samudrala     <sri@us.ibm.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -55,7 +56,8 @@ void sctp_datamsg_init(struct sctp_datam
 	atomic_set(&msg->refcnt, 1);
 	msg->send_failed = 0;
 	msg->send_error = 0;
-	msg->can_expire = 0;
+	msg->can_abandon = 0;
+	msg->expires_at = 0;
 	INIT_LIST_HEAD(&msg->chunks);
 }
 
@@ -185,27 +187,14 @@ struct sctp_datamsg *sctp_datamsg_from_u
 		/* sinfo_timetolive is in milliseconds */
 		msg->expires_at = jiffies +
 				     SCTP_MSECS_TO_JIFFIES(sinfo->sinfo_timetolive);
-		msg->can_expire = 1;
+		msg->can_abandon = 1;
+		SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
+				  __FUNCTION__, msg, msg->expires_at, jiffies);
 	}
 
-	/* What is a reasonable fragmentation point right now? */
-	max = asoc->pmtu;
-	if (max < SCTP_MIN_PMTU)
-		max = SCTP_MIN_PMTU;
-	max -= SCTP_IP_OVERHEAD;
-
-	/* Make sure not beyond maximum chunk size. */
-	if (max > SCTP_MAX_CHUNK_LEN)
-		max = SCTP_MAX_CHUNK_LEN;
+	max = asoc->frag_point;
 
-	/* Subtract out the overhead of a data chunk header. */
-	max -= sizeof(struct sctp_data_chunk);
 	whole = 0;
-
-	/* If user has specified smaller fragmentation, make it so. */
-	if (sctp_sk(asoc->base.sk)->user_frag)
-		max = min_t(int, max, sctp_sk(asoc->base.sk)->user_frag);
-
 	first_len = max;
 
 	/* Encourage Cookie-ECHO bundling. */
@@ -299,14 +288,11 @@ errout:
 }
 
 /* Check whether this message has expired. */
-int sctp_datamsg_expires(struct sctp_chunk *chunk)
+int sctp_chunk_abandoned(struct sctp_chunk *chunk)
 {
 	struct sctp_datamsg *msg = chunk->msg;
 
-	/* FIXME: When PR-SCTP is supported we can make this
-	 * check more lenient.
-	 */
-	if (!msg->can_expire)
+	if (!msg->can_abandon)
 		return 0;
 
 	if (time_after(jiffies, msg->expires_at))
@@ -316,7 +302,7 @@ int sctp_datamsg_expires(struct sctp_chu
 }
 
 /* This chunk (and consequently entire message) has failed in its sending. */
-void sctp_datamsg_fail(struct sctp_chunk *chunk, int error)
+void sctp_chunk_fail(struct sctp_chunk *chunk, int error)
 {
 	chunk->msg->send_failed = 1;
 	chunk->msg->send_error = error;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/crc32c.c linux-2.4.27-pre3/net/sctp/crc32c.c
--- linux-2.4.26/net/sctp/crc32c.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/crc32c.c	2004-05-18 16:55:04.000000000 +0000
@@ -69,7 +69,7 @@
 /* with 24 and 32 Parity Bits",                                  */
 /* IEEE Transactions on Communications, Vol.41, No.6, June 1993  */
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-__u32 crc_c[256] = {
+static const __u32 crc_c[256] = {
 	0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
 	0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
 	0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/debug.c linux-2.4.27-pre3/net/sctp/debug.c
--- linux-2.4.26/net/sctp/debug.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/debug.c	2004-05-18 16:52:47.000000000 +0000
@@ -1,8 +1,8 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001 Intel Corp.
- * Copyright (c) 2001 International Business Machines Corp.
  * 
  * This file is part of the SCTP kernel reference Implementation
  * 
@@ -43,6 +43,7 @@
  *    Xingang Guo           <xingang.guo@intel.com>
  *    Jon Grimm             <jgrimm@us.ibm.com>
  *    Daisy Chang	    <daisyc@us.ibm.com>
+ *    Sridhar Samudrala	    <sri@us.ibm.com>
  * 
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -88,6 +89,9 @@ const char *sctp_cname(const sctp_subtyp
 	case SCTP_CID_ASCONF_ACK:
 		return "ASCONF_ACK";
 
+	case SCTP_CID_FWD_TSN:
+		return "FWD_TSN";
+
 	default:
 		return "unknown chunk";
 	};
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/ipv6.c linux-2.4.27-pre3/net/sctp/ipv6.c
--- linux-2.4.26/net/sctp/ipv6.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/ipv6.c	2004-05-18 16:53:13.000000000 +0000
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2002, 2004
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
- * Copyright (c) 2002-2003 International Business Machines, Corp.
  * Copyright (c) 2002-2003 Intel Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
@@ -703,7 +703,7 @@ static void sctp_inet6_event_msgname(str
 		union sctp_addr *addr;
 		struct sctp_association *asoc;
 
-		asoc = event->sndrcvinfo.sinfo_assoc_id;
+		asoc = event->asoc;
 		sctp_inet6_msgname(msgname, addrlen);
 		sin6 = (struct sockaddr_in6 *)msgname;
 		sin6->sin6_port = htons(asoc->peer.port);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/objcnt.c linux-2.4.27-pre3/net/sctp/objcnt.c
--- linux-2.4.26/net/sctp/objcnt.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/objcnt.c	2004-05-18 16:52:34.000000000 +0000
@@ -132,7 +132,7 @@ void sctp_dbg_objcnt_init(void)
 /* Cleanup the objcount entry in the proc filesystem.  */
 void sctp_dbg_objcnt_exit(void)
 {
-	remove_proc_entry("sctp_dbg_objcount", proc_net_sctp);
+	remove_proc_entry("sctp_dbg_objcnt", proc_net_sctp);
 }
 
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/output.c linux-2.4.27-pre3/net/sctp/output.c
--- linux-2.4.26/net/sctp/output.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/output.c	2004-05-18 16:53:04.000000000 +0000
@@ -62,29 +62,35 @@
 #include <net/sctp/sm.h>
 
 /* Forward declarations for private helpers. */
-static void sctp_packet_reset(struct sctp_packet *packet);
 static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
 					   struct sctp_chunk *chunk);
 
 /* Config a packet.
- * This appears to be a followup set of initializations.)
+ * This appears to be a followup set of initializations.
  */
 struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
-				       __u32 vtag, int ecn_capable,
-				       sctp_packet_phandler_t *prepend_handler)
+				       __u32 vtag, int ecn_capable)
 {
-	int packet_empty = (packet->size == SCTP_IP_OVERHEAD);
+	struct sctp_chunk *chunk = NULL;
+
+	SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __FUNCTION__,
+			  packet, vtag);
 
 	packet->vtag = vtag;
-	packet->ecn_capable = ecn_capable;
-	packet->get_prepend_chunk = prepend_handler;
 	packet->has_cookie_echo = 0;
 	packet->has_sack = 0;
 	packet->ipfragok = 0;
 
-	/* We might need to call the prepend_handler right away.  */
-	if (packet_empty)
-		sctp_packet_reset(packet);
+	if (ecn_capable && sctp_packet_empty(packet)) {
+		chunk = sctp_get_ecne_prepend(packet->transport->asoc);
+
+		/* If there a is a prepend chunk stick it on the list before
+	 	 * any other chunks get appended.
+	 	 */
+		if (chunk)
+			sctp_packet_append_chunk(packet, chunk);
+	}
+
 	return packet;
 }
 
@@ -93,19 +99,30 @@ struct sctp_packet *sctp_packet_init(str
 				     struct sctp_transport *transport,
 				     __u16 sport, __u16 dport)
 {
+	struct sctp_association *asoc = transport->asoc;
+	size_t overhead;
+
+	SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __FUNCTION__,
+			  packet, transport);
+
 	packet->transport = transport;
 	packet->source_port = sport;
 	packet->destination_port = dport;
 	skb_queue_head_init(&packet->chunks);
-	packet->size = SCTP_IP_OVERHEAD;
+	if (asoc) {
+		struct sctp_opt *sp = sctp_sk(asoc->base.sk);	
+		overhead = sp->pf->af->net_header_len; 
+	} else {
+		overhead = sizeof(struct ipv6hdr);
+	}
+	overhead += sizeof(struct sctphdr);
+	packet->overhead = overhead;
+	packet->size = overhead;
 	packet->vtag = 0;
-	packet->ecn_capable = 0;
-	packet->get_prepend_chunk = NULL;
 	packet->has_cookie_echo = 0;
 	packet->has_sack = 0;
 	packet->ipfragok = 0;
 	packet->malloced = 0;
-	sctp_packet_reset(packet);
 	return packet;
 }
 
@@ -114,6 +131,8 @@ void sctp_packet_free(struct sctp_packet
 {
 	struct sctp_chunk *chunk;
 
+	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
+
         while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)))
 		sctp_chunk_free(chunk);
 
@@ -134,6 +153,9 @@ sctp_xmit_t sctp_packet_transmit_chunk(s
 	sctp_xmit_t retval;
 	int error = 0;
 
+	SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__,
+			  packet, chunk);
+
 	switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) {
 	case SCTP_XMIT_PMTU_FULL:
 		if (!packet->has_cookie_echo) {
@@ -148,7 +170,6 @@ sctp_xmit_t sctp_packet_transmit_chunk(s
 		}
 		break;
 
-	case SCTP_XMIT_MUST_FRAG:
 	case SCTP_XMIT_RWND_FULL:
 	case SCTP_XMIT_OK:
 	case SCTP_XMIT_NAGLE_DELAY:
@@ -201,6 +222,9 @@ sctp_xmit_t sctp_packet_append_chunk(str
 	size_t pmtu;
 	int too_big;
 
+	SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet,
+			  chunk);
+
 	retval = sctp_packet_bundle_sack(packet, chunk);
 	psize = packet->size;
 
@@ -215,17 +239,14 @@ sctp_xmit_t sctp_packet_append_chunk(str
 
 	/* Decide if we need to fragment or resubmit later. */
 	if (too_big) {
-		int packet_empty = (packet->size == SCTP_IP_OVERHEAD);
-
 		/* Both control chunks and data chunks with TSNs are
 		 * non-fragmentable.
 		 */
-		if (packet_empty || !sctp_chunk_is_data(chunk)) {
+		if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk)) {
 			/* We no longer do re-fragmentation.
 			 * Just fragment at the IP layer, if we
 			 * actually hit this condition
 			 */
-
 			packet->ipfragok = 1;
 			goto append;
 
@@ -233,9 +254,6 @@ sctp_xmit_t sctp_packet_append_chunk(str
 			retval = SCTP_XMIT_PMTU_FULL;
 			goto finish;
 		}
-	} else {
-		/* The chunk fits in the packet.  */
-		goto append;
 	}
 
 append:
@@ -260,6 +278,7 @@ append:
 	/* It is OK to send this chunk.  */
 	__skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
 	packet->size += chunk_len;
+	chunk->transport = packet->transport;
 finish:
 	return retval;
 }
@@ -283,6 +302,8 @@ int sctp_packet_transmit(struct sctp_pac
 	__u8 has_data = 0;
 	struct dst_entry *dst;
 
+	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
+
 	/* Do NOT generate a chunkless packet. */
 	chunk = (struct sctp_chunk *)skb_peek(&packet->chunks);
 	if (unlikely(!chunk))
@@ -297,7 +318,7 @@ int sctp_packet_transmit(struct sctp_pac
 		goto nomem;
 
 	/* Make sure the outbound skb has enough header room reserved. */
-	skb_reserve(nskb, SCTP_IP_OVERHEAD);
+	skb_reserve(nskb, packet->overhead);
 
 	/* Set the owning socket so that we know where to get the
 	 * destination IP address.
@@ -471,7 +492,7 @@ int sctp_packet_transmit(struct sctp_pac
 	(*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);
 
 out:
-	packet->size = SCTP_IP_OVERHEAD;
+	packet->size = packet->overhead;
 	return err;
 no_route:
 	kfree_skb(nskb);
@@ -497,7 +518,6 @@ err:
 	goto out;
 nomem:
 	err = -ENOMEM;
-	printk("%s alloc_skb failed.\n", __FUNCTION__);
 	goto err;
 }
 
@@ -505,25 +525,6 @@ nomem:
  * 2nd Level Abstractions
  ********************************************************************/
 
-/*
- * This private function resets the packet to a fresh state.
- */
-static void sctp_packet_reset(struct sctp_packet *packet)
-{
-	struct sctp_chunk *chunk = NULL;
-
-	packet->size = SCTP_IP_OVERHEAD;
-
-	if (packet->get_prepend_chunk)
-		chunk = packet->get_prepend_chunk(packet->transport->asoc);
-
-	/* If there a is a prepend chunk stick it on the list before
-	 * any other chunks get appended.
-	 */
-	if (chunk)
-		sctp_packet_append_chunk(packet, chunk);
-}
-
 /* This private function handles the specifics of appending DATA chunks.  */
 static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
 					   struct sctp_chunk *chunk)
@@ -609,7 +610,7 @@ static sctp_xmit_t sctp_packet_append_da
 	 * if any previously transmitted data on the connection remains
 	 * unacknowledged.
 	 */
-	if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size &&
+	if (!sp->nodelay && sctp_packet_empty(packet) &&
 	    q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) {
 		unsigned len = datasize + q->out_qlen;
 
@@ -617,7 +618,7 @@ static sctp_xmit_t sctp_packet_append_da
 		 * data will fit or delay in hopes of bundling a full
 		 * sized packet.
 		 */
-		if (len < asoc->pmtu - SCTP_IP_OVERHEAD) {
+		if (len < asoc->pmtu - packet->overhead) {
 			retval = SCTP_XMIT_NAGLE_DELAY;
 			goto finish;
 		}
@@ -637,7 +638,8 @@ static sctp_xmit_t sctp_packet_append_da
 
 	asoc->peer.rwnd = rwnd;
 	/* Has been accepted for transmission. */
-	chunk->msg->can_expire = 0;
+	if (!asoc->peer.prsctp_capable)
+		chunk->msg->can_abandon = 0;
 
 finish:
 	return retval;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/outqueue.c linux-2.4.27-pre3/net/sctp/outqueue.c
--- linux-2.4.26/net/sctp/outqueue.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/outqueue.c	2004-05-18 16:52:05.000000000 +0000
@@ -1,8 +1,8 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001-2003 Intel Corp.
- * Copyright (c) 2001-2003 International Business Machines Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
  *
@@ -69,6 +69,8 @@ static void sctp_mark_missing(struct sct
 			      __u32 highest_new_tsn,
 			      int count_of_newacks);
 
+static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
+
 /* Add data to the front of the queue. */
 static inline void sctp_outq_head_data(struct sctp_outq *q,
 					struct sctp_chunk *ch)
@@ -222,12 +224,7 @@ void sctp_outq_init(struct sctp_associat
 	skb_queue_head_init(&q->control);
 	INIT_LIST_HEAD(&q->retransmit);
 	INIT_LIST_HEAD(&q->sacked);
-
-	q->init_output = NULL;
-	q->config_output = NULL;
-	q->append_output = NULL;
-	q->build_output = NULL;
-	q->force_output = NULL;
+	INIT_LIST_HEAD(&q->abandoned);
 
 	q->outstanding_bytes = 0;
 	q->empty = 1;
@@ -252,7 +249,7 @@ void sctp_outq_teardown(struct sctp_outq
 			chunk = list_entry(lchunk, struct sctp_chunk,
 					   transmitted_list);
 			/* Mark as part of a failed message. */
-			sctp_datamsg_fail(chunk, q->error);
+			sctp_chunk_fail(chunk, q->error);
 			sctp_chunk_free(chunk);
 		}
 	}
@@ -262,7 +259,7 @@ void sctp_outq_teardown(struct sctp_outq
 		list_del_init(lchunk);
 		chunk = list_entry(lchunk, struct sctp_chunk,
 				   transmitted_list);
-		sctp_datamsg_fail(chunk, q->error);
+		sctp_chunk_fail(chunk, q->error);
 		sctp_chunk_free(chunk);
 	}
 
@@ -271,7 +268,16 @@ void sctp_outq_teardown(struct sctp_outq
 		list_del_init(lchunk);
 		chunk = list_entry(lchunk, struct sctp_chunk,
 				   transmitted_list);
-		sctp_datamsg_fail(chunk, q->error);
+		sctp_chunk_fail(chunk, q->error);
+		sctp_chunk_free(chunk);
+	}
+
+	/* Throw away any chunks that are in the abandoned queue. */
+	list_for_each_safe(lchunk, temp, &q->abandoned) {
+		list_del_init(lchunk);
+		chunk = list_entry(lchunk, struct sctp_chunk,
+				   transmitted_list);
+		sctp_chunk_fail(chunk, q->error);
 		sctp_chunk_free(chunk);
 	}
 
@@ -279,7 +285,7 @@ void sctp_outq_teardown(struct sctp_outq
 	while ((chunk = sctp_outq_dequeue_data(q))) {
 
 		/* Mark as send failure. */
-		sctp_datamsg_fail(chunk, q->error);
+		sctp_chunk_fail(chunk, q->error);
 		sctp_chunk_free(chunk);
 	}
 
@@ -363,32 +369,30 @@ int sctp_outq_tail(struct sctp_outq *q, 
 	return error;
 }
 
-/* Insert a chunk into the retransmit queue.  Chunks on the retransmit
- * queue are kept in order, based on the TSNs.
+/* Insert a chunk into the sorted list based on the TSNs.  The retransmit list
+ * and the abandoned list are in ascending order.
  */
-void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q)
+void sctp_insert_list(struct list_head *head, struct list_head *new)
 {
-	struct list_head *rlchunk;
-	struct sctp_chunk *tchunk, *rchunk;
-	__u32 ttsn, rtsn;
+	struct list_head *pos;
+	struct sctp_chunk *nchunk, *lchunk;
+	__u32 ntsn, ltsn;
 	int done = 0;
 
-	tchunk = list_entry(tlchunk, struct sctp_chunk, transmitted_list);
-	ttsn = ntohl(tchunk->subh.data_hdr->tsn);
+	nchunk = list_entry(new, struct sctp_chunk, transmitted_list);
+	ntsn = ntohl(nchunk->subh.data_hdr->tsn);
 
-	list_for_each(rlchunk, &q->retransmit) {
-		rchunk = list_entry(rlchunk, struct sctp_chunk,
-				    transmitted_list);
-		rtsn = ntohl(rchunk->subh.data_hdr->tsn);
-		if (TSN_lt(ttsn, rtsn)) {
-			list_add(tlchunk, rlchunk->prev);
+	list_for_each(pos, head) {
+		lchunk = list_entry(pos, struct sctp_chunk, transmitted_list);
+		ltsn = ntohl(lchunk->subh.data_hdr->tsn);
+		if (TSN_lt(ntsn, ltsn)) {
+			list_add(new, pos->prev);
 			done = 1;
 			break;
 		}
 	}
-	if (!done) {
-		list_add_tail(tlchunk, &q->retransmit);
-	}
+	if (!done)
+		list_add_tail(new, head); 
 }
 
 /* Mark all the eligible packets on a transport for retransmission.  */
@@ -404,6 +408,13 @@ void sctp_retransmit_mark(struct sctp_ou
 		chunk = list_entry(lchunk, struct sctp_chunk,
 				   transmitted_list);
 
+		/* If the chunk is abandoned, move it to abandoned list. */
+		if (sctp_chunk_abandoned(chunk)) {
+			list_del_init(lchunk);
+			sctp_insert_list(&q->abandoned, lchunk);
+			continue;
+		}
+
 		/* If we are doing retransmission due to a fast retransmit,
 		 * only the chunk's that are marked for fast retransmit
 		 * should be added to the retransmit queue.  If we are doing
@@ -444,10 +455,10 @@ void sctp_retransmit_mark(struct sctp_ou
 			}
 
 			/* Move the chunk to the retransmit queue. The chunks
-			 * on the retransmit queue is always kept in order.
+			 * on the retransmit queue are always kept in order.
 			 */
 			list_del_init(lchunk);
-			sctp_retransmit_insert(lchunk, q);
+			sctp_insert_list(&q->retransmit, lchunk);
 		}
 	}
 
@@ -490,6 +501,12 @@ void sctp_retransmit(struct sctp_outq *q
 
 	sctp_retransmit_mark(q, transport, fast_retransmit);
 
+	/* PR-SCTP A5) Any time the T3-rtx timer expires, on any destination,
+	 * the sender SHOULD try to advance the "Advanced.Peer.Ack.Point" by
+	 * following the procedures outlined in C1 - C5.
+	 */
+	sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point);
+
 	error = sctp_outq_flush(q, /* rtx_timeout */ 1);
 
 	if (error)
@@ -552,12 +569,12 @@ static int sctp_outq_flush_rtx(struct sc
 		}
 
 		/* Attempt to append this chunk to the packet. */
-		status = (*q->append_output)(pkt, chunk);
+		status = sctp_packet_append_chunk(pkt, chunk);
 
 		switch (status) {
 		case SCTP_XMIT_PMTU_FULL:
 			/* Send this packet.  */
-			if ((error = (*q->force_output)(pkt)) == 0)
+			if ((error = sctp_packet_transmit(pkt)) == 0)
 				*start_timer = 1;
 
 			/* If we are retransmitting, we should only
@@ -573,7 +590,7 @@ static int sctp_outq_flush_rtx(struct sc
 
 		case SCTP_XMIT_RWND_FULL:
 		        /* Send this packet. */
-			if ((error = (*q->force_output)(pkt)) == 0)
+			if ((error = sctp_packet_transmit(pkt)) == 0)
 				*start_timer = 1;
 
 			/* Stop sending DATA as there is no more room
@@ -583,6 +600,16 @@ static int sctp_outq_flush_rtx(struct sc
 			lchunk = NULL;
 			break;
 
+		case SCTP_XMIT_NAGLE_DELAY:
+		        /* Send this packet. */
+			if ((error = sctp_packet_transmit(pkt)) == 0)
+				*start_timer = 1;
+
+			/* Stop sending DATA because of nagle delay. */
+			list_add(lchunk, lqueue);
+			lchunk = NULL;
+			break;
+
 		default:
 			/* The append was successful, so add this chunk to
 			 * the transmitted list.
@@ -625,13 +652,9 @@ int sctp_outq_flush(struct sctp_outq *q,
 	struct sctp_packet *packet;
 	struct sctp_packet singleton;
 	struct sctp_association *asoc = q->asoc;
-	int ecn_capable = asoc->peer.ecn_capable;
 	__u16 sport = asoc->base.bind_addr.port;
 	__u16 dport = asoc->peer.port;
 	__u32 vtag = asoc->peer.i.init_tag;
-	/* This is the ECNE handler for singleton packets.  */
-	sctp_packet_phandler_t *s_ecne_handler = NULL;
-	sctp_packet_phandler_t *ecne_handler = NULL;
 	struct sk_buff_head *queue;
 	struct sctp_transport *transport = NULL;
 	struct sctp_transport *new_transport;
@@ -656,10 +679,6 @@ int sctp_outq_flush(struct sctp_outq *q,
 	 *   within a SCTP packet in increasing order of TSN.
 	 *   ...
 	 */
-	if (ecn_capable) {
-		s_ecne_handler = &sctp_get_no_prepend;
-		ecne_handler = &sctp_get_ecne_prepend;
-	}
 
 	queue = &q->control;
 	while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) {
@@ -686,8 +705,8 @@ int sctp_outq_flush(struct sctp_outq *q,
 					      &transport_list);
 			}
 			packet = &transport->packet;
-			(*q->config_output)(packet, vtag,
-					    ecn_capable, ecne_handler);
+			sctp_packet_config(packet, vtag,
+					   asoc->peer.ecn_capable);
 		}
 
 		switch (chunk->chunk_hdr->type) {
@@ -700,11 +719,10 @@ int sctp_outq_flush(struct sctp_outq *q,
 		case SCTP_CID_INIT:
 		case SCTP_CID_INIT_ACK:
 		case SCTP_CID_SHUTDOWN_COMPLETE:
-			(*q->init_output)(&singleton, transport, sport, dport);
-			(*q->config_output)(&singleton, vtag, ecn_capable,
-					    s_ecne_handler);
-			(void) (*q->build_output)(&singleton, chunk);
-			error = (*q->force_output)(&singleton);
+			sctp_packet_init(&singleton, transport, sport, dport);
+			sctp_packet_config(&singleton, vtag, 0);
+			sctp_packet_append_chunk(&singleton, chunk);
+			error = sctp_packet_transmit(&singleton);
 			if (error < 0)
 				return error;
 			break;
@@ -720,12 +738,10 @@ int sctp_outq_flush(struct sctp_outq *q,
 		case SCTP_CID_COOKIE_ACK:
 		case SCTP_CID_ECN_ECNE:
 		case SCTP_CID_ECN_CWR:
-			(void) (*q->build_output)(packet, chunk);
-			break;
-
 		case SCTP_CID_ASCONF:
 		case SCTP_CID_ASCONF_ACK:
-			(void) (*q->build_output)(packet, chunk);
+		case SCTP_CID_FWD_TSN:
+			sctp_packet_transmit_chunk(packet, chunk);
 			break;
 
 		default:
@@ -770,8 +786,8 @@ int sctp_outq_flush(struct sctp_outq *q,
 			}
 
 			packet = &transport->packet;
-			(*q->config_output)(packet, vtag,
-					    ecn_capable, ecne_handler);
+			sctp_packet_config(packet, vtag,
+					   asoc->peer.ecn_capable);
 		retran:
 			error = sctp_outq_flush_rtx(q, packet,
 						    rtx_timeout, &start_timer);
@@ -803,15 +819,15 @@ int sctp_outq_flush(struct sctp_outq *q,
 			if (chunk->sinfo.sinfo_stream >=
 			    asoc->c.sinit_num_ostreams) {
 
-				/* Mark as s failed send. */
-				sctp_datamsg_fail(chunk, SCTP_ERROR_INV_STRM);
+				/* Mark as failed send. */
+				sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM);
 				sctp_chunk_free(chunk);
 				continue;
 			}
 
 			/* Has this chunk expired? */
-			if (sctp_datamsg_expires(chunk)) {
-				sctp_datamsg_fail(chunk, 0);
+			if (sctp_chunk_abandoned(chunk)) {
+				sctp_chunk_fail(chunk, 0);
 				sctp_chunk_free(chunk);
 				continue;
 			}
@@ -836,11 +852,11 @@ int sctp_outq_flush(struct sctp_outq *q,
 				}
 
 				packet = &transport->packet;
-				(*q->config_output)(packet, vtag,
-						    ecn_capable, ecne_handler);
+				sctp_packet_config(packet, vtag,
+						   asoc->peer.ecn_capable);
 			}
 
-			SCTP_DEBUG_PRINTK("sctp_transmit_packet(%p, %p[%s]), ",
+			SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ",
 					  q, chunk,
 					  chunk && chunk->chunk_hdr ?
 					  sctp_cname(SCTP_ST_CHUNK(
@@ -855,7 +871,7 @@ int sctp_outq_flush(struct sctp_outq *q,
 					atomic_read(&chunk->skb->users) : -1);
 
 			/* Add the chunk to the packet.  */
-			status = (*q->build_output)(packet, chunk);
+			status = sctp_packet_transmit_chunk(packet, chunk);
 
 			switch (status) {
 			case SCTP_XMIT_PMTU_FULL:
@@ -879,7 +895,7 @@ int sctp_outq_flush(struct sctp_outq *q,
 				BUG();
 			}
 
-			/* BUG: We assume that the (*q->force_output())
+			/* BUG: We assume that the sctp_packet_transmit() 
 			 * call below will succeed all the time and add the
 			 * chunk to the transmitted list and restart the
 			 * timers.
@@ -922,33 +938,14 @@ sctp_flush_out:
 		struct sctp_transport *t = list_entry(ltransport,
 						      struct sctp_transport,
 						      send_ready);
-		if (t != transport)
-			transport = t;
-
-		packet = &transport->packet;
-		if (packet->size != SCTP_IP_OVERHEAD)
-			error = (*q->force_output)(packet);
+		packet = &t->packet;
+		if (!sctp_packet_empty(packet))
+			error = sctp_packet_transmit(packet);
 	}
 
 	return error;
 }
 
-/* Set the various output handling callbacks.  */
-int sctp_outq_set_output_handlers(struct sctp_outq *q,
-				      sctp_outq_ohandler_init_t init,
-				      sctp_outq_ohandler_config_t config,
-				      sctp_outq_ohandler_t append,
-				      sctp_outq_ohandler_t build,
-				      sctp_outq_ohandler_force_t force)
-{
-	q->init_output = init;
-	q->config_output = config;
-	q->append_output = append;
-	q->build_output = build;
-	q->force_output = force;
-	return 0;
-}
-
 /* Update unack_data based on the incoming SACK chunk */
 static void sctp_sack_update_unack_data(struct sctp_association *assoc,
 					struct sctp_sackhdr *sack)
@@ -1007,7 +1004,7 @@ int sctp_outq_sack(struct sctp_outq *q, 
 {
 	struct sctp_association *asoc = q->asoc;
 	struct sctp_transport *transport;
-	struct sctp_chunk *tchunk;
+	struct sctp_chunk *tchunk = NULL;
 	struct list_head *lchunk, *transport_list, *pos, *temp;
 	sctp_sack_variable_t *frags = sack->variable;
 	__u32 sack_ctsn, ctsn, tsn;
@@ -1110,11 +1107,6 @@ int sctp_outq_sack(struct sctp_outq *q, 
 
 	ctsn = asoc->ctsn_ack_point;
 
-	SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n",
-			  __FUNCTION__, sack_ctsn);
-	SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association "
-			  "%p is 0x%x.\n", __FUNCTION__, asoc, ctsn);
-
 	/* Throw away stuff rotting on the sack queue.  */
 	list_for_each_safe(lchunk, temp, &q->sacked) {
 		tchunk = list_entry(lchunk, struct sctp_chunk,
@@ -1139,10 +1131,19 @@ int sctp_outq_sack(struct sctp_outq *q, 
 
 	asoc->peer.rwnd = sack_a_rwnd;
 
+	sctp_generate_fwdtsn(q, sack_ctsn);
+
+	SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n",
+			  __FUNCTION__, sack_ctsn);
+	SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, "
+			  "%p is 0x%x. Adv peer ack point: 0x%x\n",
+			  __FUNCTION__, asoc, ctsn, asoc->adv_peer_ack_point);
+
 	/* See if all chunks are acked.
 	 * Make sure the empty queue handler will get run later.
 	 */
-	q->empty = skb_queue_empty(&q->out) && list_empty(&q->retransmit);
+	q->empty = skb_queue_empty(&q->out) && skb_queue_empty(&q->control) &&
+			list_empty(&q->retransmit);
 	if (!q->empty)
 		goto finish;
 
@@ -1218,6 +1219,12 @@ static void sctp_check_transmitted(struc
 		tchunk = list_entry(lchunk, struct sctp_chunk,
 				    transmitted_list);
 
+		if (sctp_chunk_abandoned(tchunk)) {
+			/* Move the chunk to abandoned list. */
+			sctp_insert_list(&q->abandoned, lchunk);
+			continue;
+		}
+
 		tsn = ntohl(tchunk->subh.data_hdr->tsn);
 		if (sctp_acked(sack, tsn)) {
 			/* If this queue is the retransmit queue, the
@@ -1599,3 +1606,123 @@ static int sctp_acked(struct sctp_sackhd
 pass:
 	return 1;
 }
+
+static inline int sctp_get_skip_pos(struct sctp_fwdtsn_skip *skiplist,
+				    int nskips, __u16 stream)
+{
+	int i;
+
+	for (i = 0; i < nskips; i++) {
+		if (skiplist[i].stream == stream)
+			return i;
+	}
+	return i;
+}
+
+/* Create and add a fwdtsn chunk to the outq's control queue if needed. */
+static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
+{
+	struct sctp_association *asoc = q->asoc;
+	struct sctp_chunk *ftsn_chunk = NULL;
+	struct sctp_fwdtsn_skip ftsn_skip_arr[10];
+	int nskips = 0;
+	int skip_pos = 0;
+	__u32 tsn;
+	struct sctp_chunk *chunk;
+	struct list_head *lchunk, *temp;
+
+	/* PR-SCTP C1) Let SackCumAck be the Cumulative TSN ACK carried in the
+	 * received SACK.
+	 * 
+	 * If (Advanced.Peer.Ack.Point < SackCumAck), then update
+	 * Advanced.Peer.Ack.Point to be equal to SackCumAck.
+	 */
+	if (TSN_lt(asoc->adv_peer_ack_point, ctsn))
+		asoc->adv_peer_ack_point = ctsn;
+
+	/* PR-SCTP C2) Try to further advance the "Advanced.Peer.Ack.Point"
+	 * locally, that is, to move "Advanced.Peer.Ack.Point" up as long as
+	 * the chunk next in the out-queue space is marked as "abandoned" as
+	 * shown in the following example:
+	 *
+	 * Assuming that a SACK arrived with the Cumulative TSN ACK 102
+	 * and the Advanced.Peer.Ack.Point is updated to this value:
+	 * 
+	 *   out-queue at the end of  ==>   out-queue after Adv.Ack.Point
+	 *   normal SACK processing           local advancement
+	 *                ...                           ...
+	 *   Adv.Ack.Pt-> 102 acked                     102 acked
+	 *                103 abandoned                 103 abandoned
+	 *                104 abandoned     Adv.Ack.P-> 104 abandoned
+	 *                105                           105
+	 *                106 acked                     106 acked
+	 *                ...                           ...
+	 *
+	 * In this example, the data sender successfully advanced the
+	 * "Advanced.Peer.Ack.Point" from 102 to 104 locally.
+	 */
+	list_for_each_safe(lchunk, temp, &q->abandoned) {
+		chunk = list_entry(lchunk, struct sctp_chunk,
+					transmitted_list);
+		tsn = ntohl(chunk->subh.data_hdr->tsn);
+
+		/* Remove any chunks in the abandoned queue that are acked by
+		 * the ctsn.
+		 */ 
+		if (TSN_lte(tsn, ctsn)) {
+			list_del_init(lchunk);
+			if (!chunk->tsn_gap_acked) {
+			chunk->transport->flight_size -=
+						 sctp_data_size(chunk);
+			q->outstanding_bytes -= sctp_data_size(chunk);
+			}
+			sctp_chunk_free(chunk);
+		} else {
+			if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) {
+				asoc->adv_peer_ack_point = tsn;
+				if (chunk->chunk_hdr->flags &
+					 SCTP_DATA_UNORDERED)
+					continue;
+				skip_pos = sctp_get_skip_pos(&ftsn_skip_arr[0],
+						nskips,
+						chunk->subh.data_hdr->stream);
+				ftsn_skip_arr[skip_pos].stream =
+					chunk->subh.data_hdr->stream;
+				ftsn_skip_arr[skip_pos].ssn =
+					 chunk->subh.data_hdr->ssn;
+				if (skip_pos == nskips)
+					nskips++;
+				if (nskips == 10)
+					break;
+			} else
+				break;
+		}
+	}
+
+	/* PR-SCTP C3) If, after step C1 and C2, the "Advanced.Peer.Ack.Point"
+	 * is greater than the Cumulative TSN ACK carried in the received
+	 * SACK, the data sender MUST send the data receiver a FORWARD TSN
+	 * chunk containing the latest value of the
+	 * "Advanced.Peer.Ack.Point".
+	 *
+	 * C4) For each "abandoned" TSN the sender of the FORWARD TSN SHOULD
+	 * list each stream and sequence number in the forwarded TSN. This
+	 * information will enable the receiver to easily find any
+	 * stranded TSN's waiting on stream reorder queues. Each stream
+	 * SHOULD only be reported once; this means that if multiple
+	 * abandoned messages occur in the same stream then only the
+	 * highest abandoned stream sequence number is reported. If the
+	 * total size of the FORWARD TSN does NOT fit in a single MTU then
+	 * the sender of the FORWARD TSN SHOULD lower the
+	 * Advanced.Peer.Ack.Point to the last TSN that will fit in a
+	 * single MTU.
+	 */
+	if (asoc->adv_peer_ack_point > ctsn)
+		ftsn_chunk = sctp_make_fwdtsn(asoc, asoc->adv_peer_ack_point,
+					      nskips, &ftsn_skip_arr[0]); 
+
+	if (ftsn_chunk) {
+		__skb_queue_tail(&q->control, (struct sk_buff *)ftsn_chunk);
+		SCTP_INC_STATS(SctpOutCtrlChunks);
+	}
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/protocol.c linux-2.4.27-pre3/net/sctp/protocol.c
--- linux-2.4.26/net/sctp/protocol.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/protocol.c	2004-05-18 16:53:25.000000000 +0000
@@ -719,7 +719,7 @@ static void sctp_inet_event_msgname(stru
 	if (msgname) {
 		struct sctp_association *asoc;
 
-		asoc = event->sndrcvinfo.sinfo_assoc_id;
+		asoc = event->asoc;
 		sctp_inet_msgname(msgname, addr_len);
 		sin = (struct sockaddr_in *)msgname;
 		sinfrom = &asoc->peer.primary_addr.v4;
@@ -981,6 +981,8 @@ __init int sctp_init(void)
 
 	/* Initialize proc fs directory.  */
 	sctp_proc_init();
+	if (status)
+		goto err_init_proc;
 
 	/* Initialize object count debugging.  */
 	sctp_dbg_objcnt_init();
@@ -1099,6 +1101,9 @@ __init int sctp_init(void)
 	/* Disable ADDIP by default. */
 	sctp_addip_enable = 0;
 
+	/* Enable PR-SCTP by default. */
+	sctp_prsctp_enable = 1;
+
 	sctp_sysctl_register();
 
 	INIT_LIST_HEAD(&sctp_address_families);
@@ -1143,6 +1148,7 @@ err_ehash_alloc:
 			     sizeof(struct sctp_hashbucket)));
 err_ahash_alloc:
 	sctp_dbg_objcnt_exit();
+err_init_proc:
 	sctp_proc_exit();
 	cleanup_sctp_mibs();
 err_init_mibs:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/sm_make_chunk.c linux-2.4.27-pre3/net/sctp/sm_make_chunk.c
--- linux-2.4.26/net/sctp/sm_make_chunk.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/sm_make_chunk.c	2004-05-18 16:50:57.000000000 +0000
@@ -6,10 +6,6 @@
  *
  * This file is part of the SCTP kernel reference Implementation
  *
- * This file includes part of the implementation of the add-IP extension,
- * based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001,
- * for the SCTP kernel reference Implementation.
- *
  * These functions work with the state functions in sctp_sm_statefuns.c
  * to implement the state operations.  These functions implement the
  * steps which require modifying existing data structures.
@@ -89,11 +85,13 @@ int sctp_chunk_iif(const struct sctp_chu
  * Note 2: The ECN capable field is reserved for future use of
  * Explicit Congestion Notification.
  */
-static const sctp_ecn_capable_param_t ecap_param = {
-	{
-		SCTP_PARAM_ECN_CAPABLE,
-		__constant_htons(sizeof(sctp_ecn_capable_param_t)),
-	}
+static const struct sctp_paramhdr ecap_param = {
+	SCTP_PARAM_ECN_CAPABLE,
+	__constant_htons(sizeof(struct sctp_paramhdr)),
+};
+static const struct sctp_paramhdr prsctp_param = {
+	SCTP_PARAM_FWD_TSN_SUPPORT,
+	__constant_htons(sizeof(struct sctp_paramhdr)),
 };
 
 /* A helper to initialize to initialize an op error inside a
@@ -196,6 +194,8 @@ struct sctp_chunk *sctp_make_init(const 
 
 	chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types);
 	chunksize += sizeof(ecap_param);
+	if (sctp_prsctp_enable)
+		chunksize += sizeof(prsctp_param);
 	chunksize += vparam_len;
 
 	/* RFC 2960 3.3.2 Initiation (INIT) (1)
@@ -232,6 +232,8 @@ struct sctp_chunk *sctp_make_init(const 
 	sctp_addto_chunk(retval, num_types * sizeof(__u16), &types);
 
 	sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
+	if (sctp_prsctp_enable)
+		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 nodata:
 	if (addrs.v)
 		kfree(addrs.v);
@@ -278,6 +280,10 @@ struct sctp_chunk *sctp_make_init_ack(co
 	if (asoc->peer.ecn_capable)
 		chunksize += sizeof(ecap_param);
 
+        /* Tell peer that we'll do PR-SCTP only if peer advertised.  */
+	if (asoc->peer.prsctp_capable)
+		chunksize += sizeof(prsctp_param);
+
 	/* Now allocate and fill out the chunk.  */
 	retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
 	if (!retval)
@@ -293,6 +299,8 @@ struct sctp_chunk *sctp_make_init_ack(co
 	sctp_addto_chunk(retval, cookie_len, cookie);
 	if (asoc->peer.ecn_capable)
 		sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
+	if (asoc->peer.prsctp_capable)
+		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 
 	/* We need to remove the const qualifier at this point.  */
 	retval->asoc = (struct sctp_association *) asoc;
@@ -1286,6 +1294,9 @@ sctp_cookie_param_t *sctp_pack_cookie(co
 	/* Save the raw address list length in the cookie. */
 	cookie->c.raw_addr_list_len = addrs_len;
 
+	/* Remember PR-SCTP capability. */
+	cookie->c.prsctp_capable = asoc->peer.prsctp_capable;
+
 	/* Set an expiration time for the cookie.  */
 	do_gettimeofday(&cookie->c.expiration);
 	TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration);
@@ -1442,6 +1453,8 @@ no_hmac:
 	retval->next_tsn = retval->c.initial_tsn;
 	retval->ctsn_ack_point = retval->next_tsn - 1;
 	retval->addip_serial = retval->c.initial_tsn;
+	retval->adv_peer_ack_point = retval->ctsn_ack_point;
+	retval->peer.prsctp_capable = retval->c.prsctp_capable;
 
 	/* The INIT stuff will be done by the side effects.  */
 	return retval;
@@ -1653,6 +1666,10 @@ static int sctp_verify_param(const struc
 	case SCTP_PARAM_HOST_NAME_ADDRESS:
 		/* Tell the peer, we won't support this param.  */
 		return sctp_process_hn_param(asoc, param, chunk, err_chunk);
+	case SCTP_PARAM_FWD_TSN_SUPPORT:
+		if (sctp_prsctp_enable)
+			break;
+		/* Fall Through */ 
 	default:
 		SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
 				ntohs(param.p->type), cid);
@@ -1956,6 +1973,12 @@ int sctp_process_param(struct sctp_assoc
 		asoc->peer.ecn_capable = 1;
 		break;
 
+	case SCTP_PARAM_FWD_TSN_SUPPORT:
+		if (sctp_prsctp_enable) {
+			asoc->peer.prsctp_capable = 1;
+			break;
+		}
+		/* Fall Through */ 
 	default:
 		/* Any unrecognized parameters should have been caught
 		 * and handled by sctp_verify_param() which should be
@@ -2610,3 +2633,38 @@ int sctp_process_asconf_ack(struct sctp_
 
 	return retval;
 }
+
+/* Make a FWD TSN chunk. */ 
+struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
+				    __u32 new_cum_tsn, size_t nstreams,
+				    struct sctp_fwdtsn_skip *skiplist)
+{
+	struct sctp_chunk *retval = NULL;
+	struct sctp_fwdtsn_chunk *ftsn_chunk;
+	struct sctp_fwdtsn_hdr ftsn_hdr; 
+	struct sctp_fwdtsn_skip skip;
+	size_t hint;
+	int i;
+
+	hint = (nstreams + 1) * sizeof(__u32);
+
+	/* Maybe set the T-bit if we have no association.  */
+	retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint);
+
+	if (!retval)
+		return NULL;
+
+	ftsn_chunk = (struct sctp_fwdtsn_chunk *)retval->subh.fwdtsn_hdr;
+
+	ftsn_hdr.new_cum_tsn = htonl(new_cum_tsn);
+	retval->subh.fwdtsn_hdr =
+		sctp_addto_chunk(retval, sizeof(ftsn_hdr), &ftsn_hdr);
+
+	for (i = 0; i < nstreams; i++) {
+		skip.stream = skiplist[i].stream;
+		skip.ssn = skiplist[i].ssn;
+		sctp_addto_chunk(retval, sizeof(skip), &skip);
+	}
+
+	return retval;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/sm_sideeffect.c linux-2.4.27-pre3/net/sctp/sm_sideeffect.c
--- linux-2.4.26/net/sctp/sm_sideeffect.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/sm_sideeffect.c	2004-05-18 16:53:50.000000000 +0000
@@ -579,7 +579,7 @@ static void sctp_cmd_transport_reset(sct
 /* Helper function to process the process SACK command.  */
 static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
 				 struct sctp_association *asoc,
-				 sctp_sackhdr_t *sackh)
+				 struct sctp_sackhdr *sackh)
 {
 	int err;
 
@@ -729,6 +729,19 @@ static void sctp_cmd_process_operr(sctp_
 	}
 }
 
+/* Process variable FWDTSN chunk information. */
+static void sctp_cmd_process_fwdtsn(struct sctp_ulpq *ulpq, 
+				    struct sctp_chunk *chunk)
+{
+	struct sctp_fwdtsn_skip *skip;
+	/* Walk through all the skipped SSNs */
+	sctp_walk_fwdtsn(skip, chunk) {
+		sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn));
+	}
+
+	return;
+}
+
 /* These three macros allow us to pull the debugging code out of the
  * main flow of sctp_do_sm() to keep attention focused on the real
  * functionality there.
@@ -903,7 +916,7 @@ int sctp_cmd_interpreter(sctp_event_t ev
 	struct timer_list *timer;
 	unsigned long timeout;
 	struct sctp_transport *t;
-	sctp_sackhdr_t sackh;
+	struct sctp_sackhdr sackh;
 	int local_cork = 0;
 
 	if (SCTP_EVENT_T_TIMEOUT != event_type)
@@ -962,6 +975,18 @@ int sctp_cmd_interpreter(sctp_event_t ev
 			sctp_tsnmap_mark(&asoc->peer.tsn_map, cmd->obj.u32);
 			break;
 
+		case SCTP_CMD_REPORT_FWDTSN:
+			/* Move the Cumulattive TSN Ack ahead. */
+			sctp_tsnmap_skip(&asoc->peer.tsn_map, cmd->obj.u32);
+
+			/* Abort any in progress partial delivery. */
+			sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
+			break;
+
+		case SCTP_CMD_PROCESS_FWDTSN:
+			sctp_cmd_process_fwdtsn(&asoc->ulpq, cmd->obj.ptr);
+                        break;
+
 		case SCTP_CMD_GEN_SACK:
 			/* Generate a Selective ACK.
 			 * The argument tells us whether to just count
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/sm_statefuns.c linux-2.4.27-pre3/net/sctp/sm_statefuns.c
--- linux-2.4.26/net/sctp/sm_statefuns.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/sm_statefuns.c	2004-05-18 16:53:04.000000000 +0000
@@ -3205,6 +3205,143 @@ sctp_disposition_t sctp_sf_do_asconf_ack
 }
 
 /*
+ * PR-SCTP Section 3.6 Receiver Side Implementation of PR-SCTP
+ *
+ * When a FORWARD TSN chunk arrives, the data receiver MUST first update
+ * its cumulative TSN point to the value carried in the FORWARD TSN
+ * chunk, and then MUST further advance its cumulative TSN point locally
+ * if possible.
+ * After the above processing, the data receiver MUST stop reporting any
+ * missing TSNs earlier than or equal to the new cumulative TSN point.
+ *
+ * Verification Tag:  8.5 Verification Tag [Normal verification]
+ *
+ * The return value is the disposition of the chunk.
+ */
+sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
+				       const struct sctp_association *asoc,
+				       const sctp_subtype_t type,
+				       void *arg,
+				       sctp_cmd_seq_t *commands)
+{
+	struct sctp_chunk *chunk = arg;
+	struct sctp_fwdtsn_hdr *fwdtsn_hdr;
+	__u16 len;
+	__u32 tsn;
+
+	/* RFC 2960 8.5 Verification Tag
+	 *
+	 * When receiving an SCTP packet, the endpoint MUST ensure
+	 * that the value in the Verification Tag field of the
+	 * received SCTP packet matches its own Tag.
+	 */
+	if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) {
+		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
+				SCTP_NULL());
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+	}
+
+	fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
+	chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
+	len = ntohs(chunk->chunk_hdr->length);
+	len -= sizeof(struct sctp_chunkhdr);
+	skb_pull(chunk->skb, len);
+
+	tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
+	SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+
+	/* The TSN is too high--silently discard the chunk and count on it
+	 * getting retransmitted later.
+	 */
+	if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0)
+		goto discard_noforce;
+
+	sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn));
+	if (len > sizeof(struct sctp_fwdtsn_hdr))
+		sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, 
+				SCTP_CHUNK(chunk));
+	
+	/* Count this as receiving DATA. */
+	if (asoc->autoclose) {
+		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
+				SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
+	}
+	
+	/* FIXME: For now send a SACK, but DATA processing may
+	 * send another. 
+	 */
+	sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE());
+	/* Start the SACK timer.  */
+	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
+			SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
+
+	return SCTP_DISPOSITION_CONSUME;
+
+discard_noforce:
+	return SCTP_DISPOSITION_DISCARD;
+}
+
+sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
+{
+	struct sctp_chunk *chunk = arg;
+	struct sctp_fwdtsn_hdr *fwdtsn_hdr;
+	__u16 len;
+	__u32 tsn;
+
+	/* RFC 2960 8.5 Verification Tag
+	 *
+	 * When receiving an SCTP packet, the endpoint MUST ensure
+	 * that the value in the Verification Tag field of the
+	 * received SCTP packet matches its own Tag.
+	 */
+	if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) {
+		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
+				SCTP_NULL());
+		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+	}
+
+	fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
+	chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
+	len = ntohs(chunk->chunk_hdr->length);
+	len -= sizeof(struct sctp_chunkhdr);
+	skb_pull(chunk->skb, len);
+
+	tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
+	SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+
+	/* The TSN is too high--silently discard the chunk and count on it
+	 * getting retransmitted later.
+	 */
+	if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0)
+		goto gen_shutdown;
+
+	sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn));
+	if (len > sizeof(struct sctp_fwdtsn_hdr))
+		sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, 
+				SCTP_CHUNK(chunk));
+	
+	/* Go a head and force a SACK, since we are shutting down. */
+gen_shutdown:
+	/* Implementor's Guide.
+	 *
+	 * While in SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
+	 * respond to each received packet containing one or more DATA chunk(s)
+	 * with a SACK, a SHUTDOWN chunk, and restart the T2-shutdown timer
+	 */
+	sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SHUTDOWN, SCTP_NULL());
+	sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE());
+	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
+			SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
+
+        return SCTP_DISPOSITION_CONSUME;
+}
+
+/*
  * Process an unknown chunk.
  *
  * Section: 3.2. Also, 2.1 in the implementor's guide.
@@ -4671,28 +4808,20 @@ struct sctp_packet *sctp_ootb_pkt_new(co
 
 	/* Make a transport for the bucket, Eliza... */
 	transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC);
-
 	if (!transport)
 		goto nomem;
 
-	/* Allocate a new packet for sending the response. */
-	packet = t_new(struct sctp_packet, GFP_ATOMIC);
-	if (!packet)
-		goto nomem_packet;
-
 	/* Cache a route for the transport with the chunk's destination as
 	 * the source address.
 	 */
 	sctp_transport_route(transport, (union sctp_addr *)&chunk->dest,
 			     sctp_sk(sctp_get_ctl_sock()));
 
-	packet = sctp_packet_init(packet, transport, sport, dport);
-	packet = sctp_packet_config(packet, vtag, 0, NULL);
+	packet = sctp_packet_init(&transport->packet, transport, sport, dport);
+	packet = sctp_packet_config(packet, vtag, 0);
 
 	return packet;
 
-nomem_packet:
-	sctp_transport_free(transport);
 nomem:
 	return NULL;
 }
@@ -4701,7 +4830,6 @@ nomem:
 void sctp_ootb_pkt_free(struct sctp_packet *packet)
 {
 	sctp_transport_free(packet->transport);
-	sctp_packet_free(packet);
 }
 
 /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found  */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/sm_statetable.c linux-2.4.27-pre3/net/sctp/sm_statetable.c
--- linux-2.4.26/net/sctp/sm_statetable.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/sm_statetable.c	2004-05-18 16:53:57.000000000 +0000
@@ -1,5 +1,5 @@
 /* SCTP kernel reference Implementation
- * (C) Copyright IBM Corp. 2001, 2003
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001 Intel Corp.
@@ -40,6 +40,7 @@
  *    Hui Huang		    <hui.huang@nokia.com>
  *    Daisy Chang	    <daisyc@us.ibm.com>
  *    Ardelle Fan	    <ardelle.fan@intel.com>
+ *    Sridhar Samudrala	    <sri@us.ibm.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -50,7 +51,7 @@
 #include <net/sctp/sm.h>
 
 static const sctp_sm_table_entry_t bug = {
-	.fn = sctp_sf_bug, 
+	.fn = sctp_sf_bug,
 	.name = "sctp_sf_bug"
 };
 
@@ -73,7 +74,7 @@ const sctp_sm_table_entry_t *sctp_sm_loo
 		return sctp_chunk_event_lookup(event_subtype.chunk, state);
 		break;
 	case SCTP_EVENT_T_TIMEOUT:
-		DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout, 
+		DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout,
 			  timeout_event_table);
 		break;
 
@@ -486,6 +487,34 @@ const sctp_sm_table_entry_t addip_chunk_
 	TYPE_SCTP_ASCONF_ACK,
 }; /*state_fn_t addip_chunk_event_table[][] */
 
+#define TYPE_SCTP_FWD_TSN { \
+	/* SCTP_STATE_EMPTY */ \
+	{.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
+	/* SCTP_STATE_CLOSED */ \
+	{.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"}, \
+	/* SCTP_STATE_COOKIE_WAIT */ \
+	{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
+	/* SCTP_STATE_COOKIE_ECHOED */ \
+	{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
+	/* SCTP_STATE_ESTABLISHED */ \
+	{.fn = sctp_sf_eat_fwd_tsn, .name = "sctp_sf_eat_fwd_tsn"}, \
+	/* SCTP_STATE_SHUTDOWN_PENDING */ \
+	{.fn = sctp_sf_eat_fwd_tsn, .name = "sctp_sf_eat_fwd_tsn"}, \
+	/* SCTP_STATE_SHUTDOWN_SENT */ \
+	{.fn = sctp_sf_eat_fwd_tsn_fast, .name = "sctp_sf_eat_fwd_tsn_fast"}, \
+	/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
+	{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
+	/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
+	{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
+} /* TYPE_SCTP_FWD_TSN */
+
+/* The primary index for this table is the chunk type.
+ * The secondary index for this table is the state.
+ */
+const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
+	TYPE_SCTP_FWD_TSN,
+}; /*state_fn_t prsctp_chunk_event_table[][] */
+
 static const sctp_sm_table_entry_t
 chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
 	/* SCTP_STATE_EMPTY */
@@ -924,6 +953,11 @@ const sctp_sm_table_entry_t *sctp_chunk_
 	if (cid >= 0 && cid <= SCTP_CID_BASE_MAX)
 		return &chunk_event_table[cid][state];
 
+	if (sctp_prsctp_enable) {
+		if (cid == SCTP_CID_FWD_TSN)
+			return &prsctp_chunk_event_table[0][state];
+	}
+
 	if (sctp_addip_enable) {
 		if (cid == SCTP_CID_ASCONF)
 			return &addip_chunk_event_table[0][state];
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/socket.c linux-2.4.27-pre3/net/sctp/socket.c
--- linux-2.4.26/net/sctp/socket.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/socket.c	2004-05-18 16:51:45.000000000 +0000
@@ -1495,8 +1495,7 @@ SCTP_STATIC int sctp_recvmsg(struct sock
 		 * rwnd by that amount. If all the data in the skb is read,
 		 * rwnd is updated when the event is freed.
 		 */
-		sctp_assoc_rwnd_increase(event->sndrcvinfo.sinfo_assoc_id,
-					 copied);
+		sctp_assoc_rwnd_increase(event->asoc, copied);
 		goto out;
 	} else if ((event->msg_flags & MSG_NOTIFICATION) ||
 		   (event->msg_flags & MSG_EOR))
@@ -1940,6 +1939,9 @@ static int sctp_setsockopt_mappedv4(stru
  */
 static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen)
 {
+	struct sctp_association *asoc;
+	struct list_head *pos;
+	struct sctp_opt *sp = sctp_sk(sk);
 	int val;
 
 	if (optlen < sizeof(int))
@@ -1948,7 +1950,15 @@ static int sctp_setsockopt_maxseg(struct
 		return -EFAULT;
 	if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))
 		return -EINVAL;
-	sctp_sk(sk)->user_frag = val;
+	sp->user_frag = val;
+
+	if (val) {
+		/* Update the frag_point of the existing associations. */
+		list_for_each(pos, &(sp->ep->asocs)) {
+			asoc = list_entry(pos, struct sctp_association, asocs);
+			asoc->frag_point = sctp_frag_point(sp, asoc->pmtu); 
+		}
+	}
 
 	return 0;
 }
@@ -2523,10 +2533,6 @@ static int sctp_getsockopt_sctp_status(s
 	status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
 	status.sstat_instrms = asoc->c.sinit_max_instreams;
 	status.sstat_outstrms = asoc->c.sinit_num_ostreams;
-	/* Just in time frag_point update. */
-	if (sctp_sk(sk)->user_frag)
-		asoc->frag_point
-			= min_t(int, asoc->frag_point, sctp_sk(sk)->user_frag);
 	status.sstat_fragmentation_point = asoc->frag_point;
 	status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
 	memcpy(&status.sstat_primary.spinfo_address,
@@ -4486,7 +4492,7 @@ static void sctp_sock_migrate(struct soc
 	 */
 	sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
 		event = sctp_skb2event(skb);
-		if (event->sndrcvinfo.sinfo_assoc_id == assoc) {
+		if (event->asoc == assoc) {
 			__skb_unlink(skb, skb->list);
 			__skb_queue_tail(&newsk->sk_receive_queue, skb);
 		}
@@ -4515,7 +4521,7 @@ static void sctp_sock_migrate(struct soc
 		 */
 		sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
 			event = sctp_skb2event(skb);
-			if (event->sndrcvinfo.sinfo_assoc_id == assoc) {
+			if (event->asoc == assoc) {
 				__skb_unlink(skb, skb->list);
 				__skb_queue_tail(queue, skb);
 			}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/sysctl.c linux-2.4.27-pre3/net/sctp/sysctl.c
--- linux-2.4.26/net/sctp/sysctl.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/sysctl.c	2004-05-18 16:51:37.000000000 +0000
@@ -1,5 +1,5 @@
 /* SCTP kernel reference Implementation
- * Copyright (c) 2002 International Business Machines Corp.
+ * (C) Copyright IBM Corp. 2002, 2004
  * Copyright (c) 2002 Intel Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
@@ -35,6 +35,7 @@
  *    Jon Grimm             <jgrimm@us.ibm.com>
  *    Ardelle Fan           <ardelle.fan@intel.com>
  *    Ryan Layer            <rmlayer@us.ibm.com>
+ *    Sridhar Samudrala     <sri@us.ibm.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -170,6 +171,14 @@ static ctl_table sctp_table[] = {
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec
 	},
+	{
+		.ctl_name	= NET_SCTP_PRSCTP_ENABLE,
+		.procname	= "prsctp_enable",
+		.data		= &sctp_prsctp_enable,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
 	{ .ctl_name = 0 }
 };
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/transport.c linux-2.4.27-pre3/net/sctp/transport.c
--- linux-2.4.26/net/sctp/transport.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/transport.c	2004-05-18 16:53:19.000000000 +0000
@@ -118,7 +118,6 @@ struct sctp_transport *sctp_transport_in
 	INIT_LIST_HEAD(&peer->transmitted);
 	INIT_LIST_HEAD(&peer->send_ready);
 	INIT_LIST_HEAD(&peer->transports);
-	sctp_packet_init(&peer->packet, peer, 0, 0);
 
 	/* Set up the retransmission timer.  */
 	init_timer(&peer->T3_rtx_timer);
@@ -169,6 +168,8 @@ void sctp_transport_destroy(struct sctp_
 	if (transport->asoc)
 		sctp_association_put(transport->asoc);
 
+        sctp_packet_free(&transport->packet);
+
 	dst_release(transport->dst);
 	kfree(transport);
 	SCTP_DBG_OBJCNT_DEC(transport);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/tsnmap.c linux-2.4.27-pre3/net/sctp/tsnmap.c
--- linux-2.4.26/net/sctp/tsnmap.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/tsnmap.c	2004-05-18 16:51:11.000000000 +0000
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001-2003 International Business Machines, Corp.
  * Copyright (c) 2001 Intel Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
@@ -36,6 +36,7 @@
  *    La Monte H.P. Yarroll <piggy@acm.org>
  *    Jon Grimm             <jgrimm@us.ibm.com>
  *    Karl Knutson          <karl@athena.chicago.il.us>
+ *    Sridhar Samudrala     <sri@us.ibm.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -253,6 +254,40 @@ int sctp_tsnmap_next_gap_ack(const struc
 	return ended;
 }
 
+/* Mark this and any lower TSN as seen.  */
+void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn)
+{
+	__s32 gap;
+
+	/* Vacuously mark any TSN which precedes the map base or
+	 * exceeds the end of the map.
+	 */
+	if (TSN_lt(tsn, map->base_tsn))
+		return;
+	if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
+		return;
+
+	/* Bump the max.  */
+	if (TSN_lt(map->max_tsn_seen, tsn))
+		map->max_tsn_seen = tsn;
+
+	/* Assert: TSN is in range.  */
+	gap = tsn - map->base_tsn + 1;
+
+	/* Mark the TSNs as received.  */
+	if (gap <= map->len)
+		memset(map->tsn_map, 0x01, gap);
+	else {
+		memset(map->tsn_map, 0x01, map->len);
+		memset(map->overflow_map, 0x01, (gap - map->len));
+	}
+
+	/* Go fixup any internal TSN mapping variables including
+	 * cumulative_tsn_ack_point.
+	 */
+	sctp_tsnmap_update(map);
+}
+
 /********************************************************************
  * 2nd Level Abstractions
  ********************************************************************/
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/ulpevent.c linux-2.4.27-pre3/net/sctp/ulpevent.c
--- linux-2.4.26/net/sctp/ulpevent.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/ulpevent.c	2004-05-18 16:54:13.000000000 +0000
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001 International Business Machines, Corp.
  * Copyright (c) 2001 Intel Corp.
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
@@ -590,8 +590,7 @@ struct sctp_ulpevent *sctp_ulpevent_make
 						struct sctp_chunk *chunk,
 						int gfp)
 {
-	struct sctp_ulpevent *event;
-	struct sctp_sndrcvinfo *info;
+	struct sctp_ulpevent *event = NULL;
 	struct sk_buff *skb;
 	size_t padding, len;
 
@@ -624,101 +623,21 @@ struct sctp_ulpevent *sctp_ulpevent_make
 	/* Initialize event with flags 0.  */
 	sctp_ulpevent_init(event, 0);
 
-	event->iif = sctp_chunk_iif(chunk);
-
 	sctp_ulpevent_receive_data(event, asoc);
 
-	info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo;
-
-	/* Sockets API Extensions for SCTP
-	 * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
-	 *
-	 * sinfo_stream: 16 bits (unsigned integer)
-	 *
-	 * For recvmsg() the SCTP stack places the message's stream number in
-	 * this value.
-	 */
-	info->sinfo_stream = ntohs(chunk->subh.data_hdr->stream);
-
-	/* Sockets API Extensions for SCTP
-	 * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
-	 *
-	 * sinfo_ssn: 16 bits (unsigned integer)
-	 *
-	 * For recvmsg() this value contains the stream sequence number that
-	 * the remote endpoint placed in the DATA chunk.  For fragmented
-	 * messages this is the same number for all deliveries of the message
-	 * (if more than one recvmsg() is needed to read the message).
-	 */
-	info->sinfo_ssn = ntohs(chunk->subh.data_hdr->ssn);
-
-        /* Sockets API Extensions for SCTP
-	 * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
-	 *
-	 * sinfo_ppid: 32 bits (unsigned integer)
-	 *
-	 * In recvmsg() this value is
-	 * the same information that was passed by the upper layer in the peer
-	 * application.  Please note that byte order issues are NOT accounted
-	 * for and this information is passed opaquely by the SCTP stack from
-	 * one end to the other.
-	 */
-	info->sinfo_ppid = chunk->subh.data_hdr->ppid;
-
-	/* Sockets API Extensions for SCTP
-	 * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
-	 *
-	 * sinfo_flags: 16 bits (unsigned integer)
-	 *
-	 * This field may contain any of the following flags and is composed of
-	 * a bitwise OR of these values.
-	 *
-	 * recvmsg() flags:
-	 *
-	 * MSG_UNORDERED - This flag is present when the message was sent
-	 *                 non-ordered.
-	 */
+	event->stream = ntohs(chunk->subh.data_hdr->stream);
+	event->ssn = ntohs(chunk->subh.data_hdr->ssn);
+	event->ppid = chunk->subh.data_hdr->ppid;
 	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
-		info->sinfo_flags |= MSG_UNORDERED;
-
-		/* sinfo_cumtsn: 32 bit (unsigned integer)
-		 *
-		 * This field will hold the current cumulative TSN as
-		 * known by the underlying SCTP layer.  Note this field is
-		 * ignored when sending and only valid for a receive
-		 * operation when sinfo_flags are set to MSG_UNORDERED.
-		 */
-		info->sinfo_cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
+		event->flags |= MSG_UNORDERED;
+		event->cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
 	}
-
-	/* Note:  For reassembly, we need to have the fragmentation bits.
-	 * For now, merge these into the msg_flags, since those bit
-	 * possitions are not used.
-	 */
+	event->tsn = ntohl(chunk->subh.data_hdr->tsn);
 	event->msg_flags |= chunk->chunk_hdr->flags;
-
-	/* With 04 draft, tsn moves into sndrcvinfo. */
-	info->sinfo_tsn = ntohl(chunk->subh.data_hdr->tsn);
-
-	/* Context is not used on receive. */
-	info->sinfo_context = 0;
-
-	/* Sockets API Extensions for SCTP
-	 * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
-	 *
-	 * sinfo_assoc_id: sizeof (sctp_assoc_t)
-	 *
-	 * The association handle field, sinfo_assoc_id, holds the identifier
-	 * for the association announced in the COMMUNICATION_UP notification.
-	 * All notifications for a given association have the same identifier.
-	 * Ignored for TCP-style sockets.
-	 */
-	info->sinfo_assoc_id = sctp_assoc2id(asoc);
-
-	return event;
+	event->iif = sctp_chunk_iif(chunk);
 
 fail:
-	return NULL;
+	return event;
 }
 
 /* Create a partial delivery related event.
@@ -797,11 +716,77 @@ __u16 sctp_ulpevent_get_notification_typ
 void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
 				   struct msghdr *msghdr)
 {
-	if (!sctp_ulpevent_is_notification(event)) {
-		put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
-			 sizeof(struct sctp_sndrcvinfo),
-			 (void *) &event->sndrcvinfo);
-	}
+	struct sctp_sndrcvinfo sinfo;
+
+	if (sctp_ulpevent_is_notification(event))
+		return;
+
+	/* Sockets API Extensions for SCTP
+ 	 * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
+ 	 *
+ 	 * sinfo_stream: 16 bits (unsigned integer)
+ 	 *
+ 	 * For recvmsg() the SCTP stack places the message's stream number in
+ 	 * this value.
+ 	*/
+	sinfo.sinfo_stream = event->stream;
+	/* sinfo_ssn: 16 bits (unsigned integer)
+	 *
+	 * For recvmsg() this value contains the stream sequence number that
+	 * the remote endpoint placed in the DATA chunk.  For fragmented
+	 * messages this is the same number for all deliveries of the message
+	 * (if more than one recvmsg() is needed to read the message).
+	 */
+	sinfo.sinfo_ssn = event->ssn;
+	/* sinfo_ppid: 32 bits (unsigned integer)
+	 *
+	 * In recvmsg() this value is
+	 * the same information that was passed by the upper layer in the peer
+	 * application.  Please note that byte order issues are NOT accounted
+	 * for and this information is passed opaquely by the SCTP stack from
+	 * one end to the other.
+	 */
+	sinfo.sinfo_ppid = event->ppid;
+	/* sinfo_flags: 16 bits (unsigned integer)
+	 *
+	 * This field may contain any of the following flags and is composed of
+	 * a bitwise OR of these values.
+	 *
+	 * recvmsg() flags:
+	 *
+	 * MSG_UNORDERED - This flag is present when the message was sent
+	 *                 non-ordered.
+	 */
+	sinfo.sinfo_flags = event->flags;
+	/* sinfo_tsn: 32 bit (unsigned integer)
+	 *
+	 * For the receiving side, this field holds a TSN that was 
+	 * assigned to one of the SCTP Data Chunks.
+	 */
+	sinfo.sinfo_tsn = event->tsn;
+	/* sinfo_cumtsn: 32 bit (unsigned integer)
+	 *
+	 * This field will hold the current cumulative TSN as
+	 * known by the underlying SCTP layer.  Note this field is
+	 * ignored when sending and only valid for a receive
+	 * operation when sinfo_flags are set to MSG_UNORDERED.
+	 */
+	sinfo.sinfo_cumtsn = event->cumtsn;
+	/* sinfo_assoc_id: sizeof (sctp_assoc_t)
+	 *
+	 * The association handle field, sinfo_assoc_id, holds the identifier
+	 * for the association announced in the COMMUNICATION_UP notification.
+	 * All notifications for a given association have the same identifier.
+	 * Ignored for one-to-one style sockets.
+	 */
+	sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc);
+
+	/* These fields are not used while receiving. */
+	sinfo.sinfo_context = 0;
+	sinfo.sinfo_timetolive = 0;
+
+	put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
+		 sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
 }
 
 /* Stub skb destructor.  */
@@ -831,14 +816,14 @@ static inline void sctp_ulpevent_set_own
 	sctp_association_hold((struct sctp_association *)asoc);
 	skb = sctp_event2skb(event);
 	skb->sk = asoc->base.sk;
-	event->sndrcvinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
+	event->asoc = (struct sctp_association *)asoc;
 	skb->destructor = sctp_stub_rfree;
 }
 
 /* A simple destructor to give up the reference to the association. */
 static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
 {
-	sctp_association_put(event->sndrcvinfo.sinfo_assoc_id);
+	sctp_association_put(event->asoc);
 }
 
 /* Do accounting for bytes received and hold a reference to the association
@@ -854,6 +839,9 @@ static void sctp_ulpevent_receive_data(s
 	sctp_ulpevent_set_owner(event, asoc);
 	sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb));
 
+	if (!skb->data_len)
+		return;
+
 	/* Note:  Not clearing the entire event struct as this is just a
 	 * fragment of the real event.  However, we still need to do rwnd
 	 * accounting.
@@ -880,8 +868,10 @@ static void sctp_ulpevent_release_data(s
 	 */
 
 	skb = sctp_event2skb(event);
-	sctp_assoc_rwnd_increase(event->sndrcvinfo.sinfo_assoc_id,
-				 skb_headlen(skb));
+	sctp_assoc_rwnd_increase(event->asoc, skb_headlen(skb));
+
+	if (!skb->data_len)
+		goto done;
 
 	/* Don't forget the fragments. */
 	for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
@@ -891,6 +881,8 @@ static void sctp_ulpevent_release_data(s
 		 */
 		sctp_ulpevent_release_data(sctp_skb2event(frag));
 	}
+
+done:
 	sctp_ulpevent_release_owner(event);
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/net/sctp/ulpqueue.c linux-2.4.27-pre3/net/sctp/ulpqueue.c
--- linux-2.4.26/net/sctp/ulpqueue.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.27-pre3/net/sctp/ulpqueue.c	2004-05-18 16:50:45.000000000 +0000
@@ -1,7 +1,7 @@
 /* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001-2003 International Business Machines, Corp.
  * Copyright (c) 2001 Intel Corp.
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
@@ -251,7 +251,7 @@ static inline void sctp_ulpq_store_reasm
 	struct sctp_ulpevent *cevent;
 	__u32 tsn, ctsn;
 
-	tsn = event->sndrcvinfo.sinfo_tsn;
+	tsn = event->tsn;
 
 	/* See if it belongs at the end. */
 	pos = skb_peek_tail(&ulpq->reasm);
@@ -262,7 +262,7 @@ static inline void sctp_ulpq_store_reasm
 
 	/* Short circuit just dropping it at the end. */
 	cevent = sctp_skb2event(pos);
-	ctsn = cevent->sndrcvinfo.sinfo_tsn;
+	ctsn = cevent->tsn;
 	if (TSN_lt(ctsn, tsn)) {
 		__skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
 		return;
@@ -271,7 +271,7 @@ static inline void sctp_ulpq_store_reasm
 	/* Find the right place in this list. We store them by TSN.  */
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
-		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+		ctsn = cevent->tsn;
 
 		if (TSN_lt(tsn, ctsn))
 			break;
@@ -368,7 +368,7 @@ static inline struct sctp_ulpevent *sctp
 	 */
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
-		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+		ctsn = cevent->tsn;
 
 		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
 		case SCTP_DATA_FIRST_FRAG:
@@ -425,7 +425,7 @@ static inline struct sctp_ulpevent *sctp
 
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
-		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+		ctsn = cevent->tsn;
 
 		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
 		case SCTP_DATA_MIDDLE_FRAG:
@@ -486,7 +486,7 @@ static inline struct sctp_ulpevent *sctp
 		/* Do not even bother unless this is the next tsn to
 		 * be delivered.
 		 */
-		ctsn = event->sndrcvinfo.sinfo_tsn;
+		ctsn = event->tsn;
 		ctsnap = sctp_tsnmap_get_ctsn(&ulpq->asoc->peer.tsn_map);
 		if (TSN_lte(ctsn, ctsnap))
 			retval = sctp_ulpq_retrieve_partial(ulpq);
@@ -517,7 +517,7 @@ static inline struct sctp_ulpevent *sctp
 
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
-		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+		ctsn = cevent->tsn;
 
 		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
 		case SCTP_DATA_FIRST_FRAG:
@@ -563,15 +563,15 @@ static inline void sctp_ulpq_retrieve_or
 	__u16 sid, csid;
 	__u16 ssn, cssn;
 
-	sid = event->sndrcvinfo.sinfo_stream;
-	ssn = event->sndrcvinfo.sinfo_ssn;
+	sid = event->stream;
+	ssn = event->ssn;
 	in  = &ulpq->asoc->ssnmap->in;
 
 	/* We are holding the chunks by stream, by SSN.  */
 	sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
 		cevent = (struct sctp_ulpevent *) pos->cb;
-		csid = cevent->sndrcvinfo.sinfo_stream;
-		cssn = cevent->sndrcvinfo.sinfo_ssn;
+		csid = cevent->stream;
+		cssn = cevent->ssn;
 
 		/* Have we gone too far?  */
 		if (csid > sid)
@@ -609,12 +609,12 @@ static inline void sctp_ulpq_store_order
 		return;
 	}
 
-	sid = event->sndrcvinfo.sinfo_stream;
-	ssn = event->sndrcvinfo.sinfo_ssn;
+	sid = event->stream;
+	ssn = event->ssn;
 	
 	cevent = (struct sctp_ulpevent *) pos->cb;
-	csid = cevent->sndrcvinfo.sinfo_stream;
-	cssn = cevent->sndrcvinfo.sinfo_ssn;
+	csid = cevent->stream;
+	cssn = cevent->ssn;
 	if (sid > csid) {
 		__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
 		return;
@@ -630,8 +630,8 @@ static inline void sctp_ulpq_store_order
 	 */
 	skb_queue_walk(&ulpq->lobby, pos) {
 		cevent = (struct sctp_ulpevent *) pos->cb;
-		csid = cevent->sndrcvinfo.sinfo_stream;
-		cssn = cevent->sndrcvinfo.sinfo_ssn;
+		csid = cevent->stream;
+		cssn = cevent->ssn;
 
 		if (csid > sid)
 			break;
@@ -656,8 +656,8 @@ static inline struct sctp_ulpevent *sctp
 		return event;
 
 	/* Note: The stream ID must be verified before this routine.  */
-	sid = event->sndrcvinfo.sinfo_stream;
-	ssn = event->sndrcvinfo.sinfo_ssn;
+	sid = event->stream;
+	ssn = event->ssn;
 	in  = &ulpq->asoc->ssnmap->in;
 
 	/* Is this the expected SSN for this stream ID?  */
@@ -680,6 +680,71 @@ static inline struct sctp_ulpevent *sctp
 	return event;
 }
 
+/* Helper function to gather skbs that have possibly become
+ * ordered by forward tsn skipping their dependencies.
+ */
+static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq)
+{
+	struct sk_buff *pos, *tmp;
+	struct sctp_ulpevent *cevent;
+	struct sctp_ulpevent *event = NULL;
+	struct sctp_stream *in;
+	struct sk_buff_head temp;
+	__u16 csid, cssn;
+
+	in  = &ulpq->asoc->ssnmap->in;
+
+	/* We are holding the chunks by stream, by SSN.  */
+	sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
+		cevent = (struct sctp_ulpevent *) pos->cb;
+		csid = cevent->stream;
+		cssn = cevent->ssn;
+
+		if (cssn != sctp_ssn_peek(in, csid))
+			break;
+
+		/* Found it, so mark in the ssnmap. */	       
+		sctp_ssn_next(in, csid);
+
+		__skb_unlink(pos, pos->list);
+		if (!event) {						
+			/* Create a temporary list to collect chunks on.  */
+			event = sctp_skb2event(pos);
+			skb_queue_head_init(&temp);
+			__skb_queue_tail(&temp, sctp_event2skb(event));
+		} else {
+			/* Attach all gathered skbs to the event.  */
+			__skb_queue_tail(sctp_event2skb(event)->list, pos);
+		}
+	}
+
+	/* Send event to the ULP.  */
+	if (event)
+		sctp_ulpq_tail_event(ulpq, event);
+}
+
+/* Skip over an SSN. */
+void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn)
+{
+	struct sctp_stream *in;
+
+	/* Note: The stream ID must be verified before this routine.  */
+	in  = &ulpq->asoc->ssnmap->in;
+
+	/* Is this an old SSN?  If so ignore. */
+	if (SSN_lt(ssn, sctp_ssn_peek(in, sid)))
+		return;
+
+	/* Mark that we are no longer expecting this SSN or lower. */
+	sctp_ssn_skip(in, sid, ssn);
+
+	/* Go find any other chunks that were waiting for
+	 * ordering and deliver them if needed. 
+	 */
+	sctp_ulpq_reap_ordered(ulpq);
+	return;
+}
+
 /* Renege 'needed' bytes from the ordering queue. */
 static __u16 sctp_ulpq_renege_order(struct sctp_ulpq *ulpq, __u16 needed)
 {
@@ -694,7 +759,7 @@ static __u16 sctp_ulpq_renege_order(stru
 	while ((skb = __skb_dequeue_tail(&ulpq->lobby))) {
 		freed += skb_headlen(skb);
 		event = sctp_skb2event(skb);
-		tsn = event->sndrcvinfo.sinfo_tsn;
+		tsn = event->tsn;
 
 		sctp_ulpevent_free(event);
 		sctp_tsnmap_renege(tsnmap, tsn);
@@ -720,7 +785,7 @@ static __u16 sctp_ulpq_renege_frags(stru
 	while ((skb = __skb_dequeue_tail(&ulpq->reasm))) {
 		freed += skb_headlen(skb);
 		event = sctp_skb2event(skb);
-		tsn = event->sndrcvinfo.sinfo_tsn;
+		tsn = event->tsn;
 
 		sctp_ulpevent_free(event);
 		sctp_tsnmap_renege(tsnmap, tsn);
