Эх сурвалжийг харах

Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git

David Woodhouse 20 жил өмнө
parent
commit
df5179854b
100 өөрчлөгдсөн 13085 нэмэгдсэн , 6974 устгасан
  1. 1 1
      Documentation/DocBook/Makefile
  2. 0 193
      Documentation/DocBook/scsidrivers.tmpl
  3. 26 25
      Documentation/networking/generic-hdlc.txt
  4. 0 1
      Documentation/networking/multicast.txt
  5. 0 3
      Documentation/networking/net-modules.txt
  6. 66 0
      Documentation/scsi/ChangeLog.megaraid
  7. 180 0
      Documentation/scsi/scsi-changer.txt
  8. 4 8
      Documentation/scsi/scsi_mid_low_api.txt
  9. 5 0
      MAINTAINERS
  10. 137 117
      arch/arm/kernel/entry-armv.S
  11. 3 4
      arch/arm/kernel/entry-header.S
  12. 44 0
      arch/arm/kernel/head.S
  13. 50 2
      arch/arm/kernel/setup.c
  14. 107 0
      arch/arm/kernel/smp.c
  15. 1 0
      arch/arm/mach-integrator/Makefile
  16. 19 1
      arch/arm/mach-integrator/core.c
  17. 37 0
      arch/arm/mach-integrator/headsmp.S
  18. 3 1
      arch/arm/mach-integrator/leds.c
  19. 192 0
      arch/arm/mach-integrator/platsmp.c
  20. 2 0
      arch/arm/mach-pxa/pm.c
  21. 2 0
      arch/arm/mach-sa1100/pm.c
  22. 3 9
      drivers/block/cciss.c
  23. 13 0
      drivers/block/elevator.c
  24. 6 14
      drivers/block/ll_rw_blk.c
  25. 1 1
      drivers/block/paride/pd.c
  26. 2 2
      drivers/block/sx8.c
  27. 4 0
      drivers/char/vt.c
  28. 15 11
      drivers/fc4/fc.c
  29. 0 1
      drivers/fc4/fc_syms.c
  30. 0 1
      drivers/fc4/fcp_impl.h
  31. 16 135
      drivers/ieee1394/sbp2.c
  32. 0 4
      drivers/ieee1394/sbp2.h
  33. 38 18
      drivers/message/fusion/Kconfig
  34. 15 29
      drivers/message/fusion/Makefile
  35. 49 21
      drivers/message/fusion/lsi/mpi.h
  36. 442 84
      drivers/message/fusion/lsi/mpi_cnfg.h
  37. 5 2
      drivers/message/fusion/lsi/mpi_fc.h
  38. 428 23
      drivers/message/fusion/lsi/mpi_history.txt
  39. 4 3
      drivers/message/fusion/lsi/mpi_inb.h
  40. 47 41
      drivers/message/fusion/lsi/mpi_init.h
  41. 183 63
      drivers/message/fusion/lsi/mpi_ioc.h
  42. 4 2
      drivers/message/fusion/lsi/mpi_lan.h
  43. 15 2
      drivers/message/fusion/lsi/mpi_raid.h
  44. 120 51
      drivers/message/fusion/lsi/mpi_sas.h
  45. 151 9
      drivers/message/fusion/lsi/mpi_targ.h
  46. 53 4
      drivers/message/fusion/lsi/mpi_tool.h
  47. 4 7
      drivers/message/fusion/lsi/mpi_type.h
  48. 121 222
      drivers/message/fusion/mptbase.c
  49. 29 23
      drivers/message/fusion/mptbase.h
  50. 20 48
      drivers/message/fusion/mptctl.c
  51. 1 14
      drivers/message/fusion/mptctl.h
  52. 431 0
      drivers/message/fusion/mptfc.c
  53. 7 30
      drivers/message/fusion/mptlan.c
  54. 47 1
      drivers/message/fusion/mptlan.h
  55. 107 524
      drivers/message/fusion/mptscsih.c
  56. 28 15
      drivers/message/fusion/mptscsih.h
  57. 486 0
      drivers/message/fusion/mptspi.c
  58. 69 31
      drivers/net/8139cp.c
  59. 87 107
      drivers/net/8139too.c
  60. 24 23
      drivers/net/Kconfig
  61. 2 2
      drivers/net/Makefile
  62. 0 6
      drivers/net/Space.c
  63. 9 7
      drivers/net/arm/etherh.c
  64. 2 8
      drivers/net/au1000_eth.c
  65. 0 2
      drivers/net/bmac.c
  66. 1219 0
      drivers/net/dm9000.c
  67. 135 0
      drivers/net/dm9000.h
  68. 0 689
      drivers/net/fmv18x.c
  69. 9 8
      drivers/net/pcmcia/pcnet_cs.c
  70. 110 67
      drivers/net/ppp_generic.c
  71. 252 68
      drivers/net/r8169.c
  72. 3 5
      drivers/net/sk98lin/skge.c
  73. 0 2066
      drivers/net/sk_g16.c
  74. 0 165
      drivers/net/sk_g16.h
  75. 3386 0
      drivers/net/skge.c
  76. 3005 0
      drivers/net/skge.h
  77. 33 25
      drivers/net/smc91x.c
  78. 4 11
      drivers/net/smc91x.h
  79. 40 102
      drivers/net/starfire.c
  80. 346 0
      drivers/net/starfire_firmware.h
  81. 2 2
      drivers/net/tlan.c
  82. 3 8
      drivers/net/tokenring/ibmtr.c
  83. 176 144
      drivers/net/wan/hdlc_fr.c
  84. 11 5
      drivers/net/wan/hdlc_generic.c
  85. 2 6
      drivers/net/wan/lmc/lmc_main.c
  86. 69 263
      drivers/net/wireless/orinoco.c
  87. 0 1
      drivers/net/wireless/orinoco.h
  88. 1 1
      drivers/pci/pci-driver.c
  89. 20 17
      drivers/s390/scsi/zfcp_aux.c
  90. 8 17
      drivers/s390/scsi/zfcp_def.h
  91. 83 38
      drivers/s390/scsi/zfcp_erp.c
  92. 3 1
      drivers/s390/scsi/zfcp_ext.h
  93. 31 179
      drivers/s390/scsi/zfcp_fsf.c
  94. 15 53
      drivers/s390/scsi/zfcp_qdio.c
  95. 13 11
      drivers/s390/scsi/zfcp_scsi.c
  96. 0 3
      drivers/scsi/3w-9xxx.c
  97. 0 3
      drivers/scsi/3w-xxxx.c
  98. 13 13
      drivers/scsi/53c700.c
  99. 7 1
      drivers/scsi/BusLogic.c
  100. 119 1046
      drivers/scsi/FlashPoint.c

+ 1 - 1
Documentation/DocBook/Makefile

@@ -8,7 +8,7 @@
 
 DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
 	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
-	    procfs-guide.xml writing_usb_driver.xml scsidrivers.xml \
+	    procfs-guide.xml writing_usb_driver.xml \
 	    sis900.xml kernel-api.xml journal-api.xml lsm.xml usb.xml \
 	    gadget.xml libata.xml mtdnand.xml librs.xml
 

+ 0 - 193
Documentation/DocBook/scsidrivers.tmpl

@@ -1,193 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
-
-<book id="scsidrivers">
- <bookinfo>
-  <title>SCSI Subsystem Interfaces</title>
-  
-  <authorgroup>
-   <author>
-    <firstname>Douglas</firstname>
-    <surname>Gilbert</surname>
-    <affiliation>
-     <address>
-      <email>dgilbert@interlog.com</email>
-     </address>
-    </affiliation>
-   </author>
-  </authorgroup>
-  <pubdate>2003-08-11</pubdate>
-
-  <copyright>
-   <year>2002</year>
-   <year>2003</year>
-   <holder>Douglas Gilbert</holder>
-  </copyright>
-
-  <legalnotice>
-   <para>
-     This documentation 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.
-   </para>
-      
-   <para>
-     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.
-   </para>
-      
-   <para>
-     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
-   </para>
-      
-   <para>
-     For more details see the file COPYING in the source
-     distribution of Linux.
-   </para>
-  </legalnotice>
-
- </bookinfo>
-
-<toc></toc>
-
-  <chapter id="intro">
-      <title>Introduction</title>
-  <para>
-This document outlines the interface between the Linux scsi mid level
-and lower level drivers. Lower level drivers are variously called HBA
-(host bus adapter) drivers, host drivers (HD) or pseudo adapter drivers.
-The latter alludes to the fact that a lower level driver may be a
-bridge to another IO subsystem (and the "ide-scsi" driver is an example
-of this). There can be many lower level drivers active in a running
-system, but only one per hardware type. For example, the aic7xxx driver
-controls adaptec controllers based on the 7xxx chip series. Most lower
-level drivers can control one or more scsi hosts (a.k.a. scsi initiators).
-  </para>
-<para>
-This document can been found in an ASCII text file in the linux kernel 
-source: <filename>Documentation/scsi/scsi_mid_low_api.txt</filename> .
-It currently hold a little more information than this document. The
-<filename>drivers/scsi/hosts.h</filename> and <filename>
-drivers/scsi/scsi.h</filename> headers contain descriptions of members
-of important structures for the scsi subsystem.
-</para>
-  </chapter>
-
-  <chapter id="driver-struct">
-      <title>Driver structure</title>
-  <para>
-Traditionally a lower level driver for the scsi subsystem has been
-at least two files in the drivers/scsi directory. For example, a
-driver called "xyz" has a header file "xyz.h" and a source file
-"xyz.c". [Actually there is no good reason why this couldn't all
-be in one file.] Some drivers that have been ported to several operating
-systems (e.g. aic7xxx which has separate  files for generic and
-OS-specific code) have more than two files. Such drivers tend to have
-their own directory under the drivers/scsi directory.
-  </para>
-  <para>
-scsi_module.c is normally included at the end of a lower
-level driver. For it to work a declaration like this is needed before
-it is included:
-<programlisting>
-    static Scsi_Host_Template driver_template = DRIVER_TEMPLATE;
-    /* DRIVER_TEMPLATE should contain pointers to supported interface
-       functions. Scsi_Host_Template is defined hosts.h */
-    #include "scsi_module.c"
-</programlisting>
-  </para>
-  <para>
-The scsi_module.c assumes the name "driver_template" is appropriately
-defined. It contains 2 functions:
-<orderedlist>
-<listitem><para>
-     init_this_scsi_driver() called during builtin and module driver
-     initialization: invokes mid level's scsi_register_host()
-</para></listitem>
-<listitem><para>
-     exit_this_scsi_driver() called during closedown: invokes
-     mid level's scsi_unregister_host()
-</para></listitem>
-</orderedlist>
-  </para>
-<para>
-When a new, lower level driver is being added to Linux, the following 
-files (all found in the drivers/scsi directory) will need some attention: 
-Makefile, Config.help and Config.in . It is probably best to look at what 
-an existing lower level driver does in this regard.
-</para>
-  </chapter>
-
-  <chapter id="intfunctions">
-     <title>Interface Functions</title>
-!EDocumentation/scsi/scsi_mid_low_api.txt
-  </chapter>
-
-  <chapter id="locks">
-     <title>Locks</title>
-<para>
-Each Scsi_Host instance has a spin_lock called Scsi_Host::default_lock
-which is initialized in scsi_register() [found in hosts.c]. Within the
-same function the Scsi_Host::host_lock pointer is initialized to point
-at default_lock with the scsi_assign_lock() function. Thereafter
-lock and unlock operations performed by the mid level use the
-Scsi_Host::host_lock pointer.
-</para>
-<para>
-Lower level drivers can override the use of Scsi_Host::default_lock by
-using scsi_assign_lock(). The earliest opportunity to do this would
-be in the detect() function after it has invoked scsi_register(). It
-could be replaced by a coarser grain lock (e.g. per driver) or a
-lock of equal granularity (i.e. per host). Using finer grain locks
-(e.g. per scsi device) may be possible by juggling locks in
-queuecommand().
-</para>
-  </chapter>
-
-  <chapter id="changes">
-     <title>Changes since lk 2.4 series</title>
-<para>
-io_request_lock has been replaced by several finer grained locks. The lock
-relevant to lower level drivers is Scsi_Host::host_lock and there is one
-per scsi host.
-</para>
-<para>
-The older error handling mechanism has been removed. This means the
-lower level interface functions abort() and reset() have been removed.
-</para>
-<para>
-In the 2.4 series the scsi subsystem configuration descriptions were
-aggregated with the configuration descriptions from all other Linux
-subsystems in the Documentation/Configure.help file. In the 2.5 series,
-the scsi subsystem now has its own (much smaller) drivers/scsi/Config.help
-file.
-</para>
-  </chapter>
-
-  <chapter id="credits">
-     <title>Credits</title>
-<para>
-The following people have contributed to this document:
-<orderedlist>
-<listitem><para>
-Mike Anderson <email>andmike@us.ibm.com</email>
-</para></listitem>
-<listitem><para>
-James Bottomley <email>James.Bottomley@steeleye.com</email>
-</para></listitem>
-<listitem><para>
-Patrick Mansfield <email>patmans@us.ibm.com</email>
-</para></listitem>
-</orderedlist>
-</para>
-  </chapter>
-
-</book>

+ 26 - 25
Documentation/networking/generic-hdlc.txt

@@ -1,21 +1,21 @@
 Generic HDLC layer
 Krzysztof Halasa <khc@pm.waw.pl>
-January, 2003
 
 
 Generic HDLC layer currently supports:
-- Frame Relay (ANSI, CCITT and no LMI), with ARP support (no InARP).
-  Normal (routed) and Ethernet-bridged (Ethernet device emulation)
-  interfaces can share a single PVC.
-- raw HDLC - either IP (IPv4) interface or Ethernet device emulation.
-- Cisco HDLC,
-- PPP (uses syncppp.c),
-- X.25 (uses X.25 routines).
-
-There are hardware drivers for the following cards:
-- C101 by Moxa Technologies Co., Ltd.
-- RISCom/N2 by SDL Communications Inc.
-- and others, some not in the official kernel.
+1. Frame Relay (ANSI, CCITT, Cisco and no LMI).
+   - Normal (routed) and Ethernet-bridged (Ethernet device emulation)
+     interfaces can share a single PVC.
+   - ARP support (no InARP support in the kernel - there is an
+     experimental InARP user-space daemon available on:
+     http://www.kernel.org/pub/linux/utils/net/hdlc/).
+2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation.
+3. Cisco HDLC.
+4. PPP (uses syncppp.c).
+5. X.25 (uses X.25 routines).
+
+Generic HDLC is a protocol driver only - it needs a low-level driver
+for your particular hardware.
 
 Ethernet device emulation (using HDLC or Frame-Relay PVC) is compatible
 with IEEE 802.1Q (VLANs) and 802.1D (Ethernet bridging).
@@ -24,7 +24,7 @@ with IEEE 802.1Q (VLANs) and 802.1D (Ethernet bridging).
 Make sure the hdlc.o and the hardware driver are loaded. It should
 create a number of "hdlc" (hdlc0 etc) network devices, one for each
 WAN port. You'll need the "sethdlc" utility, get it from:
-	http://hq.pm.waw.pl/hdlc/
+	http://www.kernel.org/pub/linux/utils/net/hdlc/
 
 Compile sethdlc.c utility:
 	gcc -O2 -Wall -o sethdlc sethdlc.c
@@ -52,12 +52,12 @@ Setting interface:
 * v35 | rs232 | x21 | t1 | e1 - sets physical interface for a given port
                                 if the card has software-selectable interfaces
   loopback - activate hardware loopback (for testing only)
-* clock ext - external clock (uses DTE RX and TX clock)
-* clock int - internal clock (provides clock signal on DCE clock output)
-* clock txint - TX internal, RX external (provides TX clock on DCE output)
-* clock txfromrx - TX clock derived from RX clock (TX clock on DCE output)
-* rate - sets clock rate in bps (not required for external clock or
-                                 for txfromrx)
+* clock ext - both RX clock and TX clock external
+* clock int - both RX clock and TX clock internal
+* clock txint - RX clock external, TX clock internal
+* clock txfromrx - RX clock external, TX clock derived from RX clock
+* rate - sets clock rate in bps (for "int" or "txint" clock only)
+
 
 Setting protocol:
 
@@ -79,7 +79,7 @@ Setting protocol:
 * x25 - sets X.25 mode
 
 * fr - Frame Relay mode
-  lmi ansi / ccitt / none - LMI (link management) type
+  lmi ansi / ccitt / cisco / none - LMI (link management) type
   dce - Frame Relay DCE (network) side LMI instead of default DTE (user).
   It has nothing to do with clocks!
   t391 - link integrity verification polling timer (in seconds) - user
@@ -119,13 +119,14 @@ or
 
 
 
-If you have a problem with N2 or C101 card, you can issue the "private"
-command to see port's packet descriptor rings (in kernel logs):
+If you have a problem with N2, C101 or PLX200SYN card, you can issue the
+"private" command to see port's packet descriptor rings (in kernel logs):
 
 	sethdlc hdlc0 private
 
-The hardware driver has to be build with CONFIG_HDLC_DEBUG_RINGS.
+The hardware driver has to be build with #define DEBUG_RINGS.
 Attaching this info to bug reports would be helpful. Anyway, let me know
 if you have problems using this.
 
-For patches and other info look at http://hq.pm.waw.pl/hdlc/
+For patches and other info look at:
+<http://www.kernel.org/pub/linux/utils/net/hdlc/>.

+ 0 - 1
Documentation/networking/multicast.txt

@@ -47,7 +47,6 @@ ni52		<------------------ Buggy ------------------>
 ni65		YES		YES		YES		Software(#)
 seeq		NO		NO		NO		N/A
 sgiseek		<------------------ Buggy ------------------>
-sk_g16		NO		NO		YES		N/A
 smc-ultra	YES		YES		YES		Hardware
 sunlance	YES		YES		YES		Hardware
 tulip		YES		YES		YES		Hardware

+ 0 - 3
Documentation/networking/net-modules.txt

@@ -284,9 +284,6 @@ ppp.c:
 seeq8005.c: *Not modularized*
 	(Probes ports: 0x300, 0x320, 0x340, 0x360)
 
-sk_g16.c: *Not modularized*
-	(Probes ports: 0x100, 0x180, 0x208, 0x220m 0x288, 0x320, 0x328, 0x390)
-
 skeleton.c: *Skeleton*
 
 slhc.c:

+ 66 - 0
Documentation/scsi/ChangeLog.megaraid

@@ -1,3 +1,69 @@
+Release Date	: Mon Mar 07 12:27:22 EST 2005 - Seokmann Ju <sju@lsil.com>
+Current Version : 2.20.4.6 (scsi module), 2.20.2.6 (cmm module)
+Older Version	: 2.20.4.5 (scsi module), 2.20.2.5 (cmm module)
+
+1.	Added IOCTL backward compatibility.
+	Convert megaraid_mm driver to new compat_ioctl entry points.
+	I don't have easy access to hardware, so only compile tested.
+		- Signed-off-by:Andi Kleen <ak@muc.de>
+
+2.	megaraid_mbox fix: wrong order of arguments in memset()
+	That, BTW, shows why cross-builds are useful-the only indication of
+	problem had been a new warning showing up in sparse output on alpha
+	build (number of exceeding 256 got truncated).
+		- Signed-off-by: Al Viro
+		<viro@parcelfarce.linux.theplanet.co.uk>
+
+3.	Convert pci_module_init to pci_register_driver
+	Convert from pci_module_init to pci_register_driver
+	(from:http://kerneljanitors.org/TODO)
+		- Signed-off-by: Domen Puncer <domen@coderock.org>
+
+4.	Use the pre defined DMA mask constants from dma-mapping.h
+	Use the DMA_{64,32}BIT_MASK constants from dma-mapping.h when calling
+	pci_set_dma_mask() or pci_set_consistend_dma_mask(). See
+	http://marc.theaimsgroup.com/?t=108001993000001&r=1&w=2 for more
+	details.
+		Signed-off-by: Tobias Klauser <tklauser@nuerscht.ch>
+		Signed-off-by: Domen Puncer <domen@coderock.org>
+
+5.	Remove SSID checking for Dobson, Lindsay, and Verde based products.
+	Checking the SSVID/SSID for controllers which have Dobson, Lindsay,
+	and Verde is unnecessary because device ID has been assigned by LSI
+	and it is unique value. So, all controllers with these IOPs have to be
+	supported by the driver regardless SSVID/SSID.
+
+6.	Date Thu, 27 Jan 2005 04:31:09 +0100 
+	From Herbert Poetzl <> 
+	Subject RFC: assert_spin_locked() for 2.6 
+
+	Greetings!
+
+	overcautious programming will kill your kernel ;)
+	ever thought about checking a spin_lock or even
+	asserting that it must be held (maybe just for
+	spinlock debugging?) ...
+
+	there are several checks present in the kernel
+	where somebody does a variation on the following:
+
+	  BUG_ON(!spin_is_locked(&some_lock));
+
+	so what's wrong about that? nothing, unless you
+	compile the code with CONFIG_DEBUG_SPINLOCK but 
+	without CONFIG_SMP ... in which case the BUG()
+	will kill your kernel ...
+
+	maybe it's not advised to make such assertions, 
+	but here is a solution which works for me ...
+	(compile tested for sh, x86_64 and x86, boot/run
+	tested for x86 only)
+
+	best,
+	Herbert
+
+		- Herbert Poetzl <herbert@13thfloor.at>, Thu, 27 Jan 2005
+
 Release Date	: Thu Feb 03 12:27:22 EST 2005 - Seokmann Ju <sju@lsil.com>
 Current Version	: 2.20.4.5 (scsi module), 2.20.2.5 (cmm module)
 Older Version	: 2.20.4.4 (scsi module), 2.20.2.4 (cmm module)

+ 180 - 0
Documentation/scsi/scsi-changer.txt

@@ -0,0 +1,180 @@
+
+README for the SCSI media changer driver
+========================================
+
+This is a driver for SCSI Medium Changer devices, which are listed
+with "Type: Medium Changer" in /proc/scsi/scsi.
+
+This is for *real* Jukeboxes.  It is *not* supported to work with
+common small CD-ROM changers, neither one-lun-per-slot SCSI changers
+nor IDE drives.
+
+Userland tools available from here:
+	http://linux.bytesex.org/misc/changer.html
+
+
+General Information
+-------------------
+
+First some words about how changers work: A changer has 2 (possibly
+more) SCSI ID's. One for the changer device which controls the robot,
+and one for the device which actually reads and writes the data. The
+later may be anything, a MOD, a CD-ROM, a tape or whatever. For the
+changer device this is a "don't care", he *only* shuffles around the
+media, nothing else.
+
+
+The SCSI changer model is complex, compared to - for example - IDE-CD
+changers. But it allows to handle nearly all possible cases. It knows
+4 different types of changer elements:
+
+  media transport - this one shuffles around the media, i.e. the
+                    transport arm.  Also known as "picker".
+  storage         - a slot which can hold a media.
+  import/export   - the same as above, but is accessable from outside,
+                    i.e. there the operator (you !) can use this to
+                    fill in and remove media from the changer.
+		    Sometimes named "mailslot".
+  data transfer   - this is the device which reads/writes, i.e. the
+		    CD-ROM / Tape / whatever drive.
+
+None of these is limited to one: A huge Jukebox could have slots for
+123 CD-ROM's, 5 CD-ROM readers (and therefore 6 SCSI ID's: the changer
+and each CD-ROM) and 2 transport arms. No problem to handle.
+
+
+How it is implemented
+---------------------
+
+I implemented the driver as character device driver with a NetBSD-like
+ioctl interface. Just grabbed NetBSD's header file and one of the
+other linux SCSI device drivers as starting point. The interface
+should be source code compatible with NetBSD. So if there is any
+software (anybody knows ???) which supports a BSDish changer driver,
+it should work with this driver too.
+
+Over time a few more ioctls where added, volume tag support for example
+wasn't covered by the NetBSD ioctl API.
+
+
+Current State
+-------------
+
+Support for more than one transport arm is not implemented yet (and
+nobody asked for it so far...).
+
+I test and use the driver myself with a 35 slot cdrom jukebox from
+Grundig.  I got some reports telling it works ok with tape autoloaders
+(Exabyte, HP and DEC).  Some People use this driver with amanda.  It
+works fine with small (11 slots) and a huge (4 MOs, 88 slots)
+magneto-optical Jukebox.  Probably with lots of other changers too, most
+(but not all :-) people mail me only if it does *not* work...
+
+I don't have any device lists, neither black-list nor white-list.  Thus
+it is quite useless to ask me whenever a specific device is supported or
+not.  In theory every changer device which supports the SCSI-2 media
+changer command set should work out-of-the-box with this driver.  If it
+doesn't, it is a bug.  Either within the driver or within the firmware
+of the changer device.
+
+
+Using it
+--------
+
+This is a character device with major number is 86, so use
+"mknod /dev/sch0 c 86 0" to create the special file for the driver.
+
+If the module finds the changer, it prints some messages about the
+device [ try "dmesg" if you don't see anything ] and should show up in
+/proc/devices. If not....  some changers use ID ? / LUN 0 for the
+device and ID ? / LUN 1 for the robot mechanism. But Linux does *not*
+look for LUN's other than 0 as default, becauce there are to many
+broken devices. So you can try:
+
+  1) echo "scsi add-single-device 0 0 ID 1" > /proc/scsi/scsi
+     (replace ID with the SCSI-ID of the device)
+  2) boot the kernel with "max_scsi_luns=1" on the command line
+     (append="max_scsi_luns=1" in lilo.conf should do the trick)
+
+
+Trouble?
+--------
+
+If you insmod the driver with "insmod debug=1", it will be verbose and
+prints a lot of stuff to the syslog.  Compiling the kernel with
+CONFIG_SCSI_CONSTANTS=y improves the quality of the error messages alot
+because the kernel will translate the error codes into human-readable
+strings then.
+
+You can display these messages with the dmesg command (or check the
+logfiles).  If you email me some question becauce of a problem with the
+driver, please include these messages.
+
+
+Insmod options
+--------------
+
+debug=0/1
+	Enable debug messages (see above, default: 0).
+
+verbose=0/1
+	Be verbose (default: 1).
+
+init=0/1
+	Send INITIALIZE ELEMENT STATUS command to the changer
+	at insmod time (default: 1).
+
+timeout_init=<seconds>
+	timeout for the INITIALIZE ELEMENT STATUS command
+	(default: 3600).
+
+timeout_move=<seconds>
+	timeout for all other commands (default: 120).
+
+dt_id=<id1>,<id2>,...
+dt_lun=<lun1>,<lun2>,...
+	These two allow to specify the SCSI ID and LUN for the data
+	transfer elements.  You likely don't need this as the jukebox
+	should provide this information.  But some devices don't ...
+
+vendor_firsts=
+vendor_counts=
+vendor_labels=
+	These insmod options can be used to tell the driver that there
+	are some vendor-specific element types.  Grundig for example
+	does this.  Some jukeboxes have a printer to label fresh burned
+	CDs, which is addressed as element 0xc000 (type 5).  To tell the
+	driver about this vendor-specific element, use this:
+		$ insmod ch			\
+			vendor_firsts=0xc000	\
+			vendor_counts=1		\
+			vendor_labels=printer
+	All three insmod options accept up to four comma-separated
+	values, this way you can configure the element types 5-8.
+	You likely need the SCSI specs for the device in question to
+	find the correct values as they are not covered by the SCSI-2
+	standard.
+
+
+Credits
+-------
+
+I wrote this driver using the famous mailing-patches-around-the-world
+method.  With (more or less) help from:
+
+	Daniel Moehwald <moehwald@hdg.de>
+	Dane Jasper <dane@sonic.net>
+	R. Scott Bailey <sbailey@dsddi.eds.com>
+	Jonathan Corbet <corbet@lwn.net>
+
+Special thanks go to
+	Martin Kuehne <martin.kuehne@bnbt.de>
+for a old, second-hand (but full functional) cdrom jukebox which I use
+to develop/test driver and tools now.
+
+Have fun,
+
+   Gerd
+
+-- 
+Gerd Knorr <kraxel@bytesex.org>

+ 4 - 8
Documentation/scsi/scsi_mid_low_api.txt

@@ -936,8 +936,7 @@ Details:
  *
  *      Returns SUCCESS if command aborted else FAILED
  *
- *      Locks: struct Scsi_Host::host_lock held (with irqsave) on entry 
- *      and assumed to be held on return.
+ *      Locks: None held
  *
  *      Calling context: kernel thread
  *
@@ -955,8 +954,7 @@ Details:
  *
  *      Returns SUCCESS if command aborted else FAILED
  *
- *      Locks: struct Scsi_Host::host_lock held (with irqsave) on entry 
- *      and assumed to be held on return.
+ *      Locks: None held
  *
  *      Calling context: kernel thread
  *
@@ -974,8 +972,7 @@ Details:
  *
  *      Returns SUCCESS if command aborted else FAILED
  *
- *      Locks: struct Scsi_Host::host_lock held (with irqsave) on entry
- *      and assumed to be held on return.
+ *      Locks: None held
  *
  *      Calling context: kernel thread
  *
@@ -993,8 +990,7 @@ Details:
  *
  *      Returns SUCCESS if command aborted else FAILED
  *
- *      Locks: struct Scsi_Host::host_lock held (with irqsave) on entry
- *      and assumed to be held on return.
+ *      Locks: None held
  *
  *      Calling context: kernel thread
  *

+ 5 - 0
MAINTAINERS

@@ -736,6 +736,11 @@ M:	tori@unhappy.mine.nu
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+DOCBOOK FOR DOCUMENTATION
+P:	Martin Waitz
+M:	tali@admingilde.org
+S:	Maintained
+
 DOUBLETALK DRIVER
 P:	James R. Van Zandt
 M:	jrv@vanzandt.mv.com

+ 137 - 117
arch/arm/kernel/entry-armv.S

@@ -23,49 +23,92 @@
 
 #include "entry-header.S"
 
+/*
+ * Interrupt handling.  Preserves r7, r8, r9
+ */
+	.macro	irq_handler
+1:	get_irqnr_and_base r0, r6, r5, lr
+	movne	r1, sp
+	@
+	@ routine called with r0 = irq number, r1 = struct pt_regs *
+	@
+	adrne	lr, 1b
+	bne	asm_do_IRQ
+
+#ifdef CONFIG_SMP
+	/*
+	 * XXX
+	 *
+	 * this macro assumes that irqstat (r6) and base (r5) are
+	 * preserved from get_irqnr_and_base above
+	 */
+	test_for_ipi r0, r6, r5, lr
+	movne	r0, sp
+	adrne	lr, 1b
+	bne	do_IPI
+#endif
+
+	.endm
+
 /*
  * Invalid mode handlers
  */
-	.macro	inv_entry, sym, reason
-	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
-	stmia	sp, {r0 - lr}			@ Save XXX r0 - lr
-	ldr	r4, .LC\sym
+	.macro	inv_entry, reason
+	sub	sp, sp, #S_FRAME_SIZE
+	stmib	sp, {r1 - lr}
 	mov	r1, #\reason
 	.endm
 
 __pabt_invalid:
-	inv_entry abt, BAD_PREFETCH
-	b	1f
+	inv_entry BAD_PREFETCH
+	b	common_invalid
 
 __dabt_invalid:
-	inv_entry abt, BAD_DATA
-	b	1f
+	inv_entry BAD_DATA
+	b	common_invalid
 
 __irq_invalid:
-	inv_entry irq, BAD_IRQ
-	b	1f
+	inv_entry BAD_IRQ
+	b	common_invalid
 
 __und_invalid:
-	inv_entry und, BAD_UNDEFINSTR
+	inv_entry BAD_UNDEFINSTR
+
+	@
+	@ XXX fall through to common_invalid
+	@
+
+@
+@ common_invalid - generic code for failed exception (re-entrant version of handlers)
+@
+common_invalid:
+	zero_fp
+
+	ldmia	r0, {r4 - r6}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r7, #-1			@  ""   ""    ""        ""
+	str	r4, [sp]		@ save preserved r0
+	stmia	r0, {r5 - r7}		@ lr_<exception>,
+					@ cpsr_<exception>, "old_r0"
 
-1:	zero_fp
-	ldmia	r4, {r5 - r7}			@ Get XXX pc, cpsr, old_r0
-	add	r4, sp, #S_PC
-	stmia	r4, {r5 - r7}			@ Save XXX pc, cpsr, old_r0
 	mov	r0, sp
-	and	r2, r6, #31			@ int mode
+	and	r2, r6, #0x1f
 	b	bad_mode
 
 /*
  * SVC mode handlers
  */
-	.macro	svc_entry, sym
+	.macro	svc_entry
 	sub	sp, sp, #S_FRAME_SIZE
-	stmia	sp, {r0 - r12}			@ save r0 - r12
-	ldr	r2, .LC\sym
-	add	r0, sp, #S_FRAME_SIZE
-	ldmia	r2, {r2 - r4}			@ get pc, cpsr
-	add	r5, sp, #S_SP
+	stmib	sp, {r1 - r12}
+
+	ldmia	r0, {r1 - r3}
+	add	r5, sp, #S_SP		@ here for interlock avoidance
+	mov	r4, #-1			@  ""  ""      ""       ""
+	add	r0, sp, #S_FRAME_SIZE   @  ""  ""      ""       ""
+	str	r1, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
+
 	mov	r1, lr
 
 	@
@@ -82,7 +125,7 @@ __und_invalid:
 
 	.align	5
 __dabt_svc:
-	svc_entry abt
+	svc_entry
 
 	@
 	@ get ready to re-enable interrupts if appropriate
@@ -129,28 +172,24 @@ __dabt_svc:
 
 	.align	5
 __irq_svc:
-	svc_entry irq
+	svc_entry
+
 #ifdef CONFIG_PREEMPT
-	get_thread_info r8
-	ldr	r9, [r8, #TI_PREEMPT]		@ get preempt count
-	add	r7, r9, #1			@ increment it
-	str	r7, [r8, #TI_PREEMPT]
+	get_thread_info tsk
+	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
+	add	r7, r8, #1			@ increment it
+	str	r7, [tsk, #TI_PREEMPT]
 #endif
-1:	get_irqnr_and_base r0, r6, r5, lr
-	movne	r1, sp
-	@
-	@ routine called with r0 = irq number, r1 = struct pt_regs *
-	@
-	adrne	lr, 1b
-	bne	asm_do_IRQ
+
+	irq_handler
 #ifdef CONFIG_PREEMPT
-	ldr	r0, [r8, #TI_FLAGS]		@ get flags
+	ldr	r0, [tsk, #TI_FLAGS]		@ get flags
 	tst	r0, #_TIF_NEED_RESCHED
 	blne	svc_preempt
 preempt_return:
-	ldr	r0, [r8, #TI_PREEMPT]		@ read preempt value
+	ldr	r0, [tsk, #TI_PREEMPT]		@ read preempt value
+	str	r8, [tsk, #TI_PREEMPT]		@ restore preempt count
 	teq	r0, r7
-	str	r9, [r8, #TI_PREEMPT]		@ restore preempt count
 	strne	r0, [r0, -r0]			@ bug()
 #endif
 	ldr	r0, [sp, #S_PSR]		@ irqs are already disabled
@@ -161,7 +200,7 @@ preempt_return:
 
 #ifdef CONFIG_PREEMPT
 svc_preempt:
-	teq	r9, #0				@ was preempt count = 0
+	teq	r8, #0				@ was preempt count = 0
 	ldreq	r6, .LCirq_stat
 	movne	pc, lr				@ no
 	ldr	r0, [r6, #4]			@ local_irq_count
@@ -169,9 +208,9 @@ svc_preempt:
 	adds	r0, r0, r1
 	movne	pc, lr
 	mov	r7, #0				@ preempt_schedule_irq
-	str	r7, [r8, #TI_PREEMPT]		@ expects preempt_count == 0
+	str	r7, [tsk, #TI_PREEMPT]		@ expects preempt_count == 0
 1:	bl	preempt_schedule_irq		@ irq en/disable is done inside
-	ldr	r0, [r8, #TI_FLAGS]		@ get new tasks TI_FLAGS
+	ldr	r0, [tsk, #TI_FLAGS]		@ get new tasks TI_FLAGS
 	tst	r0, #_TIF_NEED_RESCHED
 	beq	preempt_return			@ go again
 	b	1b
@@ -179,7 +218,7 @@ svc_preempt:
 
 	.align	5
 __und_svc:
-	svc_entry und
+	svc_entry
 
 	@
 	@ call emulation code, which returns using r9 if it has emulated
@@ -209,7 +248,7 @@ __und_svc:
 
 	.align	5
 __pabt_svc:
-	svc_entry abt
+	svc_entry
 
 	@
 	@ re-enable interrupts if appropriate
@@ -242,12 +281,8 @@ __pabt_svc:
 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 
 	.align	5
-.LCirq:
-	.word	__temp_irq
-.LCund:
-	.word	__temp_und
-.LCabt:
-	.word	__temp_abt
+.LCcralign:
+	.word	cr_alignment
 #ifdef MULTI_ABORT
 .LCprocfns:
 	.word	processor
@@ -262,12 +297,16 @@ __pabt_svc:
 /*
  * User mode handlers
  */
-	.macro	usr_entry, sym
-	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
-	stmia	sp, {r0 - r12}			@ save r0 - r12
-	ldr	r7, .LC\sym
-	add	r5, sp, #S_PC
-	ldmia	r7, {r2 - r4}			@ Get USR pc, cpsr
+	.macro	usr_entry
+	sub	sp, sp, #S_FRAME_SIZE
+	stmib	sp, {r1 - r12}
+
+	ldmia	r0, {r1 - r3}
+	add	r0, sp, #S_PC		@ here for interlock avoidance
+	mov	r4, #-1			@  ""  ""     ""        ""
+
+	str	r1, [sp]		@ save the "real" r0 copied
+					@ from the exception stack
 
 #if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
 	@ make sure our user space atomic helper is aborted
@@ -284,13 +323,13 @@ __pabt_svc:
 	@
 	@ Also, separately save sp_usr and lr_usr
 	@
-	stmia	r5, {r2 - r4}
-	stmdb	r5, {sp, lr}^
+	stmia	r0, {r2 - r4}
+	stmdb	r0, {sp, lr}^
 
 	@
 	@ Enable the alignment trap while in kernel mode
 	@
-	alignment_trap r7, r0, __temp_\sym
+	alignment_trap r0
 
 	@
 	@ Clear FP to mark the first stack frame
@@ -300,7 +339,7 @@ __pabt_svc:
 
 	.align	5
 __dabt_usr:
-	usr_entry abt
+	usr_entry
 
 	@
 	@ Call the processor-specific abort handler:
@@ -329,30 +368,23 @@ __dabt_usr:
 
 	.align	5
 __irq_usr:
-	usr_entry irq
+	usr_entry
 
+	get_thread_info tsk
 #ifdef CONFIG_PREEMPT
-	get_thread_info r8
-	ldr	r9, [r8, #TI_PREEMPT]		@ get preempt count
-	add	r7, r9, #1			@ increment it
-	str	r7, [r8, #TI_PREEMPT]
+	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
+	add	r7, r8, #1			@ increment it
+	str	r7, [tsk, #TI_PREEMPT]
 #endif
-1:	get_irqnr_and_base r0, r6, r5, lr
-	movne	r1, sp
-	adrne	lr, 1b
-	@
-	@ routine called with r0 = irq number, r1 = struct pt_regs *
-	@
-	bne	asm_do_IRQ
+
+	irq_handler
 #ifdef CONFIG_PREEMPT
-	ldr	r0, [r8, #TI_PREEMPT]
+	ldr	r0, [tsk, #TI_PREEMPT]
+	str	r8, [tsk, #TI_PREEMPT]
 	teq	r0, r7
-	str	r9, [r8, #TI_PREEMPT]
 	strne	r0, [r0, -r0]
-	mov	tsk, r8
-#else
-	get_thread_info tsk
 #endif
+
 	mov	why, #0
 	b	ret_to_user
 
@@ -360,7 +392,7 @@ __irq_usr:
 
 	.align	5
 __und_usr:
-	usr_entry und
+	usr_entry
 
 	tst	r3, #PSR_T_BIT			@ Thumb mode?
 	bne	fpundefinstr			@ ignore FP
@@ -476,7 +508,7 @@ fpundefinstr:
 
 	.align	5
 __pabt_usr:
-	usr_entry abt
+	usr_entry
 
 	enable_irq				@ Enable interrupts
 	mov	r0, r2				@ address (pc)
@@ -741,29 +773,41 @@ __kuser_helper_end:
  *
  * Common stub entry macro:
  *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
+ *
+ * SP points to a minimal amount of processor-private memory, the address
+ * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, sym, correction=0
+	.macro	vector_stub, name, correction=0
 	.align	5
 
 vector_\name:
-	ldr	r13, .LCs\sym
 	.if \correction
 	sub	lr, lr, #\correction
 	.endif
-	str	lr, [r13]			@ save lr_IRQ
+
+	@
+	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
+	@ (parent CPSR)
+	@
+	stmia	sp, {r0, lr}		@ save r0, lr
 	mrs	lr, spsr
-	str	lr, [r13, #4]			@ save spsr_IRQ
+	str	lr, [sp, #8]		@ save spsr
+
 	@
-	@ now branch to the relevant MODE handling routine
+	@ Prepare for SVC32 mode.  IRQs remain disabled.
 	@
-	mrs	r13, cpsr
-	bic	r13, r13, #MODE_MASK
-	orr	r13, r13, #SVC_MODE
-	msr	spsr_cxsf, r13			@ switch to SVC_32 mode
+	mrs	r0, cpsr
+	bic	r0, r0, #MODE_MASK
+	orr	r0, r0, #SVC_MODE
+	msr	spsr_cxsf, r0
 
-	and	lr, lr, #15
+	@
+	@ the branch table must immediately follow this code
+	@
+	mov	r0, sp
+	and	lr, lr, #0x0f
 	ldr	lr, [pc, lr, lsl #2]
-	movs	pc, lr				@ Changes mode and branches
+	movs	pc, lr			@ branch to handler in SVC mode
 	.endm
 
 	.globl	__stubs_start
@@ -771,7 +815,7 @@ __stubs_start:
 /*
  * Interrupt dispatcher
  */
-	vector_stub	irq, irq, 4
+	vector_stub	irq, 4
 
 	.long	__irq_usr			@  0  (USR_26 / USR_32)
 	.long	__irq_invalid			@  1  (FIQ_26 / FIQ_32)
@@ -794,7 +838,7 @@ __stubs_start:
  * Data abort dispatcher
  * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
  */
-	vector_stub	dabt, abt, 8
+	vector_stub	dabt, 8
 
 	.long	__dabt_usr			@  0  (USR_26 / USR_32)
 	.long	__dabt_invalid			@  1  (FIQ_26 / FIQ_32)
@@ -817,7 +861,7 @@ __stubs_start:
  * Prefetch abort dispatcher
  * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
  */
-	vector_stub	pabt, abt, 4
+	vector_stub	pabt, 4
 
 	.long	__pabt_usr			@  0 (USR_26 / USR_32)
 	.long	__pabt_invalid			@  1 (FIQ_26 / FIQ_32)
@@ -840,7 +884,7 @@ __stubs_start:
  * Undef instr entry dispatcher
  * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
  */
-	vector_stub	und, und
+	vector_stub	und
 
 	.long	__und_usr			@  0 (USR_26 / USR_32)
 	.long	__und_invalid			@  1 (FIQ_26 / FIQ_32)
@@ -894,13 +938,6 @@ vector_addrexcptn:
 .LCvswi:
 	.word	vector_swi
 
-.LCsirq:
-	.word	__temp_irq
-.LCsund:
-	.word	__temp_und
-.LCsabt:
-	.word	__temp_abt
-
 	.globl	__stubs_end
 __stubs_end:
 
@@ -922,23 +959,6 @@ __vectors_end:
 
 	.data
 
-/*
- * Do not reorder these, and do not insert extra data between...
- */
-
-__temp_irq:
-	.word	0				@ saved lr_irq
-	.word	0				@ saved spsr_irq
-	.word	-1				@ old_r0
-__temp_und:
-	.word	0				@ Saved lr_und
-	.word	0				@ Saved spsr_und
-	.word	-1				@ old_r0
-__temp_abt:
-	.word	0				@ Saved lr_abt
-	.word	0				@ Saved spsr_abt
-	.word	-1				@ old_r0
-
 	.globl	cr_alignment
 	.globl	cr_no_alignment
 cr_alignment:

+ 3 - 4
arch/arm/kernel/entry-header.S

@@ -59,11 +59,10 @@
 	mov	\rd, \rd, lsl #13
 	.endm
 
-	.macro	alignment_trap, rbase, rtemp, sym
+	.macro	alignment_trap, rtemp
 #ifdef CONFIG_ALIGNMENT_TRAP
-#define OFF_CR_ALIGNMENT(x)	cr_alignment - x
-
-	ldr	\rtemp, [\rbase, #OFF_CR_ALIGNMENT(\sym)]
+	ldr	\rtemp, .LCcralign
+	ldr	\rtemp, [\rtemp]
 	mcr	p15, 0, \rtemp, c1, c0
 #endif
 	.endm

+ 44 - 0
arch/arm/kernel/head.S

@@ -2,6 +2,8 @@
  *  linux/arch/arm/kernel/head.S
  *
  *  Copyright (C) 1994-2002 Russell King
+ *  Copyright (c) 2003 ARM Limited
+ *  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 version 2 as
@@ -165,6 +167,48 @@ __mmap_switched:
 	stmia	r6, {r0, r4}			@ Save control register values
 	b	start_kernel
 
+#if defined(CONFIG_SMP)
+	.type   secondary_startup, #function
+ENTRY(secondary_startup)
+	/*
+	 * Common entry point for secondary CPUs.
+	 *
+	 * Ensure that we're in SVC mode, and IRQs are disabled.  Lookup
+	 * the processor type - there is no need to check the machine type
+	 * as it has already been validated by the primary processor.
+	 */
+	msr	cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC
+	bl	__lookup_processor_type
+	movs	r10, r5				@ invalid processor?
+	moveq	r0, #'p'			@ yes, error 'p'
+	beq	__error
+
+	/*
+	 * Use the page tables supplied from  __cpu_up.
+	 */
+	adr	r4, __secondary_data
+	ldmia	r4, {r5, r6, r13}		@ address to jump to after
+	sub	r4, r4, r5			@ mmu has been enabled
+	ldr	r4, [r6, r4]			@ get secondary_data.pgdir
+	adr	lr, __enable_mmu		@ return address
+	add	pc, r10, #12			@ initialise processor
+						@ (return control reg)
+
+	/*
+	 * r6  = &secondary_data
+	 */
+ENTRY(__secondary_switched)
+	ldr	sp, [r6, #4]			@ get secondary_data.stack
+	mov	fp, #0
+	b	secondary_start_kernel
+
+	.type	__secondary_data, %object
+__secondary_data:
+	.long	.
+	.long	secondary_data
+	.long	__secondary_switched
+#endif /* defined(CONFIG_SMP) */
+
 
 
 /*

+ 50 - 2
arch/arm/kernel/setup.c

@@ -92,6 +92,14 @@ struct cpu_user_fns cpu_user;
 struct cpu_cache_fns cpu_cache;
 #endif
 
+struct stack {
+	u32 irq[3];
+	u32 abt[3];
+	u32 und[3];
+} ____cacheline_aligned;
+
+static struct stack stacks[NR_CPUS];
+
 char elf_platform[ELF_PLATFORM_SIZE];
 EXPORT_SYMBOL(elf_platform);
 
@@ -307,8 +315,6 @@ static void __init setup_processor(void)
 	       cpu_name, processor_id, (int)processor_id & 15,
 	       proc_arch[cpu_architecture()]);
 
-	dump_cpu_info(smp_processor_id());
-
 	sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
 	sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
 	elf_hwcap = list->elf_hwcap;
@@ -316,6 +322,46 @@ static void __init setup_processor(void)
 	cpu_proc_init();
 }
 
+/*
+ * cpu_init - initialise one CPU.
+ *
+ * cpu_init dumps the cache information, initialises SMP specific
+ * information, and sets up the per-CPU stacks.
+ */
+void cpu_init(void)
+{
+	unsigned int cpu = smp_processor_id();
+	struct stack *stk = &stacks[cpu];
+
+	if (cpu >= NR_CPUS) {
+		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
+		BUG();
+	}
+
+	dump_cpu_info(cpu);
+
+	/*
+	 * setup stacks for re-entrant exception handlers
+	 */
+	__asm__ (
+	"msr	cpsr_c, %1\n\t"
+	"add	sp, %0, %2\n\t"
+	"msr	cpsr_c, %3\n\t"
+	"add	sp, %0, %4\n\t"
+	"msr	cpsr_c, %5\n\t"
+	"add	sp, %0, %6\n\t"
+	"msr	cpsr_c, %7"
+	    :
+	    : "r" (stk),
+	      "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
+	      "I" (offsetof(struct stack, irq[0])),
+	      "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
+	      "I" (offsetof(struct stack, abt[0])),
+	      "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
+	      "I" (offsetof(struct stack, und[0])),
+	      "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE));
+}
+
 static struct machine_desc * __init setup_machine(unsigned int nr)
 {
 	struct machine_desc *list;
@@ -715,6 +761,8 @@ void __init setup_arch(char **cmdline_p)
 	paging_init(&meminfo, mdesc);
 	request_standard_resources(&meminfo, mdesc);
 
+	cpu_init();
+
 	/*
 	 * Set up various architecture-specific pointers
 	 */

+ 107 - 0
arch/arm/kernel/smp.c

@@ -24,6 +24,9 @@
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
 #include <asm/cpu.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
@@ -36,6 +39,13 @@
 cpumask_t cpu_present_mask;
 cpumask_t cpu_online_map;
 
+/*
+ * as from 2.5, kernels no longer have an init_tasks structure
+ * so we need some other way of telling a new secondary core
+ * where to place its SVC stack
+ */
+struct secondary_data secondary_data;
+
 /*
  * structures for inter-processor calls
  * - A collection of single bit ipi messages.
@@ -71,6 +81,8 @@ static DEFINE_SPINLOCK(smp_call_function_lock);
 int __init __cpu_up(unsigned int cpu)
 {
 	struct task_struct *idle;
+	pgd_t *pgd;
+	pmd_t *pmd;
 	int ret;
 
 	/*
@@ -83,10 +95,55 @@ int __init __cpu_up(unsigned int cpu)
 		return PTR_ERR(idle);
 	}
 
+	/*
+	 * Allocate initial page tables to allow the new CPU to
+	 * enable the MMU safely.  This essentially means a set
+	 * of our "standard" page tables, with the addition of
+	 * a 1:1 mapping for the physical address of the kernel.
+	 */
+	pgd = pgd_alloc(&init_mm);
+	pmd = pmd_offset(pgd, PHYS_OFFSET);
+	*pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) |
+		     PMD_TYPE_SECT | PMD_SECT_AP_WRITE);
+
+	/*
+	 * We need to tell the secondary core where to find
+	 * its stack and the page tables.
+	 */
+	secondary_data.stack = (void *)idle->thread_info + THREAD_SIZE - 8;
+	secondary_data.pgdir = virt_to_phys(pgd);
+	wmb();
+
 	/*
 	 * Now bring the CPU into our world.
 	 */
 	ret = boot_secondary(cpu, idle);
+	if (ret == 0) {
+		unsigned long timeout;
+
+		/*
+		 * CPU was successfully started, wait for it
+		 * to come online or time out.
+		 */
+		timeout = jiffies + HZ;
+		while (time_before(jiffies, timeout)) {
+			if (cpu_online(cpu))
+				break;
+
+			udelay(10);
+			barrier();
+		}
+
+		if (!cpu_online(cpu))
+			ret = -EIO;
+	}
+
+	secondary_data.stack = 0;
+	secondary_data.pgdir = 0;
+
+	*pmd_offset(pgd, PHYS_OFFSET) = __pmd(0);
+	pgd_free(pgd);
+
 	if (ret) {
 		printk(KERN_CRIT "cpu_up: processor %d failed to boot\n", cpu);
 		/*
@@ -97,6 +154,56 @@ int __init __cpu_up(unsigned int cpu)
 	return ret;
 }
 
+/*
+ * This is the secondary CPU boot entry.  We're using this CPUs
+ * idle thread stack, but a set of temporary page tables.
+ */
+asmlinkage void __init secondary_start_kernel(void)
+{
+	struct mm_struct *mm = &init_mm;
+	unsigned int cpu = smp_processor_id();
+
+	printk("CPU%u: Booted secondary processor\n", cpu);
+
+	/*
+	 * All kernel threads share the same mm context; grab a
+	 * reference and switch to it.
+	 */
+	atomic_inc(&mm->mm_users);
+	atomic_inc(&mm->mm_count);
+	current->active_mm = mm;
+	cpu_set(cpu, mm->cpu_vm_mask);
+	cpu_switch_mm(mm->pgd, mm);
+	enter_lazy_tlb(mm, current);
+
+	cpu_init();
+
+	/*
+	 * Give the platform a chance to do its own initialisation.
+	 */
+	platform_secondary_init(cpu);
+
+	/*
+	 * Enable local interrupts.
+	 */
+	local_irq_enable();
+	local_fiq_enable();
+
+	calibrate_delay();
+
+	smp_store_cpu_info(cpu);
+
+	/*
+	 * OK, now it's safe to let the boot CPU continue
+	 */
+	cpu_set(cpu, cpu_online_map);
+
+	/*
+	 * OK, it's off to the idle thread for us
+	 */
+	cpu_idle();
+}
+
 /*
  * Called by both boot and secondaries to move global data into
  * per-processor storage.

+ 1 - 0
arch/arm/mach-integrator/Makefile

@@ -12,3 +12,4 @@ obj-$(CONFIG_LEDS)			+= leds.o
 obj-$(CONFIG_PCI)			+= pci_v3.o pci.o
 obj-$(CONFIG_CPU_FREQ_INTEGRATOR)	+= cpu.o
 obj-$(CONFIG_INTEGRATOR_IMPD1)		+= impd1.o
+obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o

+ 19 - 1
arch/arm/mach-integrator/core.c

@@ -14,6 +14,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -221,7 +222,24 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 	 */
 	timer1->TimerClear = 1;
 
-	timer_tick(regs);
+	/*
+	 * the clock tick routines are only processed on the
+	 * primary CPU
+	 */
+	if (hard_smp_processor_id() == 0) {
+		nmi_tick();
+		timer_tick(regs);
+#ifdef CONFIG_SMP
+		smp_send_timer();
+#endif
+	}
+
+#ifdef CONFIG_SMP
+	/*
+	 * this is the ARM equivalent of the APIC timer interrupt
+	 */
+	update_process_times(user_mode(regs));
+#endif /* CONFIG_SMP */
 
 	write_sequnlock(&xtime_lock);
 

+ 37 - 0
arch/arm/mach-integrator/headsmp.S

@@ -0,0 +1,37 @@
+/*
+ *  linux/arch/arm/mach-integrator/headsmp.S
+ *
+ *  Copyright (c) 2003 ARM Limited
+ *  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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+	__INIT
+
+/*
+ * Integrator specific entry point for secondary CPUs.  This provides
+ * a "holding pen" into which all secondary cores are held until we're
+ * ready for them to initialise.
+ */
+ENTRY(integrator_secondary_startup)
+	adr	r4, 1f
+	ldmia	r4, {r5, r6}
+	sub	r4, r4, r5
+	ldr	r6, [r6, r4]
+pen:	ldr	r7, [r6]
+	cmp	r7, r0
+	bne	pen
+
+	/*
+	 * we've been released from the holding pen: secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
+
+1:	.long	.
+	.long	phys_pen_release

+ 3 - 1
arch/arm/mach-integrator/leds.c

@@ -22,6 +22,8 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -85,4 +87,4 @@ static int __init leds_init(void)
 	return 0;
 }
 
-__initcall(leds_init);
+core_initcall(leds_init);

+ 192 - 0
arch/arm/mach-integrator/platsmp.c

@@ -0,0 +1,192 @@
+/*
+ *  linux/arch/arm/mach-cintegrator/platsmp.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+
+#include <asm/atomic.h>
+#include <asm/delay.h>
+#include <asm/mmu_context.h>
+#include <asm/procinfo.h>
+#include <asm/ptrace.h>
+#include <asm/smp.h>
+
+extern void integrator_secondary_startup(void);
+
+/*
+ * control for which core is the next to come out of the secondary
+ * boot "holding pen"
+ */
+volatile int __initdata pen_release = -1;
+unsigned long __initdata phys_pen_release = 0;
+
+static DEFINE_SPINLOCK(boot_lock);
+
+void __init platform_secondary_init(unsigned int cpu)
+{
+	/*
+	 * the primary core may have used a "cross call" soft interrupt
+	 * to get this processor out of WFI in the BootMonitor - make
+	 * sure that we are no longer being sent this soft interrupt
+	 */
+	smp_cross_call_done(cpumask_of_cpu(cpu));
+
+	/*
+	 * if any interrupts are already enabled for the primary
+	 * core (e.g. timer irq), then they will not have been enabled
+	 * for us: do so
+	 */
+	secondary_scan_irqs();
+
+	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	pen_release = -1;
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+int __init boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	/*
+	 * set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * The secondary processor is waiting to be released from
+	 * the holding pen - release it, then wait for it to flag
+	 * that it has been released by resetting pen_release.
+	 *
+	 * Note that "pen_release" is the hardware CPU ID, whereas
+	 * "cpu" is Linux's internal ID.
+	 */
+	pen_release = cpu;
+
+	/*
+	 * XXX
+	 *
+	 * This is a later addition to the booting protocol: the
+	 * bootMonitor now puts secondary cores into WFI, so
+	 * poke_milo() no longer gets the cores moving; we need
+	 * to send a soft interrupt to wake the secondary core.
+	 * Use smp_cross_call() for this, since there's little
+	 * point duplicating the code here
+	 */
+	smp_cross_call(cpumask_of_cpu(cpu));
+
+	timeout = jiffies + (1 * HZ);
+	while (time_before(jiffies, timeout)) {
+		if (pen_release == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return pen_release != -1 ? -ENOSYS : 0;
+}
+
+static void __init poke_milo(void)
+{
+	extern void secondary_startup(void);
+
+	/* nobody is to be released from the pen yet */
+	pen_release = -1;
+
+	phys_pen_release = virt_to_phys(&pen_release);
+
+	/*
+	 * write the address of secondary startup into the system-wide
+	 * flags register, then clear the bottom two bits, which is what
+	 * BootMonitor is waiting for
+	 */
+#if 1
+#define CINTEGRATOR_HDR_FLAGSS_OFFSET 0x30
+	__raw_writel(virt_to_phys(integrator_secondary_startup),
+		     (IO_ADDRESS(INTEGRATOR_HDR_BASE) +
+		      CINTEGRATOR_HDR_FLAGSS_OFFSET));
+#define CINTEGRATOR_HDR_FLAGSC_OFFSET 0x34
+	__raw_writel(3,
+		     (IO_ADDRESS(INTEGRATOR_HDR_BASE) +
+		      CINTEGRATOR_HDR_FLAGSC_OFFSET));
+#endif
+
+	mb();
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+	unsigned int ncores = get_core_count();
+	unsigned int cpu = smp_processor_id();
+	int i;
+
+	/* sanity check */
+	if (ncores == 0) {
+		printk(KERN_ERR
+		       "Integrator/CP: strange CM count of 0? Default to 1\n");
+
+		ncores = 1;
+	}
+
+	if (ncores > NR_CPUS) {
+		printk(KERN_WARNING
+		       "Integrator/CP: no. of cores (%d) greater than configured "
+		       "maximum of %d - clipping\n",
+		       ncores, NR_CPUS);
+		ncores = NR_CPUS;
+	}
+
+	/*
+	 * start with some more config for the Boot CPU, now that
+	 * the world is a bit more alive (which was not the case
+	 * when smp_prepare_boot_cpu() was called)
+	 */
+	smp_store_cpu_info(cpu);
+
+	/*
+	 * are we trying to boot more cores than exist?
+	 */
+	if (max_cpus > ncores)
+		max_cpus = ncores;
+
+	/*
+	 * Initialise the present mask - this tells us which CPUs should
+	 * be present.
+	 */
+	for (i = 0; i < max_cpus; i++) {
+		cpu_set(i, cpu_present_mask);
+	}
+
+	/*
+	 * Do we need any more CPUs? If so, then let them know where
+	 * to start. Note that, on modern versions of MILO, the "poke"
+	 * doesn't actually do anything until each individual core is
+	 * sent a soft interrupt to get it out of WFI
+	 */
+	if (max_cpus > 1)
+		poke_milo();
+}

+ 2 - 0
arch/arm/mach-pxa/pm.c

@@ -133,6 +133,8 @@ static int pxa_pm_enter(suspend_state_t state)
 	/* *** go zzz *** */
 	pxa_cpu_pm_enter(state);
 
+	cpu_init();
+
 	/* after sleeping, validate the checksum */
 	checksum = 0;
 	for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)

+ 2 - 0
arch/arm/mach-sa1100/pm.c

@@ -88,6 +88,8 @@ static int sa11x0_pm_enter(suspend_state_t state)
 	/* go zzz */
 	sa1100_cpu_suspend();
 
+	cpu_init();
+
 	/*
 	 * Ensure not to come back here if it wasn't intended
 	 */

+ 3 - 9
drivers/block/cciss.c

@@ -41,6 +41,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
+#include <linux/dma-mapping.h>
 #include <linux/blkdev.h>
 #include <linux/genhd.h>
 #include <linux/completion.h>
@@ -126,8 +127,6 @@ static struct board_type products[] = {
 #define MAX_CTLR_ORIG 	8
 
 
-#define CCISS_DMA_MASK	0xFFFFFFFF	/* 32 bit DMA */
-
 static ctlr_info_t *hba[MAX_CTLR];
 
 static void do_cciss_request(request_queue_t *q);
@@ -2393,11 +2392,6 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 		printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
 		return( -1);
 	}
-	if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0)
-	{
-		printk(KERN_ERR "cciss:  Unable to set DMA mask\n");
-		return(-1);
-	}
 
 	subsystem_vendor_id = pdev->subsystem_vendor;
 	subsystem_device_id = pdev->subsystem_device;
@@ -2747,9 +2741,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 	hba[i]->pdev = pdev;
 
 	/* configure PCI DMA stuff */
-	if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL))
+	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK))
 		printk("cciss: using DAC cycles\n");
-	else if (!pci_set_dma_mask(pdev, 0xffffffff))
+	else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
 		printk("cciss: not using DAC cycles\n");
 	else {
 		printk("cciss: no suitable DMA available\n");

+ 13 - 0
drivers/block/elevator.c

@@ -285,6 +285,13 @@ void elv_requeue_request(request_queue_t *q, struct request *rq)
 		rq = rq->end_io_data;
 	}
 
+	/*
+	 * the request is prepped and may have some resources allocated.
+	 * allowing unprepped requests to pass this one may cause resource
+	 * deadlock.  turn on softbarrier.
+	 */
+	rq->flags |= REQ_SOFTBARRIER;
+
 	/*
 	 * if iosched has an explicit requeue hook, then use that. otherwise
 	 * just put the request at the front of the queue
@@ -381,6 +388,12 @@ struct request *elv_next_request(request_queue_t *q)
 		if (ret == BLKPREP_OK) {
 			break;
 		} else if (ret == BLKPREP_DEFER) {
+			/*
+			 * the request may have been (partially) prepped.
+			 * we need to keep this request in the front to
+			 * avoid resource deadlock.  turn on softbarrier.
+			 */
+			rq->flags |= REQ_SOFTBARRIER;
 			rq = NULL;
 			break;
 		} else if (ret == BLKPREP_KILL) {

+ 6 - 14
drivers/block/ll_rw_blk.c

@@ -2038,7 +2038,6 @@ EXPORT_SYMBOL(blk_requeue_request);
  * @rq:		request to be inserted
  * @at_head:	insert request at head or tail of queue
  * @data:	private data
- * @reinsert:	true if request it a reinsertion of previously processed one
  *
  * Description:
  *    Many block devices need to execute commands asynchronously, so they don't
@@ -2053,8 +2052,9 @@ EXPORT_SYMBOL(blk_requeue_request);
  *    host that is unable to accept a particular command.
  */
 void blk_insert_request(request_queue_t *q, struct request *rq,
-			int at_head, void *data, int reinsert)
+			int at_head, void *data)
 {
+	int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
 	unsigned long flags;
 
 	/*
@@ -2071,20 +2071,12 @@ void blk_insert_request(request_queue_t *q, struct request *rq,
 	/*
 	 * If command is tagged, release the tag
 	 */
-	if (reinsert)
-		blk_requeue_request(q, rq);
-	else {
-		int where = ELEVATOR_INSERT_BACK;
-
-		if (at_head)
-			where = ELEVATOR_INSERT_FRONT;
+	if (blk_rq_tagged(rq))
+		blk_queue_end_tag(q, rq);
 
-		if (blk_rq_tagged(rq))
-			blk_queue_end_tag(q, rq);
+	drive_stat_acct(rq, rq->nr_sectors, 1);
+	__elv_add_request(q, rq, where, 0);
 
-		drive_stat_acct(rq, rq->nr_sectors, 1);
-		__elv_add_request(q, rq, where, 0);
-	}
 	if (blk_queue_plugged(q))
 		__generic_unplug_device(q);
 	else

+ 1 - 1
drivers/block/paride/pd.c

@@ -723,7 +723,7 @@ static int pd_special_command(struct pd_unit *disk,
 	rq.ref_count = 1;
 	rq.waiting = &wait;
 	rq.end_io = blk_end_sync_rq;
-	blk_insert_request(disk->gd->queue, &rq, 0, func, 0);
+	blk_insert_request(disk->gd->queue, &rq, 0, func);
 	wait_for_completion(&wait);
 	rq.waiting = NULL;
 	if (rq.errors)

+ 2 - 2
drivers/block/sx8.c

@@ -614,7 +614,7 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx)
 	spin_unlock_irq(&host->lock);
 
 	DPRINTK("blk_insert_request, tag == %u\n", idx);
-	blk_insert_request(host->oob_q, crq->rq, 1, crq, 0);
+	blk_insert_request(host->oob_q, crq->rq, 1, crq);
 
 	return 0;
 
@@ -653,7 +653,7 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func)
 	crq->msg_bucket = (u32) rc;
 
 	DPRINTK("blk_insert_request, tag == %u\n", idx);
-	blk_insert_request(host->oob_q, crq->rq, 1, crq, 0);
+	blk_insert_request(host->oob_q, crq->rq, 1, crq);
 
 	return 0;
 }

+ 4 - 0
drivers/char/vt.c

@@ -2867,6 +2867,10 @@ void unblank_screen(void)
  */
 static void blank_screen_t(unsigned long dummy)
 {
+	if (unlikely(!keventd_up())) {
+		mod_timer(&console_timer, jiffies + blankinterval);
+		return;
+	}
 	blank_timer_expired = 1;
 	schedule_work(&console_work);
 }

+ 15 - 11
drivers/fc4/fc.c

@@ -767,10 +767,8 @@ static void fcp_scsi_done (Scsi_Cmnd *SCpnt)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
 	if (FCP_CMND(SCpnt)->done)
 		FCP_CMND(SCpnt)->done(SCpnt);
-	spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
 }
 
 static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, int prepare)
@@ -912,9 +910,7 @@ int fcp_scsi_abort(Scsi_Cmnd *SCpnt)
 		unsigned long flags;
 
 		SCpnt->result = DID_ABORT;
-		spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
 		fcmd->done(SCpnt);
-		spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
 		printk("FC: soft abort\n");
 		return SUCCESS;
 	} else {
@@ -987,7 +983,10 @@ int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt)
 	fc->rst_pkt->request->rq_status = RQ_SCSI_BUSY;
 
 	fc->rst_pkt->done = fcp_scsi_reset_done;
+
+	spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
 	fcp_scsi_queue_it(fc, fc->rst_pkt, fcmd, 0);
+	spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
 	
 	down(&sem);
 
@@ -1006,13 +1005,7 @@ int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt)
 	return SUCCESS;
 }
 
-int fcp_scsi_bus_reset(Scsi_Cmnd *SCpnt)
-{
-	printk ("FC: bus reset!\n");
-	return FAILED;
-}
-
-int fcp_scsi_host_reset(Scsi_Cmnd *SCpnt)
+static int __fcp_scsi_host_reset(Scsi_Cmnd *SCpnt)
 {
 	fc_channel *fc = FC_SCMND(SCpnt);
 	fcp_cmnd *fcmd = FCP_CMND(SCpnt);
@@ -1033,6 +1026,17 @@ int fcp_scsi_host_reset(Scsi_Cmnd *SCpnt)
 	else return FAILED;
 }
 
+int fcp_scsi_host_reset(Scsi_Cmnd *SCpnt)
+{
+	int rc;
+
+	spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
+	rc = __fcp_scsi_host_reset(SCpnt);
+	spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
+
+	return rc;
+}
+
 static int fcp_els_queue_it(fc_channel *fc, fcp_cmnd *fcmd)
 {
 	long i;

+ 0 - 1
drivers/fc4/fc_syms.c

@@ -27,7 +27,6 @@ EXPORT_SYMBOL(fc_do_prli);
 EXPORT_SYMBOL(fcp_scsi_queuecommand);
 EXPORT_SYMBOL(fcp_scsi_abort);
 EXPORT_SYMBOL(fcp_scsi_dev_reset);
-EXPORT_SYMBOL(fcp_scsi_bus_reset);
 EXPORT_SYMBOL(fcp_scsi_host_reset);
 
 #endif /* CONFIG_MODULES */

+ 0 - 1
drivers/fc4/fcp_impl.h

@@ -158,7 +158,6 @@ int fc_do_prli(fc_channel *, unsigned char);
 int fcp_scsi_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 int fcp_scsi_abort(Scsi_Cmnd *);
 int fcp_scsi_dev_reset(Scsi_Cmnd *);
-int fcp_scsi_bus_reset(Scsi_Cmnd *);
 int fcp_scsi_host_reset(Scsi_Cmnd *);
 
 #endif /* !(_FCP_SCSI_H) */

+ 16 - 135
drivers/ieee1394/sbp2.c

@@ -1071,7 +1071,7 @@ static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_
 static __inline__ int sbp2_command_conversion_device_type(u8 device_type)
 {
 	return (((device_type == TYPE_DISK) ||
-		 (device_type == TYPE_SDAD) ||
+		 (device_type == TYPE_RBC) ||
 		 (device_type == TYPE_ROM)) ? 1:0);
 }
 
@@ -2112,102 +2112,6 @@ static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
  */
 static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd)
 {
-	unchar new_cmd[16];
-	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
-
-	SBP2_DEBUG("sbp2_check_sbp2_command");
-
-	switch (*cmd) {
-
-		case READ_6:
-
-			if (sbp2_command_conversion_device_type(device_type)) {
-
-				SBP2_DEBUG("Convert READ_6 to READ_10");
-
-				/*
-				 * Need to turn read_6 into read_10
-				 */
-				new_cmd[0] = 0x28;
-				new_cmd[1] = (cmd[1] & 0xe0);
-				new_cmd[2] = 0x0;
-				new_cmd[3] = (cmd[1] & 0x1f);
-				new_cmd[4] = cmd[2];
-				new_cmd[5] = cmd[3];
-				new_cmd[6] = 0x0;
-				new_cmd[7] = 0x0;
-				new_cmd[8] = cmd[4];
-				new_cmd[9] = cmd[5];
-
-				memcpy(cmd, new_cmd, 10);
-
-			}
-
-			break;
-
-		case WRITE_6:
-
-			if (sbp2_command_conversion_device_type(device_type)) {
-
-				SBP2_DEBUG("Convert WRITE_6 to WRITE_10");
-
-				/*
-				 * Need to turn write_6 into write_10
-				 */
-				new_cmd[0] = 0x2a;
-				new_cmd[1] = (cmd[1] & 0xe0);
-				new_cmd[2] = 0x0;
-				new_cmd[3] = (cmd[1] & 0x1f);
-				new_cmd[4] = cmd[2];
-				new_cmd[5] = cmd[3];
-				new_cmd[6] = 0x0;
-				new_cmd[7] = 0x0;
-				new_cmd[8] = cmd[4];
-				new_cmd[9] = cmd[5];
-
-				memcpy(cmd, new_cmd, 10);
-
-			}
-
-			break;
-
-		case MODE_SENSE:
-
-			if (sbp2_command_conversion_device_type(device_type)) {
-
-				SBP2_DEBUG("Convert MODE_SENSE_6 to MODE_SENSE_10");
-
-				/*
-				 * Need to turn mode_sense_6 into mode_sense_10
-				 */
-				new_cmd[0] = 0x5a;
-				new_cmd[1] = cmd[1];
-				new_cmd[2] = cmd[2];
-				new_cmd[3] = 0x0;
-				new_cmd[4] = 0x0;
-				new_cmd[5] = 0x0;
-				new_cmd[6] = 0x0;
-				new_cmd[7] = 0x0;
-				new_cmd[8] = cmd[4];
-				new_cmd[9] = cmd[5];
-
-				memcpy(cmd, new_cmd, 10);
-
-			}
-
-			break;
-
-		case MODE_SELECT:
-
-			/*
-			 * TODO. Probably need to change mode select to 10 byte version
-			 */
-
-		default:
-			break;
-	}
-
-	return;
 }
 
 /*
@@ -2248,7 +2152,6 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id,
 				     struct scsi_cmnd *SCpnt)
 {
 	u8 *scsi_buf = SCpnt->request_buffer;
-	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
 
 	SBP2_DEBUG("sbp2_check_sbp2_response");
 
@@ -2272,14 +2175,6 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id,
 				scsi_buf[4] = 36 - 5;
 			}
 
-			/*
-			 * Check for Simple Direct Access Device and change it to TYPE_DISK
-			 */
-			if ((scsi_buf[0] & 0x1f) == TYPE_SDAD) {
-				SBP2_DEBUG("Changing TYPE_SDAD to TYPE_DISK");
-				scsi_buf[0] &= 0xe0;
-			}
-
 			/*
 			 * Fix ansi revision and response data format
 			 */
@@ -2288,27 +2183,6 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id,
 
 			break;
 
-		case MODE_SENSE:
-
-			if (sbp2_command_conversion_device_type(device_type)) {
-
-				SBP2_DEBUG("Modify mode sense response (10 byte version)");
-
-				scsi_buf[0] = scsi_buf[1];	/* Mode data length */
-				scsi_buf[1] = scsi_buf[2];	/* Medium type */
-				scsi_buf[2] = scsi_buf[3];	/* Device specific parameter */
-				scsi_buf[3] = scsi_buf[7];	/* Block descriptor length */
-				memcpy(scsi_buf + 4, scsi_buf + 8, scsi_buf[0]);
-			}
-
-			break;
-
-		case MODE_SELECT:
-
-			/*
-			 * TODO. Probably need to change mode select to 10 byte version
-			 */
-
 		default:
 			break;
 	}
@@ -2580,8 +2454,6 @@ static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
 				      u32 scsi_status, struct scsi_cmnd *SCpnt,
 				      void (*done)(struct scsi_cmnd *))
 {
-	unsigned long flags;
-
 	SBP2_DEBUG("sbp2scsi_complete_command");
 
 	/*
@@ -2680,18 +2552,15 @@ static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
 	/*
 	 * Tell scsi stack that we're done with this command
 	 */
-	spin_lock_irqsave(scsi_id->scsi_host->host_lock,flags);
 	done (SCpnt);
-	spin_unlock_irqrestore(scsi_id->scsi_host->host_lock,flags);
-
-	return;
 }
 
 
 static int sbp2scsi_slave_configure (struct scsi_device *sdev)
 {
 	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
-
+	sdev->use_10_for_rw = 1;
+	sdev->use_10_for_ms = 1;
 	return 0;
 }
 
@@ -2747,7 +2616,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
 /*
  * Called by scsi stack when something has really gone wrong.
  */
-static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
+static int __sbp2scsi_reset(struct scsi_cmnd *SCpnt)
 {
 	struct scsi_id_instance_data *scsi_id =
 		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
@@ -2762,6 +2631,18 @@ static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
 	return(SUCCESS);
 }
 
+static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
+	rc = __sbp2scsi_reset(SCpnt);
+	spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
+
+	return rc;
+}
+
 static const char *sbp2scsi_info (struct Scsi_Host *host)
 {
         return "SCSI emulation for IEEE-1394 SBP-2 Devices";

+ 0 - 4
drivers/ieee1394/sbp2.h

@@ -266,10 +266,6 @@ struct sbp2_status_block {
 #define SBP2_MAX_UDS_PER_NODE		16	/* Maximum scsi devices per node */
 #define SBP2_MAX_SECTORS		255	/* Max sectors supported */
 
-#ifndef TYPE_SDAD
-#define TYPE_SDAD			0x0e	/* simplified direct access device */
-#endif
-
 /*
  * SCSI direction table...
  * (now used as a back-up in case the direction passed down from above is "unknown")

+ 38 - 18
drivers/message/fusion/Kconfig

@@ -2,34 +2,54 @@
 menu "Fusion MPT device support"
 
 config FUSION
-	tristate "Fusion MPT (base + ScsiHost) drivers"
+	bool
+	default n
+
+config FUSION_SPI
+	tristate "Fusion MPT ScsiHost drivers for SPI"
+	depends on PCI && SCSI
+	select FUSION
+	---help---
+	  SCSI HOST support for a parallel SCSI host adapters.
+
+	  List of supported controllers:
+
+	  LSI53C1020
+	  LSI53C1020A
+	  LSI53C1030
+	  LSI53C1035
+
+config FUSION_FC
+	tristate "Fusion MPT ScsiHost drivers for FC"
 	depends on PCI && SCSI
+	select FUSION
 	---help---
-	  LSI Logic Fusion(TM) Message Passing Technology (MPT) device support
-	  provides high performance SCSI host initiator, and LAN [1] interface
-	  services to a host system.  The Fusion architecture is capable of
-	  duplexing these protocols on high-speed Fibre Channel
-	  (up to 2 GHz x 2 ports = 4 GHz) and parallel SCSI (up to Ultra-320)
-	  physical medium.
+	  SCSI HOST support for a Fiber Channel host adapters.
 
-	  [1] LAN is not supported on parallel SCSI medium.
+	  List of supported controllers:
+
+	  LSIFC909
+	  LSIFC919
+	  LSIFC919X
+	  LSIFC929
+	  LSIFC929X
+	  LSIFC929XL
 
 config FUSION_MAX_SGE
-	int "Maximum number of scatter gather entries"
+	int "Maximum number of scatter gather entries (16 - 128)"
 	depends on FUSION
-	default "40"
+	default "128"
+	range 16 128
 	help
 	  This option allows you to specify the maximum number of scatter-
-	  gather entries per I/O. The driver defaults to 40, a reasonable number
-	  for most systems. However, the user may increase this up to 128.
-	  Increasing this parameter will require significantly more memory 
-	  on a per controller instance. Increasing the parameter is not
-	  necessary (or recommended) unless the user will be running 
-	  large I/O's via the raw interface.
+	  gather entries per I/O. The driver default is 128, which matches
+	  SCSI_MAX_PHYS_SEGMENTS. However, it may decreased down to 16.
+	  Decreasing this parameter will reduce memory requirements
+	  on a per controller instance.
 
 config FUSION_CTL
 	tristate "Fusion MPT misc device (ioctl) driver"
-	depends on FUSION
+	depends on FUSION_SPI || FUSION_FC
 	---help---
 	  The Fusion MPT misc device driver provides specialized control
 	  of MPT adapters via system ioctl calls.  Use of ioctl calls to
@@ -48,7 +68,7 @@ config FUSION_CTL
 
 config FUSION_LAN
 	tristate "Fusion MPT LAN driver"
-	depends on FUSION && NET_FC
+	depends on FUSION_FC && NET_FC
 	---help---
 	  This module supports LAN IP traffic over Fibre Channel port(s)
 	  on Fusion MPT compatible hardware (LSIFC9xx chips).

+ 15 - 29
drivers/message/fusion/Makefile

@@ -1,52 +1,38 @@
-#
-# Makefile for the LSI Logic Fusion MPT (Message Passing Technology) drivers.
-#
-# Note! If you want to turn on various debug defines for an extended period of
-# time but don't want them lingering around in the Makefile when you pass it on
-# to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer
-
-#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-{ LSI_LOGIC
-
-#  Architecture-specific...
-#			# intel
-#EXTRA_CFLAGS += -g
-#			# sparc64
-#EXTRA_CFLAGS += -gstabs+
-
-EXTRA_CFLAGS += ${MPT_CFLAGS}
-
 # Fusion MPT drivers; recognized debug defines...
 #  MPT general:
-#EXTRA_CFLAGS += -DMPT_DEBUG_SCSI
 #EXTRA_CFLAGS += -DMPT_DEBUG
 #EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
 #EXTRA_CFLAGS += -DMPT_DEBUG_SG
+#EXTRA_CFLAGS += -DMPT_DEBUG_EVENTS
+#EXTRA_CFLAGS += -DMPT_DEBUG_INIT
+#EXTRA_CFLAGS += -DMPT_DEBUG_EXIT
+#EXTRA_CFLAGS += -DMPT_DEBUG_FAIL
+
 
 #
 # driver/module specifics...
 #
 #  For mptbase:
 #CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE
+#CFLAGS_mptbase.o += -DMPT_DEBUG_CONFIG
+#CFLAGS_mptbase.o += -DMPT_DEBUG_DL
 #CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ
+#CFLAGS_mptbase.o += -DMPT_DEBUG_RESET
 #
 #  For mptscsih:
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_SCANDV
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_RESET
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_NEH
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_DV
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_NEGO
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_TM
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_SCSI
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_REPLY
 #
 #  For mptctl:
 #CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
 #
-#  For mptlan:
-#CFLAGS_mptlan.o += -DMPT_LAN_IO_DEBUG
-#
-#  For isense:
-
-#  EXP...
-##mptscsih-objs	:= scsihost.o scsiherr.o
 
 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
 
-obj-$(CONFIG_FUSION)		+= mptbase.o mptscsih.o
+obj-$(CONFIG_FUSION_SPI)	+= mptbase.o mptscsih.o mptspi.o
+obj-$(CONFIG_FUSION_FC)		+= mptbase.o mptscsih.o mptfc.o
 obj-$(CONFIG_FUSION_CTL)	+= mptctl.o
 obj-$(CONFIG_FUSION_LAN)	+= mptlan.o

+ 49 - 21
drivers/message/fusion/lsi/mpi.h

@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2003 LSI Logic Corporation.
+ *  Copyright (c) 2000-2005 LSI Logic Corporation.
  *
  *
  *           Name:  mpi.h
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    mpi.h Version:  01.05.xx
+ *    mpi.h Version:  01.05.07
  *
  *  Version History
  *  ---------------
@@ -52,6 +52,25 @@
  *                      obsoleted define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX.
  *  04-01-03  01.02.09  New IOCStatus code: MPI_IOCSTATUS_FC_EXCHANGE_CANCELED
  *  06-26-03  01.02.10  Bumped MPI_HEADER_VERSION_UNIT value.
+ *  01-16-04  01.02.11  Added define for MPI_IOCLOGINFO_TYPE_SHIFT.
+ *  04-29-04  01.02.12  Added function codes for MPI_FUNCTION_DIAG_BUFFER_POST
+ *                      and MPI_FUNCTION_DIAG_RELEASE.
+ *                      Added MPI_IOCSTATUS_DIAGNOSTIC_RELEASED define.
+ *                      Bumped MPI_HEADER_VERSION_UNIT value.
+ *  05-11-04  01.03.01  Bumped MPI_VERSION_MINOR for MPI v1.3.
+ *                      Added codes for Inband.
+ *  08-19-04  01.05.01  Added defines for Host Buffer Access Control doorbell.
+ *                      Added define for offset of High Priority Request Queue.
+ *                      Added new function codes and new IOCStatus codes.
+ *                      Added a IOCLogInfo type of SAS.
+ *  12-07-04  01.05.02  Bumped MPI_HEADER_VERSION_UNIT.
+ *  12-09-04  01.05.03  Bumped MPI_HEADER_VERSION_UNIT.
+ *  01-15-05  01.05.04  Bumped MPI_HEADER_VERSION_UNIT.
+ *  02-09-05  01.05.05  Bumped MPI_HEADER_VERSION_UNIT.
+ *  02-22-05  01.05.06  Bumped MPI_HEADER_VERSION_UNIT.
+ *  03-11-05  01.05.07  Removed function codes for SCSI IO 32 and
+ *                      TargetAssistExtended requests.
+ *                      Removed EEDP IOCStatus codes.
  *  --------------------------------------------------------------------------
  */
 
@@ -82,7 +101,7 @@
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 
 /* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT             (0x00)
+#define MPI_HEADER_VERSION_UNIT             (0x09)
 #define MPI_HEADER_VERSION_DEV              (0x00)
 #define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
 #define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
@@ -122,7 +141,11 @@
 *
 *****************************************************************************/
 
-/* S y s t e m    D o o r b e l l */
+/*
+ * Defines for working with the System Doorbell register.
+ * Values for doorbell function codes are included in the section that defines
+ * all the function codes (further on in this file).
+ */
 #define MPI_DOORBELL_OFFSET                 (0x00000000)
 #define MPI_DOORBELL_ACTIVE                 (0x08000000) /* DoorbellUsed */
 #define MPI_DOORBELL_USED                   (MPI_DOORBELL_ACTIVE)
@@ -134,6 +157,13 @@
 #define MPI_DOORBELL_ADD_DWORDS_MASK        (0x00FF0000)
 #define MPI_DOORBELL_ADD_DWORDS_SHIFT       (16)
 #define MPI_DOORBELL_DATA_MASK              (0x0000FFFF)
+#define MPI_DOORBELL_FUNCTION_SPECIFIC_MASK (0x0000FFFF)
+
+/* values for Host Buffer Access Control doorbell function */
+#define MPI_DB_HPBAC_VALUE_MASK             (0x0000F000)
+#define MPI_DB_HPBAC_ENABLE_ACCESS          (0x01)
+#define MPI_DB_HPBAC_DISABLE_ACCESS         (0x02)
+#define MPI_DB_HPBAC_FREE_BUFFER            (0x03)
 
 
 #define MPI_WRITE_SEQUENCE_OFFSET           (0x00000004)
@@ -257,16 +287,18 @@
 
 #define MPI_FUNCTION_SMP_PASSTHROUGH                (0x1A)
 #define MPI_FUNCTION_SAS_IO_UNIT_CONTROL            (0x1B)
+#define MPI_FUNCTION_SATA_PASSTHROUGH               (0x1C)
 
-#define MPI_DIAG_BUFFER_POST                        (0x1D)
-#define MPI_DIAG_RELEASE                            (0x1E)
-
-#define MPI_FUNCTION_SCSI_IO_32                     (0x1F)
+#define MPI_FUNCTION_DIAG_BUFFER_POST               (0x1D)
+#define MPI_FUNCTION_DIAG_RELEASE                   (0x1E)
 
 #define MPI_FUNCTION_LAN_SEND                       (0x20)
 #define MPI_FUNCTION_LAN_RECEIVE                    (0x21)
 #define MPI_FUNCTION_LAN_RESET                      (0x22)
 
+#define MPI_FUNCTION_TARGET_CMD_BUF_BASE_POST       (0x24)
+#define MPI_FUNCTION_TARGET_CMD_BUF_LIST_POST       (0x25)
+
 #define MPI_FUNCTION_INBAND_BUFFER_POST             (0x28)
 #define MPI_FUNCTION_INBAND_SEND                    (0x29)
 #define MPI_FUNCTION_INBAND_RSP                     (0x2A)
@@ -276,6 +308,7 @@
 #define MPI_FUNCTION_IO_UNIT_RESET                  (0x41)
 #define MPI_FUNCTION_HANDSHAKE                      (0x42)
 #define MPI_FUNCTION_REPLY_FRAME_REMOVAL            (0x43)
+#define MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL    (0x44)
 
 
 /* standard version format */
@@ -328,8 +361,8 @@ typedef struct _SGE_SIMPLE_UNION
         U32                 Address32;
         U64                 Address64;
     }u;
-} SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t,
-  SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION;
+} SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION,
+  SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t;
 
 /****************************************************************************/
 /*  Chain element structures                                                */
@@ -648,27 +681,21 @@ typedef struct _MSG_DEFAULT_REPLY
 #define MPI_IOCSTATUS_SCSI_EXT_TERMINATED       (0x004C)
 
 /****************************************************************************/
-/*  For use by SCSI Initiator and SCSI Target end-to-end data protection    */
-/****************************************************************************/
-
-#define MPI_IOCSTATUS_EEDP_CRC_ERROR            (0x004D)
-#define MPI_IOCSTATUS_EEDP_LBA_TAG_ERROR        (0x004E)
-#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR        (0x004F)
-
-
-/****************************************************************************/
-/*  SCSI (SPI & FCP) target values                                          */
+/*  SCSI Target values                                                      */
 /****************************************************************************/
 
 #define MPI_IOCSTATUS_TARGET_PRIORITY_IO         (0x0060)
 #define MPI_IOCSTATUS_TARGET_INVALID_PORT        (0x0061)
-#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX    (0x0062)   /* obsolete */
+#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX    (0x0062)   /* obsolete name */
 #define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX    (0x0062)
 #define MPI_IOCSTATUS_TARGET_ABORTED             (0x0063)
 #define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE   (0x0064)
 #define MPI_IOCSTATUS_TARGET_NO_CONNECTION       (0x0065)
 #define MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A)
 #define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT   (0x006B)
+#define MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR   (0x006D)
+#define MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E)
+#define MPI_IOCSTATUS_TARGET_IU_TOO_SHORT        (0x006F)
 
 /****************************************************************************/
 /*  Additional FCP target values (obsolete)                                 */
@@ -707,6 +734,7 @@ typedef struct _MSG_DEFAULT_REPLY
 /****************************************************************************/
 
 #define MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED    (0x0090)
+#define MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN      (0x0091)
 
 /****************************************************************************/
 /*  Inband values                                                           */

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 442 - 84
drivers/message/fusion/lsi/mpi_cnfg.h


+ 5 - 2
drivers/message/fusion/lsi/mpi_fc.h

@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2003 LSI Logic Corporation.
+ *  Copyright (c) 2000-2004 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_fc.h
  *          Title:  MPI Fibre Channel messages and structures
  *  Creation Date:  June 12, 2000
  *
- *    mpi_fc.h Version:  01.05.xx
+ *    mpi_fc.h Version:  01.05.01
  *
  *  Version History
  *  ---------------
@@ -36,6 +36,9 @@
  *  09-28-01  01.02.02  Change name of reserved field in
  *                      MSG_LINK_SERVICE_RSP_REPLY.
  *  05-31-02  01.02.03  Adding AliasIndex to FC Direct Access requests.
+ *  01-16-04  01.02.04  Added define for MPI_FC_PRIM_SEND_FLAGS_ML_RESET_LINK.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
  *  --------------------------------------------------------------------------
  */
 

+ 428 - 23
drivers/message/fusion/lsi/mpi_history.txt

@@ -3,25 +3,28 @@
  MPI Header File Change History
  ==============================
 
- Copyright (c) 2000-2001 LSI Logic Corporation.
+ Copyright (c) 2000-2005 LSI Logic Corporation.
 
  ---------------------------------------
- Header Set Release Version:    01.01.10
- Header Set Release Date:       04-09-01
+ Header Set Release Version:    01.05.09
+ Header Set Release Date:       03-11-05
  ---------------------------------------
 
  Filename               Current version     Prior version
  ----------             ---------------     -------------
- mpi.h                  01.01.07            01.01.06
- mpi_ioc.h              01.01.07            01.01.06
- mpi_cnfg.h             01.01.11            01.01.10
- mpi_init.h             01.01.05            01.01.04
- mpi_targ.h             01.01.04            01.01.04
- mpi_fc.h               01.01.07            01.01.06
- mpi_lan.h              01.01.03            01.01.03
- mpi_raid.h             01.01.02            01.01.02
- mpi_type.h             01.01.02            01.01.02
- mpi_history.txt        01.01.09            01.01.09
+ mpi.h                  01.05.07            01.05.06
+ mpi_ioc.h              01.05.08            01.05.07
+ mpi_cnfg.h             01.05.08            01.05.07
+ mpi_init.h             01.05.04            01.05.03
+ mpi_targ.h             01.05.04            01.05.03
+ mpi_fc.h               01.05.01            01.05.01
+ mpi_lan.h              01.05.01            01.05.01
+ mpi_raid.h             01.05.02            01.05.02
+ mpi_tool.h             01.05.03            01.05.03
+ mpi_inb.h              01.05.01            01.05.01
+ mpi_sas.h              01.05.01            01.05.01
+ mpi_type.h             01.05.01            01.05.01
+ mpi_history.txt        01.05.09            01.05.08
 
 
  *  Date      Version   Description
@@ -53,6 +56,38 @@ mpi.h
  *                      Added function codes for RAID.
  *  04-09-01  01.01.07  Added alternate define for MPI_DOORBELL_ACTIVE,
  *                      MPI_DOORBELL_USED, to better match the spec.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      Changed MPI_VERSION_MINOR from 0x01 to 0x02.
+ *                      Added define MPI_FUNCTION_TOOLBOX.
+ *  09-28-01  01.02.02  New function code MPI_SCSI_ENCLOSURE_PROCESSOR.
+ *  11-01-01  01.02.03  Changed name to MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR.
+ *  03-14-02  01.02.04  Added MPI_HEADER_VERSION_ defines.
+ *  05-31-02  01.02.05  Bumped MPI_HEADER_VERSION_UNIT.
+ *  07-12-02  01.02.06  Added define for MPI_FUNCTION_MAILBOX.
+ *  09-16-02  01.02.07  Bumped value for MPI_HEADER_VERSION_UNIT.
+ *  11-15-02  01.02.08  Added define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX and
+ *                      obsoleted define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX.
+ *  04-01-03  01.02.09  New IOCStatus code: MPI_IOCSTATUS_FC_EXCHANGE_CANCELED
+ *  06-26-03  01.02.10  Bumped MPI_HEADER_VERSION_UNIT value.
+ *  01-16-04  01.02.11  Added define for MPI_IOCLOGINFO_TYPE_SHIFT.
+ *  04-29-04  01.02.12  Added function codes for MPI_FUNCTION_DIAG_BUFFER_POST
+ *                      and MPI_FUNCTION_DIAG_RELEASE.
+ *                      Added MPI_IOCSTATUS_DIAGNOSTIC_RELEASED define.
+ *                      Bumped MPI_HEADER_VERSION_UNIT value.
+ *  05-11-04  01.03.01  Bumped MPI_VERSION_MINOR for MPI v1.3.
+ *                      Added codes for Inband.
+ *  08-19-04  01.05.01  Added defines for Host Buffer Access Control doorbell.
+ *                      Added define for offset of High Priority Request Queue.
+ *                      Added new function codes and new IOCStatus codes.
+ *                      Added a IOCLogInfo type of SAS.
+ *  12-07-04  01.05.02  Bumped MPI_HEADER_VERSION_UNIT.
+ *  12-09-04  01.05.03  Bumped MPI_HEADER_VERSION_UNIT.
+ *  01-15-05  01.05.04  Bumped MPI_HEADER_VERSION_UNIT.
+ *  02-09-05  01.05.05  Bumped MPI_HEADER_VERSION_UNIT.
+ *  02-22-05  01.05.06  Bumped MPI_HEADER_VERSION_UNIT.
+ *  03-11-05  01.05.07  Removed function codes for SCSI IO 32 and
+ *                      TargetAssistExtended requests.
+ *                      Removed EEDP IOCStatus codes.
  *  --------------------------------------------------------------------------
 
 mpi_ioc.h
@@ -81,6 +116,49 @@ mpi_ioc.h
  *  03-27-01  01.01.06  Added defines for ProductId field of MPI_FW_HEADER.
  *                      Added structure offset comments.
  *  04-09-01  01.01.07  Added structure EVENT_DATA_EVENT_CHANGE.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      New format for FWVersion and ProductId in
+ *                      MSG_IOC_FACTS_REPLY and MPI_FW_HEADER.
+ *  08-31-01  01.02.02  Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
+ *                      related structure and defines.
+ *                      Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED.
+ *                      Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE.
+ *                      Replaced a reserved field in MSG_IOC_FACTS_REPLY with
+ *                      IOCExceptions and changed DataImageSize to reserved.
+ *                      Added MPI_FW_DOWNLOAD_ITYPE_NVSTORE_DATA and
+ *                      MPI_FW_UPLOAD_ITYPE_NVDATA.
+ *  09-28-01  01.02.03  Modified Event Data for Integrated RAID.
+ *  11-01-01  01.02.04  Added defines for MPI_EXT_IMAGE_HEADER ImageType field.
+ *  03-14-02  01.02.05  Added HeaderVersion field to MSG_IOC_FACTS_REPLY.
+ *  05-31-02  01.02.06  Added define for
+ *                      MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID.
+ *                      Added AliasIndex to EVENT_DATA_LOGOUT structure.
+ *  04-01-03  01.02.07  Added defines for MPI_FW_HEADER_SIGNATURE_.
+ *  06-26-03  01.02.08  Added new values to the product family defines.
+ *  04-29-04  01.02.09  Added IOCCapabilities field to MSG_IOC_FACTS_REPLY and
+ *                      added related defines.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Added four new fields to MSG_IOC_INIT.
+ *                      Added three new fields to MSG_IOC_FACTS_REPLY.
+ *                      Defined four new bits for the IOCCapabilities field of
+ *                      the IOCFacts reply.
+ *                      Added two new PortTypes for the PortFacts reply.
+ *                      Added six new events along with their EventData
+ *                      structures.
+ *                      Added a new MsgFlag to the FwDownload request to
+ *                      indicate last segment.
+ *                      Defined a new image type of boot loader.
+ *                      Added FW family codes for SAS product families.
+ *  10-05-04  01.05.02  Added ReplyFifoHostSignalingAddr field to
+ *                      MSG_IOC_FACTS_REPLY.
+ *  12-07-04  01.05.03  Added more defines for SAS Discovery Error event.
+ *  12-09-04  01.05.04  Added Unsupported device to SAS Device event.
+ *  01-15-05  01.05.05  Added event data for SAS SES Event.
+ *  02-09-05  01.05.06  Added MPI_FW_UPLOAD_ITYPE_FW_BACKUP define.
+ *  02-22-05  01.05.07  Added Host Page Buffer Persistent flag to IOC Facts
+ *                      Reply and IOC Init Request.
+ *  03-11-05  01.05.08  Added family code for 1068E family.
+ *                      Removed IOCFacts Reply EEDP Capability bit.
  *  --------------------------------------------------------------------------
 
 mpi_cnfg.h
@@ -142,6 +220,166 @@ mpi_cnfg.h
  *                      Added IO Unit Page 3.
  *                      Modified defines for Scsi Port Page 2.
  *                      Modified RAID Volume Pages.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      Added SepID and SepBus to RVP2 IMPhysicalDisk struct.
+ *                      Added defines for the SEP bits in RVP2 VolumeSettings.
+ *                      Modified the DeviceSettings field in RVP2 to use the
+ *                      proper structure.
+ *                      Added defines for SES, SAF-TE, and cross channel for
+ *                      IOCPage2 CapabilitiesFlags.
+ *                      Removed define for MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE.
+ *                      Removed define for
+ *                      MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE.
+ *                      Added define for MPI_CONFIG_PAGEATTR_RO_PERSISTENT.
+ *  08-29-01 01.02.02   Fixed value for MPI_MANUFACTPAGE_DEVID_53C1035.
+ *                      Added defines for MPI_FCPORTPAGE1_FLAGS_HARD_ALPA_ONLY
+ *                      and MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY.
+ *                      Removed MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS,
+ *                      MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS, and
+ *                      MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS, and
+ *                      MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED.
+ *                      Added defines for MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED
+ *                      and MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED.
+ *                      Added OnBusTimerValue to CONFIG_PAGE_SCSI_PORT_1.
+ *                      Added rejected bits to SCSI Device Page 0 Information.
+ *                      Increased size of ALPA array in FC Port Page 2 by one
+ *                      and removed a one byte reserved field.
+ *  09-28-01 01.02.03   Swapped NegWireSpeedLow and NegWireSpeedLow in
+ *                      CONFIG_PAGE_LAN_1 to match preferred 64-bit ordering.
+ *                      Added structures for Manufacturing Page 4, IO Unit
+ *                      Page 3, IOC Page 3, IOC Page 4, RAID Volume Page 0, and
+ *                      RAID PhysDisk Page 0.
+ *  10-04-01 01.02.04   Added define for MPI_CONFIG_PAGETYPE_RAID_PHYSDISK.
+ *                      Modified some of the new defines to make them 32
+ *                      character unique.
+ *                      Modified how variable length pages (arrays) are defined.
+ *                      Added generic defines for hot spare pools and RAID
+ *                      volume types.
+ *  11-01-01 01.02.05   Added define for MPI_IOUNITPAGE1_DISABLE_IR.
+ *  03-14-02 01.02.06   Added PCISlotNum field to CONFIG_PAGE_IOC_1 along with
+ *                      related define, and bumped the page version define.
+ *  05-31-02 01.02.07   Added a Flags field to CONFIG_PAGE_IOC_2_RAID_VOL in a
+ *                      reserved byte and added a define.
+ *                      Added define for
+ *                      MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE.
+ *                      Added new config page: CONFIG_PAGE_IOC_5.
+ *                      Added MaxAliases, MaxHardAliases, and NumCurrentAliases
+ *                      fields to CONFIG_PAGE_FC_PORT_0.
+ *                      Added AltConnector and NumRequestedAliases fields to
+ *                      CONFIG_PAGE_FC_PORT_1.
+ *                      Added new config page: CONFIG_PAGE_FC_PORT_10.
+ *  07-12-02 01.02.08   Added more MPI_MANUFACTPAGE_DEVID_ defines.
+ *                      Added additional MPI_SCSIDEVPAGE0_NP_ defines.
+ *                      Added more MPI_SCSIDEVPAGE1_RP_ defines.
+ *                      Added define for
+ *                      MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE.
+ *                      Added new config page: CONFIG_PAGE_SCSI_DEVICE_3.
+ *                      Modified MPI_FCPORTPAGE5_FLAGS_ defines.
+ *  09-16-02 01.02.09   Added MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define.
+ *  11-15-02 01.02.10   Added ConnectedID defines for CONFIG_PAGE_SCSI_PORT_0.
+ *                      Added more Flags defines for CONFIG_PAGE_FC_PORT_1.
+ *                      Added more Flags defines for CONFIG_PAGE_FC_DEVICE_0.
+ *  04-01-03 01.02.11   Added RR_TOV field and additional Flags defines for
+ *                      CONFIG_PAGE_FC_PORT_1.
+ *                      Added define MPI_FCPORTPAGE5_FLAGS_DISABLE to disable
+ *                      an alias.
+ *                      Added more device id defines.
+ *  06-26-03 01.02.12   Added MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID define.
+ *                      Added TargetConfig and IDConfig fields to
+ *                      CONFIG_PAGE_SCSI_PORT_1.
+ *                      Added more PortFlags defines for CONFIG_PAGE_SCSI_PORT_2
+ *                      to control DV.
+ *                      Added more Flags defines for CONFIG_PAGE_FC_PORT_1.
+ *                      In CONFIG_PAGE_FC_DEVICE_0, replaced Reserved1 field
+ *                      with ADISCHardALPA.
+ *                      Added MPI_FC_DEVICE_PAGE0_PROT_FCP_RETRY define.
+ *  01-16-04  01.02.13  Added InitiatorDeviceTimeout and InitiatorIoPendTimeout
+ *                      fields and related defines to CONFIG_PAGE_FC_PORT_1.
+ *                      Added define for
+ *                      MPI_FCPORTPAGE1_FLAGS_SOFT_ALPA_FALLBACK.
+ *                      Added new fields to the substructures of
+ *                      CONFIG_PAGE_FC_PORT_10.
+ *  04-29-04 01.02.14   Added define for IDP bit for CONFIG_PAGE_SCSI_PORT_0,
+ *                      CONFIG_PAGE_SCSI_DEVICE_0, and
+ *                      CONFIG_PAGE_SCSI_DEVICE_1. Also bumped Page Version for
+ *                      these pages.
+ *  05-11-04 01.03.01   Added structure for CONFIG_PAGE_INBAND_0.
+ *  08-19-04 01.05.01   Modified MSG_CONFIG request to support extended config
+ *                      pages.
+ *                      Added a new structure for extended config page header.
+ *                      Added new extended config pages types and structures for
+ *                      SAS IO Unit, SAS Expander, SAS Device, and SAS PHY.
+ *                      Replaced a reserved byte in CONFIG_PAGE_MANUFACTURING_4
+ *                      to add a Flags field.
+ *                      Two new Manufacturing config pages (5 and 6).
+ *                      Two new bits defined for IO Unit Page 1 Flags field.
+ *                      Modified CONFIG_PAGE_IO_UNIT_2 to add three new fields
+ *                      to specify the BIOS boot device.
+ *                      Four new Flags bits defined for IO Unit Page 2.
+ *                      Added IO Unit Page 4.
+ *                      Added EEDP Flags settings to IOC Page 1.
+ *                      Added new BIOS Page 1 config page.
+ *  10-05-04 01.05.02   Added define for
+ *                      MPI_IOCPAGE1_INITIATOR_CONTEXT_REPLY_DISABLE.
+ *                      Added new Flags field to CONFIG_PAGE_MANUFACTURING_5 and
+ *                      associated defines.
+ *                      Added more defines for SAS IO Unit Page 0
+ *                      DiscoveryStatus field.
+ *                      Added define for MPI_SAS_IOUNIT0_DS_SUBTRACTIVE_LINK
+ *                      and MPI_SAS_IOUNIT0_DS_TABLE_LINK.
+ *                      Added defines for Physical Mapping Modes to SAS IO Unit
+ *                      Page 2.
+ *                      Added define for
+ *                      MPI_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH.
+ *  10-27-04 01.05.03   Added defines for new SAS PHY page addressing mode.
+ *                      Added defines for MaxTargetSpinUp to BIOS Page 1.
+ *                      Added 5 new ControlFlags defines for SAS IO Unit
+ *                      Page 1.
+ *                      Added MaxNumPhysicalMappedIDs field to SAS IO Unit
+ *                      Page 2.
+ *                      Added AccessStatus field to SAS Device Page 0 and added
+ *                      new Flags bits for supported SATA features.
+ *  12-07-04  01.05.04  Added config page structures for BIOS Page 2, RAID
+ *                      Volume Page 1, and RAID Physical Disk Page 1.
+ *                      Replaced IO Unit Page 1 BootTargetID,BootBus, and
+ *                      BootAdapterNum with reserved field.
+ *                      Added DataScrubRate and ResyncRate to RAID Volume
+ *                      Page 0.
+ *                      Added MPI_SAS_IOUNIT2_FLAGS_RESERVE_ID_0_FOR_BOOT
+ *                      define.
+ *  12-09-04  01.05.05  Added Target Mode Large CDB Enable to FC Port Page 1
+ *                      Flags field.
+ *                      Added Auto Port Config flag define for SAS IOUNIT
+ *                      Page 1 ControlFlags.
+ *                      Added Disabled bad Phy define to Expander Page 1
+ *                      Discovery Info field.
+ *                      Added SAS/SATA device support to SAS IOUnit Page 1
+ *                      ControlFlags.
+ *                      Added Unsupported device to SAS Dev Page 0 Flags field
+ *                      Added disable use SATA Hash Address for SAS IOUNIT
+ *                      page 1 in ControlFields.
+ *  01-15-05  01.05.06  Added defaults for data scrub rate and resync rate to
+ *                      Manufacturing Page 4.
+ *                      Added new defines for BIOS Page 1 IOCSettings field.
+ *                      Added ExtDiskIdentifier field to RAID Physical Disk
+ *                      Page 0.
+ *                      Added new defines for SAS IO Unit Page 1 ControlFlags
+ *                      and to SAS Device Page 0 Flags to control SATA devices.
+ *                      Added defines and structures for the new Log Page 0, a
+ *                      new type of configuration page.
+ *  02-09-05  01.05.07  Added InactiveStatus field to RAID Volume Page 0.
+ *                      Added WWID field to RAID Volume Page 1.
+ *                      Added PhysicalPort field to SAS Expander pages 0 and 1.
+ *  03-11-05  01.05.08  Removed the EEDP flags from IOC Page 1.
+ *                      Added Enclosure/Slot boot device format to BIOS Page 2.
+ *                      New status value for RAID Volume Page 0 VolumeStatus
+ *                      (VolumeState subfield).
+ *                      New value for RAID Physical Page 0 InactiveStatus.
+ *                      Added Inactive Volume Member flag RAID Physical Disk
+ *                      Page 0 PhysDiskStatus field.
+ *                      New physical mapping mode in SAS IO Unit Page 2.
+ *                      Added CONFIG_PAGE_SAS_ENCLOSURE_0.
+ *                      Added Slot and Enclosure fields to SAS Device Page 0.
  *  --------------------------------------------------------------------------
 
 mpi_init.h
@@ -154,6 +392,32 @@ mpi_init.h
  *  02-20-01  01.01.03  Started using MPI_POINTER.
  *  03-27-01  01.01.04  Added structure offset comments.
  *  04-10-01  01.01.05  Added new MsgFlag for MSG_SCSI_TASK_MGMT.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  08-29-01  01.02.02  Added MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET.
+ *                      Added MPI_SCSI_STATE_QUEUE_TAG_REJECTED for
+ *                      MSG_SCSI_IO_REPLY.
+ *  09-28-01  01.02.03  Added structures and defines for SCSI Enclosure
+ *                      Processor messages.
+ *  10-04-01  01.02.04  Added defines for SEP request Action field.
+ *  05-31-02  01.02.05  Added MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR define
+ *                      for SCSI IO requests.
+ *  11-15-02  01.02.06  Added special extended SCSI Status defines for FCP.
+ *  06-26-03  01.02.07  Added MPI_SCSI_STATUS_FCPEXT_UNASSIGNED define.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Added MsgFlags defines for EEDP to SCSI IO request.
+ *                      Added new word to MSG_SCSI_IO_REPLY to add TaskTag field
+ *                      and a reserved U16.
+ *                      Added new MSG_SCSI_IO32_REQUEST structure.
+ *                      Added a TaskType of Clear Task Set to SCSI
+ *                      Task Management request.
+ *  12-07-04  01.05.02  Added support for Task Management Query Task.
+ *  01-15-05  01.05.03  Modified SCSI Enclosure Processor Request to support
+ *                      WWID addressing.
+ *  03-11-05  01.05.04  Removed EEDP flags from SCSI IO Request.
+ *                      Removed SCSI IO 32 Request.
+ *                      Modified SCSI Enclosure Processor Request and Reply to
+ *                      support Enclosure/Slot addressing rather than WWID
+ *                      addressing.
  *  --------------------------------------------------------------------------
 
 mpi_targ.h
@@ -170,6 +434,33 @@ mpi_targ.h
  *                      Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
  *                      MPI_TARGET_FCP_CMD_BUFFER.
  *  03-27-01  01.01.04  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Added structure for MPI_TARGET_SCSI_SPI_STATUS_IU.
+ *                      Added PriorityReason field to some replies and
+ *                      defined more PriorityReason codes.
+ *                      Added some defines for to support previous version
+ *                      of MPI.
+ *  10-04-01  01.02.03  Added PriorityReason to MSG_TARGET_ERROR_REPLY.
+ *  11-01-01  01.02.04  Added define for TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY.
+ *  03-14-02  01.02.05  Modified MPI_TARGET_FCP_RSP_BUFFER to get the proper
+ *                      byte ordering.
+ *  05-31-02  01.02.06  Modified TARGET_MODE_REPLY_ALIAS_MASK to only include
+ *                      one bit.
+ *                      Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER.
+ *  09-16-02  01.02.07  Added flags for confirmed completion.
+ *                      Added PRIORITY_REASON_TARGET_BUSY.
+ *  11-15-02  01.02.08  Added AliasID field to MPI_TARGET_SCSI_SPI_CMD_BUFFER.
+ *  04-01-03  01.02.09  Added OptionalOxid field to MPI_TARGET_FCP_CMD_BUFFER.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Added new request message structures for
+ *                      MSG_TARGET_CMD_BUF_POST_BASE_REQUEST,
+ *                      MSG_TARGET_CMD_BUF_POST_LIST_REQUEST, and
+ *                      MSG_TARGET_ASSIST_EXT_REQUEST.
+ *                      Added new structures for SAS SSP Command buffer, SSP
+ *                      Task buffer, and SSP Status IU.
+ *  10-05-04  01.05.02  MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY added.
+ *  02-22-05  01.05.03  Changed a comment.
+ *  03-11-05  01.05.04  Removed TargetAssistExtended Request.
  *  --------------------------------------------------------------------------
 
 mpi_fc.h
@@ -192,6 +483,13 @@ mpi_fc.h
  *                      Added MPI_FC_PRIM_SEND_FLAGS_RESET_LINK define.
  *                      Added structure offset comments.
  *  04-09-01  01.01.07  Added RspLength field to MSG_LINK_SERVICE_RSP_REQUEST.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Change name of reserved field in
+ *                      MSG_LINK_SERVICE_RSP_REPLY.
+ *  05-31-02  01.02.03  Adding AliasIndex to FC Direct Access requests.
+ *  01-16-04  01.02.04  Added define for MPI_FC_PRIM_SEND_FLAGS_ML_RESET_LINK.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
  *  --------------------------------------------------------------------------
 
 mpi_lan.h
@@ -209,11 +507,56 @@ mpi_lan.h
  *  11-02-00  01.01.01  Original release for post 1.0 work
  *  02-20-01  01.01.02  Started using MPI_POINTER.
  *  03-27-01  01.01.03  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
  *  --------------------------------------------------------------------------
 
 mpi_raid.h
  *  02-27-01  01.01.01  Original release for this file.
  *  03-27-01  01.01.02  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  08-29-01  01.02.02  Added DIAG_DATA_UPLOAD_HEADER and related defines.
+ *  09-28-01  01.02.02  Major rework for MPI v1.2 Integrated RAID changes.
+ *  10-04-01  01.02.03  Added ActionData defines for
+ *                      MPI_RAID_ACTION_DELETE_VOLUME action.
+ *  11-01-01  01.02.04  Added define for MPI_RAID_ACTION_ADATA_DO_NOT_SYNC.
+ *  03-14-02  01.02.05  Added define for MPI_RAID_ACTION_ADATA_LOW_LEVEL_INIT.
+ *  05-07-02  01.02.06  Added define for MPI_RAID_ACTION_ACTIVATE_VOLUME,
+ *                      MPI_RAID_ACTION_INACTIVATE_VOLUME, and
+ *                      MPI_RAID_ACTION_ADATA_INACTIVATE_ALL.
+ *  07-12-02  01.02.07  Added structures for Mailbox request and reply.
+ *  11-15-02  01.02.08  Added missing MsgContext field to MSG_MAILBOX_REQUEST.
+ *  04-01-03  01.02.09  New action data option flag for
+ *                      MPI_RAID_ACTION_DELETE_VOLUME.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
+ *  01-15-05  01.05.02  Added defines for the two new RAID Actions for
+ *                      _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
+ *  --------------------------------------------------------------------------
+
+mpi_tool.h
+ *  08-08-01  01.02.01  Original release.
+ *  08-29-01  01.02.02  Added DIAG_DATA_UPLOAD_HEADER and related defines.
+ *  01-16-04  01.02.03  Added defines and structures for new tools
+ *.                     MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL and
+ *                      MPI_TOOLBOX_FC_MANAGEMENT_TOOL.
+ *  04-29-04  01.02.04  Added message structures for Diagnostic Buffer Post and
+ *                      Diagnostic Release requests and replies.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
+ *  10-06-04  01.05.02  Added define for MPI_DIAG_BUF_TYPE_COUNT.
+ *  02-09-05  01.05.03  Added frame size option to FC management tool.
+ *                      Added Beacon tool to the Toolbox.
+ *  --------------------------------------------------------------------------
+
+mpi_inb.h
+ *  05-11-04  01.03.01  Original release.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
+ *  --------------------------------------------------------------------------
+
+mpi_sas.h
+ *  08-19-04  01.05.01  Original release.
  *  --------------------------------------------------------------------------
 
 mpi_type.h
@@ -221,21 +564,83 @@ mpi_type.h
  *  06-06-00  01.00.01  Update version number for 1.0 release.
  *  11-02-00  01.01.01  Original release for post 1.0 work
  *  02-20-01  01.01.02  Added define and ifdef for MPI_POINTER.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
  *  --------------------------------------------------------------------------
 
 mpi_history.txt         Parts list history
 
-Filename    01.01.10
+Filename    01.05.09
 ----------  --------
-mpi.h       01.01.07
-mpi_ioc.h   01.01.07
-mpi_cnfg.h  01.01.11
-mpi_init.h  01.01.05
-mpi_targ.h  01.01.04
-mpi_fc.h    01.01.07
-mpi_lan.h   01.01.03
-mpi_raid.h  01.01.02
-mpi_type.h  01.01.02
+mpi.h       01.05.07
+mpi_ioc.h   01.05.08
+mpi_cnfg.h  01.05.08
+mpi_init.h  01.05.04
+mpi_targ.h  01.05.04
+mpi_fc.h    01.05.01
+mpi_lan.h   01.05.01
+mpi_raid.h  01.05.02
+mpi_tool.h  01.05.03
+mpi_inb.h   01.05.01
+mpi_sas.h   01.05.01
+mpi_type.h  01.05.01
+
+Filename    01.05.08   01.05.07   01.05.06   01.05.05   01.05.04   01.05.03
+----------  --------   --------   --------   --------   --------   --------
+mpi.h       01.05.06   01.05.05   01.05.04   01.05.03   01.05.02   01.05.01
+mpi_ioc.h   01.05.07   01.05.06   01.05.05   01.05.04   01.05.03   01.05.02
+mpi_cnfg.h  01.05.07   01.05.07   01.05.06   01.05.05   01.05.04   01.05.03
+mpi_init.h  01.05.03   01.05.03   01.05.03   01.05.02   01.05.02   01.05.01
+mpi_targ.h  01.05.03   01.05.02   01.05.02   01.05.02   01.05.02   01.05.02
+mpi_fc.h    01.05.01   01.05.01   01.05.01   01.05.01   01.05.01   01.05.01
+mpi_lan.h   01.05.01   01.05.01   01.05.01   01.05.01   01.05.01   01.05.01
+mpi_raid.h  01.05.02   01.05.02   01.05.02   01.05.01   01.05.01   01.05.01
+mpi_tool.h  01.05.03   01.05.03   01.05.02   01.05.02   01.05.02   01.05.02
+mpi_inb.h   01.05.01   01.05.01   01.05.01   01.05.01   01.05.01   01.05.01
+mpi_sas.h   01.05.01   01.05.01   01.05.01   01.05.01   01.05.01   01.05.01
+mpi_type.h  01.05.01   01.05.01   01.05.01   01.05.01   01.05.01   01.05.01
+
+Filename    01.05.02   01.05.01   01.03.01   01.02.14   01.02.13   01.02.12
+----------  --------   --------   --------   --------   --------   --------
+mpi.h       01.05.01   01.05.01   01.03.01   01.02.12   01.02.11   01.02.10
+mpi_ioc.h   01.05.02   01.05.01   01.03.01   01.02.09   01.02.08   01.02.08
+mpi_cnfg.h  01.05.02   01.05.01   01.03.01   01.02.14   01.02.13   01.02.12
+mpi_init.h  01.05.01   01.05.01   01.03.01   01.02.07   01.02.07   01.02.07
+mpi_targ.h  01.05.02   01.05.01   01.03.01   01.02.09   01.02.09   01.02.09
+mpi_fc.h    01.05.01   01.05.01   01.03.01   01.02.04   01.02.04   01.02.03
+mpi_lan.h   01.05.01   01.05.01   01.03.01   01.02.01   01.02.01   01.02.01
+mpi_raid.h  01.05.01   01.05.01   01.03.01   01.02.09   01.02.09   01.02.09
+mpi_tool.h  01.05.02   01.05.01   01.03.01   01.02.01   01.02.01   01.02.01
+mpi_inb.h   01.05.01   01.05.01   01.03.01
+mpi_sas.h   01.05.01   01.05.01
+mpi_type.h  01.05.01   01.05.01   01.03.01   01.02.04   01.02.03   01.02.02
+
+Filename    01.02.11   01.02.10   01.02.09   01.02.08   01.02.07   01.02.06
+----------  --------   --------   --------   --------   --------   --------
+mpi.h       01.02.09   01.02.08   01.02.07   01.02.06   01.02.05   01.02.04
+mpi_ioc.h   01.02.07   01.02.06   01.02.06   01.02.06   01.02.06   01.02.05
+mpi_cnfg.h  01.02.11   01.02.10   01.02.09   01.02.08   01.02.07   01.02.06
+mpi_init.h  01.02.06   01.02.06   01.02.05   01.02.05   01.02.05   01.02.04
+mpi_targ.h  01.02.09   01.02.08   01.02.07   01.02.06   01.02.06   01.02.05
+mpi_fc.h    01.02.03   01.02.03   01.02.03   01.02.03   01.02.03   01.02.02
+mpi_lan.h   01.02.01   01.02.01   01.02.01   01.02.01   01.02.01   01.02.01
+mpi_raid.h  01.02.09   01.02.08   01.02.07   01.02.07   01.02.06   01.02.05
+mpi_tool.h  01.02.01   01.02.01   01.02.01   01.02.01   01.02.01   01.02.01
+mpi_type.h  01.02.02   01.02.02   01.02.02   01.02.02   01.02.02   01.02.02
+
+Filename    01.02.05   01.02.04   01.02.03   01.02.02   01.02.01   01.01.10
+----------  --------   --------   --------   --------   --------   --------
+mpi.h       01.02.03   01.02.02   01.02.02   01.02.01   01.02.01   01.01.07
+mpi_ioc.h   01.02.04   01.02.03   01.02.03   01.02.02   01.02.01   01.01.07
+mpi_cnfg.h  01.02.05   01.02.04   01.02.03   01.02.02   01.02.01   01.01.11
+mpi_init.h  01.02.04   01.02.04   01.02.03   01.02.02   01.02.01   01.01.05
+mpi_targ.h  01.02.04   01.02.03   01.02.02   01.02.01   01.02.01   01.01.04
+mpi_fc.h    01.02.02   01.02.02   01.02.02   01.02.01   01.02.01   01.01.07
+mpi_lan.h   01.02.01   01.02.01   01.02.01   01.02.01   01.02.01   01.01.03
+mpi_raid.h  01.02.04   01.02.03   01.02.02   01.02.01   01.02.01   01.01.02
+mpi_tool.h  01.02.02   01.02.02   01.02.02   01.02.02   01.02.01
+mpi_type.h  01.02.02   01.02.02   01.02.02   01.02.02   01.02.01   01.01.02
 
 Filename    01.01.09   01.01.08   01.01.07   01.01.06   01.01.05   01.01.04
 ----------  --------   --------   --------   --------   --------   --------

+ 4 - 3
drivers/message/fusion/lsi/mpi_inb.h

@@ -1,19 +1,20 @@
 /*
- *  Copyright (c) 2003 LSI Logic Corporation.
+ *  Copyright (c) 2003-2004 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_inb.h
  *          Title:  MPI Inband structures and definitions
  *  Creation Date:  September 30, 2003
  *
- *    mpi_inb.h Version:  01.03.xx
+ *    mpi_inb.h Version:  01.05.01
  *
  *  Version History
  *  ---------------
  *
  *  Date      Version   Description
  *  --------  --------  ------------------------------------------------------
- *  ??-??-??  01.03.01  Original release.
+ *  05-11-04  01.03.01  Original release.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
  *  --------------------------------------------------------------------------
  */
 

+ 47 - 41
drivers/message/fusion/lsi/mpi_init.h

@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2003 LSI Logic Corporation.
+ *  Copyright (c) 2000-2005 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_init.h
  *          Title:  MPI initiator mode messages and structures
  *  Creation Date:  June 8, 2000
  *
- *    mpi_init.h Version:  01.05.xx
+ *    mpi_init.h Version:  01.05.04
  *
  *  Version History
  *  ---------------
@@ -33,6 +33,21 @@
  *                      for SCSI IO requests.
  *  11-15-02  01.02.06  Added special extended SCSI Status defines for FCP.
  *  06-26-03  01.02.07  Added MPI_SCSI_STATUS_FCPEXT_UNASSIGNED define.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Added MsgFlags defines for EEDP to SCSI IO request.
+ *                      Added new word to MSG_SCSI_IO_REPLY to add TaskTag field
+ *                      and a reserved U16.
+ *                      Added new MSG_SCSI_IO32_REQUEST structure.
+ *                      Added a TaskType of Clear Task Set to SCSI
+ *                      Task Management request.
+ *  12-07-04  01.05.02  Added support for Task Management Query Task.
+ *  01-15-05  01.05.03  Modified SCSI Enclosure Processor Request to support
+ *                      WWID addressing.
+ *  03-11-05  01.05.04  Removed EEDP flags from SCSI IO Request.
+ *                      Removed SCSI IO 32 Request.
+ *                      Modified SCSI Enclosure Processor Request and Reply to
+ *                      support Enclosure/Slot addressing rather than WWID
+ *                      addressing.
  *  --------------------------------------------------------------------------
  */
 
@@ -76,20 +91,12 @@ typedef struct _MSG_SCSI_IO_REQUEST
 #define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH              (0x01)
 #define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32           (0x00)
 #define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64           (0x01)
+
 #define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION           (0x02)
 #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST           (0x00)
 #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC            (0x02)
-#define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR  (0x04)
-#define MPI_SCSIIO_MSGFLGS_EEDP_TYPE_MASK           (0xE0)
-#define MPI_SCSIIO_MSGFLGS_EEDP_NONE                (0x00)
-#define MPI_SCSIIO_MSGFLGS_EEDP_RDPROTECT_T10       (0x20)
-#define MPI_SCSIIO_MSGFLGS_EEDP_VRPROTECT_T10       (0x40)
-#define MPI_SCSIIO_MSGFLGS_EEDP_WRPROTECT_T10       (0x60)
-#define MPI_SCSIIO_MSGFLGS_EEDP_520_READ_MODE1      (0x20)
-#define MPI_SCSIIO_MSGFLGS_EEDP_520_WRITE_MODE1     (0x40)
-#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_READ_MODE1      (0x60)
-#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_WRITE_MODE1     (0x80)
 
+#define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR  (0x04)
 
 /* SCSI IO LUN fields */
 
@@ -148,6 +155,8 @@ typedef struct _MSG_SCSI_IO_REPLY
     U32                     TransferCount;      /* 14h */
     U32                     SenseCount;         /* 18h */
     U32                     ResponseInfo;       /* 1Ch */
+    U16                     TaskTag;            /* 20h */
+    U16                     Reserved1;          /* 22h */
 } MSG_SCSI_IO_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_REPLY,
   SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t;
 
@@ -190,32 +199,7 @@ typedef struct _MSG_SCSI_IO_REPLY
 #define MPI_SCSI_RSP_INFO_TASK_MGMT_FAILED      (0x05000000)
 #define MPI_SCSI_RSP_INFO_SPI_LQ_INVALID_TYPE   (0x06000000)
 
-
-/****************************************************************************/
-/*  SCSI IO 32 Request message structure                                    */
-/****************************************************************************/
-
-typedef struct _MSG_SCSI_IO32_REQUEST
-{
-    U8                      TargetID;           /* 00h */
-    U8                      Bus;                /* 01h */
-    U8                      ChainOffset;        /* 02h */
-    U8                      Function;           /* 03h */
-    U8                      CDBLength;          /* 04h */
-    U8                      SenseBufferLength;  /* 05h */
-    U8                      Reserved;           /* 06h */
-    U8                      MsgFlags;           /* 07h */
-    U32                     MsgContext;         /* 08h */
-    U8                      LUN[8];             /* 0Ch */
-    U32                     Control;            /* 14h */
-    U8                      CDB[32];            /* 18h */
-    U32                     DataLength;         /* 38h */
-    U32                     SenseBufferLowAddr; /* 3Ch */
-    SGE_IO_UNION            SGL;                /* 40h */
-} MSG_SCSI_IO32_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO32_REQUEST,
-  SCSIIO32Request_t, MPI_POINTER pSCSIIO32Request_t;
-
-/* SCSI IO 32 uses the same defines as above for SCSI IO */
+#define MPI_SCSI_TASKTAG_UNKNOWN                (0xFFFF)
 
 
 /****************************************************************************/
@@ -247,6 +231,7 @@ typedef struct _MSG_SCSI_TASK_MGMT
 #define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS             (0x04)
 #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET    (0x05)
 #define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET        (0x06)
+#define MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK            (0x07)
 
 /* MsgFlags bits */
 #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION   (0x00)
@@ -260,7 +245,7 @@ typedef struct _MSG_SCSI_TASK_MGMT_REPLY
     U8                      Bus;                /* 01h */
     U8                      MsgLength;          /* 02h */
     U8                      Function;           /* 03h */
-    U8                      Reserved;           /* 04h */
+    U8                      ResponseCode;       /* 04h */
     U8                      TaskType;           /* 05h */
     U8                      Reserved1;          /* 06h */
     U8                      MsgFlags;           /* 07h */
@@ -272,6 +257,15 @@ typedef struct _MSG_SCSI_TASK_MGMT_REPLY
 } MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY,
   SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t;
 
+/* ResponseCode values */
+#define MPI_SCSITASKMGMT_RSP_TM_COMPLETE                (0x00)
+#define MPI_SCSITASKMGMT_RSP_INVALID_FRAME              (0x02)
+#define MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED           (0x04)
+#define MPI_SCSITASKMGMT_RSP_TM_FAILED                  (0x05)
+#define MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED               (0x08)
+#define MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN             (0x09)
+#define MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC           (0x80)
+
 
 /****************************************************************************/
 /*  SCSI Enclosure Processor messages                                       */
@@ -284,11 +278,16 @@ typedef struct _MSG_SEP_REQUEST
     U8                      ChainOffset;        /* 02h */
     U8                      Function;           /* 03h */
     U8                      Action;             /* 04h */
-    U8                      Reserved1;          /* 05h */
-    U8                      Reserved2;          /* 06h */
+    U8                      Flags;              /* 05h */
+    U8                      Reserved1;          /* 06h */
     U8                      MsgFlags;           /* 07h */
     U32                     MsgContext;         /* 08h */
     U32                     SlotStatus;         /* 0Ch */
+    U32                     Reserved2;          /* 10h */
+    U32                     Reserved3;          /* 14h */
+    U32                     Reserved4;          /* 18h */
+    U16                     Slot;               /* 1Ch */
+    U16                     EnclosureHandle;    /* 1Eh */
 } MSG_SEP_REQUEST, MPI_POINTER PTR_MSG_SEP_REQUEST,
   SEPRequest_t, MPI_POINTER pSEPRequest_t;
 
@@ -296,6 +295,10 @@ typedef struct _MSG_SEP_REQUEST
 #define MPI_SEP_REQ_ACTION_WRITE_STATUS                 (0x00)
 #define MPI_SEP_REQ_ACTION_READ_STATUS                  (0x01)
 
+/* Flags defines */
+#define MPI_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS        (0x01)
+#define MPI_SEP_REQ_FLAGS_BUS_TARGETID_ADDRESS          (0x00)
+
 /* SlotStatus bits for MSG_SEP_REQUEST */
 #define MPI_SEP_REQ_SLOTSTATUS_NO_ERROR                 (0x00000001)
 #define MPI_SEP_REQ_SLOTSTATUS_DEV_FAULTY               (0x00000002)
@@ -332,6 +335,9 @@ typedef struct _MSG_SEP_REPLY
     U16                     IOCStatus;          /* 0Eh */
     U32                     IOCLogInfo;         /* 10h */
     U32                     SlotStatus;         /* 14h */
+    U32                     Reserved4;          /* 18h */
+    U16                     Slot;               /* 1Ch */
+    U16                     EnclosureHandle;    /* 1Eh */
 } MSG_SEP_REPLY, MPI_POINTER PTR_MSG_SEP_REPLY,
   SEPReply_t, MPI_POINTER pSEPReply_t;
 

+ 183 - 63
drivers/message/fusion/lsi/mpi_ioc.h

@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2003 LSI Logic Corporation.
+ *  Copyright (c) 2000-2005 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_ioc.h
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    mpi_ioc.h Version:  01.05.xx
+ *    mpi_ioc.h Version:  01.05.08
  *
  *  Version History
  *  ---------------
@@ -57,6 +57,30 @@
  *                      Added AliasIndex to EVENT_DATA_LOGOUT structure.
  *  04-01-03  01.02.07  Added defines for MPI_FW_HEADER_SIGNATURE_.
  *  06-26-03  01.02.08  Added new values to the product family defines.
+ *  04-29-04  01.02.09  Added IOCCapabilities field to MSG_IOC_FACTS_REPLY and
+ *                      added related defines.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Added four new fields to MSG_IOC_INIT.
+ *                      Added three new fields to MSG_IOC_FACTS_REPLY.
+ *                      Defined four new bits for the IOCCapabilities field of
+ *                      the IOCFacts reply.
+ *                      Added two new PortTypes for the PortFacts reply.
+ *                      Added six new events along with their EventData
+ *                      structures.
+ *                      Added a new MsgFlag to the FwDownload request to
+ *                      indicate last segment.
+ *                      Defined a new image type of boot loader.
+ *                      Added FW family codes for SAS product families.
+ *  10-05-04  01.05.02  Added ReplyFifoHostSignalingAddr field to
+ *                      MSG_IOC_FACTS_REPLY.
+ *  12-07-04  01.05.03  Added more defines for SAS Discovery Error event.
+ *  12-09-04  01.05.04  Added Unsupported device to SAS Device event.
+ *  01-15-05  01.05.05  Added event data for SAS SES Event.
+ *  02-09-05  01.05.06  Added MPI_FW_UPLOAD_ITYPE_FW_BACKUP define.
+ *  02-22-05  01.05.07  Added Host Page Buffer Persistent flag to IOC Facts
+ *                      Reply and IOC Init Request.
+ *  03-11-05  01.05.08  Added family code for 1068E family.
+ *                      Removed IOCFacts Reply EEDP Capability bit.
  *  --------------------------------------------------------------------------
  */
 
@@ -90,20 +114,37 @@ typedef struct _MSG_IOC_INIT
     U32                     HostMfaHighAddr;            /* 10h */
     U32                     SenseBufferHighAddr;        /* 14h */
     U32                     ReplyFifoHostSignalingAddr; /* 18h */
+    SGE_SIMPLE_UNION        HostPageBufferSGE;          /* 1Ch */
+    U16                     MsgVersion;                 /* 28h */
+    U16                     HeaderVersion;              /* 2Ah */
 } MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT,
   IOCInit_t, MPI_POINTER pIOCInit_t;
 
 /* WhoInit values */
-#define MPI_WHOINIT_NO_ONE                          (0x00)
-#define MPI_WHOINIT_SYSTEM_BIOS                     (0x01)
-#define MPI_WHOINIT_ROM_BIOS                        (0x02)
-#define MPI_WHOINIT_PCI_PEER                        (0x03)
-#define MPI_WHOINIT_HOST_DRIVER                     (0x04)
-#define MPI_WHOINIT_MANUFACTURER                    (0x05)
+#define MPI_WHOINIT_NO_ONE                              (0x00)
+#define MPI_WHOINIT_SYSTEM_BIOS                         (0x01)
+#define MPI_WHOINIT_ROM_BIOS                            (0x02)
+#define MPI_WHOINIT_PCI_PEER                            (0x03)
+#define MPI_WHOINIT_HOST_DRIVER                         (0x04)
+#define MPI_WHOINIT_MANUFACTURER                        (0x05)
 
 /* Flags values */
-#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE          (0x01)
-#define MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL    (0x02)
+#define MPI_IOCINIT_FLAGS_HOST_PAGE_BUFFER_PERSISTENT   (0x04)
+#define MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL        (0x02)
+#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE              (0x01)
+
+/* MsgVersion */
+#define MPI_IOCINIT_MSGVERSION_MAJOR_MASK               (0xFF00)
+#define MPI_IOCINIT_MSGVERSION_MAJOR_SHIFT              (8)
+#define MPI_IOCINIT_MSGVERSION_MINOR_MASK               (0x00FF)
+#define MPI_IOCINIT_MSGVERSION_MINOR_SHIFT              (0)
+
+/* HeaderVersion */
+#define MPI_IOCINIT_HEADERVERSION_UNIT_MASK             (0xFF00)
+#define MPI_IOCINIT_HEADERVERSION_UNIT_SHIFT            (8)
+#define MPI_IOCINIT_HEADERVERSION_DEV_MASK              (0x00FF)
+#define MPI_IOCINIT_HEADERVERSION_DEV_SHIFT             (0)
+
 
 typedef struct _MSG_IOC_INIT_REPLY
 {
@@ -187,32 +228,39 @@ typedef struct _MSG_IOC_FACTS_REPLY
     MPI_FW_VERSION          FWVersion;                  /* 38h */
     U16                     HighPriorityQueueDepth;     /* 3Ch */
     U16                     Reserved2;                  /* 3Eh */
+    SGE_SIMPLE_UNION        HostPageBufferSGE;          /* 40h */
+    U32                     ReplyFifoHostSignalingAddr; /* 4Ch */
 } MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY,
   IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t;
 
-#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK          (0xFF00)
-#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK          (0x00FF)
+#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK              (0xFF00)
+#define MPI_IOCFACTS_MSGVERSION_MAJOR_SHIFT             (8)
+#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK              (0x00FF)
+#define MPI_IOCFACTS_MSGVERSION_MINOR_SHIFT             (0)
 
-#define MPI_IOCFACTS_HEADERVERSION_UNIT_MASK        (0xFF00)
-#define MPI_IOCFACTS_HEADERVERSION_DEV_MASK         (0x00FF)
+#define MPI_IOCFACTS_HDRVERSION_UNIT_MASK               (0xFF00)
+#define MPI_IOCFACTS_HDRVERSION_UNIT_SHIFT              (8)
+#define MPI_IOCFACTS_HDRVERSION_DEV_MASK                (0x00FF)
+#define MPI_IOCFACTS_HDRVERSION_DEV_SHIFT               (0)
 
-#define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL    (0x0001)
-#define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID     (0x0002)
-#define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL        (0x0004)
-#define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL   (0x0008)
+#define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL        (0x0001)
+#define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID         (0x0002)
+#define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL            (0x0004)
+#define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL       (0x0008)
 
-#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT         (0x01)
+#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT             (0x01)
+#define MPI_IOCFACTS_FLAGS_REPLY_FIFO_HOST_SIGNAL       (0x02)
+#define MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT  (0x04)
 
-#define MPI_IOCFACTS_EVENTSTATE_DISABLED            (0x00)
-#define MPI_IOCFACTS_EVENTSTATE_ENABLED             (0x01)
+#define MPI_IOCFACTS_EVENTSTATE_DISABLED                (0x00)
+#define MPI_IOCFACTS_EVENTSTATE_ENABLED                 (0x01)
 
-#define MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q          (0x00000001)
-#define MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL   (0x00000002)
-#define MPI_IOCFACTS_CAPABILITY_QUEUE_FULL_HANDLING (0x00000004)
-#define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER   (0x00000008)
-#define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER     (0x00000010)
-#define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER     (0x00000020)
-#define MPI_IOCFACTS_CAPABILITY_EEDP                (0x00000040)
+#define MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q              (0x00000001)
+#define MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL       (0x00000002)
+#define MPI_IOCFACTS_CAPABILITY_QUEUE_FULL_HANDLING     (0x00000004)
+#define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER       (0x00000008)
+#define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER         (0x00000010)
+#define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER         (0x00000020)
 
 
 
@@ -408,6 +456,8 @@ typedef struct _MSG_EVENT_ACK_REPLY
 #define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE  (0x0000000F)
 #define MPI_EVENT_SAS_SES                   (0x00000010)
 #define MPI_EVENT_PERSISTENT_TABLE_FULL     (0x00000011)
+#define MPI_EVENT_SAS_PHY_LINK_STATUS       (0x00000012)
+#define MPI_EVENT_SAS_DISCOVERY_ERROR       (0x00000013)
 
 /* AckRequired field values */
 
@@ -467,6 +517,10 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
     U8                      ASCQ;                       /* 05h */
     U16                     DevHandle;                  /* 06h */
     U32                     DeviceInfo;                 /* 08h */
+    U16                     ParentDevHandle;            /* 0Ch */
+    U8                      PhyNum;                     /* 0Eh */
+    U8                      Reserved1;                  /* 0Fh */
+    U64                     SASAddress;                 /* 10h */
 } EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
   MPI_POINTER PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
   MpiEventDataSasDeviceStatusChange_t,
@@ -477,6 +531,8 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
 #define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING        (0x04)
 #define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA            (0x05)
 #define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED      (0x06)
+#define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED           (0x07)
+
 
 /* SCSI Event data for Queue Full event */
 
@@ -488,6 +544,35 @@ typedef struct _EVENT_DATA_QUEUE_FULL
 } EVENT_DATA_QUEUE_FULL, MPI_POINTER PTR_EVENT_DATA_QUEUE_FULL,
   EventDataQueueFull_t, MPI_POINTER pEventDataQueueFull_t;
 
+/* MPI Integrated RAID Event data */
+
+typedef struct _EVENT_DATA_RAID
+{
+    U8                      VolumeID;                   /* 00h */
+    U8                      VolumeBus;                  /* 01h */
+    U8                      ReasonCode;                 /* 02h */
+    U8                      PhysDiskNum;                /* 03h */
+    U8                      ASC;                        /* 04h */
+    U8                      ASCQ;                       /* 05h */
+    U16                     Reserved;                   /* 06h */
+    U32                     SettingsStatus;             /* 08h */
+} EVENT_DATA_RAID, MPI_POINTER PTR_EVENT_DATA_RAID,
+  MpiEventDataRaid_t, MPI_POINTER pMpiEventDataRaid_t;
+
+/* MPI Integrated RAID Event data ReasonCode values */
+#define MPI_EVENT_RAID_RC_VOLUME_CREATED                (0x00)
+#define MPI_EVENT_RAID_RC_VOLUME_DELETED                (0x01)
+#define MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED       (0x02)
+#define MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED         (0x03)
+#define MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED       (0x04)
+#define MPI_EVENT_RAID_RC_PHYSDISK_CREATED              (0x05)
+#define MPI_EVENT_RAID_RC_PHYSDISK_DELETED              (0x06)
+#define MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED     (0x07)
+#define MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED       (0x08)
+#define MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED             (0x09)
+#define MPI_EVENT_RAID_RC_SMART_DATA                    (0x0A)
+#define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED        (0x0B)
+
 /* MPI Link Status Change Event data */
 
 typedef struct _EVENT_DATA_LINK_STATUS
@@ -535,35 +620,63 @@ typedef struct _EVENT_DATA_LOGOUT
 
 #define MPI_EVENT_LOGOUT_ALL_ALIASES        (0xFF)
 
+/* SAS SES Event data */
 
-/* MPI Integrated RAID Event data */
-
-typedef struct _EVENT_DATA_RAID
+typedef struct _EVENT_DATA_SAS_SES
 {
-    U8                      VolumeID;                   /* 00h */
-    U8                      VolumeBus;                  /* 01h */
-    U8                      ReasonCode;                 /* 02h */
-    U8                      PhysDiskNum;                /* 03h */
-    U8                      ASC;                        /* 04h */
-    U8                      ASCQ;                       /* 05h */
-    U16                     Reserved;                   /* 06h */
-    U32                     SettingsStatus;             /* 08h */
-} EVENT_DATA_RAID, MPI_POINTER PTR_EVENT_DATA_RAID,
-  MpiEventDataRaid_t, MPI_POINTER pMpiEventDataRaid_t;
+    U8                      PhyNum;                     /* 00h */
+    U8                      Port;                       /* 01h */
+    U8                      PortWidth;                  /* 02h */
+    U8                      Reserved1;                  /* 04h */
+} EVENT_DATA_SAS_SES, MPI_POINTER PTR_EVENT_DATA_SAS_SES,
+  MpiEventDataSasSes_t, MPI_POINTER pMpiEventDataSasSes_t;
 
-/* MPI Integrated RAID Event data ReasonCode values */
-#define MPI_EVENT_RAID_RC_VOLUME_CREATED                (0x00)
-#define MPI_EVENT_RAID_RC_VOLUME_DELETED                (0x01)
-#define MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED       (0x02)
-#define MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED         (0x03)
-#define MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED       (0x04)
-#define MPI_EVENT_RAID_RC_PHYSDISK_CREATED              (0x05)
-#define MPI_EVENT_RAID_RC_PHYSDISK_DELETED              (0x06)
-#define MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED     (0x07)
-#define MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED       (0x08)
-#define MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED             (0x09)
-#define MPI_EVENT_RAID_RC_SMART_DATA                    (0x0A)
-#define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED        (0x0B)
+/* SAS Phy Link Status Event data */
+
+typedef struct _EVENT_DATA_SAS_PHY_LINK_STATUS
+{
+    U8                      PhyNum;                     /* 00h */
+    U8                      LinkRates;                  /* 01h */
+    U16                     DevHandle;                  /* 02h */
+    U64                     SASAddress;                 /* 04h */
+} EVENT_DATA_SAS_PHY_LINK_STATUS, MPI_POINTER PTR_EVENT_DATA_SAS_PHY_LINK_STATUS,
+  MpiEventDataSasPhyLinkStatus_t, MPI_POINTER pMpiEventDataSasPhyLinkStatus_t;
+
+/* defines for the LinkRates field of the SAS PHY Link Status event */
+#define MPI_EVENT_SAS_PLS_LR_CURRENT_MASK                   (0xF0)
+#define MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT                  (4)
+#define MPI_EVENT_SAS_PLS_LR_PREVIOUS_MASK                  (0x0F)
+#define MPI_EVENT_SAS_PLS_LR_PREVIOUS_SHIFT                 (0)
+#define MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN                   (0x00)
+#define MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED              (0x01)
+#define MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION  (0x02)
+#define MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE         (0x03)
+#define MPI_EVENT_SAS_PLS_LR_RATE_1_5                       (0x08)
+#define MPI_EVENT_SAS_PLS_LR_RATE_3_0                       (0x09)
+
+/* SAS Discovery Errror Event data */
+
+typedef struct _EVENT_DATA_DISCOVERY_ERROR
+{
+    U32                     DiscoveryStatus;            /* 00h */
+    U8                      Port;                       /* 04h */
+    U8                      Reserved1;                  /* 05h */
+    U16                     Reserved2;                  /* 06h */
+} EVENT_DATA_DISCOVERY_ERROR, MPI_POINTER PTR_EVENT_DATA_DISCOVERY_ERROR,
+  EventDataDiscoveryError_t, MPI_POINTER pEventDataDiscoveryError_t;
+
+#define MPI_EVENT_DSCVRY_ERR_DS_LOOP_DETECTED               (0x00000001)
+#define MPI_EVENT_DSCVRY_ERR_DS_UNADDRESSABLE_DEVICE        (0x00000002)
+#define MPI_EVENT_DSCVRY_ERR_DS_MULTIPLE_PORTS              (0x00000004)
+#define MPI_EVENT_DSCVRY_ERR_DS_EXPANDER_ERR                (0x00000008)
+#define MPI_EVENT_DSCVRY_ERR_DS_SMP_TIMEOUT                 (0x00000010)
+#define MPI_EVENT_DSCVRY_ERR_DS_OUT_ROUTE_ENTRIES           (0x00000020)
+#define MPI_EVENT_DSCVRY_ERR_DS_INDEX_NOT_EXIST             (0x00000040)
+#define MPI_EVENT_DSCVRY_ERR_DS_SMP_FUNCTION_FAILED         (0x00000080)
+#define MPI_EVENT_DSCVRY_ERR_DS_SMP_CRC_ERROR               (0x00000100)
+#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_SUBTRACTIVE          (0x00000200)
+#define MPI_EVENT_DSCVRY_ERR_DS_TABLE_TO_TABLE              (0x00000400)
+#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS                (0x00000800)
 
 
 /*****************************************************************************
@@ -589,11 +702,13 @@ typedef struct _MSG_FW_DOWNLOAD
 } MSG_FW_DOWNLOAD, MPI_POINTER PTR_MSG_FW_DOWNLOAD,
   FWDownload_t, MPI_POINTER pFWDownload_t;
 
-#define MPI_FW_DOWNLOAD_ITYPE_RESERVED      (0x00)
-#define MPI_FW_DOWNLOAD_ITYPE_FW            (0x01)
-#define MPI_FW_DOWNLOAD_ITYPE_BIOS          (0x02)
-#define MPI_FW_DOWNLOAD_ITYPE_NVDATA        (0x03)
-#define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER    (0x04)
+#define MPI_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT    (0x01)
+
+#define MPI_FW_DOWNLOAD_ITYPE_RESERVED          (0x00)
+#define MPI_FW_DOWNLOAD_ITYPE_FW                (0x01)
+#define MPI_FW_DOWNLOAD_ITYPE_BIOS              (0x02)
+#define MPI_FW_DOWNLOAD_ITYPE_NVDATA            (0x03)
+#define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER        (0x04)
 
 
 typedef struct _FWDownloadTCSGE
@@ -647,6 +762,7 @@ typedef struct _MSG_FW_UPLOAD
 #define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH      (0x02)
 #define MPI_FW_UPLOAD_ITYPE_NVDATA          (0x03)
 #define MPI_FW_UPLOAD_ITYPE_BOOTLOADER      (0x04)
+#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP       (0x05)
 
 typedef struct _FWUploadTCSGE
 {
@@ -723,6 +839,7 @@ typedef struct _MPI_FW_HEADER
 #define MPI_FW_HEADER_PID_PROD_IM_SCSI                  (0x0400)
 #define MPI_FW_HEADER_PID_PROD_IS_SCSI                  (0x0500)
 #define MPI_FW_HEADER_PID_PROD_CTX_SCSI                 (0x0600)
+#define MPI_FW_HEADER_PID_PROD_IR_SCSI                  (0x0700)
 
 #define MPI_FW_HEADER_PID_FAMILY_MASK           (0x00FF)
 /* SCSI */
@@ -740,13 +857,16 @@ typedef struct _MPI_FW_HEADER
 #define MPI_FW_HEADER_PID_FAMILY_1020TA0_SCSI   (0x000C)
 /* Fibre Channel */
 #define MPI_FW_HEADER_PID_FAMILY_909_FC         (0x0000)
-#define MPI_FW_HEADER_PID_FAMILY_919_FC         (0x0001)
-#define MPI_FW_HEADER_PID_FAMILY_919X_FC        (0x0002)
-#define MPI_FW_HEADER_PID_FAMILY_919XL_FC       (0x0003)
-#define MPI_FW_HEADER_PID_FAMILY_949_FC         (0x0004)
+#define MPI_FW_HEADER_PID_FAMILY_919_FC         (0x0001) /* 919 and 929     */
+#define MPI_FW_HEADER_PID_FAMILY_919X_FC        (0x0002) /* 919X and 929X   */
+#define MPI_FW_HEADER_PID_FAMILY_919XL_FC       (0x0003) /* 919XL and 929XL */
+#define MPI_FW_HEADER_PID_FAMILY_939X_FC        (0x0004) /* 939X and 949X   */
 #define MPI_FW_HEADER_PID_FAMILY_959_FC         (0x0005)
 /* SAS */
 #define MPI_FW_HEADER_PID_FAMILY_1064_SAS       (0x0001)
+#define MPI_FW_HEADER_PID_FAMILY_1068_SAS       (0x0002)
+#define MPI_FW_HEADER_PID_FAMILY_1078_SAS       (0x0003)
+#define MPI_FW_HEADER_PID_FAMILY_106xE_SAS      (0x0004) /* 1068E, 1066E, and 1064E */
 
 typedef struct _MPI_EXT_IMAGE_HEADER
 {

+ 4 - 2
drivers/message/fusion/lsi/mpi_lan.h

@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2003 LSI Logic Corporation.
+ *  Copyright (c) 2000-2004 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_lan.h
  *          Title:  MPI LAN messages and structures
  *  Creation Date:  June 30, 2000
  *
- *    mpi_lan.h Version:  01.05.xx
+ *    mpi_lan.h Version:  01.05.01
  *
  *  Version History
  *  ---------------
@@ -28,6 +28,8 @@
  *  02-20-01  01.01.02  Started using MPI_POINTER.
  *  03-27-01  01.01.03  Added structure offset comments.
  *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
  *  --------------------------------------------------------------------------
  */
 

+ 15 - 2
drivers/message/fusion/lsi/mpi_raid.h

@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2001-2003 LSI Logic Corporation.
+ *  Copyright (c) 2001-2005 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_raid.h
  *          Title:  MPI RAID message and structures
  *  Creation Date:  February 27, 2001
  *
- *    mpi_raid.h Version:  01.05.xx
+ *    mpi_raid.h Version:  01.05.02
  *
  *  Version History
  *  ---------------
@@ -28,6 +28,10 @@
  *  11-15-02  01.02.08  Added missing MsgContext field to MSG_MAILBOX_REQUEST.
  *  04-01-03  01.02.09  New action data option flag for
  *                      MPI_RAID_ACTION_DELETE_VOLUME.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
+ *  01-15-05  01.05.02  Added defines for the two new RAID Actions for
+ *                      _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
  *  --------------------------------------------------------------------------
  */
 
@@ -84,6 +88,8 @@ typedef struct _MSG_RAID_ACTION
 #define MPI_RAID_ACTION_REPLACE_PHYSDISK            (0x10)
 #define MPI_RAID_ACTION_ACTIVATE_VOLUME             (0x11)
 #define MPI_RAID_ACTION_INACTIVATE_VOLUME           (0x12)
+#define MPI_RAID_ACTION_SET_RESYNC_RATE             (0x13)
+#define MPI_RAID_ACTION_SET_DATA_SCRUB_RATE         (0x14)
 
 /* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
 #define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC           (0x00000001)
@@ -99,6 +105,13 @@ typedef struct _MSG_RAID_ACTION
 /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */
 #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL        (0x00000001)
 
+/* ActionDataWord defines for use with MPI_RAID_ACTION_SET_RESYNC_RATE action */
+#define MPI_RAID_ACTION_ADATA_RESYNC_RATE_MASK      (0x000000FF)
+
+/* ActionDataWord defines for use with MPI_RAID_ACTION_SET_DATA_SCRUB_RATE action */
+#define MPI_RAID_ACTION_ADATA_DATA_SCRUB_RATE_MASK  (0x000000FF)
+
+
 
 /* RAID Action reply message */
 

+ 120 - 51
drivers/message/fusion/lsi/mpi_sas.h

@@ -1,25 +1,76 @@
 /*
- *  Copyright (c) 2003 LSI Logic Corporation.
+ *  Copyright (c) 2004 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_sas.h
  *          Title:  MPI Serial Attached SCSI structures and definitions
- *  Creation Date:  April 23, 2003
+ *  Creation Date:  August 19, 2004
  *
- *    mpi_sas.h Version:  01.05.xx
+ *    mpi_sas.h Version:  01.05.01
  *
  *  Version History
  *  ---------------
  *
  *  Date      Version   Description
  *  --------  --------  ------------------------------------------------------
- *  xx-yy-zz  01.05.01  Original release.
+ *  08-19-04  01.05.01  Original release.
  *  --------------------------------------------------------------------------
  */
 
 #ifndef MPI_SAS_H
 #define MPI_SAS_H
 
+
+/*
+ * Values for SASStatus.
+ */
+#define MPI_SASSTATUS_SUCCESS                           (0x00)
+#define MPI_SASSTATUS_UNKNOWN_ERROR                     (0x01)
+#define MPI_SASSTATUS_INVALID_FRAME                     (0x02)
+#define MPI_SASSTATUS_UTC_BAD_DEST                      (0x03)
+#define MPI_SASSTATUS_UTC_BREAK_RECEIVED                (0x04)
+#define MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED    (0x05)
+#define MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST            (0x06)
+#define MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED        (0x07)
+#define MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY            (0x08)
+#define MPI_SASSTATUS_UTC_WRONG_DESTINATION             (0x09)
+#define MPI_SASSTATUS_SHORT_INFORMATION_UNIT            (0x0A)
+#define MPI_SASSTATUS_LONG_INFORMATION_UNIT             (0x0B)
+#define MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA     (0x0C)
+#define MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR     (0x0D)
+#define MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED             (0x0E)
+#define MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH        (0x0F)
+#define MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA           (0x10)
+#define MPI_SASSTATUS_DATA_OFFSET_ERROR                 (0x11)
+#define MPI_SASSTATUS_SDSF_NAK_RECEIVED                 (0x12)
+#define MPI_SASSTATUS_SDSF_CONNECTION_FAILED            (0x13)
+#define MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT        (0x14)
+
+
+/*
+ * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
+ * data and SAS IO Unit Configuration pages.
+ */
+#define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE        (0x00002000)
+#define MPI_SAS_DEVICE_INFO_LSI_DEVICE          (0x00001000)
+#define MPI_SAS_DEVICE_INFO_DIRECT_ATTACH       (0x00000800)
+#define MPI_SAS_DEVICE_INFO_SSP_TARGET          (0x00000400)
+#define MPI_SAS_DEVICE_INFO_STP_TARGET          (0x00000200)
+#define MPI_SAS_DEVICE_INFO_SMP_TARGET          (0x00000100)
+#define MPI_SAS_DEVICE_INFO_SATA_DEVICE         (0x00000080)
+#define MPI_SAS_DEVICE_INFO_SSP_INITIATOR       (0x00000040)
+#define MPI_SAS_DEVICE_INFO_STP_INITIATOR       (0x00000020)
+#define MPI_SAS_DEVICE_INFO_SMP_INITIATOR       (0x00000010)
+#define MPI_SAS_DEVICE_INFO_SATA_HOST           (0x00000008)
+
+#define MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE    (0x00000007)
+#define MPI_SAS_DEVICE_INFO_NO_DEVICE           (0x00000000)
+#define MPI_SAS_DEVICE_INFO_END_DEVICE          (0x00000001)
+#define MPI_SAS_DEVICE_INFO_EDGE_EXPANDER       (0x00000002)
+#define MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER     (0x00000003)
+
+
+
 /*****************************************************************************
 *
 *        S e r i a l    A t t a c h e d    S C S I     M e s s a g e s
@@ -48,8 +99,10 @@ typedef struct _MSG_SMP_PASSTHROUGH_REQUEST
 } MSG_SMP_PASSTHROUGH_REQUEST, MPI_POINTER PTR_MSG_SMP_PASSTHROUGH_REQUEST,
   SmpPassthroughRequest_t, MPI_POINTER pSmpPassthroughRequest_t;
 
+/* values for PassthroughFlags field */
 #define MPI_SMP_PT_REQ_PT_FLAGS_IMMEDIATE       (0x80)
 
+/* values for ConnectionRate field */
 #define MPI_SMP_PT_REQ_CONNECT_RATE_NEGOTIATED  (0x00)
 #define MPI_SMP_PT_REQ_CONNECT_RATE_1_5         (0x08)
 #define MPI_SMP_PT_REQ_CONNECT_RATE_3_0         (0x09)
@@ -77,51 +130,69 @@ typedef struct _MSG_SMP_PASSTHROUGH_REPLY
 
 #define MPI_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE     (0x80)
 
-/* values for the SASStatus field */
-#define MPI_SASSTATUS_SUCCESS                           (0x00)
-#define MPI_SASSTATUS_UNKNOWN_ERROR                     (0x01)
-#define MPI_SASSTATUS_INVALID_FRAME                     (0x02)
-#define MPI_SASSTATUS_UTC_BAD_DEST                      (0x03)
-#define MPI_SASSTATUS_UTC_BREAK_RECEIVED                (0x04)
-#define MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED    (0x05)
-#define MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST            (0x06)
-#define MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED        (0x07)
-#define MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY            (0x08)
-#define MPI_SASSTATUS_UTC_WRONG_DESTINATION             (0x09)
-#define MPI_SASSTATUS_SHORT_INFORMATION_UNIT            (0x0A)
-#define MPI_SASSTATUS_LONG_INFORMATION_UNIT             (0x0B)
-#define MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA     (0x0C)
-#define MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR     (0x0D)
-#define MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED             (0x0E)
-#define MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH        (0x0F)
-#define MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA           (0x10)
-#define MPI_SASSTATUS_DATA_OFFSET_ERROR                 (0x11)
-#define MPI_SASSTATUS_SDSF_NAK_RECEIVED                 (0x12)
-#define MPI_SASSTATUS_SDSF_CONNECTION_FAILED            (0x13)
-#define MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT        (0x14)
 
+/****************************************************************************/
+/* SATA Passthrough Request                                                 */
+/****************************************************************************/
+
+typedef struct _MSG_SATA_PASSTHROUGH_REQUEST
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     PassthroughFlags;   /* 04h */
+    U8                      ConnectionRate;     /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Reserved1;          /* 0Ch */
+    U32                     Reserved2;          /* 10h */
+    U32                     Reserved3;          /* 14h */
+    U32                     DataLength;         /* 18h */
+    U8                      CommandFIS[20];     /* 1Ch */
+    SGE_SIMPLE_UNION        SGL;                /* 30h */
+} MSG_SATA_PASSTHROUGH_REQUEST, MPI_POINTER PTR_MSG_SATA_PASSTHROUGH_REQUEST,
+  SataPassthroughRequest_t, MPI_POINTER pSataPassthroughRequest_t;
+
+/* values for PassthroughFlags field */
+#define MPI_SATA_PT_REQ_PT_FLAGS_RESET_DEVICE   (0x0200)
+#define MPI_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG   (0x0100)
+#define MPI_SATA_PT_REQ_PT_FLAGS_DMA_QUEUED     (0x0080)
+#define MPI_SATA_PT_REQ_PT_FLAGS_PACKET_COMMAND (0x0040)
+#define MPI_SATA_PT_REQ_PT_FLAGS_DMA            (0x0020)
+#define MPI_SATA_PT_REQ_PT_FLAGS_PIO            (0x0010)
+#define MPI_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004)
+#define MPI_SATA_PT_REQ_PT_FLAGS_WRITE          (0x0002)
+#define MPI_SATA_PT_REQ_PT_FLAGS_READ           (0x0001)
+
+/* values for ConnectionRate field */
+#define MPI_SATA_PT_REQ_CONNECT_RATE_NEGOTIATED (0x00)
+#define MPI_SATA_PT_REQ_CONNECT_RATE_1_5        (0x08)
+#define MPI_SATA_PT_REQ_CONNECT_RATE_3_0        (0x09)
+
+
+/* SATA Passthrough Reply */
+typedef struct _MSG_SATA_PASSTHROUGH_REPLY
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     PassthroughFlags;   /* 04h */
+    U8                      Reserved1;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      Reserved2;          /* 0Ch */
+    U8                      SASStatus;          /* 0Dh */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U8                      StatusFIS[20];      /* 14h */
+    U32                     StatusControlRegisters; /* 28h */
+    U32                     TransferCount;      /* 2Ch */
+} MSG_SATA_PASSTHROUGH_REPLY, MPI_POINTER PTR_MSG_SATA_PASSTHROUGH_REPLY,
+  SataPassthroughReply_t, MPI_POINTER pSataPassthroughReply_t;
 
-/*
- * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
- * data and SAS IO Unit Configuration pages.
- */
-#define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE        (0x00002000)
-#define MPI_SAS_DEVICE_INFO_LSI_DEVICE          (0x00001000)
-#define MPI_SAS_DEVICE_INFO_DIRECT_ATTACH       (0x00000800)
-#define MPI_SAS_DEVICE_INFO_SSP_TARGET          (0x00000400)
-#define MPI_SAS_DEVICE_INFO_STP_TARGET          (0x00000200)
-#define MPI_SAS_DEVICE_INFO_SMP_TARGET          (0x00000100)
-#define MPI_SAS_DEVICE_INFO_SATA_DEVICE         (0x00000080)
-#define MPI_SAS_DEVICE_INFO_SSP_INITIATOR       (0x00000040)
-#define MPI_SAS_DEVICE_INFO_STP_INITIATOR       (0x00000020)
-#define MPI_SAS_DEVICE_INFO_SMP_INITIATOR       (0x00000010)
-#define MPI_SAS_DEVICE_INFO_SATA_HOST           (0x00000008)
 
-#define MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE    (0x00000007)
-#define MPI_SAS_DEVICE_INFO_NO_DEVICE           (0x00000000)
-#define MPI_SAS_DEVICE_INFO_END_DEVICE          (0x00000001)
-#define MPI_SAS_DEVICE_INFO_EDGE_EXPANDER       (0x00000002)
-#define MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER     (0x00000003)
 
 
 /****************************************************************************/
@@ -148,15 +219,13 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST
 } MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST,
   SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t;
 
-/* values for the ... field */
+/* values for the Operation field */
 #define MPI_SAS_OP_CLEAR_NOT_PRESENT             (0x01)
-#define MPI_SAS_OP_CLEAR_ALL                     (0x02)
-#define MPI_SAS_OP_MAP                           (0x03)
-#define MPI_SAS_OP_MOVE                          (0x04)
-#define MPI_SAS_OP_CLEAR                         (0x05)
+#define MPI_SAS_OP_CLEAR_ALL_PERSISTENT          (0x02)
 #define MPI_SAS_OP_PHY_LINK_RESET                (0x06)
 #define MPI_SAS_OP_PHY_HARD_RESET                (0x07)
 #define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG           (0x08)
+#define MPI_SAS_OP_MAP_CURRENT                   (0x09)
 
 
 /* SAS IO Unit Control Reply */

+ 151 - 9
drivers/message/fusion/lsi/mpi_targ.h

@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2003 LSI Logic Corporation.
+ *  Copyright (c) 2000-2004 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_targ.h
  *          Title:  MPI Target mode messages and structures
  *  Creation Date:  June 22, 2000
  *
- *    mpi_targ.h Version:  01.05.xx
+ *    mpi_targ.h Version:  01.05.04
  *
  *  Version History
  *  ---------------
@@ -43,6 +43,16 @@
  *                      Added PRIORITY_REASON_TARGET_BUSY.
  *  11-15-02  01.02.08  Added AliasID field to MPI_TARGET_SCSI_SPI_CMD_BUFFER.
  *  04-01-03  01.02.09  Added OptionalOxid field to MPI_TARGET_FCP_CMD_BUFFER.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Added new request message structures for
+ *                      MSG_TARGET_CMD_BUF_POST_BASE_REQUEST,
+ *                      MSG_TARGET_CMD_BUF_POST_LIST_REQUEST, and
+ *                      MSG_TARGET_ASSIST_EXT_REQUEST.
+ *                      Added new structures for SAS SSP Command buffer, SSP
+ *                      Task buffer, and SSP Status IU.
+ *  10-05-04  01.05.02  MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY added.
+ *  02-22-05  01.05.03  Changed a comment.
+ *  03-11-05  01.05.04  Removed TargetAssistExtended Request.
  *  --------------------------------------------------------------------------
  */
 
@@ -133,6 +143,25 @@ typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY
 } MSG_PRIORITY_CMD_RECEIVED_REPLY, MPI_POINTER PTR_MSG_PRIORITY_CMD_RECEIVED_REPLY,
   PriorityCommandReceivedReply_t, MPI_POINTER pPriorityCommandReceivedReply_t;
 
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY
+{
+    U16                     Reserved;                   /* 00h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U8                      PriorityReason;             /* 0Ch */
+    U8                      Reserved3;                  /* 0Dh */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+    U32                     ReplyWord;                  /* 14h */
+} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+  MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+  TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t;
+
 #define PRIORITY_REASON_NO_DISCONNECT           (0x00)
 #define PRIORITY_REASON_SCSI_TASK_MANAGEMENT    (0x01)
 #define PRIORITY_REASON_CMD_PARITY_ERR          (0x02)
@@ -146,7 +175,34 @@ typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY
 #define PRIORITY_REASON_UNKNOWN                 (0xFF)
 
 
-typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY
+/****************************************************************************/
+/* Target Command Buffer Post Base Request                                  */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_CMD_BUF_POST_BASE_REQUEST
+{
+    U8                      BufferPostFlags;            /* 00h */
+    U8                      PortNumber;                 /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     TotalCmdBuffers;            /* 04h */
+    U8                      Reserved;                   /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     Reserved1;                  /* 0Ch */
+    U16                     CmdBufferLength;            /* 10h */
+    U16                     NextCmdBufferOffset;        /* 12h */
+    U32                     BaseAddressLow;             /* 14h */
+    U32                     BaseAddressHigh;            /* 18h */
+} MSG_TARGET_CMD_BUF_POST_BASE_REQUEST,
+  MPI_POINTER PTR__MSG_TARGET_CMD_BUF_POST_BASE_REQUEST,
+  TargetCmdBufferPostBaseRequest_t,
+  MPI_POINTER pTargetCmdBufferPostBaseRequest_t;
+
+#define CMD_BUFFER_POST_BASE_FLAGS_AUTO_POST_ALL    (0x01)
+
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY
 {
     U16                     Reserved;                   /* 00h */
     U8                      MsgLength;                  /* 02h */
@@ -155,16 +211,41 @@ typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY
     U8                      Reserved2;                  /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
-    U8                      PriorityReason;             /* 0Ch */
-    U8                      Reserved3;                  /* 0Dh */
+    U16                     Reserved3;                  /* 0Ch */
     U16                     IOCStatus;                  /* 0Eh */
     U32                     IOCLogInfo;                 /* 10h */
-    U32                     ReplyWord;                  /* 14h */
-} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
-  MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
-  TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t;
+} MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY,
+  MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY,
+  TargetCmdBufferPostBaseListReply_t,
+  MPI_POINTER pTargetCmdBufferPostBaseListReply_t;
+
+
+/****************************************************************************/
+/* Target Command Buffer Post List Request                                  */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_CMD_BUF_POST_LIST_REQUEST
+{
+    U8                      Reserved;                   /* 00h */
+    U8                      PortNumber;                 /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     CmdBufferCount;             /* 04h */
+    U8                      Reserved1;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     Reserved2;                  /* 0Ch */
+    U16                     IoIndex[2];                 /* 10h */
+} MSG_TARGET_CMD_BUF_POST_LIST_REQUEST,
+  MPI_POINTER PTR_MSG_TARGET_CMD_BUF_POST_LIST_REQUEST,
+  TargetCmdBufferPostListRequest_t,
+  MPI_POINTER pTargetCmdBufferPostListRequest_t;
 
 
+/****************************************************************************/
+/* Command Buffer Formats (with 16 byte CDB)                                */
+/****************************************************************************/
+
 typedef struct _MPI_TARGET_FCP_CMD_BUFFER
 {
     U8      FcpLun[8];                                  /* 00h */
@@ -201,6 +282,46 @@ typedef struct _MPI_TARGET_SCSI_SPI_CMD_BUFFER
   MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer;
 
 
+typedef struct _MPI_TARGET_SSP_CMD_BUFFER
+{
+    U8      FrameType;                                  /* 00h */
+    U8      Reserved1;                                  /* 01h */
+    U16     Reserved2;                                  /* 02h */
+    U16     InitiatorTag;                               /* 04h */
+    U16     DevHandle;                                  /* 06h */
+    /* COMMAND information unit starts here */
+    U8      LogicalUnitNumber[8];                       /* 08h */
+    U8      Reserved3;                                  /* 10h */
+    U8      TaskAttribute; /* lower 3 bits */           /* 11h */
+    U8      Reserved4;                                  /* 12h */
+    U8      AdditionalCDBLength; /* upper 5 bits */     /* 13h */
+    U8      CDB[16];                                    /* 14h */
+    /* Additional CDB bytes extend past the CDB field */
+} MPI_TARGET_SSP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_SSP_CMD_BUFFER,
+  MpiTargetSspCmdBuffer, MPI_POINTER pMpiTargetSspCmdBuffer;
+
+typedef struct _MPI_TARGET_SSP_TASK_BUFFER
+{
+    U8      FrameType;                                  /* 00h */
+    U8      Reserved1;                                  /* 01h */
+    U16     Reserved2;                                  /* 02h */
+    U16     InitiatorTag;                               /* 04h */
+    U16     DevHandle;                                  /* 06h */
+    /* TASK information unit starts here */
+    U8      LogicalUnitNumber[8];                       /* 08h */
+    U8      Reserved3;                                  /* 10h */
+    U8      Reserved4;                                  /* 11h */
+    U8      TaskManagementFunction;                     /* 12h */
+    U8      Reserved5;                                  /* 13h */
+    U16     ManagedTaskTag;                             /* 14h */
+    U16     Reserved6;                                  /* 16h */
+    U32     Reserved7;                                  /* 18h */
+    U32     Reserved8;                                  /* 1Ch */
+    U32     Reserved9;                                  /* 20h */
+} MPI_TARGET_SSP_TASK_BUFFER, MPI_POINTER PTR_MPI_TARGET_SSP_TASK_BUFFER,
+  MpiTargetSspTaskBuffer, MPI_POINTER pMpiTargetSspTaskBuffer;
+
+
 /****************************************************************************/
 /* Target Assist Request                                                    */
 /****************************************************************************/
@@ -308,6 +429,27 @@ typedef struct _MPI_TARGET_SCSI_SPI_STATUS_IU
 } MPI_TARGET_SCSI_SPI_STATUS_IU, MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_STATUS_IU,
   TargetScsiSpiStatusIU_t, MPI_POINTER pTargetScsiSpiStatusIU_t;
 
+/*
+ * NOTE: The SSP status IU is big-endian. When used on a little-endian system,
+ * this structure properly orders the bytes.
+ */
+typedef struct _MPI_TARGET_SSP_RSP_IU
+{
+    U32     Reserved0[6]; /* reserved for SSP header */ /* 00h */
+    /* start of RESPONSE information unit */
+    U32     Reserved1;                                  /* 18h */
+    U32     Reserved2;                                  /* 1Ch */
+    U16     Reserved3;                                  /* 20h */
+    U8      DataPres; /* lower 2 bits */                /* 22h */
+    U8      Status;                                     /* 23h */
+    U32     Reserved4;                                  /* 24h */
+    U32     SenseDataLength;                            /* 28h */
+    U32     ResponseDataLength;                         /* 2Ch */
+    U8      ResponseSenseData[4];                       /* 30h */
+} MPI_TARGET_SSP_RSP_IU, MPI_POINTER PTR_MPI_TARGET_SSP_RSP_IU,
+  MpiTargetSspRspIu_t, MPI_POINTER pMpiTargetSspRspIu_t;
+
+
 /****************************************************************************/
 /* Target Mode Abort Request                                                */
 /****************************************************************************/

+ 53 - 4
drivers/message/fusion/lsi/mpi_tool.h

@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2001-2003 LSI Logic Corporation.
+ *  Copyright (c) 2001-2005 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_tool.h
  *          Title:  MPI Toolbox structures and definitions
  *  Creation Date:  July 30, 2001
  *
- *    mpi_tool.h Version:  01.05.xx
+ *    mpi_tool.h Version:  01.05.03
  *
  *  Version History
  *  ---------------
@@ -15,6 +15,16 @@
  *  --------  --------  ------------------------------------------------------
  *  08-08-01  01.02.01  Original release.
  *  08-29-01  01.02.02  Added DIAG_DATA_UPLOAD_HEADER and related defines.
+ *  01-16-04  01.02.03  Added defines and structures for new tools
+ *.                     MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL and
+ *                      MPI_TOOLBOX_FC_MANAGEMENT_TOOL.
+ *  04-29-04  01.02.04  Added message structures for Diagnostic Buffer Post and
+ *                      Diagnostic Release requests and replies.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
+ *  10-06-04  01.05.02  Added define for MPI_DIAG_BUF_TYPE_COUNT.
+ *  02-09-05  01.05.03  Added frame size option to FC management tool.
+ *                      Added Beacon tool to the Toolbox.
  *  --------------------------------------------------------------------------
  */
 
@@ -26,6 +36,7 @@
 #define MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL           (0x02)
 #define MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL           (0x03)
 #define MPI_TOOLBOX_FC_MANAGEMENT_TOOL              (0x04)
+#define MPI_TOOLBOX_BEACON_TOOL                     (0x05)
 
 
 /****************************************************************************/
@@ -185,11 +196,21 @@ typedef struct _MPI_TB_FC_MANAGE_PID_AI
 } MPI_TB_FC_MANAGE_PID_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_PID_AI,
   MpiTbFcManagePidAi_t, MPI_POINTER pMpiTbFcManagePidAi_t;
 
+/* ActionInfo for set max frame size */
+typedef struct _MPI_TB_FC_MANAGE_FRAME_SIZE_AI
+{
+    U16                     FrameSize;                  /* 00h */
+    U8                      PortNum;                    /* 02h */
+    U8                      Reserved1;                  /* 03h */
+} MPI_TB_FC_MANAGE_FRAME_SIZE_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_FRAME_SIZE_AI,
+  MpiTbFcManageFrameSizeAi_t, MPI_POINTER pMpiTbFcManageFrameSizeAi_t;
+
 /* union of ActionInfo */
 typedef union _MPI_TB_FC_MANAGE_AI_UNION
 {
     MPI_TB_FC_MANAGE_BUS_TID_AI     BusTid;
     MPI_TB_FC_MANAGE_PID_AI         Port;
+    MPI_TB_FC_MANAGE_FRAME_SIZE_AI  FrameSize;
 } MPI_TB_FC_MANAGE_AI_UNION, MPI_POINTER PTR_MPI_TB_FC_MANAGE_AI_UNION,
   MpiTbFcManageAiUnion_t, MPI_POINTER pMpiTbFcManageAiUnion_t;
 
@@ -214,6 +235,32 @@ typedef struct _MSG_TOOLBOX_FC_MANAGE_REQUEST
 #define MPI_TB_FC_MANAGE_ACTION_DISC_ALL            (0x00)
 #define MPI_TB_FC_MANAGE_ACTION_DISC_PID            (0x01)
 #define MPI_TB_FC_MANAGE_ACTION_DISC_BUS_TID        (0x02)
+#define MPI_TB_FC_MANAGE_ACTION_SET_MAX_FRAME_SIZE  (0x03)
+
+
+/****************************************************************************/
+/* Toolbox Beacon Tool request                                               */
+/****************************************************************************/
+
+typedef struct _MSG_TOOLBOX_BEACON_REQUEST
+{
+    U8                      Tool;                       /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U8                      ConnectNum;                 /* 0Ch */
+    U8                      PortNum;                    /* 0Dh */
+    U8                      Reserved3;                  /* 0Eh */
+    U8                      Flags;                      /* 0Fh */
+} MSG_TOOLBOX_BEACON_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_BEACON_REQUEST,
+  ToolboxBeaconRequest_t, MPI_POINTER pToolboxBeaconRequest_t;
+
+#define MPI_TOOLBOX_FLAGS_BEACON_MODE_OFF       (0x00)
+#define MPI_TOOLBOX_FLAGS_BEACON_MODE_ON        (0x01)
 
 
 /****************************************************************************/
@@ -233,14 +280,16 @@ typedef struct _MSG_DIAG_BUFFER_POST_REQUEST
     U32                     ExtendedType;               /* 0Ch */
     U32                     BufferLength;               /* 10h */
     U32                     ProductSpecific[4];         /* 14h */
-    U32                     Reserved3;                  /* 18h */
-    SGE_SIMPLE_UNION        SGL;                        /* 28h */
+    U32                     Reserved3;                  /* 24h */
+    U64                     BufferAddress;              /* 28h */
 } MSG_DIAG_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_DIAG_BUFFER_POST_REQUEST,
   DiagBufferPostRequest_t, MPI_POINTER pDiagBufferPostRequest_t;
 
 #define MPI_DIAG_BUF_TYPE_TRACE                     (0x00)
 #define MPI_DIAG_BUF_TYPE_SNAPSHOT                  (0x01)
 #define MPI_DIAG_BUF_TYPE_EXTENDED                  (0x02)
+/* count of the number of buffer types */
+#define MPI_DIAG_BUF_TYPE_COUNT                     (0x03)
 
 #define MPI_DIAG_EXTENDED_QTAG                      (0x00000001)
 

+ 4 - 7
drivers/message/fusion/lsi/mpi_type.h

@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2003 LSI Logic Corporation.
+ *  Copyright (c) 2000-2004 LSI Logic Corporation.
  *
  *
  *           Name:  mpi_type.h
  *          Title:  MPI Basic type definitions
  *  Creation Date:  June 6, 2000
  *
- *    mpi_type.h Version:  01.05.xx
+ *    mpi_type.h Version:  01.05.01
  *
  *  Version History
  *  ---------------
@@ -18,6 +18,8 @@
  *  11-02-00  01.01.01  Original release for post 1.0 work
  *  02-20-01  01.01.02  Added define and ifdef for MPI_POINTER.
  *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  05-11-04  01.03.01  Original release for MPI v1.3.
+ *  08-19-04  01.05.01  Original release for MPI v1.5.
  *  --------------------------------------------------------------------------
  */
 
@@ -50,11 +52,6 @@ typedef unsigned short  U16;
 typedef int32_t   S32;
 typedef u_int32_t U32;
 
-/*
- *  The only way crap below could work on big-endian boxen would be if it
- *  wasn't used at all.
- */
-
 typedef struct _S64
 {
     U32          Low;

+ 121 - 222
drivers/message/fusion/mptbase.c

@@ -1,55 +1,13 @@
 /*
  *  linux/drivers/message/fusion/mptbase.c
- *      High performance SCSI + LAN / Fibre Channel device drivers.
  *      This is the Fusion MPT base driver which supports multiple
  *      (SCSI + LAN) specialized protocol drivers.
- *      For use with PCI chip/adapter(s):
- *          LSIFC9xx/LSI409xx Fibre Channel
+ *      For use with LSI Logic PCI chip/adapter(s)
  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
  *
- *  Credits:
- *      There are lots of people not mentioned below that deserve credit
- *      and thanks but won't get it here - sorry in advance that you
- *      got overlooked.
- *
- *      This driver would not exist if not for Alan Cox's development
- *      of the linux i2o driver.
- *
- *      A special thanks to Noah Romer (LSI Logic) for tons of work
- *      and tough debugging on the LAN driver, especially early on;-)
- *      And to Roger Hickerson (LSI Logic) for tirelessly supporting
- *      this driver project.
- *
- *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
- *      and countless enhancements while adding support for the 1030
- *      chip family.  Pam has been instrumental in the development of
- *      of the 2.xx.xx series fusion drivers, and her contributions are
- *      far too numerous to hope to list in one place.
- *
- *      All manner of help from Stephen Shirron (LSI Logic):
- *      low-level FC analysis, debug + various fixes in FCxx firmware,
- *      initial port to alpha platform, various driver code optimizations,
- *      being a faithful sounding board on all sorts of issues & ideas,
- *      etc.
- *
- *      A huge debt of gratitude is owed to David S. Miller (DaveM)
- *      for fixing much of the stupid and broken stuff in the early
- *      driver while porting to sparc64 platform.  THANK YOU!
- *
- *      Special thanks goes to the I2O LAN driver people at the
- *      University of Helsinki, who, unbeknownst to them, provided
- *      the inspiration and initial structure for this driver.
- *
- *      A really huge debt of gratitude is owed to Eddie C. Dost
- *      for gobs of hard work fixing and optimizing LAN code.
- *      THANK YOU!
- *
- *  Copyright (c) 1999-2004 LSI Logic Corporation
- *  Originally By: Steven J. Ralston
- *  (mailto:sjralston1@netscape.net)
+ *  Copyright (c) 1999-2005 LSI Logic Corporation
  *  (mailto:mpt_linux_developer@lsil.com)
  *
- *  $Id: mptbase.c,v 1.126 2002/12/16 15:28:45 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -101,6 +59,7 @@
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>		/* needed for in_interrupt() proto */
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
@@ -218,41 +177,35 @@ static void	mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void	mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
 
 /* module entry point */
-static int  __devinit mptbase_probe (struct pci_dev *, const struct pci_device_id *);
-static void __devexit mptbase_remove(struct pci_dev *);
-static void mptbase_shutdown(struct device * );
 static int  __init    fusion_init  (void);
 static void __exit    fusion_exit  (void);
 
-/****************************************************************************
- * Supported hardware
- */
-
-static struct pci_device_id mptbase_pci_table[] = {
-	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC909,
-		PCI_ANY_ID, PCI_ANY_ID },
-	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929,
-		PCI_ANY_ID, PCI_ANY_ID },
-	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919,
-		PCI_ANY_ID, PCI_ANY_ID },
-	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929X,
-		PCI_ANY_ID, PCI_ANY_ID },
-	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919X,
-		PCI_ANY_ID, PCI_ANY_ID },
-	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1030,
-		PCI_ANY_ID, PCI_ANY_ID },
-	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_1030_53C1035,
-		PCI_ANY_ID, PCI_ANY_ID },
-	{0}	/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, mptbase_pci_table);
-
 #define CHIPREG_READ32(addr) 		readl_relaxed(addr)
 #define CHIPREG_READ32_dmasync(addr)	readl(addr)
 #define CHIPREG_WRITE32(addr,val) 	writel(val, addr)
 #define CHIPREG_PIO_WRITE32(addr,val)	outl(val, (unsigned long)addr)
 #define CHIPREG_PIO_READ32(addr) 	inl((unsigned long)addr)
 
+static void
+pci_disable_io_access(struct pci_dev *pdev)
+{
+	u16 command_reg;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
+	command_reg &= ~1;
+	pci_write_config_word(pdev, PCI_COMMAND, command_reg);
+}
+
+static void
+pci_enable_io_access(struct pci_dev *pdev)
+{
+	u16 command_reg;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
+	command_reg |= 1;
+	pci_write_config_word(pdev, PCI_COMMAND, command_reg);
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
@@ -330,8 +283,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
 					ioc->name, mr, req_idx));
 			DBG_DUMP_REPLY_FRAME(mr)
 
-			/* NEW!  20010301 -sralston
-			 *  Check/log IOC log info
+			/*  Check/log IOC log info
 			 */
 			ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
 			if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
@@ -357,9 +309,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
 				mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
 			} else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) {
 				cb_idx = mpt_lan_index;
-				/*
-				 * BUG FIX!  20001218 -sralston
-				 *  Blind set of mf to NULL here was fatal
+				 /*  Blind set of mf to NULL here was fatal
 				 *  after lan_reply says "freeme"
 				 *  Fix sort of combined with an optimization here;
 				 *  added explicit check for case where lan_reply
@@ -430,15 +380,8 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
 		}
 
 		if (freeme) {
-			unsigned long flags;
-
 			/*  Put Request back on FreeQ!  */
-			spin_lock_irqsave(&ioc->FreeQlock, flags);
-			list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
-#ifdef MFCNT
-			ioc->mfcnt--;
-#endif
-			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+			mpt_free_msg_frame(ioc, mf);
 		}
 
 		mb();
@@ -725,11 +668,9 @@ int
 mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
 {
 	MPT_ADAPTER	*ioc;
-	int 		error=0;
 
 	if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
-		error= -EINVAL;
-		return error;
+		return -EINVAL;
 	}
 
 	MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
@@ -737,14 +678,12 @@ mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
 	/* call per pci device probe entry point */
 	list_for_each_entry(ioc, &ioc_list, list) {
 		if(dd_cbfunc->probe) {
-			error = dd_cbfunc->probe(ioc->pcidev,
+			dd_cbfunc->probe(ioc->pcidev,
 			  ioc->pcidev->driver->id_table);
-			if(error != 0)
-				return error;
   		}
 	 }
 
-	return error;
+	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -809,8 +748,8 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
 		mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;	/* byte */
 		req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
 								/* u16! */
-		req_idx = cpu_to_le16(req_offset / ioc->req_sz);
-		mf->u.frame.hwhdr.msgctxu.fld.req_idx = req_idx;
+		req_idx = req_offset / ioc->req_sz;
+		mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
 		mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
 		ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
 #ifdef MFCNT
@@ -856,8 +795,8 @@ mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
 	mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;		/* byte */
 	req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
 								/* u16! */
-	req_idx = cpu_to_le16(req_offset / ioc->req_sz);
-	mf->u.frame.hwhdr.msgctxu.fld.req_idx = req_idx;
+	req_idx = req_offset / ioc->req_sz;
+	mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
 	mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
 
 #ifdef MPT_DEBUG_MSG_FRAME
@@ -1058,7 +997,7 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	mptbase_probe - Install a PCI intelligent MPT adapter.
+ *	mpt_attach - Install a PCI intelligent MPT adapter.
  *	@pdev: Pointer to pci_dev structure
  *
  *	This routine performs all the steps necessary to bring the IOC of
@@ -1073,8 +1012,8 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
  *
  *	TODO: Add support for polled controllers
  */
-static int __devinit
-mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+int
+mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	MPT_ADAPTER	*ioc;
 	u8		__iomem *mem;
@@ -1084,7 +1023,6 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	u32		 psize;
 	int		 ii;
 	int		 r = -ENODEV;
-	u64		 mask = 0xffffffffffffffffULL;
 	u8		 revision;
 	u8		 pcixcmd;
 	static int	 mpt_ids = 0;
@@ -1097,15 +1035,15 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	
 	dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
 	
-	if (!pci_set_dma_mask(pdev, mask)) {
+	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
 		dprintk((KERN_INFO MYNAM
 			": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
-	} else if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
+	} else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
 		printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
 		return r;
 	}
 
-	if (!pci_set_consistent_dma_mask(pdev, mask))
+	if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
 		dprintk((KERN_INFO MYNAM
 			": Using 64 bit consistent mask\n"));
 	else
@@ -1243,6 +1181,16 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		pcixcmd &= 0x8F;
 		pci_write_config_byte(pdev, 0x6a, pcixcmd);
 	}
+	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
+		ioc->prod_name = "LSIFC939X";
+		ioc->bus_type = FC;
+		ioc->errata_flag_1064 = 1;
+	}
+	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
+		ioc->prod_name = "LSIFC949X";
+		ioc->bus_type = FC;
+		ioc->errata_flag_1064 = 1;
+	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
 		ioc->prod_name = "LSI53C1030";
 		ioc->bus_type = SCSI;
@@ -1261,6 +1209,9 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		ioc->bus_type = SCSI;
 	}
 
+	if (ioc->errata_flag_1064)
+		pci_disable_io_access(pdev);
+
 	sprintf(ioc->name, "ioc%d", ioc->id);
 
 	spin_lock_init(&ioc->FreeQlock);
@@ -1303,8 +1254,7 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 #endif
 	}
 
-	/* NEW!  20010220 -sralston
-	 * Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
+	/* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
 	 */
 	mpt_detect_bound_ports(ioc, pdev);
 
@@ -1354,13 +1304,13 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	mptbase_remove - Remove a PCI intelligent MPT adapter.
+ *	mpt_detach - Remove a PCI intelligent MPT adapter.
  *	@pdev: Pointer to pci_dev structure
  *
  */
 
-static void __devexit
-mptbase_remove(struct pci_dev *pdev)
+void
+mpt_detach(struct pci_dev *pdev)
 {
 	MPT_ADAPTER 	*ioc = pci_get_drvdata(pdev);
 	char pname[32];
@@ -1397,43 +1347,21 @@ mptbase_remove(struct pci_dev *pdev)
 	pci_set_drvdata(pdev, NULL);
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *	mptbase_shutdown -
- *
- */
-static void
-mptbase_shutdown(struct device * dev)
-{
-	int ii;
-
-	/* call per device driver shutdown entry point */
-	for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
-		if(MptDeviceDriverHandlers[ii] &&
-		  MptDeviceDriverHandlers[ii]->shutdown) {
-			MptDeviceDriverHandlers[ii]->shutdown(dev);
-		}
-	}
-
-}
-
-
 /**************************************************************************
  * Power Management
  */
 #ifdef CONFIG_PM
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	mptbase_suspend - Fusion MPT base driver suspend routine.
+ *	mpt_suspend - Fusion MPT base driver suspend routine.
  *
  *
  */
-static int
-mptbase_suspend(struct pci_dev *pdev, pm_message_t state)
+int
+mpt_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	u32 device_state;
 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
-	int ii;
 
 	switch(state)
 	{
@@ -1453,14 +1381,6 @@ mptbase_suspend(struct pci_dev *pdev, pm_message_t state)
 	"pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
 		ioc->name, pdev, pci_name(pdev), device_state);
 
-	/* call per device driver suspend entry point */
-	for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
-		if(MptDeviceDriverHandlers[ii] &&
-		  MptDeviceDriverHandlers[ii]->suspend) {
-			MptDeviceDriverHandlers[ii]->suspend(pdev, state);
-		}
-	}
-
 	pci_save_state(pdev);
 
 	/* put ioc into READY_STATE */
@@ -1484,18 +1404,18 @@ mptbase_suspend(struct pci_dev *pdev, pm_message_t state)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	mptbase_resume - Fusion MPT base driver resume routine.
+ *	mpt_resume - Fusion MPT base driver resume routine.
  *
  *
  */
-static int
-mptbase_resume(struct pci_dev *pdev)
+int
+mpt_resume(struct pci_dev *pdev)
 {
 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
 	u32 device_state = pdev->current_state;
 	int recovery_state;
 	int ii;
-
+	
 	printk(MYIOC_s_INFO_FMT
 	"pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
 		ioc->name, pdev, pci_name(pdev), device_state);
@@ -1533,14 +1453,6 @@ mptbase_resume(struct pci_dev *pdev)
 			"pci-resume: success\n", ioc->name);
 	}
 
-	/* call per device driver resume entry point */
-	for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
-		if(MptDeviceDriverHandlers[ii] &&
-		  MptDeviceDriverHandlers[ii]->resume) {
-			MptDeviceDriverHandlers[ii]->resume(pdev);
-		}
-	}
-
 	return 0;
 }
 #endif
@@ -1719,8 +1631,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 		ioc->alt_ioc->active = 1;
 	}
 
-	/* NEW!  20010120 -sralston
-	 *  Enable MPT base driver management of EventNotification
+	/*  Enable MPT base driver management of EventNotification
 	 *  and EventAck handling.
 	 */
 	if ((ret == 0) && (!ioc->facts.EventState))
@@ -1729,9 +1640,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
 		(void) SendEventNotification(ioc->alt_ioc, 1);	/* 1=Enable EventNotification */
 
-	/* (Bugzilla:fibrebugs, #513)
-	 * Bug fix (part 2)!  20010905 -sralston
-	 *	Add additional "reason" check before call to GetLanConfigPages
+	/*	Add additional "reason" check before call to GetLanConfigPages
 	 *	(combined with GetIoUnitPage2 call).  This prevents a somewhat
 	 *	recursive scenario; GetLanConfigPages times out, timer expired
 	 *	routine calls HardResetHandler, which calls into here again,
@@ -1829,37 +1738,43 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 static void
 mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
 {
-	unsigned int match_lo, match_hi;
+	struct pci_dev *peer=NULL;
+	unsigned int slot = PCI_SLOT(pdev->devfn);
+	unsigned int func = PCI_FUNC(pdev->devfn);
 	MPT_ADAPTER *ioc_srch;
 
-	match_lo = pdev->devfn-1;
-	match_hi = pdev->devfn+1;
-	dprintk((MYIOC_s_INFO_FMT "PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
-			ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi));
+	dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
+	    " searching for devfn match on %x or %x\n",
+		ioc->name, pci_name(pdev), pdev->devfn,
+		func-1, func+1));
+
+	peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
+	if (!peer) {
+		peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
+		if (!peer)
+			return;
+	}
 
 	list_for_each_entry(ioc_srch, &ioc_list, list) {
 		struct pci_dev *_pcidev = ioc_srch->pcidev;
-
-		if ((_pcidev->device == pdev->device) &&
-		    (_pcidev->bus->number == pdev->bus->number) &&
-		    (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
+		if (_pcidev == peer) {
 			/* Paranoia checks */
 			if (ioc->alt_ioc != NULL) {
 				printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
-						ioc->name, ioc->alt_ioc->name);
+					ioc->name, ioc->alt_ioc->name);
 				break;
 			} else if (ioc_srch->alt_ioc != NULL) {
 				printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
-						ioc_srch->name, ioc_srch->alt_ioc->name);
+					ioc_srch->name, ioc_srch->alt_ioc->name);
 				break;
 			}
 			dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
-					ioc->name, ioc_srch->name));
+				ioc->name, ioc_srch->name));
 			ioc_srch->alt_ioc = ioc;
 			ioc->alt_ioc = ioc_srch;
-			break;
 		}
 	}
+	pci_dev_put(peer);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1922,15 +1837,10 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
 		ioc->alloc_total -= sz;
 	}
 
-	if (ioc->spi_data.nvram != NULL) {
-		kfree(ioc->spi_data.nvram);
-		ioc->spi_data.nvram = NULL;
-	}
-
-	if (ioc->spi_data.pIocPg3 != NULL) {
-		kfree(ioc->spi_data.pIocPg3);
-		ioc->spi_data.pIocPg3 = NULL;
-	}
+	kfree(ioc->spi_data.nvram);
+	kfree(ioc->spi_data.pIocPg3);
+	ioc->spi_data.nvram = NULL;
+	ioc->spi_data.pIocPg3 = NULL;
 
 	if (ioc->spi_data.pIocPg4 != NULL) {
 		sz = ioc->spi_data.IocPg4Sz;
@@ -1947,10 +1857,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
 		ioc->ReqToChain = NULL;
 	}
 
-	if (ioc->ChainToChain != NULL) {
-		kfree(ioc->ChainToChain);
-		ioc->ChainToChain = NULL;
-	}
+	kfree(ioc->ChainToChain);
+	ioc->ChainToChain = NULL;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2333,7 +2241,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
 			return -55;
 		}
 
-		r = sz = le32_to_cpu(facts->BlockSize);
+		r = sz = facts->BlockSize;
 		vv = ((63 / (sz * 4)) + 1) & 0x03;
 		ioc->NB_for_64_byte_frame = vv;
 		while ( sz )
@@ -2785,7 +2693,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
 	/* prevent a second downloadboot and memory free with alt_ioc */
 	if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
 		ioc->alt_ioc->cached_fw = NULL;
-	
+
 	CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
 	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
 	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
@@ -2843,6 +2751,9 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
 	/* Write the LoadStartAddress to the DiagRw Address Register
 	 * using Programmed IO
 	 */
+	if (ioc->errata_flag_1064)
+		pci_enable_io_access(ioc->pcidev);
+
 	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
 	ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
 		ioc->name, pFwHeader->LoadStartAddress));
@@ -2889,6 +2800,9 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
 	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
 	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
 
+	if (ioc->errata_flag_1064)
+		pci_disable_io_access(ioc->pcidev);
+
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 	ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off PREVENT_IOC_BOOT, DISABLE_ARM\n",
 		ioc->name, diag0val));
@@ -4250,7 +4164,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
 				if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
 					(ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE))  {
 
-					if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
+				if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
 						ioc->spi_data.minSyncFactor = MPT_ULTRA;
 				}
 			}
@@ -4482,10 +4396,8 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
 
 	/* Free the old page
 	 */
-	if (ioc->spi_data.pIocPg3) {
-		kfree(ioc->spi_data.pIocPg3);
-		ioc->spi_data.pIocPg3 = NULL;
-	}
+	kfree(ioc->spi_data.pIocPg3);
+	ioc->spi_data.pIocPg3 = NULL;
 
 	/* There is at least one physical disk.
 	 * Read and save IOC Page 3
@@ -4753,9 +4665,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
 	u32		 flagsLength;
 	int		 in_isr;
 
-	/* (Bugzilla:fibrebugs, #513)
-	 * Bug fix (part 1)!  20010905 -sralston
-	 *	Prevent calling wait_event() (below), if caller happens
+	/*	Prevent calling wait_event() (below), if caller happens
 	 *	to be in ISR context, because that is fatal!
 	 */
 	in_isr = in_interrupt();
@@ -4861,9 +4771,7 @@ mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
 	u32		 flagsLength;
 	int		 in_isr;
 
-	/* (Bugzilla:fibrebugs, #513)
-	 * Bug fix (part 1)!  20010905 -sralston
-	 *	Prevent calling wait_event() (below), if caller happens
+	/*	Prevent calling wait_event() (below), if caller happens
 	 *	to be in ISR context, because that is fatal!
 	 */
 	in_isr = in_interrupt();
@@ -5130,20 +5038,26 @@ static int
 procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
 {
 	int	 ii;
-	int	 scsi, lan, ctl, targ, dmp;
+	int	 scsi, fc, sas, lan, ctl, targ, dmp;
 	char	*drvname;
 	int	 len;
 
 	len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
 	len += sprintf(buf+len, "  Fusion MPT base driver\n");
 
-	scsi = lan = ctl = targ = dmp = 0;
+	scsi = fc = sas = lan = ctl = targ = dmp = 0;
 	for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
 		drvname = NULL;
 		if (MptCallbacks[ii]) {
 			switch (MptDriverClass[ii]) {
-			case MPTSCSIH_DRIVER:
-				if (!scsi++) drvname = "SCSI host";
+			case MPTSPI_DRIVER:
+				if (!scsi++) drvname = "SPI host";
+				break;
+			case MPTFC_DRIVER:
+				if (!fc++) drvname = "FC host";
+				break;
+			case MPTSAS_DRIVER:
+				if (!sas++) drvname = "SAS host";
 				break;
 			case MPTLAN_DRIVER:
 				if (!lan++) drvname = "LAN";
@@ -5832,6 +5746,12 @@ mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+EXPORT_SYMBOL(mpt_attach);
+EXPORT_SYMBOL(mpt_detach);
+#ifdef CONFIG_PM
+EXPORT_SYMBOL(mpt_resume);
+EXPORT_SYMBOL(mpt_suspend);
+#endif
 EXPORT_SYMBOL(ioc_list);
 EXPORT_SYMBOL(mpt_proc_root_dir);
 EXPORT_SYMBOL(mpt_register);
@@ -5860,19 +5780,6 @@ EXPORT_SYMBOL(mpt_read_ioc_pg_3);
 EXPORT_SYMBOL(mpt_alloc_fw_memory);
 EXPORT_SYMBOL(mpt_free_fw_memory);
 
-static struct pci_driver mptbase_driver = {
-	.name		= "mptbase",
-	.id_table	= mptbase_pci_table,
-	.probe		= mptbase_probe,
-	.remove		= __devexit_p(mptbase_remove),
-	.driver         = {
-		.shutdown = mptbase_shutdown,
-        },
-#ifdef CONFIG_PM
-	.suspend	= mptbase_suspend,
-	.resume		= mptbase_resume,
-#endif
-};
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -5884,7 +5791,6 @@ static int __init
 fusion_init(void)
 {
 	int i;
-	int r;
 
 	show_mptmod_ver(my_NAME, my_VERSION);
 	printk(KERN_INFO COPYRIGHT "\n");
@@ -5896,8 +5802,7 @@ fusion_init(void)
 		MptResetHandlers[i] = NULL;
 	}
 
-	/* NEW!  20010120 -sralston
-	 *  Register ourselves (mptbase) in order to facilitate
+	/*  Register ourselves (mptbase) in order to facilitate
 	 *  EventNotification handling.
 	 */
 	mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
@@ -5913,11 +5818,7 @@ fusion_init(void)
 #ifdef CONFIG_PROC_FS
 	(void) procmpt_create();
 #endif
-	r = pci_register_driver(&mptbase_driver);
-	if(r)
-		return(r);
-
-	return r;
+	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5933,7 +5834,6 @@ fusion_exit(void)
 
 	dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
 
-	pci_unregister_driver(&mptbase_driver);
 	mpt_reset_deregister(mpt_base_index);
 
 #ifdef CONFIG_PROC_FS
@@ -5941,6 +5841,5 @@ fusion_exit(void)
 #endif
 }
 
-
 module_init(fusion_init);
 module_exit(fusion_exit);

+ 29 - 23
drivers/message/fusion/mptbase.h

@@ -5,15 +5,9 @@
  *          LSIFC9xx/LSI409xx Fibre Channel
  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
  *
- *  Credits:
- *     (see mptbase.c)
- *
- *  Copyright (c) 1999-2004 LSI Logic Corporation
- *  Originally By: Steven J. Ralston
- *  (mailto:sjralston1@netscape.net)
+ *  Copyright (c) 1999-2005 LSI Logic Corporation
  *  (mailto:mpt_linux_developer@lsil.com)
  *
- *  $Id: mptbase.h,v 1.144 2003/01/28 21:31:56 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -71,7 +65,6 @@
 #include "lsi/mpi_fc.h"		/* Fibre Channel (lowlevel) support */
 #include "lsi/mpi_targ.h"	/* SCSI/FCP Target protcol support */
 #include "lsi/mpi_tool.h"	/* Tools support */
-#include "lsi/fc_log.h"
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
@@ -80,11 +73,11 @@
 #endif
 
 #ifndef COPYRIGHT
-#define COPYRIGHT	"Copyright (c) 1999-2004 " MODULEAUTHOR
+#define COPYRIGHT	"Copyright (c) 1999-2005 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.01.20"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.01.20"
+#define MPT_LINUX_VERSION_COMMON	"3.03.02"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.03.02"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -203,7 +196,9 @@
 typedef enum {
 	MPTBASE_DRIVER,		/* MPT base class */
 	MPTCTL_DRIVER,		/* MPT ioctl class */
-	MPTSCSIH_DRIVER,	/* MPT SCSI host (initiator) class */
+	MPTSPI_DRIVER,		/* MPT SPI host class */
+	MPTFC_DRIVER,		/* MPT FC host class */
+	MPTSAS_DRIVER,		/* MPT SAS host class */
 	MPTLAN_DRIVER,		/* MPT LAN class */
 	MPTSTM_DRIVER,		/* MPT SCSI target mode class */
 	MPTUNKNOWN_DRIVER
@@ -212,11 +207,6 @@ typedef enum {
 struct mpt_pci_driver{
 	int  (*probe) (struct pci_dev *dev, const struct pci_device_id *id);
 	void (*remove) (struct pci_dev *dev);
-	void (*shutdown) (struct device * dev);
-#ifdef CONFIG_PM
-	int  (*resume) (struct pci_dev *dev);
-	int  (*suspend) (struct pci_dev *dev, pm_message_t state);
-#endif
 };
 
 /*
@@ -483,6 +473,7 @@ typedef	struct _ScsiCfgData {
 	u8		 forceDv;		/* 1 to force DV scheduling */
 	u8		 noQas;			/* Disable QAS for this adapter */
 	u8		 Saf_Te;		/* 1 to force all Processors as SAF-TE if Inquiry data length is too short to check for SAF-TE */
+	u8		 mpt_dv;		/* command line option: enhanced=1, basic=0 */
 	u8		 rsvd[1];
 } ScsiCfgData;
 
@@ -571,11 +562,21 @@ typedef struct _MPT_ADAPTER
 	FCPortPage0_t		 fc_port_page0[2];
 	LANPage0_t		 lan_cnfg_page0;
 	LANPage1_t		 lan_cnfg_page1;
+	/*  
+	 * Description: errata_flag_1064
+	 * If a PCIX read occurs within 1 or 2 cycles after the chip receives
+	 * a split completion for a read data, an internal address pointer incorrectly
+	 * increments by 32 bytes
+	 */
+	int			 errata_flag_1064;	
 	u8			 FirstWhoInit;
 	u8			 upload_fw;	/* If set, do a fw upload */
 	u8			 reload_fw;	/* Force a FW Reload on next reset */
 	u8			 NBShiftFactor;  /* NB Shift Factor based on Block Size (Facts)  */     
 	u8			 pad1[4];
+	int			 DoneCtx;
+	int			 TaskCtx;
+	int			 InternalCtx;
 	struct list_head	 list; 
 	struct net_device	*netdev;
 } MPT_ADAPTER;
@@ -773,12 +774,6 @@ typedef struct _mpt_sge {
 #define DBG_DUMP_TM_REPLY_FRAME(mfp)
 #endif
 
-#ifdef MPT_DEBUG_NEH
-#define nehprintk(x) printk x
-#else
-#define nehprintk(x)
-#endif
-
 #if defined(MPT_DEBUG_CONFIG) || defined(MPT_DEBUG)
 #define dcprintk(x) printk x
 #else
@@ -898,6 +893,11 @@ typedef struct _MPT_SCSI_HOST {
 	unsigned long		  soft_resets;		/* fw/external bus resets count */
 	unsigned long		  timeouts;		/* cmd timeouts */
 	ushort			  sel_timeout[MPT_MAX_FC_DEVICES];
+	char 			  *info_kbuf;
+	wait_queue_head_t	  scandv_waitq;
+	int			  scandv_wait_done;
+	long			  last_queue_full;
+	u8		 	  mpt_pq_filter;
 } MPT_SCSI_HOST;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -931,6 +931,12 @@ typedef struct _x_config_parms {
 /*
  *  Public entry points...
  */
+extern int	 mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id);
+extern void	 mpt_detach(struct pci_dev *pdev);
+#ifdef CONFIG_PM
+extern int	 mpt_suspend(struct pci_dev *pdev, pm_message_t state);
+extern int	 mpt_resume(struct pci_dev *pdev);
+#endif
 extern int	 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
 extern void	 mpt_deregister(int cb_idx);
 extern int	 mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc);

+ 20 - 48
drivers/message/fusion/mptctl.c

@@ -1,40 +1,12 @@
 /*
  *  linux/drivers/message/fusion/mptctl.c
- *      Fusion MPT misc device (ioctl) driver.
- *      For use with PCI chip/adapter(s):
- *          LSIFC9xx/LSI409xx Fibre Channel
+ *      mpt Ioctl driver.
+ *      For use with LSI Logic PCI chip/adapters
  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
  *
- *  Credits:
- *      This driver would not exist if not for Alan Cox's development
- *      of the linux i2o driver.
- *
- *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
- *      and countless enhancements while adding support for the 1030
- *      chip family.  Pam has been instrumental in the development of
- *      of the 2.xx.xx series fusion drivers, and her contributions are
- *      far too numerous to hope to list in one place.
- *
- *      A huge debt of gratitude is owed to David S. Miller (DaveM)
- *      for fixing much of the stupid and broken stuff in the early
- *      driver while porting to sparc64 platform.  THANK YOU!
- *
- *      A big THANKS to Eddie C. Dost for fixing the ioctl path
- *      and most importantly f/w download on sparc64 platform!
- *      (plus Eddie's other helpful hints and insights)
- *
- *      Thanks to Arnaldo Carvalho de Melo for finding and patching
- *      a potential memory leak in mptctl_do_fw_download(),
- *      and for some kmalloc insight:-)
- *
- *      (see also mptbase.c)
- *
- *  Copyright (c) 1999-2004 LSI Logic Corporation
- *  Originally By: Steven J. Ralston, Noah Romer
- *  (mailto:sjralston1@netscape.net)
+ *  Copyright (c) 1999-2005 LSI Logic Corporation
  *  (mailto:mpt_linux_developer@lsil.com)
  *
- *  $Id: mptctl.c,v 1.63 2002/12/03 21:26:33 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -95,8 +67,8 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
 
-#define COPYRIGHT	"Copyright (c) 1999-2004 LSI Logic Corporation"
-#define MODULEAUTHOR	"Steven J. Ralston, Noah Romer, Pamela Delaney"
+#define COPYRIGHT	"Copyright (c) 1999-2005 LSI Logic Corporation"
+#define MODULEAUTHOR	"LSI Logic Corporation"
 #include "mptbase.h"
 #include "mptctl.h"
 
@@ -127,14 +99,14 @@ struct buflist {
  * arg contents specific to function.
  */
 static int mptctl_fw_download(unsigned long arg);
-static int mptctl_getiocinfo (unsigned long arg, unsigned int cmd);
-static int mptctl_gettargetinfo (unsigned long arg);
-static int mptctl_readtest (unsigned long arg);
-static int mptctl_mpt_command (unsigned long arg);
-static int mptctl_eventquery (unsigned long arg);
-static int mptctl_eventenable (unsigned long arg);
-static int mptctl_eventreport (unsigned long arg);
-static int mptctl_replace_fw (unsigned long arg);
+static int mptctl_getiocinfo(unsigned long arg, unsigned int cmd);
+static int mptctl_gettargetinfo(unsigned long arg);
+static int mptctl_readtest(unsigned long arg);
+static int mptctl_mpt_command(unsigned long arg);
+static int mptctl_eventquery(unsigned long arg);
+static int mptctl_eventenable(unsigned long arg);
+static int mptctl_eventreport(unsigned long arg);
+static int mptctl_replace_fw(unsigned long arg);
 
 static int mptctl_do_reset(unsigned long arg);
 static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd);
@@ -149,11 +121,11 @@ static long compat_mpctl_ioctl(struct file *f, unsigned cmd, unsigned long arg);
 /*
  * Private function calls.
  */
-static int mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr);
+static int mptctl_do_mpt_command(struct mpt_ioctl_command karg, void __user *mfPtr);
 static int mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen);
-static MptSge_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int sge_offset, int *frags,
+static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags,
 		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
-static void kfree_sgl( MptSge_t *sgl, dma_addr_t sgl_dma,
+static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
 		struct buflist *buflist, MPT_ADAPTER *ioc);
 static void mptctl_timeout_expired (MPT_IOCTL *ioctl);
 static int  mptctl_bus_reset(MPT_IOCTL *ioctl);
@@ -1119,7 +1091,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 	int			numDevices = 0;
 	unsigned int		max_id;
 	int			ii;
-	int			port;
+	unsigned int		port;
 	int			cim_rev;
 	u8			revision;
 
@@ -1162,9 +1134,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 		return -ENODEV;
 	}
 
-	/* Verify the data transfer size is correct.
-	 * Ignore the port setting.
-	 */
+	/* Verify the data transfer size is correct. */
 	if (karg->hdr.maxDataSize != data_size) {
 		printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
 			"Structure size mismatch. Command not completed.\n",
@@ -1181,6 +1151,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 	else
 		karg->adapterType = MPT_IOCTL_INTERFACE_SCSI;
 
+	if (karg->hdr.port > 1)
+		return -EINVAL;
 	port = karg->hdr.port;
 
 	karg->port = port;

+ 1 - 14
drivers/message/fusion/mptctl.h

@@ -5,22 +5,9 @@
  *          LSIFC9xx/LSI409xx Fibre Channel
  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
  *
- *  Credits:
- *      This driver would not exist if not for Alan Cox's development
- *      of the linux i2o driver.
- *
- *      A huge debt of gratitude is owed to David S. Miller (DaveM)
- *      for fixing much of the stupid and broken stuff in the early
- *      driver while porting to sparc64 platform.  THANK YOU!
- *
- *      (see also mptbase.c)
- *
- *  Copyright (c) 1999-2004 LSI Logic Corporation
- *  Originally By: Steven J. Ralston
- *  (mailto:sjralston1@netscape.net)
+ *  Copyright (c) 1999-2005 LSI Logic Corporation
  *  (mailto:mpt_linux_developer@lsil.com)
  *
- *  $Id: mptctl.h,v 1.13 2002/12/03 21:26:33 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*

+ 431 - 0
drivers/message/fusion/mptfc.c

@@ -0,0 +1,431 @@
+/*
+ *  linux/drivers/message/fusion/mptfc.c
+ *      For use with LSI Logic PCI chip/adapter(s)
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Copyright (c) 1999-2005 LSI Logic Corporation
+ *  (mailto:mpt_linux_developer@lsil.com)
+ *
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    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.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#include "linux_compat.h"	/* linux-2.6 tweaks */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>	/* for mdelay */
+#include <linux/interrupt.h>	/* needed for in_interrupt() proto */
+#include <linux/reboot.h>	/* notifier code */
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#include "mptbase.h"
+#include "mptscsih.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME		"Fusion MPT FC Host driver"
+#define my_VERSION	MPT_LINUX_VERSION_COMMON
+#define MYNAM		"mptfc"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+MODULE_LICENSE("GPL");
+
+/* Command line args */
+static int mpt_pq_filter = 0;
+module_param(mpt_pq_filter, int, 0);
+MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1  (default=0)");
+
+static int	mptfcDoneCtx = -1;
+static int	mptfcTaskCtx = -1;
+static int	mptfcInternalCtx = -1; /* Used only for internal commands */
+
+static struct device_attribute mptfc_queue_depth_attr = {
+	.attr = {
+		.name = 	"queue_depth",
+		.mode =		S_IWUSR,
+	},
+	.store = mptscsih_store_queue_depth,
+};
+
+static struct device_attribute *mptfc_dev_attrs[] = {
+	&mptfc_queue_depth_attr,
+	NULL,
+};
+
+static struct scsi_host_template mptfc_driver_template = {
+	.proc_name			= "mptfc",
+	.proc_info			= mptscsih_proc_info,
+	.name				= "MPT FC Host",
+	.info				= mptscsih_info,
+	.queuecommand			= mptscsih_qcmd,
+	.slave_alloc			= mptscsih_slave_alloc,
+	.slave_configure		= mptscsih_slave_configure,
+	.slave_destroy			= mptscsih_slave_destroy,
+	.eh_abort_handler		= mptscsih_abort,
+	.eh_device_reset_handler	= mptscsih_dev_reset,
+	.eh_bus_reset_handler		= mptscsih_bus_reset,
+	.eh_host_reset_handler		= mptscsih_host_reset,
+	.bios_param			= mptscsih_bios_param,
+	.can_queue			= MPT_FC_CAN_QUEUE,
+	.this_id			= -1,
+	.sg_tablesize			= MPT_SCSI_SG_DEPTH,
+	.max_sectors			= 8192,
+	.cmd_per_lun			= 7,
+	.use_clustering			= ENABLE_CLUSTERING,
+	.sdev_attrs			= mptfc_dev_attrs,
+};
+
+/****************************************************************************
+ * Supported hardware
+ */
+
+static struct pci_device_id mptfc_pci_table[] = {
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC909,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919X,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929X,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC939X,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{0}	/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptfc_probe - Installs scsi devices per bus.
+ *	@pdev: Pointer to pci_dev structure
+ *
+ *	Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct Scsi_Host	*sh;
+	MPT_SCSI_HOST		*hd;
+	MPT_ADAPTER 		*ioc;
+	unsigned long		 flags;
+	int			 sz, ii;
+	int			 numSGE = 0;
+	int			 scale;
+	int			 ioc_cap;
+	u8			*mem;
+	int			error=0;
+	int			r;
+		
+	if ((r = mpt_attach(pdev,id)) != 0)
+		return r;
+	
+	ioc = pci_get_drvdata(pdev);
+	ioc->DoneCtx = mptfcDoneCtx;
+	ioc->TaskCtx = mptfcTaskCtx;
+	ioc->InternalCtx = mptfcInternalCtx;
+
+	/*  Added sanity check on readiness of the MPT adapter.
+	 */
+	if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
+		printk(MYIOC_s_WARN_FMT
+		  "Skipping because it's not operational!\n",
+		  ioc->name);
+		return -ENODEV;
+	}
+
+	if (!ioc->active) {
+		printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
+		  ioc->name);
+		return -ENODEV;
+	}
+
+	/*  Sanity check - ensure at least 1 port is INITIATOR capable
+	 */
+	ioc_cap = 0;
+	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+		if (ioc->pfacts[ii].ProtocolFlags &
+		    MPI_PORTFACTS_PROTOCOL_INITIATOR)
+			ioc_cap ++;
+	}
+
+	if (!ioc_cap) {
+		printk(MYIOC_s_WARN_FMT
+			"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
+			ioc->name, ioc);
+		return -ENODEV;
+	}
+
+	sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
+
+	if (!sh) {
+		printk(MYIOC_s_WARN_FMT
+			"Unable to register controller with SCSI subsystem\n",
+			ioc->name);
+                return -1;
+        }
+
+	spin_lock_irqsave(&ioc->FreeQlock, flags);
+
+	/* Attach the SCSI Host to the IOC structure
+	 */
+	ioc->sh = sh;
+
+	sh->io_port = 0;
+	sh->n_io_port = 0;
+	sh->irq = 0;
+
+	/* set 16 byte cdb's */
+	sh->max_cmd_len = 16;
+
+	sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
+
+	sh->max_lun = MPT_LAST_LUN + 1;
+	sh->max_channel = 0;
+	sh->this_id = ioc->pfacts[0].PortSCSIID;
+
+	/* Required entry.
+	 */
+	sh->unique_id = ioc->id;
+
+	/* Verify that we won't exceed the maximum
+	 * number of chain buffers
+	 * We can optimize:  ZZ = req_sz/sizeof(SGE)
+	 * For 32bit SGE's:
+	 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
+	 *               + (req_sz - 64)/sizeof(SGE)
+	 * A slightly different algorithm is required for
+	 * 64bit SGEs.
+	 */
+	scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+	if (sizeof(dma_addr_t) == sizeof(u64)) {
+		numSGE = (scale - 1) *
+		  (ioc->facts.MaxChainDepth-1) + scale +
+		  (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
+		  sizeof(u32));
+	} else {
+		numSGE = 1 + (scale - 1) *
+		  (ioc->facts.MaxChainDepth-1) + scale +
+		  (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
+		  sizeof(u32));
+	}
+
+	if (numSGE < sh->sg_tablesize) {
+		/* Reset this value */
+		dprintk((MYIOC_s_INFO_FMT
+		  "Resetting sg_tablesize to %d from %d\n",
+		  ioc->name, numSGE, sh->sg_tablesize));
+		sh->sg_tablesize = numSGE;
+	}
+
+	/* Set the pci device pointer in Scsi_Host structure.
+	 */
+	scsi_set_device(sh, &ioc->pcidev->dev);
+
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+	hd = (MPT_SCSI_HOST *) sh->hostdata;
+	hd->ioc = ioc;
+
+	/* SCSI needs scsi_cmnd lookup table!
+	 * (with size equal to req_depth*PtrSz!)
+	 */
+	sz = ioc->req_depth * sizeof(void *);
+	mem = kmalloc(sz, GFP_ATOMIC);
+	if (mem == NULL) {
+		error = -ENOMEM;
+		goto mptfc_probe_failed;
+	}
+
+	memset(mem, 0, sz);
+	hd->ScsiLookup = (struct scsi_cmnd **) mem;
+
+	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
+		 ioc->name, hd->ScsiLookup, sz));
+
+	/* Allocate memory for the device structures.
+	 * A non-Null pointer at an offset
+	 * indicates a device exists.
+	 * max_id = 1 + maximum id (hosts.h)
+	 */
+	sz = sh->max_id * sizeof(void *);
+	mem = kmalloc(sz, GFP_ATOMIC);
+	if (mem == NULL) {
+		error = -ENOMEM;
+		goto mptfc_probe_failed;
+	}
+
+	memset(mem, 0, sz);
+	hd->Targets = (VirtDevice **) mem;
+
+	dprintk((KERN_INFO
+	  "  Targets @ %p, sz=%d\n", hd->Targets, sz));
+
+	/* Clear the TM flags
+	 */
+	hd->tmPending = 0;
+	hd->tmState = TM_STATE_NONE;
+	hd->resetPending = 0;
+	hd->abortSCpnt = NULL;
+
+	/* Clear the pointer used to store
+	 * single-threaded commands, i.e., those
+	 * issued during a bus scan, dv and
+	 * configuration pages.
+	 */
+	hd->cmdPtr = NULL;
+
+	/* Initialize this SCSI Hosts' timers
+	 * To use, set the timer expires field
+	 * and add_timer
+	 */
+	init_timer(&hd->timer);
+	hd->timer.data = (unsigned long) hd;
+	hd->timer.function = mptscsih_timer_expired;
+
+	hd->mpt_pq_filter = mpt_pq_filter;
+
+	ddvprintk((MYIOC_s_INFO_FMT
+		"mpt_pq_filter %x\n",
+		ioc->name, 
+		mpt_pq_filter));
+
+	init_waitqueue_head(&hd->scandv_waitq);
+	hd->scandv_wait_done = 0;
+	hd->last_queue_full = 0;
+
+	error = scsi_add_host (sh, &ioc->pcidev->dev);
+	if(error) {
+		dprintk((KERN_ERR MYNAM
+		  "scsi_add_host failed\n"));
+		goto mptfc_probe_failed;
+	}
+
+	scsi_scan_host(sh);
+	return 0;
+
+mptfc_probe_failed:
+
+	mptscsih_remove(pdev);
+	return error;
+}
+
+static struct pci_driver mptfc_driver = {
+	.name		= "mptfc",
+	.id_table	= mptfc_pci_table,
+	.probe		= mptfc_probe,
+	.remove		= __devexit_p(mptscsih_remove),
+	.driver         = {
+		.shutdown = mptscsih_shutdown,
+        },
+#ifdef CONFIG_PM
+	.suspend	= mptscsih_suspend,
+	.resume		= mptscsih_resume,
+#endif
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptfc_init - Register MPT adapter(s) as SCSI host(s) with
+ *	linux scsi mid-layer.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int __init
+mptfc_init(void)
+{
+
+	show_mptmod_ver(my_NAME, my_VERSION);
+
+	mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
+	mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
+	mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
+
+	if (mpt_event_register(mptfcDoneCtx, mptscsih_event_process) == 0) {
+		devtprintk((KERN_INFO MYNAM
+		  ": Registered for IOC event notifications\n"));
+	}
+
+	if (mpt_reset_register(mptfcDoneCtx, mptscsih_ioc_reset) == 0) {
+		dprintk((KERN_INFO MYNAM
+		  ": Registered for IOC reset notifications\n"));
+	}
+
+	return pci_register_driver(&mptfc_driver);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptfc_exit - Unregisters MPT adapter(s)
+ *
+ */
+static void __exit
+mptfc_exit(void)
+{
+	pci_unregister_driver(&mptfc_driver);
+	
+	mpt_reset_deregister(mptfcDoneCtx);
+	dprintk((KERN_INFO MYNAM
+	  ": Deregistered for IOC reset notifications\n"));
+
+	mpt_event_deregister(mptfcDoneCtx);
+	dprintk((KERN_INFO MYNAM
+	  ": Deregistered for IOC event notifications\n"));
+
+	mpt_deregister(mptfcInternalCtx);
+	mpt_deregister(mptfcTaskCtx);
+	mpt_deregister(mptfcDoneCtx);
+}
+
+module_init(mptfc_init);
+module_exit(mptfc_exit);

+ 7 - 30
drivers/message/fusion/mptlan.c

@@ -1,33 +1,11 @@
 /*
  *  linux/drivers/message/fusion/mptlan.c
  *      IP Over Fibre Channel device driver.
- *      For use with PCI chip/adapter(s):
- *          LSIFC9xx/LSI409xx Fibre Channel
+ *      For use with LSI Logic Fibre Channel PCI chip/adapters
  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
  *
- *  Credits:
- *      This driver would not exist if not for Alan Cox's development
- *      of the linux i2o driver.
+ *  Copyright (c) 2000-2005 LSI Logic Corporation
  *
- *      Special thanks goes to the I2O LAN driver people at the
- *      University of Helsinki, who, unbeknownst to them, provided
- *      the inspiration and initial structure for this driver.
- *
- *      A huge debt of gratitude is owed to David S. Miller (DaveM)
- *      for fixing much of the stupid and broken stuff in the early
- *      driver while porting to sparc64 platform.  THANK YOU!
- *
- *      A really huge debt of gratitude is owed to Eddie C. Dost
- *      for gobs of hard work fixing and optimizing LAN code.
- *      THANK YOU!
- *
- *      (see also mptbase.c)
- *
- *  Copyright (c) 2000-2004 LSI Logic Corporation
- *  Originally By: Noah Romer
- *  (mailto:mpt_linux_developer@lsil.com)
- *
- *  $Id: mptlan.c,v 1.53 2002/10/17 20:15:58 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -221,7 +199,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
 
 		// NOTE!  (Optimization) First case here is now caught in
 		//  mptbase.c::mpt_interrupt() routine and callcack here
-		//  is now skipped for this case!  20001218 -sralston
+		//  is now skipped for this case!
 #if 0
 		case LAN_REPLY_FORM_MESSAGE_CONTEXT:
 //			dioprintk((KERN_INFO MYNAM "/lan_reply: "
@@ -234,7 +212,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
 //			dioprintk((MYNAM "/lan_reply: "
 //				  "calling mpt_lan_send_reply (turbo)\n"));
 
-			// Potential BUG here?  -sralston
+			// Potential BUG here?
 			//	FreeReqFrame = mpt_lan_send_turbo(dev, tmsg);
 			//  If/when mpt_lan_send_turbo would return 1 here,
 			//  calling routine (mptbase.c|mpt_interrupt)
@@ -310,8 +288,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
 
 	case MPI_FUNCTION_EVENT_NOTIFICATION:
 	case MPI_FUNCTION_EVENT_ACK:
-		/* UPDATE!  20010120 -sralston
-		 *  _EVENT_NOTIFICATION should NOT come down this path any more.
+		/*  _EVENT_NOTIFICATION should NOT come down this path any more.
 		 *  Should be routed to mpt_lan_event_process(), but just in case...
 		 */
 		FreeReqFrame = 1;
@@ -561,8 +538,8 @@ mpt_lan_close(struct net_device *dev)
 		}
 	}
 
-	kfree (priv->RcvCtl);
-	kfree (priv->mpt_rxfidx);
+	kfree(priv->RcvCtl);
+	kfree(priv->mpt_rxfidx);
 
 	for (i = 0; i < priv->tx_max_out; i++) {
 		if (priv->SendCtl[i].skb != NULL) {

+ 47 - 1
drivers/message/fusion/mptlan.h

@@ -1,3 +1,49 @@
+/*
+ *  linux/drivers/message/fusion/mptlan.h
+ *      IP Over Fibre Channel device driver.
+ *      For use with LSI Logic Fibre Channel PCI chip/adapters
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Copyright (c) 2000-2005 LSI Logic Corporation
+ *
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    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.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    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
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
 /* mptlan.h */
 
 #ifndef LINUX_MPTLAN_H_INCLUDED
@@ -29,7 +75,7 @@
 #include <asm/io.h>
 
     /* Override mptbase.h by pre-defining these! */
-    #define MODULEAUTHOR "Noah Romer, Eddie C. Dost"
+#define MODULEAUTHOR	"LSI Logic Corporation"
 
 #include "mptbase.h"
 

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 107 - 524
drivers/message/fusion/mptscsih.c


+ 28 - 15
drivers/message/fusion/mptscsih.h

@@ -1,26 +1,13 @@
 /*
- *  linux/drivers/message/fusion/mptscsih.h
+ *  linux/drivers/message/fusion/mptscsi.h
  *      High performance SCSI / Fibre Channel SCSI Host device driver.
  *      For use with PCI chip/adapter(s):
  *          LSIFC9xx/LSI409xx Fibre Channel
  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
  *
- *  Credits:
- *      This driver would not exist if not for Alan Cox's development
- *      of the linux i2o driver.
- *
- *      A huge debt of gratitude is owed to David S. Miller (DaveM)
- *      for fixing much of the stupid and broken stuff in the early
- *      driver while porting to sparc64 platform.  THANK YOU!
- *
- *      (see also mptbase.c)
- *
- *  Copyright (c) 1999-2004 LSI Logic Corporation
- *  Originally By: Steven J. Ralston
- *  (mailto:netscape.net)
+ *  Copyright (c) 1999-2005 LSI Logic Corporation
  *  (mailto:mpt_linux_developer@lsil.com)
  *
- *  $Id: mptscsih.h,v 1.21 2002/12/03 21:26:35 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -91,4 +78,30 @@
 #define MPTSCSIH_MIN_SYNC               0x08
 #define MPTSCSIH_SAF_TE                 0
 
+
+#endif
+
+extern void mptscsih_remove(struct pci_dev *);
+extern void mptscsih_shutdown(struct device *);
+#ifdef CONFIG_PM
+extern int mptscsih_suspend(struct pci_dev *pdev, u32 state);
+extern int mptscsih_resume(struct pci_dev *pdev);
 #endif
+extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func);
+extern const char * mptscsih_info(struct Scsi_Host *SChost);
+extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
+extern int mptscsih_slave_alloc(struct scsi_device *device);
+extern void mptscsih_slave_destroy(struct scsi_device *device);
+extern int mptscsih_slave_configure(struct scsi_device *device);
+extern int mptscsih_abort(struct scsi_cmnd * SCpnt);
+extern int mptscsih_dev_reset(struct scsi_cmnd * SCpnt);
+extern int mptscsih_bus_reset(struct scsi_cmnd * SCpnt);
+extern int mptscsih_host_reset(struct scsi_cmnd *SCpnt);
+extern int mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int geom[]);
+extern int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+extern int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
+extern ssize_t mptscsih_store_queue_depth(struct device *dev, const char *buf, size_t count);
+extern void mptscsih_timer_expired(unsigned long data);

+ 486 - 0
drivers/message/fusion/mptspi.c

@@ -0,0 +1,486 @@
+/*
+ *  linux/drivers/message/fusion/mptspi.c
+ *      For use with LSI Logic PCI chip/adapter(s)
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Copyright (c) 1999-2005 LSI Logic Corporation
+ *  (mailto:mpt_linux_developer@lsil.com)
+ *
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    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.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "linux_compat.h"	/* linux-2.6 tweaks */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>	/* for mdelay */
+#include <linux/interrupt.h>	/* needed for in_interrupt() proto */
+#include <linux/reboot.h>	/* notifier code */
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#include "mptbase.h"
+#include "mptscsih.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME		"Fusion MPT SPI Host driver"
+#define my_VERSION	MPT_LINUX_VERSION_COMMON
+#define MYNAM		"mptspi"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+MODULE_LICENSE("GPL");
+
+/* Command line args */
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+static int mpt_dv = MPTSCSIH_DOMAIN_VALIDATION;
+module_param(mpt_dv, int, 0);
+MODULE_PARM_DESC(mpt_dv, " DV Algorithm: enhanced=1, basic=0 (default=MPTSCSIH_DOMAIN_VALIDATION=1)");
+
+static int mpt_width = MPTSCSIH_MAX_WIDTH;
+module_param(mpt_width, int, 0);
+MODULE_PARM_DESC(mpt_width, " Max Bus Width: wide=1, narrow=0 (default=MPTSCSIH_MAX_WIDTH=1)");
+
+static ushort mpt_factor = MPTSCSIH_MIN_SYNC;
+module_param(mpt_factor, ushort, 0);
+MODULE_PARM_DESC(mpt_factor, " Min Sync Factor (default=MPTSCSIH_MIN_SYNC=0x08)");
+#endif
+
+static int mpt_saf_te = MPTSCSIH_SAF_TE;
+module_param(mpt_saf_te, int, 0);
+MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1  (default=MPTSCSIH_SAF_TE=0)");
+
+static int mpt_pq_filter = 0;
+module_param(mpt_pq_filter, int, 0);
+MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1  (default=0)");
+
+static int	mptspiDoneCtx = -1;
+static int	mptspiTaskCtx = -1;
+static int	mptspiInternalCtx = -1; /* Used only for internal commands */
+
+static struct device_attribute mptspi_queue_depth_attr = {
+	.attr = {
+		.name = 	"queue_depth",
+		.mode =		S_IWUSR,
+	},
+	.store = mptscsih_store_queue_depth,
+};
+
+static struct device_attribute *mptspi_dev_attrs[] = {
+	&mptspi_queue_depth_attr,
+	NULL,
+};
+
+static struct scsi_host_template mptspi_driver_template = {
+	.proc_name			= "mptspi",
+	.proc_info			= mptscsih_proc_info,
+	.name				= "MPT SPI Host",
+	.info				= mptscsih_info,
+	.queuecommand			= mptscsih_qcmd,
+	.slave_alloc			= mptscsih_slave_alloc,
+	.slave_configure		= mptscsih_slave_configure,
+	.slave_destroy			= mptscsih_slave_destroy,
+	.eh_abort_handler		= mptscsih_abort,
+	.eh_device_reset_handler	= mptscsih_dev_reset,
+	.eh_bus_reset_handler		= mptscsih_bus_reset,
+	.eh_host_reset_handler		= mptscsih_host_reset,
+	.bios_param			= mptscsih_bios_param,
+	.can_queue			= MPT_SCSI_CAN_QUEUE,
+	.this_id			= -1,
+	.sg_tablesize			= MPT_SCSI_SG_DEPTH,
+	.max_sectors			= 8192,
+	.cmd_per_lun			= 7,
+	.use_clustering			= ENABLE_CLUSTERING,
+	.sdev_attrs			= mptspi_dev_attrs,
+};
+
+
+/****************************************************************************
+ * Supported hardware
+ */
+
+static struct pci_device_id mptspi_pci_table[] = {
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1030,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_1030_53C1035,
+		PCI_ANY_ID, PCI_ANY_ID },
+	{0}	/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, mptspi_pci_table);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	mptspi_probe - Installs scsi devices per bus.
+ *	@pdev: Pointer to pci_dev structure
+ *
+ *	Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct Scsi_Host	*sh;
+	MPT_SCSI_HOST		*hd;
+	MPT_ADAPTER 		*ioc;
+	unsigned long		 flags;
+	int			 sz, ii;
+	int			 numSGE = 0;
+	int			 scale;
+	int			 ioc_cap;
+	u8			*mem;
+	int			error=0;
+	int			r;
+	
+	if ((r = mpt_attach(pdev,id)) != 0)
+		return r;
+	
+	ioc = pci_get_drvdata(pdev);
+	ioc->DoneCtx = mptspiDoneCtx;
+	ioc->TaskCtx = mptspiTaskCtx;
+	ioc->InternalCtx = mptspiInternalCtx;
+	
+	/*  Added sanity check on readiness of the MPT adapter.
+	 */
+	if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
+		printk(MYIOC_s_WARN_FMT
+		  "Skipping because it's not operational!\n",
+		  ioc->name);
+		return -ENODEV;
+	}
+
+	if (!ioc->active) {
+		printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
+		  ioc->name);
+		return -ENODEV;
+	}
+
+	/*  Sanity check - ensure at least 1 port is INITIATOR capable
+	 */
+	ioc_cap = 0;
+	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+		if (ioc->pfacts[ii].ProtocolFlags &
+		    MPI_PORTFACTS_PROTOCOL_INITIATOR)
+			ioc_cap ++;
+	}
+
+	if (!ioc_cap) {
+		printk(MYIOC_s_WARN_FMT
+			"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
+			ioc->name, ioc);
+		return -ENODEV;
+	}
+
+	sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST));
+
+	if (!sh) {
+		printk(MYIOC_s_WARN_FMT
+			"Unable to register controller with SCSI subsystem\n",
+			ioc->name);
+                return -1;
+        }
+
+	spin_lock_irqsave(&ioc->FreeQlock, flags);
+
+	/* Attach the SCSI Host to the IOC structure
+	 */
+	ioc->sh = sh;
+
+	sh->io_port = 0;
+	sh->n_io_port = 0;
+	sh->irq = 0;
+
+	/* set 16 byte cdb's */
+	sh->max_cmd_len = 16;
+
+	/* Yikes!  This is important!
+	 * Otherwise, by default, linux
+	 * only scans target IDs 0-7!
+	 * pfactsN->MaxDevices unreliable
+	 * (not supported in early
+	 *	versions of the FW).
+	 * max_id = 1 + actual max id,
+	 * max_lun = 1 + actual last lun,
+	 *	see hosts.h :o(
+	 */
+	sh->max_id = MPT_MAX_SCSI_DEVICES;
+
+	sh->max_lun = MPT_LAST_LUN + 1;
+	sh->max_channel = 0;
+	sh->this_id = ioc->pfacts[0].PortSCSIID;
+
+	/* Required entry.
+	 */
+	sh->unique_id = ioc->id;
+
+	/* Verify that we won't exceed the maximum
+	 * number of chain buffers
+	 * We can optimize:  ZZ = req_sz/sizeof(SGE)
+	 * For 32bit SGE's:
+	 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
+	 *               + (req_sz - 64)/sizeof(SGE)
+	 * A slightly different algorithm is required for
+	 * 64bit SGEs.
+	 */
+	scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+	if (sizeof(dma_addr_t) == sizeof(u64)) {
+		numSGE = (scale - 1) *
+		  (ioc->facts.MaxChainDepth-1) + scale +
+		  (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
+		  sizeof(u32));
+	} else {
+		numSGE = 1 + (scale - 1) *
+		  (ioc->facts.MaxChainDepth-1) + scale +
+		  (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
+		  sizeof(u32));
+	}
+
+	if (numSGE < sh->sg_tablesize) {
+		/* Reset this value */
+		dprintk((MYIOC_s_INFO_FMT
+		  "Resetting sg_tablesize to %d from %d\n",
+		  ioc->name, numSGE, sh->sg_tablesize));
+		sh->sg_tablesize = numSGE;
+	}
+
+	/* Set the pci device pointer in Scsi_Host structure.
+	 */
+	scsi_set_device(sh, &ioc->pcidev->dev);
+
+	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+	hd = (MPT_SCSI_HOST *) sh->hostdata;
+	hd->ioc = ioc;
+
+	/* SCSI needs scsi_cmnd lookup table!
+	 * (with size equal to req_depth*PtrSz!)
+	 */
+	sz = ioc->req_depth * sizeof(void *);
+	mem = kmalloc(sz, GFP_ATOMIC);
+	if (mem == NULL) {
+		error = -ENOMEM;
+		goto mptspi_probe_failed;
+	}
+
+	memset(mem, 0, sz);
+	hd->ScsiLookup = (struct scsi_cmnd **) mem;
+
+	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
+		 ioc->name, hd->ScsiLookup, sz));
+
+	/* Allocate memory for the device structures.
+	 * A non-Null pointer at an offset
+	 * indicates a device exists.
+	 * max_id = 1 + maximum id (hosts.h)
+	 */
+	sz = sh->max_id * sizeof(void *);
+	mem = kmalloc(sz, GFP_ATOMIC);
+	if (mem == NULL) {
+		error = -ENOMEM;
+		goto mptspi_probe_failed;
+	}
+
+	memset(mem, 0, sz);
+	hd->Targets = (VirtDevice **) mem;
+
+	dprintk((KERN_INFO
+	  "  Targets @ %p, sz=%d\n", hd->Targets, sz));
+
+	/* Clear the TM flags
+	 */
+	hd->tmPending = 0;
+	hd->tmState = TM_STATE_NONE;
+	hd->resetPending = 0;
+	hd->abortSCpnt = NULL;
+
+	/* Clear the pointer used to store
+	 * single-threaded commands, i.e., those
+	 * issued during a bus scan, dv and
+	 * configuration pages.
+	 */
+	hd->cmdPtr = NULL;
+
+	/* Initialize this SCSI Hosts' timers
+	 * To use, set the timer expires field
+	 * and add_timer
+	 */
+	init_timer(&hd->timer);
+	hd->timer.data = (unsigned long) hd;
+	hd->timer.function = mptscsih_timer_expired;
+
+	ioc->spi_data.Saf_Te = mpt_saf_te;
+	hd->mpt_pq_filter = mpt_pq_filter;
+
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+	if (ioc->spi_data.maxBusWidth > mpt_width)
+		ioc->spi_data.maxBusWidth = mpt_width;
+	if (ioc->spi_data.minSyncFactor < mpt_factor)
+		ioc->spi_data.minSyncFactor = mpt_factor;
+	if (ioc->spi_data.minSyncFactor == MPT_ASYNC) {
+		ioc->spi_data.maxSyncOffset = 0;
+	}
+	ioc->spi_data.mpt_dv = mpt_dv;
+	hd->negoNvram = 0;
+
+	ddvprintk((MYIOC_s_INFO_FMT
+		"dv %x width %x factor %x saf_te %x mpt_pq_filter %x\n",
+		ioc->name,
+		mpt_dv,
+		mpt_width,
+		mpt_factor,
+		mpt_saf_te,
+		mpt_pq_filter));
+#else
+	hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
+	ddvprintk((MYIOC_s_INFO_FMT
+		"saf_te %x mpt_pq_filter %x\n",
+		ioc->name,
+		mpt_saf_te,
+		mpt_pq_filter));
+#endif
+
+	ioc->spi_data.forceDv = 0;
+	ioc->spi_data.noQas = 0;
+
+	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+		ioc->spi_data.dvStatus[ii] =
+		  MPT_SCSICFG_NEGOTIATE;
+
+	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+		ioc->spi_data.dvStatus[ii] |=
+		  MPT_SCSICFG_DV_NOT_DONE;
+
+	init_waitqueue_head(&hd->scandv_waitq);
+	hd->scandv_wait_done = 0;
+	hd->last_queue_full = 0;
+
+	error = scsi_add_host (sh, &ioc->pcidev->dev);
+	if(error) {
+		dprintk((KERN_ERR MYNAM
+		  "scsi_add_host failed\n"));
+		goto mptspi_probe_failed;
+	}
+
+	scsi_scan_host(sh);
+	return 0;
+
+mptspi_probe_failed:
+
+	mptscsih_remove(pdev);
+	return error;
+}
+
+static struct pci_driver mptspi_driver = {
+	.name		= "mptspi",
+	.id_table	= mptspi_pci_table,
+	.probe		= mptspi_probe,
+	.remove		= __devexit_p(mptscsih_remove),
+	.driver         = {
+		.shutdown = mptscsih_shutdown,
+        },
+#ifdef CONFIG_PM
+	.suspend	= mptscsih_suspend,
+	.resume		= mptscsih_resume,
+#endif
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptspi_init - Register MPT adapter(s) as SCSI host(s) with
+ *	linux scsi mid-layer.
+ *
+ *	Returns 0 for success, non-zero for failure.
+ */
+static int __init
+mptspi_init(void)
+{
+
+	show_mptmod_ver(my_NAME, my_VERSION);
+
+	mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER);
+	mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER);
+	mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER);
+
+	if (mpt_event_register(mptspiDoneCtx, mptscsih_event_process) == 0) {
+		devtprintk((KERN_INFO MYNAM
+		  ": Registered for IOC event notifications\n"));
+	}
+
+	if (mpt_reset_register(mptspiDoneCtx, mptscsih_ioc_reset) == 0) {
+		dprintk((KERN_INFO MYNAM
+		  ": Registered for IOC reset notifications\n"));
+	}
+
+	return pci_register_driver(&mptspi_driver);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptspi_exit - Unregisters MPT adapter(s)
+ *
+ */
+static void __exit
+mptspi_exit(void)
+{
+	pci_unregister_driver(&mptspi_driver);
+	
+	mpt_reset_deregister(mptspiDoneCtx);
+	dprintk((KERN_INFO MYNAM
+	  ": Deregistered for IOC reset notifications\n"));
+
+	mpt_event_deregister(mptspiDoneCtx);
+	dprintk((KERN_INFO MYNAM
+	  ": Deregistered for IOC event notifications\n"));
+
+	mpt_deregister(mptspiInternalCtx);
+	mpt_deregister(mptspiTaskCtx);
+	mpt_deregister(mptspiDoneCtx);
+}
+
+module_init(mptspi_init);
+module_exit(mptspi_exit);

+ 69 - 31
drivers/net/8139cp.c

@@ -54,6 +54,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/compiler.h>
 #include <linux/netdevice.h>
@@ -91,16 +92,17 @@ KERN_INFO DRV_NAME ": 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE
 
 MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION("RealTek RTL-8139C+ series 10/100 PCI Ethernet driver");
+MODULE_VERSION(DRV_VERSION);
 MODULE_LICENSE("GPL");
 
 static int debug = -1;
-MODULE_PARM (debug, "i");
+module_param(debug, int, 0);
 MODULE_PARM_DESC (debug, "8139cp: bitmapped message enable number");
 
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
    The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
 static int multicast_filter_limit = 32;
-MODULE_PARM (multicast_filter_limit, "i");
+module_param(multicast_filter_limit, int, 0);
 MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered multicast addresses");
 
 #define PFX			DRV_NAME ": "
@@ -186,6 +188,9 @@ enum {
 	RingEnd		= (1 << 30), /* End of descriptor ring */
 	FirstFrag	= (1 << 29), /* First segment of a packet */
 	LastFrag	= (1 << 28), /* Final segment of a packet */
+	LargeSend	= (1 << 27), /* TCP Large Send Offload (TSO) */
+	MSSShift	= 16,	     /* MSS value position */
+	MSSMask		= 0xfff,     /* MSS value: 11 bits */
 	TxError		= (1 << 23), /* Tx error summary */
 	RxError		= (1 << 20), /* Rx error summary */
 	IPCS		= (1 << 18), /* Calculate IP checksum */
@@ -312,7 +317,7 @@ struct cp_desc {
 struct ring_info {
 	struct sk_buff		*skb;
 	dma_addr_t		mapping;
-	unsigned		frag;
+	u32			len;
 };
 
 struct cp_dma_stats {
@@ -394,6 +399,9 @@ struct cp_private {
 static void __cp_set_rx_mode (struct net_device *dev);
 static void cp_tx (struct cp_private *cp);
 static void cp_clean_rings (struct cp_private *cp);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void cp_poll_controller(struct net_device *dev);
+#endif
 
 static struct pci_device_id cp_pci_tbl[] = {
 	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
@@ -688,6 +696,19 @@ cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+static void cp_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	cp_interrupt(dev->irq, dev, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
 static void cp_tx (struct cp_private *cp)
 {
 	unsigned tx_head = cp->tx_head;
@@ -707,7 +728,7 @@ static void cp_tx (struct cp_private *cp)
 			BUG();
 
 		pci_unmap_single(cp->pdev, cp->tx_skb[tx_tail].mapping,
-					skb->len, PCI_DMA_TODEVICE);
+				 cp->tx_skb[tx_tail].len, PCI_DMA_TODEVICE);
 
 		if (status & LastFrag) {
 			if (status & (TxError | TxFIFOUnder)) {
@@ -749,10 +770,11 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
 	struct cp_private *cp = netdev_priv(dev);
 	unsigned entry;
-	u32 eor;
+	u32 eor, flags;
 #if CP_VLAN_TAG_USED
 	u32 vlan_tag = 0;
 #endif
+	int mss = 0;
 
 	spin_lock_irq(&cp->lock);
 
@@ -772,6 +794,9 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
 
 	entry = cp->tx_head;
 	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+	if (dev->features & NETIF_F_TSO)
+		mss = skb_shinfo(skb)->tso_size;
+
 	if (skb_shinfo(skb)->nr_frags == 0) {
 		struct cp_desc *txd = &cp->tx_ring[entry];
 		u32 len;
@@ -783,26 +808,26 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
 		txd->addr = cpu_to_le64(mapping);
 		wmb();
 
-		if (skb->ip_summed == CHECKSUM_HW) {
+		flags = eor | len | DescOwn | FirstFrag | LastFrag;
+
+		if (mss)
+			flags |= LargeSend | ((mss & MSSMask) << MSSShift);
+		else if (skb->ip_summed == CHECKSUM_HW) {
 			const struct iphdr *ip = skb->nh.iph;
 			if (ip->protocol == IPPROTO_TCP)
-				txd->opts1 = cpu_to_le32(eor | len | DescOwn |
-							 FirstFrag | LastFrag |
-							 IPCS | TCPCS);
+				flags |= IPCS | TCPCS;
 			else if (ip->protocol == IPPROTO_UDP)
-				txd->opts1 = cpu_to_le32(eor | len | DescOwn |
-							 FirstFrag | LastFrag |
-							 IPCS | UDPCS);
+				flags |= IPCS | UDPCS;
 			else
-				BUG();
-		} else
-			txd->opts1 = cpu_to_le32(eor | len | DescOwn |
-						 FirstFrag | LastFrag);
+				WARN_ON(1);	/* we need a WARN() */
+		}
+
+		txd->opts1 = cpu_to_le32(flags);
 		wmb();
 
 		cp->tx_skb[entry].skb = skb;
 		cp->tx_skb[entry].mapping = mapping;
-		cp->tx_skb[entry].frag = 0;
+		cp->tx_skb[entry].len = len;
 		entry = NEXT_TX(entry);
 	} else {
 		struct cp_desc *txd;
@@ -820,7 +845,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
 					       first_len, PCI_DMA_TODEVICE);
 		cp->tx_skb[entry].skb = skb;
 		cp->tx_skb[entry].mapping = first_mapping;
-		cp->tx_skb[entry].frag = 1;
+		cp->tx_skb[entry].len = first_len;
 		entry = NEXT_TX(entry);
 
 		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
@@ -836,16 +861,19 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
 						 len, PCI_DMA_TODEVICE);
 			eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 
-			if (skb->ip_summed == CHECKSUM_HW) {
-				ctrl = eor | len | DescOwn | IPCS;
+			ctrl = eor | len | DescOwn;
+
+			if (mss)
+				ctrl |= LargeSend |
+					((mss & MSSMask) << MSSShift);
+			else if (skb->ip_summed == CHECKSUM_HW) {
 				if (ip->protocol == IPPROTO_TCP)
-					ctrl |= TCPCS;
+					ctrl |= IPCS | TCPCS;
 				else if (ip->protocol == IPPROTO_UDP)
-					ctrl |= UDPCS;
+					ctrl |= IPCS | UDPCS;
 				else
 					BUG();
-			} else
-				ctrl = eor | len | DescOwn;
+			}
 
 			if (frag == skb_shinfo(skb)->nr_frags - 1)
 				ctrl |= LastFrag;
@@ -860,7 +888,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
 
 			cp->tx_skb[entry].skb = skb;
 			cp->tx_skb[entry].mapping = mapping;
-			cp->tx_skb[entry].frag = frag + 2;
+			cp->tx_skb[entry].len = len;
 			entry = NEXT_TX(entry);
 		}
 
@@ -1074,7 +1102,6 @@ static int cp_refill_rx (struct cp_private *cp)
 		cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
 			skb->tail, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		cp->rx_skb[i].skb = skb;
-		cp->rx_skb[i].frag = 0;
 
 		cp->rx_ring[i].opts2 = 0;
 		cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping);
@@ -1126,9 +1153,6 @@ static void cp_clean_rings (struct cp_private *cp)
 {
 	unsigned i;
 
-	memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
-	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
-
 	for (i = 0; i < CP_RX_RING_SIZE; i++) {
 		if (cp->rx_skb[i].skb) {
 			pci_unmap_single(cp->pdev, cp->rx_skb[i].mapping,
@@ -1140,13 +1164,18 @@ static void cp_clean_rings (struct cp_private *cp)
 	for (i = 0; i < CP_TX_RING_SIZE; i++) {
 		if (cp->tx_skb[i].skb) {
 			struct sk_buff *skb = cp->tx_skb[i].skb;
+
 			pci_unmap_single(cp->pdev, cp->tx_skb[i].mapping,
-					 skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb(skb);
+				 	 cp->tx_skb[i].len, PCI_DMA_TODEVICE);
+			if (le32_to_cpu(cp->tx_ring[i].opts1) & LastFrag)
+				dev_kfree_skb(skb);
 			cp->net_stats.tx_dropped++;
 		}
 	}
 
+	memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
+	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
+
 	memset(&cp->rx_skb, 0, sizeof(struct ring_info) * CP_RX_RING_SIZE);
 	memset(&cp->tx_skb, 0, sizeof(struct ring_info) * CP_TX_RING_SIZE);
 }
@@ -1538,6 +1567,8 @@ static struct ethtool_ops cp_ethtool_ops = {
 	.set_tx_csum		= ethtool_op_set_tx_csum, /* local! */
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= ethtool_op_set_tso,
 	.get_regs		= cp_get_regs,
 	.get_wol		= cp_get_wol,
 	.set_wol		= cp_set_wol,
@@ -1749,6 +1780,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 	dev->get_stats = cp_get_stats;
 	dev->do_ioctl = cp_ioctl;
 	dev->poll = cp_rx_poll;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = cp_poll_controller;
+#endif
 	dev->weight = 16;	/* arbitrary? from NAPI_HOWTO.txt. */
 #ifdef BROKEN
 	dev->change_mtu = cp_change_mtu;
@@ -1768,6 +1802,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (pci_using_dac)
 		dev->features |= NETIF_F_HIGHDMA;
 
+#if 0 /* disabled by default until verified */
+	dev->features |= NETIF_F_TSO;
+#endif
+
 	dev->irq = pdev->irq;
 
 	rc = register_netdev(dev);

+ 87 - 107
drivers/net/8139too.c

@@ -569,7 +569,7 @@ struct rtl_extra_stats {
 };
 
 struct rtl8139_private {
-	void *mmio_addr;
+	void __iomem *mmio_addr;
 	int drv_flags;
 	struct pci_dev *pci_dev;
 	u32 msg_enable;
@@ -614,7 +614,7 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered mu
 MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");
 MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)");
 
-static int read_eeprom (void *ioaddr, int location, int addr_len);
+static int read_eeprom (void __iomem *ioaddr, int location, int addr_len);
 static int rtl8139_open (struct net_device *dev);
 static int mdio_read (struct net_device *dev, int phy_id, int location);
 static void mdio_write (struct net_device *dev, int phy_id, int location,
@@ -638,46 +638,20 @@ static void __set_rx_mode (struct net_device *dev);
 static void rtl8139_hw_start (struct net_device *dev);
 static struct ethtool_ops rtl8139_ethtool_ops;
 
-#ifdef USE_IO_OPS
-
-#define RTL_R8(reg)		inb (((unsigned long)ioaddr) + (reg))
-#define RTL_R16(reg)		inw (((unsigned long)ioaddr) + (reg))
-#define RTL_R32(reg)		((unsigned long) inl (((unsigned long)ioaddr) + (reg)))
-#define RTL_W8(reg, val8)	outb ((val8), ((unsigned long)ioaddr) + (reg))
-#define RTL_W16(reg, val16)	outw ((val16), ((unsigned long)ioaddr) + (reg))
-#define RTL_W32(reg, val32)	outl ((val32), ((unsigned long)ioaddr) + (reg))
-#define RTL_W8_F		RTL_W8
-#define RTL_W16_F		RTL_W16
-#define RTL_W32_F		RTL_W32
-#undef readb
-#undef readw
-#undef readl
-#undef writeb
-#undef writew
-#undef writel
-#define readb(addr) inb((unsigned long)(addr))
-#define readw(addr) inw((unsigned long)(addr))
-#define readl(addr) inl((unsigned long)(addr))
-#define writeb(val,addr) outb((val),(unsigned long)(addr))
-#define writew(val,addr) outw((val),(unsigned long)(addr))
-#define writel(val,addr) outl((val),(unsigned long)(addr))
-
-#else
-
 /* write MMIO register, with flush */
 /* Flush avoids rtl8139 bug w/ posted MMIO writes */
-#define RTL_W8_F(reg, val8)	do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0)
-#define RTL_W16_F(reg, val16)	do { writew ((val16), ioaddr + (reg)); readw (ioaddr + (reg)); } while (0)
-#define RTL_W32_F(reg, val32)	do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)
+#define RTL_W8_F(reg, val8)	do { iowrite8 ((val8), ioaddr + (reg)); ioread8 (ioaddr + (reg)); } while (0)
+#define RTL_W16_F(reg, val16)	do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0)
+#define RTL_W32_F(reg, val32)	do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0)
 
 
 #define MMIO_FLUSH_AUDIT_COMPLETE 1
 #if MMIO_FLUSH_AUDIT_COMPLETE
 
 /* write MMIO register */
-#define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
-#define RTL_W16(reg, val16)	writew ((val16), ioaddr + (reg))
-#define RTL_W32(reg, val32)	writel ((val32), ioaddr + (reg))
+#define RTL_W8(reg, val8)	iowrite8 ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16)	iowrite16 ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32)	iowrite32 ((val32), ioaddr + (reg))
 
 #else
 
@@ -689,11 +663,9 @@ static struct ethtool_ops rtl8139_ethtool_ops;
 #endif /* MMIO_FLUSH_AUDIT_COMPLETE */
 
 /* read MMIO register */
-#define RTL_R8(reg)		readb (ioaddr + (reg))
-#define RTL_R16(reg)		readw (ioaddr + (reg))
-#define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
-
-#endif /* USE_IO_OPS */
+#define RTL_R8(reg)		ioread8 (ioaddr + (reg))
+#define RTL_R16(reg)		ioread16 (ioaddr + (reg))
+#define RTL_R32(reg)		((unsigned long) ioread32 (ioaddr + (reg)))
 
 
 static const u16 rtl8139_intr_mask =
@@ -740,10 +712,13 @@ static void __rtl8139_cleanup_dev (struct net_device *dev)
 	assert (tp->pci_dev != NULL);
 	pdev = tp->pci_dev;
 
-#ifndef USE_IO_OPS
+#ifdef USE_IO_OPS
+	if (tp->mmio_addr)
+		ioport_unmap (tp->mmio_addr);
+#else
 	if (tp->mmio_addr)
-		iounmap (tp->mmio_addr);
-#endif /* !USE_IO_OPS */
+		pci_iounmap (pdev, tp->mmio_addr);
+#endif /* USE_IO_OPS */
 
 	/* it's ok to call this even if we have no regions to free */
 	pci_release_regions (pdev);
@@ -753,7 +728,7 @@ static void __rtl8139_cleanup_dev (struct net_device *dev)
 }
 
 
-static void rtl8139_chip_reset (void *ioaddr)
+static void rtl8139_chip_reset (void __iomem *ioaddr)
 {
 	int i;
 
@@ -773,7 +748,7 @@ static void rtl8139_chip_reset (void *ioaddr)
 static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 					 struct net_device **dev_out)
 {
-	void *ioaddr;
+	void __iomem *ioaddr;
 	struct net_device *dev;
 	struct rtl8139_private *tp;
 	u8 tmp8;
@@ -855,13 +830,18 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 	pci_set_master (pdev);
 
 #ifdef USE_IO_OPS
-	ioaddr = (void *) pio_start;
+	ioaddr = ioport_map(pio_start, pio_len);
+	if (!ioaddr) {
+		printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
+		rc = -EIO;
+		goto err_out;
+	}
 	dev->base_addr = pio_start;
 	tp->mmio_addr = ioaddr;
 	tp->regs_len = pio_len;
 #else
 	/* ioremap MMIO region */
-	ioaddr = ioremap (mmio_start, mmio_len);
+	ioaddr = pci_iomap(pdev, 1, 0);
 	if (ioaddr == NULL) {
 		printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
 		rc = -EIO;
@@ -947,7 +927,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
 	struct net_device *dev = NULL;
 	struct rtl8139_private *tp;
 	int i, addr_len, option;
-	void *ioaddr;
+	void __iomem *ioaddr;
 	static int board_idx = -1;
 	u8 pci_rev;
 
@@ -1147,47 +1127,46 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
    No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
  */
 
-#define eeprom_delay()	readl(ee_addr)
+#define eeprom_delay()	RTL_R32(Cfg9346)
 
 /* The EEPROM commands include the alway-set leading bit. */
 #define EE_WRITE_CMD	(5)
 #define EE_READ_CMD		(6)
 #define EE_ERASE_CMD	(7)
 
-static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
+static int __devinit read_eeprom (void __iomem *ioaddr, int location, int addr_len)
 {
 	int i;
 	unsigned retval = 0;
-	void *ee_addr = ioaddr + Cfg9346;
 	int read_cmd = location | (EE_READ_CMD << addr_len);
 
-	writeb (EE_ENB & ~EE_CS, ee_addr);
-	writeb (EE_ENB, ee_addr);
+	RTL_W8 (Cfg9346, EE_ENB & ~EE_CS);
+	RTL_W8 (Cfg9346, EE_ENB);
 	eeprom_delay ();
 
 	/* Shift the read command bits out. */
 	for (i = 4 + addr_len; i >= 0; i--) {
 		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
-		writeb (EE_ENB | dataval, ee_addr);
+		RTL_W8 (Cfg9346, EE_ENB | dataval);
 		eeprom_delay ();
-		writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK);
 		eeprom_delay ();
 	}
-	writeb (EE_ENB, ee_addr);
+	RTL_W8 (Cfg9346, EE_ENB);
 	eeprom_delay ();
 
 	for (i = 16; i > 0; i--) {
-		writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
+		RTL_W8 (Cfg9346, EE_ENB | EE_SHIFT_CLK);
 		eeprom_delay ();
 		retval =
-		    (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 :
+		    (retval << 1) | ((RTL_R8 (Cfg9346) & EE_DATA_READ) ? 1 :
 				     0);
-		writeb (EE_ENB, ee_addr);
+		RTL_W8 (Cfg9346, EE_ENB);
 		eeprom_delay ();
 	}
 
 	/* Terminate the EEPROM access. */
-	writeb (~EE_CS, ee_addr);
+	RTL_W8 (Cfg9346, ~EE_CS);
 	eeprom_delay ();
 
 	return retval;
@@ -1206,7 +1185,7 @@ static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
 #define MDIO_WRITE0 (MDIO_DIR)
 #define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
 
-#define mdio_delay(mdio_addr)	readb(mdio_addr)
+#define mdio_delay()	RTL_R8(Config4)
 
 
 static char mii_2_8139_map[8] = {
@@ -1223,15 +1202,15 @@ static char mii_2_8139_map[8] = {
 
 #ifdef CONFIG_8139TOO_8129
 /* Syncronize the MII management interface by shifting 32 one bits out. */
-static void mdio_sync (void *mdio_addr)
+static void mdio_sync (void __iomem *ioaddr)
 {
 	int i;
 
 	for (i = 32; i >= 0; i--) {
-		writeb (MDIO_WRITE1, mdio_addr);
-		mdio_delay (mdio_addr);
-		writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr);
-		mdio_delay (mdio_addr);
+		RTL_W8 (Config4, MDIO_WRITE1);
+		mdio_delay ();
+		RTL_W8 (Config4, MDIO_WRITE1 | MDIO_CLK);
+		mdio_delay ();
 	}
 }
 #endif
@@ -1241,35 +1220,36 @@ static int mdio_read (struct net_device *dev, int phy_id, int location)
 	struct rtl8139_private *tp = netdev_priv(dev);
 	int retval = 0;
 #ifdef CONFIG_8139TOO_8129
-	void *mdio_addr = tp->mmio_addr + Config4;
+	void __iomem *ioaddr = tp->mmio_addr;
 	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	int i;
 #endif
 
 	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
+		void __iomem *ioaddr = tp->mmio_addr;
 		return location < 8 && mii_2_8139_map[location] ?
-		    readw (tp->mmio_addr + mii_2_8139_map[location]) : 0;
+		    RTL_R16 (mii_2_8139_map[location]) : 0;
 	}
 
 #ifdef CONFIG_8139TOO_8129
-	mdio_sync (mdio_addr);
+	mdio_sync (ioaddr);
 	/* Shift the read command bits out. */
 	for (i = 15; i >= 0; i--) {
 		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
 
-		writeb (MDIO_DIR | dataval, mdio_addr);
-		mdio_delay (mdio_addr);
-		writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
-		mdio_delay (mdio_addr);
+		RTL_W8 (Config4, MDIO_DIR | dataval);
+		mdio_delay ();
+		RTL_W8 (Config4, MDIO_DIR | dataval | MDIO_CLK);
+		mdio_delay ();
 	}
 
 	/* Read the two transition, 16 data, and wire-idle bits. */
 	for (i = 19; i > 0; i--) {
-		writeb (0, mdio_addr);
-		mdio_delay (mdio_addr);
-		retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
-		writeb (MDIO_CLK, mdio_addr);
-		mdio_delay (mdio_addr);
+		RTL_W8 (Config4, 0);
+		mdio_delay ();
+		retval = (retval << 1) | ((RTL_R8 (Config4) & MDIO_DATA_IN) ? 1 : 0);
+		RTL_W8 (Config4, MDIO_CLK);
+		mdio_delay ();
 	}
 #endif
 
@@ -1282,13 +1262,13 @@ static void mdio_write (struct net_device *dev, int phy_id, int location,
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
 #ifdef CONFIG_8139TOO_8129
-	void *mdio_addr = tp->mmio_addr + Config4;
+	void __iomem *ioaddr = tp->mmio_addr;
 	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
 	int i;
 #endif
 
 	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
-		void *ioaddr = tp->mmio_addr;
+		void __iomem *ioaddr = tp->mmio_addr;
 		if (location == 0) {
 			RTL_W8 (Cfg9346, Cfg9346_Unlock);
 			RTL_W16 (BasicModeCtrl, value);
@@ -1299,23 +1279,23 @@ static void mdio_write (struct net_device *dev, int phy_id, int location,
 	}
 
 #ifdef CONFIG_8139TOO_8129
-	mdio_sync (mdio_addr);
+	mdio_sync (ioaddr);
 
 	/* Shift the command bits out. */
 	for (i = 31; i >= 0; i--) {
 		int dataval =
 		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-		writeb (dataval, mdio_addr);
-		mdio_delay (mdio_addr);
-		writeb (dataval | MDIO_CLK, mdio_addr);
-		mdio_delay (mdio_addr);
+		RTL_W8 (Config4, dataval);
+		mdio_delay ();
+		RTL_W8 (Config4, dataval | MDIO_CLK);
+		mdio_delay ();
 	}
 	/* Clear out extra bits. */
 	for (i = 2; i > 0; i--) {
-		writeb (0, mdio_addr);
-		mdio_delay (mdio_addr);
-		writeb (MDIO_CLK, mdio_addr);
-		mdio_delay (mdio_addr);
+		RTL_W8 (Config4, 0);
+		mdio_delay ();
+		RTL_W8 (Config4, MDIO_CLK);
+		mdio_delay ();
 	}
 #endif
 }
@@ -1325,7 +1305,7 @@ static int rtl8139_open (struct net_device *dev)
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
 	int retval;
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 
 	retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
 	if (retval)
@@ -1382,7 +1362,7 @@ static void rtl_check_media (struct net_device *dev, unsigned int init_media)
 static void rtl8139_hw_start (struct net_device *dev)
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	u32 i;
 	u8 tmp;
 
@@ -1484,7 +1464,7 @@ static void rtl8139_tune_twister (struct net_device *dev,
 				  struct rtl8139_private *tp)
 {
 	int linkcase;
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 
 	/* This is a complicated state machine to configure the "twister" for
 	   impedance/echos based on the cable length.
@@ -1568,7 +1548,7 @@ static void rtl8139_tune_twister (struct net_device *dev,
 
 static inline void rtl8139_thread_iter (struct net_device *dev,
 				 struct rtl8139_private *tp,
-				 void *ioaddr)
+				 void __iomem *ioaddr)
 {
 	int mii_lpa;
 
@@ -1676,7 +1656,7 @@ static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
 static void rtl8139_tx_timeout (struct net_device *dev)
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	int i;
 	u8 tmp8;
 	unsigned long flags;
@@ -1721,7 +1701,7 @@ static void rtl8139_tx_timeout (struct net_device *dev)
 static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	unsigned int entry;
 	unsigned int len = skb->len;
 
@@ -1763,7 +1743,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
 
 static void rtl8139_tx_interrupt (struct net_device *dev,
 				  struct rtl8139_private *tp,
-				  void *ioaddr)
+				  void __iomem *ioaddr)
 {
 	unsigned long dirty_tx, tx_left;
 
@@ -1833,7 +1813,7 @@ static void rtl8139_tx_interrupt (struct net_device *dev,
 
 /* TODO: clean this up!  Rx reset need not be this intensive */
 static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
-			    struct rtl8139_private *tp, void *ioaddr)
+			    struct rtl8139_private *tp, void __iomem *ioaddr)
 {
 	u8 tmp8;
 #ifdef CONFIG_8139_OLD_RX_RESET
@@ -1930,7 +1910,7 @@ static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring,
 
 static void rtl8139_isr_ack(struct rtl8139_private *tp)
 {
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	u16 status;
 
 	status = RTL_R16 (IntrStatus) & RxAckBits;
@@ -1949,7 +1929,7 @@ static void rtl8139_isr_ack(struct rtl8139_private *tp)
 static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
 		      int budget)
 {
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	int received = 0;
 	unsigned char *rx_ring = tp->rx_ring;
 	unsigned int cur_rx = tp->cur_rx;
@@ -2087,7 +2067,7 @@ out:
 
 static void rtl8139_weird_interrupt (struct net_device *dev,
 				     struct rtl8139_private *tp,
-				     void *ioaddr,
+				     void __iomem *ioaddr,
 				     int status, int link_changed)
 {
 	DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
@@ -2127,7 +2107,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
 static int rtl8139_poll(struct net_device *dev, int *budget)
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	int orig_budget = min(*budget, dev->quota);
 	int done = 1;
 
@@ -2165,7 +2145,7 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
 	struct rtl8139_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	u16 status, ackstat;
 	int link_changed = 0; /* avoid bogus "uninit" warning */
 	int handled = 0;
@@ -2241,7 +2221,7 @@ static void rtl8139_poll_controller(struct net_device *dev)
 static int rtl8139_close (struct net_device *dev)
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	int ret = 0;
 	unsigned long flags;
 
@@ -2304,7 +2284,7 @@ static int rtl8139_close (struct net_device *dev)
 static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct rtl8139_private *np = netdev_priv(dev);
-	void *ioaddr = np->mmio_addr;
+	void __iomem *ioaddr = np->mmio_addr;
 
 	spin_lock_irq(&np->lock);
 	if (rtl_chip_info[np->chipset].flags & HasLWake) {
@@ -2338,7 +2318,7 @@ static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct rtl8139_private *np = netdev_priv(dev);
-	void *ioaddr = np->mmio_addr;
+	void __iomem *ioaddr = np->mmio_addr;
 	u32 support;
 	u8 cfg3, cfg5;
 
@@ -2506,7 +2486,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
 	if (netif_running(dev)) {
@@ -2525,7 +2505,7 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
 static void __set_rx_mode (struct net_device *dev)
 {
 	struct rtl8139_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int i, rx_mode;
 	u32 tmp;
@@ -2586,7 +2566,7 @@ static int rtl8139_suspend (struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct rtl8139_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
+	void __iomem *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
 	pci_save_state (pdev);

+ 24 - 23
drivers/net/Kconfig

@@ -824,6 +824,18 @@ config SMC9194
 	  <file:Documentation/networking/net-modules.txt>. The module
 	  will be called smc9194.
 
+config DM9000
+	tristate "DM9000 support"
+	depends on ARM && NET_ETHERNET
+	select CRC32
+	select MII
+	---help---
+	  Support for DM9000 chipset.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/networking/net-modules.txt>.  The module will be
+	  called dm9000.
+
 config NET_VENDOR_RACAL
 	bool "Racal-Interlan (Micom) NI cards"
 	depends on NET_ETHERNET && ISA
@@ -989,21 +1001,6 @@ config EEXPRESS_PRO
 	  <file:Documentation/networking/net-modules.txt>. The module
 	  will be called eepro.
 
-config FMV18X
-	tristate "FMV-181/182/183/184 support (OBSOLETE)"
-	depends on NET_ISA && OBSOLETE
-	---help---
-	  If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card,
-	  say Y and read the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  If you use an FMV-183 or FMV-184 and it is not working, you may need
-	  to disable Plug & Play mode of the card.
-
-	  To compile this driver as a module, choose M here and read
-	  <file:Documentation/networking/net-modules.txt>. The module
-	  will be called fmv18x.
-
 config HPLAN_PLUS
 	tristate "HP PCLAN+ (27247B and 27252A) support"
 	depends on NET_ISA
@@ -1092,14 +1089,6 @@ config SEEQ8005
 	  <file:Documentation/networking/net-modules.txt>. The module
 	  will be called seeq8005.
 
-config SK_G16
-	tristate "SK_G16 support (OBSOLETE)"
-	depends on NET_ISA && OBSOLETE
-	help
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
 config SKMC
 	tristate "SKnet MCA support"
 	depends on NET_ETHERNET && MCA && BROKEN
@@ -1932,6 +1921,18 @@ config R8169_VLAN
 	  
 	  If in doubt, say Y.
 
+config SKGE
+	tristate "New SysKonnect GigaEthernet support (EXPERIMENTAL)"
+	depends on PCI && EXPERIMENTAL
+	select CRC32
+	---help---
+	  This driver support the Marvell Yukon or SysKonnect SK-98xx/SK-95xx
+	  and related Gigabit Ethernet adapters. It is a new smaller driver
+	  driver with better performance and more complete ethtool support.
+
+	  It does not support the link failover and network management 
+	  features that "portable" vendor supplied sk98lin driver does.
+	
 config SK98LIN
 	tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
 	depends on PCI

+ 2 - 2
drivers/net/Makefile

@@ -53,6 +53,7 @@ obj-$(CONFIG_FEALNX) += fealnx.o
 obj-$(CONFIG_TIGON3) += tg3.o
 obj-$(CONFIG_BNX2) += bnx2.o
 obj-$(CONFIG_TC35815) += tc35815.o
+obj-$(CONFIG_SKGE) += skge.o
 obj-$(CONFIG_SK98LIN) += sk98lin/
 obj-$(CONFIG_SKFP) += skfp/
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o
@@ -74,7 +75,6 @@ obj-$(CONFIG_MAC8390) += mac8390.o 8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
 obj-$(CONFIG_SHAPER) += shaper.o
-obj-$(CONFIG_SK_G16) += sk_g16.o
 obj-$(CONFIG_HP100) += hp100.o
 obj-$(CONFIG_SMC9194) += smc9194.o
 obj-$(CONFIG_FEC) += fec.o
@@ -122,7 +122,6 @@ obj-$(CONFIG_DEFXX) += defxx.o
 obj-$(CONFIG_SGISEEQ) += sgiseeq.o
 obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
 obj-$(CONFIG_AT1700) += at1700.o
-obj-$(CONFIG_FMV18X) += fmv18x.o
 obj-$(CONFIG_EL1) += 3c501.o
 obj-$(CONFIG_EL16) += 3c507.o
 obj-$(CONFIG_ELMC) += 3c523.o
@@ -180,6 +179,7 @@ obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
 obj-$(CONFIG_IBMVETH) += ibmveth.o
 obj-$(CONFIG_S2IO) += s2io.o
 obj-$(CONFIG_SMC91X) += smc91x.o
+obj-$(CONFIG_DM9000) += dm9000.o
 obj-$(CONFIG_FEC_8XX) += fec_8xx/
 
 obj-$(CONFIG_ARM) += arm/

+ 0 - 6
drivers/net/Space.c

@@ -210,9 +210,6 @@ static struct devprobe2 isa_probes[] __initdata = {
 #ifdef CONFIG_AT1700
 	{at1700_probe, 0},
 #endif
-#ifdef CONFIG_FMV18X		/* Fujitsu FMV-181/182 */
-	{fmv18x_probe, 0},
-#endif
 #ifdef CONFIG_ETH16I
 	{eth16i_probe, 0},	/* ICL EtherTeam 16i/32 */
 #endif
@@ -243,9 +240,6 @@ static struct devprobe2 isa_probes[] __initdata = {
 #ifdef CONFIG_ELPLUS		/* 3c505 */
 	{elplus_probe, 0},
 #endif
-#ifdef CONFIG_SK_G16
-	{SK_init, 0},
-#endif
 #ifdef CONFIG_NI5010
 	{ni5010_probe, 0},
 #endif

+ 9 - 7
drivers/net/arm/etherh.c

@@ -68,6 +68,7 @@ struct etherh_priv {
 	void __iomem	*dma_base;
 	unsigned int	id;
 	void __iomem	*ctrl_port;
+	void __iomem	*base;
 	unsigned char	ctrl;
 	u32		supported;
 };
@@ -177,7 +178,7 @@ etherh_setif(struct net_device *dev)
 	switch (etherh_priv(dev)->id) {
 	case PROD_I3_ETHERLAN600:
 	case PROD_I3_ETHERLAN600A:
-		addr = (void *)dev->base_addr + EN0_RCNTHI;
+		addr = etherh_priv(dev)->base + EN0_RCNTHI;
 
 		switch (dev->if_port) {
 		case IF_PORT_10BASE2:
@@ -218,7 +219,7 @@ etherh_getifstat(struct net_device *dev)
 	switch (etherh_priv(dev)->id) {
 	case PROD_I3_ETHERLAN600:
 	case PROD_I3_ETHERLAN600A:
-		addr = (void *)dev->base_addr + EN0_RCNTHI;
+		addr = etherh_priv(dev)->base + EN0_RCNTHI;
 		switch (dev->if_port) {
 		case IF_PORT_10BASE2:
 			stat = 1;
@@ -281,7 +282,7 @@ static void
 etherh_reset(struct net_device *dev)
 {
 	struct ei_device *ei_local = netdev_priv(dev);
-	void __iomem *addr = (void *)dev->base_addr;
+	void __iomem *addr = etherh_priv(dev)->base;
 
 	writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr);
 
@@ -327,7 +328,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf
 
 	ei_local->dmaing = 1;
 
-	addr = (void *)dev->base_addr;
+	addr = etherh_priv(dev)->base;
 	dma_base = etherh_priv(dev)->dma_base;
 
 	count = (count + 1) & ~1;
@@ -387,7 +388,7 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int
 
 	ei_local->dmaing = 1;
 
-	addr = (void *)dev->base_addr;
+	addr = etherh_priv(dev)->base;
 	dma_base = etherh_priv(dev)->dma_base;
 
 	buf = skb->data;
@@ -427,7 +428,7 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p
 
 	ei_local->dmaing = 1;
 
-	addr = (void *)dev->base_addr;
+	addr = etherh_priv(dev)->base;
 	dma_base = etherh_priv(dev)->dma_base;
 
 	writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
@@ -696,7 +697,8 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
 		eh->ctrl_port = eh->ioc_fast;
 	}
 
-	dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset;
+	eh->base = eh->memc + data->ns8390_offset;
+	dev->base_addr = (unsigned long)eh->base;
 	eh->dma_base = eh->memc + data->dataport_offset;
 	eh->ctrl_port += data->ctrlport_offset;
 

+ 2 - 8
drivers/net/au1000_eth.c

@@ -1681,10 +1681,6 @@ static int au1000_init(struct net_device *dev)
 		control |= MAC_FULL_DUPLEX;
 	}
 
-	/* fix for startup without cable */
-	if (!link) 
-		dev->flags &= ~IFF_RUNNING;
-
 	aup->mac->control = control;
 	aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
 	au_sync();
@@ -1709,16 +1705,14 @@ static void au1000_timer(unsigned long data)
 	if_port = dev->if_port;
 	if (aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed) == 0) {
 		if (link) {
-			if (!(dev->flags & IFF_RUNNING)) {
+			if (!netif_carrier_ok(dev)) {
 				netif_carrier_on(dev);
-				dev->flags |= IFF_RUNNING;
 				printk(KERN_INFO "%s: link up\n", dev->name);
 			}
 		}
 		else {
-			if (dev->flags & IFF_RUNNING) {
+			if (netif_carrier_ok(dev)) {
 				netif_carrier_off(dev);
-				dev->flags &= ~IFF_RUNNING;
 				dev->if_port = 0;
 				printk(KERN_INFO "%s: link down\n", dev->name);
 			}

+ 0 - 2
drivers/net/bmac.c

@@ -1412,7 +1412,6 @@ static int bmac_open(struct net_device *dev)
 	bp->opened = 1;
 	bmac_reset_and_enable(dev);
 	enable_irq(dev->irq);
-	dev->flags |= IFF_RUNNING;
 	return 0;
 }
 
@@ -1425,7 +1424,6 @@ static int bmac_close(struct net_device *dev)
 	int i;
 
 	bp->sleeping = 1;
-	dev->flags &= ~(IFF_UP | IFF_RUNNING);
 
 	/* disable rx and tx */
 	config = bmread(dev, RXCFG);

+ 1219 - 0
drivers/net/dm9000.c

@@ -0,0 +1,1219 @@
+/*
+ *   dm9000.c: Version 1.2 03/18/2003
+ *
+ *         A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
+ * 	Copyright (C) 1997  Sten Wang
+ *
+ * 	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.
+ *
+ *   (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
+ *
+ * V0.11	06/20/2001	REG_0A bit3=1, default enable BP with DA match
+ * 	06/22/2001 	Support DM9801 progrmming
+ * 	 	 	E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
+ * 		 	E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
+ * 		     		R17 = (R17 & 0xfff0) | NF + 3
+ * 		 	E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
+ * 		     		R17 = (R17 & 0xfff0) | NF
+ *
+ * v1.00               	modify by simon 2001.9.5
+ *                         change for kernel 2.4.x
+ *
+ * v1.1   11/09/2001      	fix force mode bug
+ *
+ * v1.2   03/18/2003       Weilun Huang <weilun_huang@davicom.com.tw>:
+ * 			Fixed phy reset.
+ * 			Added tx/rx 32 bit mode.
+ * 			Cleaned up for kernel merge.
+ *
+ *        03/03/2004    Sascha Hauer <s.hauer@pengutronix.de>
+ *                      Port to 2.6 kernel
+ *
+ *	  24-Sep-2004   Ben Dooks <ben@simtec.co.uk>
+ *			Cleanup of code to remove ifdefs
+ *			Allowed platform device data to influence access width
+ *			Reformatting areas of code
+ *
+ *        17-Mar-2005   Sascha Hauer <s.hauer@pengutronix.de>
+ *                      * removed 2.4 style module parameters
+ *                      * removed removed unused stat counter and fixed
+ *                        net_device_stats
+ *                      * introduced tx_timeout function
+ *                      * reworked locking
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/dm9000.h>
+#include <linux/delay.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include "dm9000.h"
+
+/* Board/System/Debug information/definition ---------------- */
+
+#define DM9000_PHY		0x40	/* PHY address 0x01 */
+
+#define TRUE			1
+#define FALSE			0
+
+#define CARDNAME "dm9000"
+#define PFX CARDNAME ": "
+
+#define DM9000_TIMER_WUT  jiffies+(HZ*2)	/* timer wakeup time : 2 second */
+
+#define DM9000_DEBUG 0
+
+#if DM9000_DEBUG > 2
+#define PRINTK3(args...)  printk(CARDNAME ": " args)
+#else
+#define PRINTK3(args...)  do { } while(0)
+#endif
+
+#if DM9000_DEBUG > 1
+#define PRINTK2(args...)  printk(CARDNAME ": " args)
+#else
+#define PRINTK2(args...)  do { } while(0)
+#endif
+
+#if DM9000_DEBUG > 0
+#define PRINTK1(args...)  printk(CARDNAME ": " args)
+#define PRINTK(args...)   printk(CARDNAME ": " args)
+#else
+#define PRINTK1(args...)  do { } while(0)
+#define PRINTK(args...)   printk(KERN_DEBUG args)
+#endif
+
+/*
+ * Transmit timeout, default 5 seconds.
+ */
+static int watchdog = 5000;
+module_param(watchdog, int, 0400);
+MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
+
+/* Structure/enum declaration ------------------------------- */
+typedef struct board_info {
+
+	void __iomem *io_addr;	/* Register I/O base address */
+	void __iomem *io_data;	/* Data I/O address */
+	u16 irq;		/* IRQ */
+
+	u16 tx_pkt_cnt;
+	u16 queue_pkt_len;
+	u16 queue_start_addr;
+	u16 dbug_cnt;
+	u8 io_mode;		/* 0:word, 2:byte */
+	u8 phy_addr;
+
+	void (*inblk)(void __iomem *port, void *data, int length);
+	void (*outblk)(void __iomem *port, void *data, int length);
+	void (*dumpblk)(void __iomem *port, int length);
+
+	struct resource	*addr_res;   /* resources found */
+	struct resource *data_res;
+	struct resource	*addr_req;   /* resources requested */
+	struct resource *data_req;
+	struct resource *irq_res;
+
+	struct timer_list timer;
+	struct net_device_stats stats;
+	unsigned char srom[128];
+	spinlock_t lock;
+
+	struct mii_if_info mii;
+	u32 msg_enable;
+} board_info_t;
+
+/* function declaration ------------------------------------- */
+static int dm9000_probe(struct device *);
+static int dm9000_open(struct net_device *);
+static int dm9000_start_xmit(struct sk_buff *, struct net_device *);
+static int dm9000_stop(struct net_device *);
+static int dm9000_do_ioctl(struct net_device *, struct ifreq *, int);
+
+
+static void dm9000_timer(unsigned long);
+static void dm9000_init_dm9000(struct net_device *);
+
+static struct net_device_stats *dm9000_get_stats(struct net_device *);
+
+static irqreturn_t dm9000_interrupt(int, void *, struct pt_regs *);
+
+static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg);
+static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg,
+			   int value);
+static u16 read_srom_word(board_info_t *, int);
+static void dm9000_rx(struct net_device *);
+static void dm9000_hash_table(struct net_device *);
+
+//#define DM9000_PROGRAM_EEPROM
+#ifdef DM9000_PROGRAM_EEPROM
+static void program_eeprom(board_info_t * db);
+#endif
+/* DM9000 network board routine ---------------------------- */
+
+static void
+dm9000_reset(board_info_t * db)
+{
+	PRINTK1("dm9000x: resetting\n");
+	/* RESET device */
+	writeb(DM9000_NCR, db->io_addr);
+	udelay(200);
+	writeb(NCR_RST, db->io_data);
+	udelay(200);
+}
+
+/*
+ *   Read a byte from I/O port
+ */
+static u8
+ior(board_info_t * db, int reg)
+{
+	writeb(reg, db->io_addr);
+	return readb(db->io_data);
+}
+
+/*
+ *   Write a byte to I/O port
+ */
+
+static void
+iow(board_info_t * db, int reg, int value)
+{
+	writeb(reg, db->io_addr);
+	writeb(value, db->io_data);
+}
+
+/* routines for sending block to chip */
+
+static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count)
+{
+	writesb(reg, data, count);
+}
+
+static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count)
+{
+	writesw(reg, data, (count+1) >> 1);
+}
+
+static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count)
+{
+	writesl(reg, data, (count+3) >> 2);
+}
+
+/* input block from chip to memory */
+
+static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count)
+{
+	readsb(reg, data, count+1);
+}
+
+
+static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count)
+{
+	readsw(reg, data, (count+1) >> 1);
+}
+
+static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count)
+{
+	readsl(reg, data, (count+3) >> 2);
+}
+
+/* dump block from chip to null */
+
+static void dm9000_dumpblk_8bit(void __iomem *reg, int count)
+{
+	int i;
+	int tmp;
+
+	for (i = 0; i < count; i++)
+		tmp = readb(reg);
+}
+
+static void dm9000_dumpblk_16bit(void __iomem *reg, int count)
+{
+	int i;
+	int tmp;
+
+	count = (count + 1) >> 1;
+
+	for (i = 0; i < count; i++)
+		tmp = readw(reg);
+}
+
+static void dm9000_dumpblk_32bit(void __iomem *reg, int count)
+{
+	int i;
+	int tmp;
+
+	count = (count + 3) >> 2;
+
+	for (i = 0; i < count; i++)
+		tmp = readl(reg);
+}
+
+/* dm9000_set_io
+ *
+ * select the specified set of io routines to use with the
+ * device
+ */
+
+static void dm9000_set_io(struct board_info *db, int byte_width)
+{
+	/* use the size of the data resource to work out what IO
+	 * routines we want to use
+	 */
+
+	switch (byte_width) {
+	case 1:
+		db->dumpblk = dm9000_dumpblk_8bit;
+		db->outblk  = dm9000_outblk_8bit;
+		db->inblk   = dm9000_inblk_8bit;
+		break;
+
+	case 2:
+		db->dumpblk = dm9000_dumpblk_16bit;
+		db->outblk  = dm9000_outblk_16bit;
+		db->inblk   = dm9000_inblk_16bit;
+		break;
+
+	case 3:
+		printk(KERN_ERR PFX ": 3 byte IO, falling back to 16bit\n");
+		db->dumpblk = dm9000_dumpblk_16bit;
+		db->outblk  = dm9000_outblk_16bit;
+		db->inblk   = dm9000_inblk_16bit;
+		break;
+
+	case 4:
+	default:
+		db->dumpblk = dm9000_dumpblk_32bit;
+		db->outblk  = dm9000_outblk_32bit;
+		db->inblk   = dm9000_inblk_32bit;
+		break;
+	}
+}
+
+
+/* Our watchdog timed out. Called by the networking layer */
+static void dm9000_timeout(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+	u8 reg_save;
+	unsigned long flags;
+
+	/* Save previous register address */
+	reg_save = readb(db->io_addr);
+	spin_lock_irqsave(db->lock,flags);
+
+	netif_stop_queue(dev);
+	dm9000_reset(db);
+	dm9000_init_dm9000(dev);
+	/* We can accept TX packets again */
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+
+	/* Restore previous register address */
+	writeb(reg_save, db->io_addr);
+	spin_unlock_irqrestore(db->lock,flags);
+}
+
+
+/* dm9000_release_board
+ *
+ * release a board, and any mapped resources
+ */
+
+static void
+dm9000_release_board(struct platform_device *pdev, struct board_info *db)
+{
+	if (db->data_res == NULL) {
+		if (db->addr_res != NULL)
+			release_mem_region((unsigned long)db->io_addr, 4);
+		return;
+	}
+
+	/* unmap our resources */
+
+	iounmap(db->io_addr);
+	iounmap(db->io_data);
+
+	/* release the resources */
+
+	if (db->data_req != NULL) {
+		release_resource(db->data_req);
+		kfree(db->data_req);
+	}
+
+	if (db->addr_res != NULL) {
+		release_resource(db->data_req);
+		kfree(db->addr_req);
+	}
+}
+
+#define res_size(_r) (((_r)->end - (_r)->start) + 1)
+
+/*
+ * Search DM9000 board, allocate space and register it
+ */
+static int
+dm9000_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dm9000_plat_data *pdata = pdev->dev.platform_data;
+	struct board_info *db;	/* Point a board information structure */
+	struct net_device *ndev;
+	unsigned long base;
+	int ret = 0;
+	int iosize;
+	int i;
+	u32 id_val;
+
+	printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME);
+
+	/* Init network device */
+	ndev = alloc_etherdev(sizeof (struct board_info));
+	if (!ndev) {
+		printk("%s: could not allocate device.\n", CARDNAME);
+		return -ENOMEM;
+	}
+
+	SET_MODULE_OWNER(ndev);
+	SET_NETDEV_DEV(ndev, dev);
+
+	PRINTK2("dm9000_probe()");
+
+	/* setup board info structure */
+	db = (struct board_info *) ndev->priv;
+	memset(db, 0, sizeof (*db));
+
+	if (pdev->num_resources < 2) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	switch (pdev->num_resources) {
+	case 2:
+		base = pdev->resource[0].start;
+
+		if (!request_mem_region(base, 4, ndev->name)) {
+			ret = -EBUSY;
+			goto out;
+		}
+
+		ndev->base_addr = base;
+		ndev->irq = pdev->resource[1].start;
+		db->io_addr = (void *)base;
+		db->io_data = (void *)(base + 4);
+
+		break;
+
+	case 3:
+		db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+		if (db->addr_res == NULL || db->data_res == NULL) {
+			printk(KERN_ERR PFX "insufficient resources\n");
+			ret = -ENOENT;
+			goto out;
+		}
+
+		i = res_size(db->addr_res);
+		db->addr_req = request_mem_region(db->addr_res->start, i,
+						  pdev->name);
+
+		if (db->addr_req == NULL) {
+			printk(KERN_ERR PFX "cannot claim address reg area\n");
+			ret = -EIO;
+			goto out;
+		}
+
+		db->io_addr = ioremap(db->addr_res->start, i);
+
+		if (db->io_addr == NULL) {
+			printk(KERN_ERR "failed to ioremap address reg\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		iosize = res_size(db->data_res);
+		db->data_req = request_mem_region(db->data_res->start, iosize,
+						  pdev->name);
+
+		if (db->data_req == NULL) {
+			printk(KERN_ERR PFX "cannot claim data reg area\n");
+			ret = -EIO;
+			goto out;
+		}
+
+		db->io_data = ioremap(db->data_res->start, iosize);
+
+		if (db->io_data == NULL) {
+			printk(KERN_ERR "failed to ioremap data reg\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		/* fill in parameters for net-dev structure */
+
+		ndev->base_addr = (unsigned long)db->io_addr;
+		ndev->irq	= db->irq_res->start;
+
+		/* ensure at least we have a default set of IO routines */
+		dm9000_set_io(db, iosize);
+
+	}
+
+	/* check to see if anything is being over-ridden */
+	if (pdata != NULL) {
+		/* check to see if the driver wants to over-ride the
+		 * default IO width */
+
+		if (pdata->flags & DM9000_PLATF_8BITONLY)
+			dm9000_set_io(db, 1);
+
+		if (pdata->flags & DM9000_PLATF_16BITONLY)
+			dm9000_set_io(db, 2);
+
+		if (pdata->flags & DM9000_PLATF_32BITONLY)
+			dm9000_set_io(db, 4);
+
+		/* check to see if there are any IO routine
+		 * over-rides */
+
+		if (pdata->inblk != NULL)
+			db->inblk = pdata->inblk;
+
+		if (pdata->outblk != NULL)
+			db->outblk = pdata->outblk;
+
+		if (pdata->dumpblk != NULL)
+			db->dumpblk = pdata->dumpblk;
+	}
+
+	dm9000_reset(db);
+
+	/* try two times, DM9000 sometimes gets the first read wrong */
+	for (i = 0; i < 2; i++) {
+		id_val  = ior(db, DM9000_VIDL);
+		id_val |= (u32)ior(db, DM9000_VIDH) << 8;
+		id_val |= (u32)ior(db, DM9000_PIDL) << 16;
+		id_val |= (u32)ior(db, DM9000_PIDH) << 24;
+
+		if (id_val == DM9000_ID)
+			break;
+		printk("%s: read wrong id 0x%08x\n", CARDNAME, id_val);
+	}
+
+	if (id_val != DM9000_ID) {
+		printk("%s: wrong id: 0x%08x\n", CARDNAME, id_val);
+		goto release;
+	}
+
+	/* from this point we assume that we have found a DM9000 */
+
+	/* driver system function */
+	ether_setup(ndev);
+
+	ndev->open		 = &dm9000_open;
+	ndev->hard_start_xmit    = &dm9000_start_xmit;
+	ndev->tx_timeout         = &dm9000_timeout;
+	ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
+	ndev->stop		 = &dm9000_stop;
+	ndev->get_stats		 = &dm9000_get_stats;
+	ndev->set_multicast_list = &dm9000_hash_table;
+	ndev->do_ioctl		 = &dm9000_do_ioctl;
+
+#ifdef DM9000_PROGRAM_EEPROM
+	program_eeprom(db);
+#endif
+	db->msg_enable       = NETIF_MSG_LINK;
+	db->mii.phy_id_mask  = 0x1f;
+	db->mii.reg_num_mask = 0x1f;
+	db->mii.force_media  = 0;
+	db->mii.full_duplex  = 0;
+	db->mii.dev	     = ndev;
+	db->mii.mdio_read    = dm9000_phy_read;
+	db->mii.mdio_write   = dm9000_phy_write;
+
+	/* Read SROM content */
+	for (i = 0; i < 64; i++)
+		((u16 *) db->srom)[i] = read_srom_word(db, i);
+
+	/* Set Node Address */
+	for (i = 0; i < 6; i++)
+		ndev->dev_addr[i] = db->srom[i];
+
+	if (!is_valid_ether_addr(ndev->dev_addr))
+		printk("%s: Invalid ethernet MAC address.  Please "
+		       "set using ifconfig\n", ndev->name);
+
+	dev_set_drvdata(dev, ndev);
+	ret = register_netdev(ndev);
+
+	if (ret == 0) {
+		printk("%s: dm9000 at %p,%p IRQ %d MAC: ",
+		       ndev->name,  db->io_addr, db->io_data, ndev->irq);
+		for (i = 0; i < 5; i++)
+			printk("%02x:", ndev->dev_addr[i]);
+		printk("%02x\n", ndev->dev_addr[5]);
+	}
+	return 0;
+
+ release:
+ out:
+	printk("%s: not found (%d).\n", CARDNAME, ret);
+
+	dm9000_release_board(pdev, db);
+	kfree(ndev);
+
+	return ret;
+}
+
+/*
+ *  Open the interface.
+ *  The interface is opened whenever "ifconfig" actives it.
+ */
+static int
+dm9000_open(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+
+	PRINTK2("entering dm9000_open\n");
+
+	if (request_irq(dev->irq, &dm9000_interrupt, SA_SHIRQ, dev->name, dev))
+		return -EAGAIN;
+
+	/* Initialize DM9000 board */
+	dm9000_reset(db);
+	dm9000_init_dm9000(dev);
+
+	/* Init driver variable */
+	db->dbug_cnt = 0;
+
+	/* set and active a timer process */
+	init_timer(&db->timer);
+	db->timer.expires  = DM9000_TIMER_WUT * 2;
+	db->timer.data     = (unsigned long) dev;
+	db->timer.function = &dm9000_timer;
+	add_timer(&db->timer);
+
+	mii_check_media(&db->mii, netif_msg_link(db), 1);
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+/*
+ * Initilize dm9000 board
+ */
+static void
+dm9000_init_dm9000(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+
+	PRINTK1("entering %s\n",__FUNCTION__);
+
+	/* I/O mode */
+	db->io_mode = ior(db, DM9000_ISR) >> 6;	/* ISR bit7:6 keeps I/O mode */
+
+	/* GPIO0 on pre-activate PHY */
+	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */
+	iow(db, DM9000_GPCR, GPCR_GEP_CNTL);	/* Let GPIO0 output */
+	iow(db, DM9000_GPR, 0);	/* Enable PHY */
+
+	/* Program operating register */
+	iow(db, DM9000_TCR, 0);	        /* TX Polling clear */
+	iow(db, DM9000_BPTR, 0x3f);	/* Less 3Kb, 200us */
+	iow(db, DM9000_FCR, 0xff);	/* Flow Control */
+	iow(db, DM9000_SMCR, 0);        /* Special Mode */
+	/* clear TX status */
+	iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
+	iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */
+
+	/* Set address filter table */
+	dm9000_hash_table(dev);
+
+	/* Activate DM9000 */
+	iow(db, DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
+	/* Enable TX/RX interrupt mask */
+	iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
+
+	/* Init Driver variable */
+	db->tx_pkt_cnt = 0;
+	db->queue_pkt_len = 0;
+	dev->trans_start = 0;
+	spin_lock_init(&db->lock);
+}
+
+/*
+ *  Hardware start transmission.
+ *  Send a packet to media from the upper layer.
+ */
+static int
+dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+
+	PRINTK3("dm9000_start_xmit\n");
+
+	if (db->tx_pkt_cnt > 1)
+		return 1;
+
+	netif_stop_queue(dev);
+
+	/* Disable all interrupts */
+	iow(db, DM9000_IMR, IMR_PAR);
+
+	/* Move data to DM9000 TX RAM */
+	writeb(DM9000_MWCMD, db->io_addr);
+
+	(db->outblk)(db->io_data, skb->data, skb->len);
+	db->stats.tx_bytes += skb->len;
+
+	/* TX control: First packet immediately send, second packet queue */
+	if (db->tx_pkt_cnt == 0) {
+
+		/* First Packet */
+		db->tx_pkt_cnt++;
+
+		/* Set TX length to DM9000 */
+		iow(db, DM9000_TXPLL, skb->len & 0xff);
+		iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);
+
+		/* Issue TX polling command */
+		iow(db, DM9000_TCR, TCR_TXREQ);	/* Cleared after TX complete */
+
+		dev->trans_start = jiffies;	/* save the time stamp */
+
+	} else {
+		/* Second packet */
+		db->tx_pkt_cnt++;
+		db->queue_pkt_len = skb->len;
+	}
+
+	/* free this SKB */
+	dev_kfree_skb(skb);
+
+	/* Re-enable resource check */
+	if (db->tx_pkt_cnt == 1)
+		netif_wake_queue(dev);
+
+	/* Re-enable interrupt */
+	iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
+
+	return 0;
+}
+
+static void
+dm9000_shutdown(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+
+	/* RESET device */
+	dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);	/* PHY RESET */
+	iow(db, DM9000_GPR, 0x01);	/* Power-Down PHY */
+	iow(db, DM9000_IMR, IMR_PAR);	/* Disable all interrupt */
+	iow(db, DM9000_RCR, 0x00);	/* Disable RX */
+}
+
+/*
+ * Stop the interface.
+ * The interface is stopped when it is brought.
+ */
+static int
+dm9000_stop(struct net_device *ndev)
+{
+	board_info_t *db = (board_info_t *) ndev->priv;
+
+	PRINTK1("entering %s\n",__FUNCTION__);
+
+	/* deleted timer */
+	del_timer(&db->timer);
+
+	netif_stop_queue(ndev);
+	netif_carrier_off(ndev);
+
+	/* free interrupt */
+	free_irq(ndev->irq, ndev);
+
+	dm9000_shutdown(ndev);
+
+	return 0;
+}
+
+/*
+ * DM9000 interrupt handler
+ * receive the packet to upper layer, free the transmitted packet
+ */
+
+void
+dm9000_tx_done(struct net_device *dev, board_info_t * db)
+{
+	int tx_status = ior(db, DM9000_NSR);	/* Got TX status */
+
+	if (tx_status & (NSR_TX2END | NSR_TX1END)) {
+		/* One packet sent complete */
+		db->tx_pkt_cnt--;
+		db->stats.tx_packets++;
+
+		/* Queue packet check & send */
+		if (db->tx_pkt_cnt > 0) {
+			iow(db, DM9000_TXPLL, db->queue_pkt_len & 0xff);
+			iow(db, DM9000_TXPLH, (db->queue_pkt_len >> 8) & 0xff);
+			iow(db, DM9000_TCR, TCR_TXREQ);
+			dev->trans_start = jiffies;
+		}
+		netif_wake_queue(dev);
+	}
+}
+
+static irqreturn_t
+dm9000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	board_info_t *db;
+	int int_status;
+	u8 reg_save;
+
+	PRINTK3("entering %s\n",__FUNCTION__);
+
+	if (!dev) {
+		PRINTK1("dm9000_interrupt() without DEVICE arg\n");
+		return IRQ_HANDLED;
+	}
+
+	/* A real interrupt coming */
+	db = (board_info_t *) dev->priv;
+	spin_lock(&db->lock);
+
+	/* Save previous register address */
+	reg_save = readb(db->io_addr);
+
+	/* Disable all interrupts */
+	iow(db, DM9000_IMR, IMR_PAR);
+
+	/* Got DM9000 interrupt status */
+	int_status = ior(db, DM9000_ISR);	/* Got ISR */
+	iow(db, DM9000_ISR, int_status);	/* Clear ISR status */
+
+	/* Received the coming packet */
+	if (int_status & ISR_PRS)
+		dm9000_rx(dev);
+
+	/* Trnasmit Interrupt check */
+	if (int_status & ISR_PTS)
+		dm9000_tx_done(dev, db);
+
+	/* Re-enable interrupt mask */
+	iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
+
+	/* Restore previous register address */
+	writeb(reg_save, db->io_addr);
+
+	spin_unlock(&db->lock);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ *  Get statistics from driver.
+ */
+static struct net_device_stats *
+dm9000_get_stats(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+	return &db->stats;
+}
+
+/*
+ *  Process the upper socket ioctl command
+ */
+static int
+dm9000_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	PRINTK1("entering %s\n",__FUNCTION__);
+	return 0;
+}
+
+/*
+ *  A periodic timer routine
+ *  Dynamic media sense, allocated Rx buffer...
+ */
+static void
+dm9000_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *) data;
+	board_info_t *db = (board_info_t *) dev->priv;
+	u8 reg_save;
+	unsigned long flags;
+
+	PRINTK3("dm9000_timer()\n");
+
+	spin_lock_irqsave(db->lock,flags);
+	/* Save previous register address */
+	reg_save = readb(db->io_addr);
+
+	mii_check_media(&db->mii, netif_msg_link(db), 0);
+
+	/* Restore previous register address */
+	writeb(reg_save, db->io_addr);
+	spin_unlock_irqrestore(db->lock,flags);
+
+	/* Set timer again */
+	db->timer.expires = DM9000_TIMER_WUT;
+	add_timer(&db->timer);
+}
+
+struct dm9000_rxhdr {
+	u16	RxStatus;
+	u16	RxLen;
+} __attribute__((__packed__));
+
+/*
+ *  Received a packet and pass to upper layer
+ */
+static void
+dm9000_rx(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+	struct dm9000_rxhdr rxhdr;
+	struct sk_buff *skb;
+	u8 rxbyte, *rdptr;
+	int GoodPacket;
+	int RxLen;
+
+	/* Check packet ready or not */
+	do {
+		ior(db, DM9000_MRCMDX);	/* Dummy read */
+
+		/* Get most updated data */
+		rxbyte = readb(db->io_data);
+
+		/* Status check: this byte must be 0 or 1 */
+		if (rxbyte > DM9000_PKT_RDY) {
+			printk("status check failed: %d\n", rxbyte);
+			iow(db, DM9000_RCR, 0x00);	/* Stop Device */
+			iow(db, DM9000_ISR, IMR_PAR);	/* Stop INT request */
+			return;
+		}
+
+		if (rxbyte != DM9000_PKT_RDY)
+			return;
+
+		/* A packet ready now  & Get status/length */
+		GoodPacket = TRUE;
+		writeb(DM9000_MRCMD, db->io_addr);
+
+		(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
+
+		RxLen = rxhdr.RxLen;
+
+		/* Packet Status check */
+		if (RxLen < 0x40) {
+			GoodPacket = FALSE;
+			PRINTK1("Bad Packet received (runt)\n");
+		}
+
+		if (RxLen > DM9000_PKT_MAX) {
+			PRINTK1("RST: RX Len:%x\n", RxLen);
+		}
+
+		if (rxhdr.RxStatus & 0xbf00) {
+			GoodPacket = FALSE;
+			if (rxhdr.RxStatus & 0x100) {
+				PRINTK1("fifo error\n");
+				db->stats.rx_fifo_errors++;
+			}
+			if (rxhdr.RxStatus & 0x200) {
+				PRINTK1("crc error\n");
+				db->stats.rx_crc_errors++;
+			}
+			if (rxhdr.RxStatus & 0x8000) {
+				PRINTK1("length error\n");
+				db->stats.rx_length_errors++;
+			}
+		}
+
+		/* Move data from DM9000 */
+		if (GoodPacket
+		    && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {
+			skb->dev = dev;
+			skb_reserve(skb, 2);
+			rdptr = (u8 *) skb_put(skb, RxLen - 4);
+
+			/* Read received packet from RX SRAM */
+
+			(db->inblk)(db->io_data, rdptr, RxLen);
+			db->stats.rx_bytes += RxLen;
+
+			/* Pass to upper layer */
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			db->stats.rx_packets++;
+
+		} else {
+			/* need to dump the packet's data */
+
+			(db->dumpblk)(db->io_data, RxLen);
+		}
+	} while (rxbyte == DM9000_PKT_RDY);
+}
+
+/*
+ *  Read a word data from SROM
+ */
+static u16
+read_srom_word(board_info_t * db, int offset)
+{
+	iow(db, DM9000_EPAR, offset);
+	iow(db, DM9000_EPCR, EPCR_ERPRR);
+	mdelay(8);		/* according to the datasheet 200us should be enough,
+				   but it doesn't work */
+	iow(db, DM9000_EPCR, 0x0);
+	return (ior(db, DM9000_EPDRL) + (ior(db, DM9000_EPDRH) << 8));
+}
+
+#ifdef DM9000_PROGRAM_EEPROM
+/*
+ * Write a word data to SROM
+ */
+static void
+write_srom_word(board_info_t * db, int offset, u16 val)
+{
+	iow(db, DM9000_EPAR, offset);
+	iow(db, DM9000_EPDRH, ((val >> 8) & 0xff));
+	iow(db, DM9000_EPDRL, (val & 0xff));
+	iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);
+	mdelay(8);		/* same shit */
+	iow(db, DM9000_EPCR, 0);
+}
+
+/*
+ * Only for development:
+ * Here we write static data to the eeprom in case
+ * we don't have valid content on a new board
+ */
+static void
+program_eeprom(board_info_t * db)
+{
+	u16 eeprom[] = { 0x0c00, 0x007f, 0x1300,	/* MAC Address */
+		0x0000,		/* Autoload: accept nothing */
+		0x0a46, 0x9000,	/* Vendor / Product ID */
+		0x0000,		/* pin control */
+		0x0000,
+	};			/* Wake-up mode control */
+	int i;
+	for (i = 0; i < 8; i++)
+		write_srom_word(db, i, eeprom[i]);
+}
+#endif
+
+
+/*
+ *  Calculate the CRC valude of the Rx packet
+ *  flag = 1 : return the reverse CRC (for the received packet CRC)
+ *         0 : return the normal CRC (for Hash Table index)
+ */
+
+static unsigned long
+cal_CRC(unsigned char *Data, unsigned int Len, u8 flag)
+{
+
+       u32 crc = ether_crc_le(Len, Data);
+
+       if (flag)
+               return ~crc;
+
+       return crc;
+}
+
+/*
+ *  Set DM9000 multicast address
+ */
+static void
+dm9000_hash_table(struct net_device *dev)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+	struct dev_mc_list *mcptr = dev->mc_list;
+	int mc_cnt = dev->mc_count;
+	u32 hash_val;
+	u16 i, oft, hash_table[4];
+	unsigned long flags;
+
+	PRINTK2("dm9000_hash_table()\n");
+
+	spin_lock_irqsave(&db->lock,flags);
+
+	for (i = 0, oft = 0x10; i < 6; i++, oft++)
+		iow(db, oft, dev->dev_addr[i]);
+
+	/* Clear Hash Table */
+	for (i = 0; i < 4; i++)
+		hash_table[i] = 0x0;
+
+	/* broadcast address */
+	hash_table[3] = 0x8000;
+
+	/* the multicast address in Hash Table : 64 bits */
+	for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
+		hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f;
+		hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
+	}
+
+	/* Write the hash table to MAC MD table */
+	for (i = 0, oft = 0x16; i < 4; i++) {
+		iow(db, oft++, hash_table[i] & 0xff);
+		iow(db, oft++, (hash_table[i] >> 8) & 0xff);
+	}
+
+	spin_unlock_irqrestore(&db->lock,flags);
+}
+
+
+/*
+ *   Read a word from phyxcer
+ */
+static int
+dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&db->lock,flags);
+	/* Fill the phyxcer register into REG_0C */
+	iow(db, DM9000_EPAR, DM9000_PHY | reg);
+
+	iow(db, DM9000_EPCR, 0xc);	/* Issue phyxcer read command */
+	udelay(100);		/* Wait read complete */
+	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer read command */
+
+	/* The read data keeps on REG_0D & REG_0E */
+	ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);
+
+	spin_unlock_irqrestore(&db->lock,flags);
+
+	return ret;
+}
+
+/*
+ *   Write a word to phyxcer
+ */
+static void
+dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value)
+{
+	board_info_t *db = (board_info_t *) dev->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&db->lock,flags);
+
+	/* Fill the phyxcer register into REG_0C */
+	iow(db, DM9000_EPAR, DM9000_PHY | reg);
+
+	/* Fill the written data into REG_0D & REG_0E */
+	iow(db, DM9000_EPDRL, (value & 0xff));
+	iow(db, DM9000_EPDRH, ((value >> 8) & 0xff));
+
+	iow(db, DM9000_EPCR, 0xa);	/* Issue phyxcer write command */
+	udelay(500);		/* Wait write complete */
+	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer write command */
+
+	spin_unlock_irqrestore(&db->lock,flags);
+}
+
+static int
+dm9000_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+
+	if (ndev && level == SUSPEND_DISABLE) {
+		if (netif_running(ndev)) {
+			netif_device_detach(ndev);
+			dm9000_shutdown(ndev);
+		}
+	}
+	return 0;
+}
+
+static int
+dm9000_drv_resume(struct device *dev, u32 level)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	board_info_t *db = (board_info_t *) ndev->priv;
+
+	if (ndev && level == RESUME_ENABLE) {
+
+		if (netif_running(ndev)) {
+			dm9000_reset(db);
+			dm9000_init_dm9000(ndev);
+
+			netif_device_attach(ndev);
+		}
+	}
+	return 0;
+}
+
+static int
+dm9000_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct net_device *ndev = dev_get_drvdata(dev);
+
+	dev_set_drvdata(dev, NULL);
+
+	unregister_netdev(ndev);
+	dm9000_release_board(pdev, (board_info_t *) ndev->priv);
+	kfree(ndev);		/* free device structure */
+
+	PRINTK1("clean_module() exit\n");
+
+	return 0;
+}
+
+static struct device_driver dm9000_driver = {
+	.name    = "dm9000",
+	.bus     = &platform_bus_type,
+	.probe   = dm9000_probe,
+	.remove  = dm9000_drv_remove,
+	.suspend = dm9000_drv_suspend,
+	.resume  = dm9000_drv_resume,
+};
+
+static int __init
+dm9000_init(void)
+{
+	return driver_register(&dm9000_driver);	/* search board and register */
+}
+
+static void __exit
+dm9000_cleanup(void)
+{
+	driver_unregister(&dm9000_driver);
+}
+
+module_init(dm9000_init);
+module_exit(dm9000_cleanup);
+
+MODULE_AUTHOR("Sascha Hauer, Ben Dooks");
+MODULE_DESCRIPTION("Davicom DM9000 network driver");
+MODULE_LICENSE("GPL");

+ 135 - 0
drivers/net/dm9000.h

@@ -0,0 +1,135 @@
+/*
+ * dm9000 Ethernet
+ */
+
+#ifndef _DM9000X_H_
+#define _DM9000X_H_
+
+#define DM9000_ID		0x90000A46
+
+/* although the registers are 16 bit, they are 32-bit aligned.
+ */
+
+#define DM9000_NCR             0x00
+#define DM9000_NSR             0x01
+#define DM9000_TCR             0x02
+#define DM9000_TSR1            0x03
+#define DM9000_TSR2            0x04
+#define DM9000_RCR             0x05
+#define DM9000_RSR             0x06
+#define DM9000_ROCR            0x07
+#define DM9000_BPTR            0x08
+#define DM9000_FCTR            0x09
+#define DM9000_FCR             0x0A
+#define DM9000_EPCR            0x0B
+#define DM9000_EPAR            0x0C
+#define DM9000_EPDRL           0x0D
+#define DM9000_EPDRH           0x0E
+#define DM9000_WCR             0x0F
+
+#define DM9000_PAR             0x10
+#define DM9000_MAR             0x16
+
+#define DM9000_GPCR	       0x1e
+#define DM9000_GPR             0x1f
+#define DM9000_TRPAL           0x22
+#define DM9000_TRPAH           0x23
+#define DM9000_RWPAL           0x24
+#define DM9000_RWPAH           0x25
+
+#define DM9000_VIDL            0x28
+#define DM9000_VIDH            0x29
+#define DM9000_PIDL            0x2A
+#define DM9000_PIDH            0x2B
+
+#define DM9000_CHIPR           0x2C
+#define DM9000_SMCR            0x2F
+
+#define DM9000_MRCMDX          0xF0
+#define DM9000_MRCMD           0xF2
+#define DM9000_MRRL            0xF4
+#define DM9000_MRRH            0xF5
+#define DM9000_MWCMDX          0xF6
+#define DM9000_MWCMD           0xF8
+#define DM9000_MWRL            0xFA
+#define DM9000_MWRH            0xFB
+#define DM9000_TXPLL           0xFC
+#define DM9000_TXPLH           0xFD
+#define DM9000_ISR             0xFE
+#define DM9000_IMR             0xFF
+
+#define NCR_EXT_PHY         (1<<7)
+#define NCR_WAKEEN          (1<<6)
+#define NCR_FCOL            (1<<4)
+#define NCR_FDX             (1<<3)
+#define NCR_LBK             (3<<1)
+#define NCR_RST	            (1<<0)
+
+#define NSR_SPEED           (1<<7)
+#define NSR_LINKST          (1<<6)
+#define NSR_WAKEST          (1<<5)
+#define NSR_TX2END          (1<<3)
+#define NSR_TX1END          (1<<2)
+#define NSR_RXOV            (1<<1)
+
+#define TCR_TJDIS           (1<<6)
+#define TCR_EXCECM          (1<<5)
+#define TCR_PAD_DIS2        (1<<4)
+#define TCR_CRC_DIS2        (1<<3)
+#define TCR_PAD_DIS1        (1<<2)
+#define TCR_CRC_DIS1        (1<<1)
+#define TCR_TXREQ           (1<<0)
+
+#define TSR_TJTO            (1<<7)
+#define TSR_LC              (1<<6)
+#define TSR_NC              (1<<5)
+#define TSR_LCOL            (1<<4)
+#define TSR_COL             (1<<3)
+#define TSR_EC              (1<<2)
+
+#define RCR_WTDIS           (1<<6)
+#define RCR_DIS_LONG        (1<<5)
+#define RCR_DIS_CRC         (1<<4)
+#define RCR_ALL	            (1<<3)
+#define RCR_RUNT            (1<<2)
+#define RCR_PRMSC           (1<<1)
+#define RCR_RXEN            (1<<0)
+
+#define RSR_RF              (1<<7)
+#define RSR_MF              (1<<6)
+#define RSR_LCS             (1<<5)
+#define RSR_RWTO            (1<<4)
+#define RSR_PLE             (1<<3)
+#define RSR_AE              (1<<2)
+#define RSR_CE              (1<<1)
+#define RSR_FOE             (1<<0)
+
+#define FCTR_HWOT(ot)	(( ot & 0xf ) << 4 )
+#define FCTR_LWOT(ot)	( ot & 0xf )
+
+#define IMR_PAR             (1<<7)
+#define IMR_ROOM            (1<<3)
+#define IMR_ROM             (1<<2)
+#define IMR_PTM             (1<<1)
+#define IMR_PRM             (1<<0)
+
+#define ISR_ROOS            (1<<3)
+#define ISR_ROS             (1<<2)
+#define ISR_PTS             (1<<1)
+#define ISR_PRS             (1<<0)
+#define ISR_CLR_STATUS      (ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS)
+
+#define EPCR_REEP           (1<<5)
+#define EPCR_WEP            (1<<4)
+#define EPCR_EPOS           (1<<3)
+#define EPCR_ERPRR          (1<<2)
+#define EPCR_ERPRW          (1<<1)
+#define EPCR_ERRE           (1<<0)
+
+#define GPCR_GEP_CNTL       (1<<0)
+
+#define DM9000_PKT_RDY		0x01	/* Packet ready to receive */
+#define DM9000_PKT_MAX		1536	/* Received packet max size */
+
+#endif /* _DM9000X_H_ */
+

+ 0 - 689
drivers/net/fmv18x.c

@@ -1,689 +0,0 @@
-/* fmv18x.c: A network device driver for the Fujitsu FMV-181/182/183/184.
-
-	Original: at1700.c (1993-94 by Donald Becker).
-		Copyright 1993 United States Government as represented by the
-		Director, National Security Agency.
-		The author may be reached as becker@scyld.com, or C/O
-			Scyld Computing Corporation
-			410 Severn Ave., Suite 210
-			Annapolis MD 21403
-
-	Modified by Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)
-		Copyright 1994 Fujitsu Laboratories Ltd.
-	Special thanks to:
-		Masayoshi UTAKA (utaka@ace.yk.fujitsu.co.jp)
-			for testing this driver.
-		H. NEGISHI (agy, negishi@sun45.psd.cs.fujitsu.co.jp)
-			for suggestion of some program modification.
-		Masahiro SEKIGUCHI <seki@sysrap.cs.fujitsu.co.jp>
-			for suggestion of some program modification.
-		Kazutoshi MORIOKA (morioka@aurora.oaks.cs.fujitsu.co.jp)
-			for testing this driver.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	This is a device driver for the Fujitsu FMV-181/182/183/184, which
-	is a straight-forward Fujitsu MB86965 implementation.
-
-  Sources:
-    at1700.c
-    The Fujitsu MB86965 datasheet.
-    The Fujitsu FMV-181/182 user's guide
-*/
-
-static const char version[] =
-	"fmv18x.c:v2.2.0 09/24/98  Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "fmv18x"
-
-static unsigned fmv18x_probe_list[] __initdata = {
-	0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
-};
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-typedef unsigned char uchar;
-
-/* Information that need to be kept for each board. */
-struct net_local {
-	struct net_device_stats stats;
-	long open_time;				/* Useless example local info. */
-	uint tx_started:1;			/* Number of packet on the Tx queue. */
-	uint tx_queue_ready:1;		/* Tx queue is ready to be sent. */
-	uint rx_started:1;			/* Packets are Rxing. */
-	uchar tx_queue;				/* Number of packet on the Tx queue. */
-	ushort tx_queue_len;		/* Current length of the Tx queue. */
-	spinlock_t lock;
-};
-
-
-/* Offsets from the base address. */
-#define STATUS			0
-#define TX_STATUS		0
-#define RX_STATUS		1
-#define TX_INTR			2		/* Bit-mapped interrupt enable registers. */
-#define RX_INTR			3
-#define TX_MODE			4
-#define RX_MODE			5
-#define CONFIG_0		6		/* Misc. configuration settings. */
-#define CONFIG_1		7
-/* Run-time register bank 2 definitions. */
-#define DATAPORT		8		/* Word-wide DMA or programmed-I/O dataport. */
-#define TX_START		10
-#define COL16CNTL		11		/* Controll Reg for 16 collisions */
-#define MODE13			13
-/* Fujitsu FMV-18x Card Configuration */
-#define	FJ_STATUS0		0x10
-#define	FJ_STATUS1		0x11
-#define	FJ_CONFIG0		0x12
-#define	FJ_CONFIG1		0x13
-#define	FJ_MACADDR		0x14	/* 0x14 - 0x19 */
-#define	FJ_BUFCNTL		0x1A
-#define	FJ_BUFDATA		0x1C
-#define FMV18X_IO_EXTENT	32
-
-/* Index to functions, as function prototypes. */
-
-static int fmv18x_probe1(struct net_device *dev, short ioaddr);
-static int net_open(struct net_device *dev);
-static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void net_rx(struct net_device *dev);
-static void net_timeout(struct net_device *dev);
-static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, allocate space for the device and return success
-   (detachable devices only).
-   */
-
-static int io = 0x220;
-static int irq;
-
-struct net_device * __init fmv18x_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	unsigned *port;
-	int err = 0;
-
-	if (!dev)
-		return ERR_PTR(-ENODEV);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-		io = dev->base_addr;
-		irq = dev->irq;
-	}
-
-	SET_MODULE_OWNER(dev);
-
-	if (io > 0x1ff) {	/* Check a single specified location. */
-		err = fmv18x_probe1(dev, io);
-	} else if (io != 0) {	/* Don't probe at all. */
-		err = -ENXIO;
-	} else {
-		for (port = fmv18x_probe_list; *port; port++)
-			if (fmv18x_probe1(dev, *port) == 0)
-				break;
-		if (!*port)
-			err = -ENODEV;
-	}
-	if (err)
-		goto out;
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, FMV18X_IO_EXTENT);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
-   "signature", the default bit pattern after a reset.  This *doesn't* work --
-   there is no way to reset the bus interface without a complete power-cycle!
-
-   It turns out that ATI came to the same conclusion I did: the only thing
-   that can be done is checking a few bits and then diving right into MAC
-   address check. */
-
-static int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
-{
-	char irqmap[4] = {3, 7, 10, 15};
-	char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
-	unsigned int i, retval;
-	struct net_local *lp;
-
-	/* Resetting the chip doesn't reset the ISA interface, so don't bother.
-	   That means we have to be careful with the register values we probe for.
-	   */
-
-	if (!request_region(ioaddr, FMV18X_IO_EXTENT, DRV_NAME))
-		return -EBUSY;
-
-	dev->irq = irq;
-	dev->base_addr = ioaddr;
-
-	/* Check I/O address configuration and Fujitsu vendor code */
-	if (inb(ioaddr+FJ_MACADDR  ) != 0x00
-	||  inb(ioaddr+FJ_MACADDR+1) != 0x00
-	||  inb(ioaddr+FJ_MACADDR+2) != 0x0e) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	/* Check PnP mode for FMV-183/184/183A/184A. */
-	/* This PnP routine is very poor. IO and IRQ should be known. */
-	if (inb(ioaddr + FJ_STATUS1) & 0x20) {
-		for (i = 0; i < 8; i++) {
-			if (dev->irq == irqmap_pnp[i])
-				break;
-		}
-		if (i == 8) {
-			retval = -ENODEV;
-			goto out;
-		}
-	} else {
-		if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr)
-			return -ENODEV;
-		dev->irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03];
-	}
-
-	/* Snarf the interrupt vector now. */
-	retval = request_irq(dev->irq, &net_interrupt, 0, DRV_NAME, dev);
-	if (retval) {
-		printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on"
-				"IRQ %d.\n", ioaddr, dev->irq);
-		goto out;
-	}
-
-	printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name,
-		   ioaddr, dev->irq);
-
-	for(i = 0; i < 6; i++) {
-		unsigned char val = inb(ioaddr + FJ_MACADDR + i);
-		printk("%02x", val);
-		dev->dev_addr[i] = val;
-	}
-
-	/* "FJ_STATUS0" 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
-	   rather than 150 ohm shielded twisted pair compensation.
-	   0x0000 == auto-sense the interface
-	   0x0800 == use TP interface
-	   0x1800 == use coax interface
-	   */
-	{
-		const char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2/5"};
-		ushort setup_value = inb(ioaddr + FJ_STATUS0);
-
-		switch( setup_value & 0x07 ){
-		case 0x01 /* 10base5 */:
-		case 0x02 /* 10base2 */: dev->if_port = 0x18; break;
-		case 0x04 /* 10baseT */: dev->if_port = 0x08; break;
-		default /* auto-sense*/: dev->if_port = 0x00; break;
-		}
-		printk(" %s interface.\n", porttype[(dev->if_port>>3) & 3]);
-	}
-
-	/* Initialize LAN Controller and LAN Card */
-	outb(0xda, ioaddr + CONFIG_0);	 /* Initialize LAN Controller */
-	outb(0x00, ioaddr + CONFIG_1);	 /* Stand by mode */
-	outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */
-	outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure (TAMIYA) */
-
-	/* wait for a while */
-	udelay(200);
-
-	/* Set the station address in bank zero. */
-	outb(0x00, ioaddr + CONFIG_1);
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + 8 + i);
-
-	/* Switch to bank 1 and set the multicast table to accept none. */
-	outb(0x04, ioaddr + CONFIG_1);
-	for (i = 0; i < 8; i++)
-		outb(0x00, ioaddr + 8 + i);
-
-	/* Switch to bank 2 and lock our I/O address. */
-	outb(0x08, ioaddr + CONFIG_1);
-	outb(dev->if_port, ioaddr + MODE13);
-	outb(0x00, ioaddr + COL16CNTL);
-
-	if (net_debug)
-		printk(version);
-
-	/* Initialize the device structure. */
-	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
-	if (!dev->priv) {
-		retval = -ENOMEM;
-		goto out_irq;
-	}
-	memset(dev->priv, 0, sizeof(struct net_local));
-	lp = dev->priv;
-	spin_lock_init(&lp->lock);
-
-	dev->open		= net_open;
-	dev->stop		= net_close;
-	dev->hard_start_xmit	= net_send_packet;
-	dev->tx_timeout		= net_timeout;
-	dev->watchdog_timeo	= HZ/10;
-	dev->get_stats		= net_get_stats;
-	dev->set_multicast_list = set_multicast_list;
-	return 0;
-
-out_irq:
-	free_irq(dev->irq, dev);
-out:
-	release_region(ioaddr, FMV18X_IO_EXTENT);
-	return retval;
-}
-
-
-static int net_open(struct net_device *dev)
-{
-	struct net_local *lp = dev->priv;
-	int ioaddr = dev->base_addr;
-
-	/* Set the configuration register 0 to 32K 100ns. byte-wide memory,
-	   16 bit bus access, and two 4K Tx, enable the Rx and Tx. */
-	outb(0x5a, ioaddr + CONFIG_0);
-
-	/* Powerup and switch to register bank 2 for the run-time registers. */
-	outb(0xe8, ioaddr + CONFIG_1);
-
-	lp->tx_started = 0;
-	lp->tx_queue_ready = 1;
-	lp->rx_started = 0;
-	lp->tx_queue = 0;
-	lp->tx_queue_len = 0;
-
-	/* Clear Tx and Rx Status */
-	outb(0xff, ioaddr + TX_STATUS);
-	outb(0xff, ioaddr + RX_STATUS);
-	lp->open_time = jiffies;
-
-	netif_start_queue(dev);
-	
-	/* Enable the IRQ of the LAN Card */
-	outb(0x80, ioaddr + FJ_CONFIG1);
-
-	/* Enable both Tx and Rx interrupts */
-	outw(0x8182, ioaddr+TX_INTR);
-
-	return 0;
-}
-
-static void net_timeout(struct net_device *dev)
-{
-	struct net_local *lp = dev->priv;
-	int ioaddr = dev->base_addr;
-	unsigned long flags;
-	
-	
-	printk(KERN_WARNING "%s: transmit timed out with status %04x, %s?\n", dev->name,
-		   htons(inw(ioaddr + TX_STATUS)),
-		   inb(ioaddr + TX_STATUS) & 0x80
-		   ? "IRQ conflict" : "network cable problem");
-	printk(KERN_WARNING "%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
-		   dev->name, htons(inw(ioaddr + 0)),
-		   htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
-		   htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
-		   htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
-		   htons(inw(ioaddr +14)));
-	printk(KERN_WARNING "eth card: %04x %04x\n",
-		htons(inw(ioaddr+FJ_STATUS0)),
-		htons(inw(ioaddr+FJ_CONFIG0)));
-	lp->stats.tx_errors++;
-	/* ToDo: We should try to restart the adaptor... */
-	spin_lock_irqsave(&lp->lock, flags);
-
-	/* Initialize LAN Controller and LAN Card */
-	outb(0xda, ioaddr + CONFIG_0);   /* Initialize LAN Controller */
-	outb(0x00, ioaddr + CONFIG_1);   /* Stand by mode */
-	outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */
-	outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure */
-	net_open(dev);
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	netif_wake_queue(dev);
-}
-
-static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *lp = dev->priv;
-	int ioaddr = dev->base_addr;
-	short length = skb->len;
-	unsigned char *buf;
-	unsigned long flags;
-
-	/* Block a transmit from overlapping.  */
-	
-	if (length > ETH_FRAME_LEN) {
-		if (net_debug)
-			printk("%s: Attempting to send a large packet (%d bytes).\n",
-				dev->name, length);
-		return 1;
-	}
-	
-	if (length < ETH_ZLEN) {
-		skb = skb_padto(skb, ETH_ZLEN);
-		if (skb == NULL)
-			return 0;
-		length = ETH_ZLEN;
-	}
-	buf = skb->data;
-	
-	if (net_debug > 4)
-		printk("%s: Transmitting a packet of length %lu.\n", dev->name,
-			   (unsigned long)skb->len);
-	/* We may not start transmitting unless we finish transferring
-	   a packet into the Tx queue. During executing the following
-	   codes we possibly catch a Tx interrupt. Thus we flag off
-	   tx_queue_ready, so that we prevent the interrupt routine
-	   (net_interrupt) to start transmitting. */
-	spin_lock_irqsave(&lp->lock, flags);
-	lp->tx_queue_ready = 0;
-	{
-		outw(length, ioaddr + DATAPORT);
-		outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-		lp->tx_queue++;
-		lp->tx_queue_len += length + 2;
-	}
-	lp->tx_queue_ready = 1;
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	if (lp->tx_started == 0) {
-		/* If the Tx is idle, always trigger a transmit. */
-		outb(0x80 | lp->tx_queue, ioaddr + TX_START);
-		lp->tx_queue = 0;
-		lp->tx_queue_len = 0;
-		dev->trans_start = jiffies;
-		lp->tx_started = 1;
-	} else if (lp->tx_queue_len >= 4096 - 1502) /* No room for a packet */
-		netif_stop_queue(dev);
-
-	dev_kfree_skb(skb);
-	return 0;
-}
-
-/* The typical workload of the driver:
-   Handle the network interface interrupts. */
-static irqreturn_t
-net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *lp;
-	int ioaddr, status;
-
-	ioaddr = dev->base_addr;
-	lp = dev->priv;
-	status = inw(ioaddr + TX_STATUS);
-	outw(status, ioaddr + TX_STATUS);
-
-	if (net_debug > 4)
-		printk("%s: Interrupt with status %04x.\n", dev->name, status);
-	if (lp->rx_started == 0 &&
-		(status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {
-		/* Got a packet(s).
-		   We cannot execute net_rx more than once at the same time for
-		   the same device. During executing net_rx, we possibly catch a
-		   Tx interrupt. Thus we flag on rx_started, so that we prevent
-		   the interrupt routine (net_interrupt) to dive into net_rx
-		   again. */
-		lp->rx_started = 1;
-		outb(0x00, ioaddr + RX_INTR);	/* Disable RX intr. */
-		net_rx(dev);
-		outb(0x81, ioaddr + RX_INTR);	/* Enable  RX intr. */
-		lp->rx_started = 0;
-	}
-	if (status & 0x00ff) {
-		if (status & 0x02) {
-			/* More than 16 collisions occurred */
-			if (net_debug > 4)
-				printk("%s: 16 Collision occur during Txing.\n", dev->name);
-			/* Cancel sending a packet. */
-			outb(0x03, ioaddr + COL16CNTL);
-			lp->stats.collisions++;
-		}
-		if (status & 0x82) {
-			spin_lock(&lp->lock);
-			lp->stats.tx_packets++;
-			if (lp->tx_queue && lp->tx_queue_ready) {
-				outb(0x80 | lp->tx_queue, ioaddr + TX_START);
-				lp->tx_queue = 0;
-				lp->tx_queue_len = 0;
-				dev->trans_start = jiffies;
-				netif_wake_queue(dev);	/* Inform upper layers. */
-			} else {
-				lp->tx_started = 0;
-				netif_wake_queue(dev);	/* Inform upper layers. */
-			}
-			spin_unlock(&lp->lock);
-		}
-	}
-	return IRQ_RETVAL(status);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void net_rx(struct net_device *dev)
-{
-	struct net_local *lp = dev->priv;
-	int ioaddr = dev->base_addr;
-	int boguscount = 5;
-
-	while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {
-		/* Clear PKT_RDY bit: by agy 19940922 */
-		/* outb(0x80, ioaddr + RX_STATUS); */
-		ushort status = inw(ioaddr + DATAPORT);
-
-		if (net_debug > 4)
-			printk("%s: Rxing packet mode %02x status %04x.\n",
-				   dev->name, inb(ioaddr + RX_MODE), status);
-#ifndef final_version
-		if (status == 0) {
-			outb(0x05, ioaddr + 14);
-			break;
-		}
-#endif
-
-		if ((status & 0xF0) != 0x20) {	/* There was an error. */
-			lp->stats.rx_errors++;
-			if (status & 0x08) lp->stats.rx_length_errors++;
-			if (status & 0x04) lp->stats.rx_frame_errors++;
-			if (status & 0x02) lp->stats.rx_crc_errors++;
-			if (status & 0x01) lp->stats.rx_over_errors++;
-		} else {
-			ushort pkt_len = inw(ioaddr + DATAPORT);
-			/* Malloc up new buffer. */
-			struct sk_buff *skb;
-
-			if (pkt_len > 1550) {
-				printk("%s: The FMV-18x claimed a very large packet, size %d.\n",
-					   dev->name, pkt_len);
-				outb(0x05, ioaddr + 14);
-				lp->stats.rx_errors++;
-				break;
-			}
-			skb = dev_alloc_skb(pkt_len+3);
-			if (skb == NULL) {
-				printk("%s: Memory squeeze, dropping packet (len %d).\n",
-					   dev->name, pkt_len);
-				outb(0x05, ioaddr + 14);
-				lp->stats.rx_dropped++;
-				break;
-			}
-			skb->dev = dev;
-			skb_reserve(skb,2);
-
-			insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
-
-			if (net_debug > 5) {
-				int i;
-				printk("%s: Rxed packet of length %d: ", dev->name, pkt_len);
-				for (i = 0; i < 14; i++)
-					printk(" %02x", skb->data[i]);
-				printk(".\n");
-			}
-
-			skb->protocol=eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += pkt_len;
-		}
-		if (--boguscount <= 0)
-			break;
-	}
-
-	/* If any worth-while packets have been received, dev_rint()
-	   has done a mark_bh(NET_BH) for us and will work on them
-	   when we get to the bottom-half routine. */
-	{
-		int i;
-		for (i = 0; i < 20; i++) {
-			if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
-				break;
-			(void)inw(ioaddr + DATAPORT);				/* dummy status read */
-			outb(0x05, ioaddr + 14);
-		}
-
-		if (net_debug > 5 && i > 0)
-			printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",
-				   dev->name, inb(ioaddr + RX_MODE), i);
-	}
-
-	return;
-}
-
-/* The inverse routine to net_open(). */
-static int net_close(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	((struct net_local *)dev->priv)->open_time = 0;
-
-	netif_stop_queue(dev);
-	
-	/* Set configuration register 0 to disable Tx and Rx. */
-	outb(0xda, ioaddr + CONFIG_0);
-
-	/* Update the statistics -- ToDo. */
-
-	/* Power-down the chip.  Green, green, green! */
-	outb(0x00, ioaddr + CONFIG_1);
-
-	/* Set the ethernet adaptor disable IRQ */
-	outb(0x00, ioaddr + FJ_CONFIG1);
-
-	return 0;
-}
-
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct net_device_stats *net_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = dev->priv;
-	return &lp->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   num_addrs == -1	Promiscuous mode, receive all packets
-   num_addrs == 0	Normal mode, clear multicast list
-   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
-			best-effort filtering.
- */
- 
-static void set_multicast_list(struct net_device *dev)
-{
-	short ioaddr = dev->base_addr;
-	if (dev->mc_count || dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
-	{
-		/*
-		 *	We must make the kernel realise we had to move
-		 *	into promisc mode or we start all out war on
-		 *	the cable. - AC
-		 */
-		dev->flags|=IFF_PROMISC;
-
-		outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
-	}
-	else
-		outb(2, ioaddr + RX_MODE);	/* Disable promiscuous, use normal mode */
-}
-
-#ifdef MODULE
-static struct net_device *dev_fmv18x;
-
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(net_debug, "i");
-MODULE_PARM_DESC(io, "FMV-18X I/O address");
-MODULE_PARM_DESC(irq, "FMV-18X IRQ number");
-MODULE_PARM_DESC(net_debug, "FMV-18X debug level (0-1,5-6)");
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
-	if (io == 0)
-		printk("fmv18x: You should not use auto-probing with insmod!\n");
-	dev_fmv18x = fmv18x_probe(-1);
-	if (IS_ERR(dev_fmv18x))
-		return PTR_ERR(dev_fmv18x);
-	return 0;
-}
-
-void
-cleanup_module(void)
-{
-	unregister_netdev(dev_fmv18x);
-	free_irq(dev_fmv18x->irq, dev_fmv18x);
-	release_region(dev_fmv18x->base_addr, FMV18X_IO_EXTENT);
-	free_netdev(dev_fmv18x);
-}
-#endif /* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c fmv18x.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
- *  c-indent-level: 4
- * End:
- */

+ 9 - 8
drivers/net/pcmcia/pcnet_cs.c

@@ -1537,20 +1537,20 @@ static void shmem_get_8390_hdr(struct net_device *dev,
 static void shmem_block_input(struct net_device *dev, int count,
 			      struct sk_buff *skb, int ring_offset)
 {
-    void __iomem *xfer_start = ei_status.mem + (TX_PAGES<<8)
-				+ ring_offset
+    void __iomem *base = ei_status.mem;
+    unsigned long offset = (TX_PAGES<<8) + ring_offset
 				- (ei_status.rx_start_page << 8);
     char *buf = skb->data;
     
-    if (xfer_start + count > (void __iomem *)ei_status.rmem_end) {
+    if (offset + count > ei_status.priv) {
 	/* We must wrap the input move. */
-	int semi_count = (void __iomem *)ei_status.rmem_end - xfer_start;
-	copyin(buf, xfer_start, semi_count);
+	int semi_count = ei_status.priv - offset;
+	copyin(buf, base + offset, semi_count);
 	buf += semi_count;
-	xfer_start = ei_status.mem + (TX_PAGES<<8);
+	offset = TX_PAGES<<8;
 	count -= semi_count;
     }
-    copyin(buf, xfer_start, count);
+    copyin(buf, base + offset, count);
 }
 
 /*====================================================================*/
@@ -1611,8 +1611,9 @@ static int setup_shmem_window(dev_link_t *link, int start_pg,
     }
     
     ei_status.mem = info->base + offset;
+    ei_status.priv = req.Size;
     dev->mem_start = (u_long)ei_status.mem;
-    dev->mem_end = ei_status.rmem_end = (u_long)info->base + req.Size;
+    dev->mem_end = dev->mem_start + req.Size;
 
     ei_status.tx_start_page = start_pg;
     ei_status.rx_start_page = start_pg + TX_PAGES;

+ 110 - 67
drivers/net/ppp_generic.c

@@ -1217,36 +1217,43 @@ ppp_push(struct ppp *ppp)
  */
 static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 {
-	int nch, len, fragsize;
+	int len, fragsize;
 	int i, bits, hdrlen, mtu;
-	int flen, fnb;
+	int flen;
+	int navail, nfree;
+	int nbigger;
 	unsigned char *p, *q;
 	struct list_head *list;
 	struct channel *pch;
 	struct sk_buff *frag;
 	struct ppp_channel *chan;
 
-	nch = 0;
+	nfree = 0;	/* # channels which have no packet already queued */
+	navail = 0;	/* total # of usable channels (not deregistered) */
 	hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
+	i = 0;
 	list = &ppp->channels;
 	while ((list = list->next) != &ppp->channels) {
 		pch = list_entry(list, struct channel, clist);
-		nch += pch->avail = (skb_queue_len(&pch->file.xq) == 0);
-		/*
-		 * If a channel hasn't had a fragment yet, it has to get
-		 * one before we send any fragments on later channels.
-		 * If it can't take a fragment now, don't give any
-		 * to subsequent channels.
-		 */
-		if (!pch->had_frag && !pch->avail) {
-			while ((list = list->next) != &ppp->channels) {
-				pch = list_entry(list, struct channel, clist);
-				pch->avail = 0;
+		navail += pch->avail = (pch->chan != NULL);
+		if (pch->avail) {
+			if (skb_queue_len(&pch->file.xq) == 0
+			    || !pch->had_frag) {
+				pch->avail = 2;
+				++nfree;
 			}
-			break;
+			if (!pch->had_frag && i < ppp->nxchan)
+				ppp->nxchan = i;
 		}
+		++i;
 	}
-	if (nch == 0)
+
+	/*
+	 * Don't start sending this packet unless at least half of
+	 * the channels are free.  This gives much better TCP
+	 * performance if we have a lot of channels.
+	 */
+	if (nfree == 0 || nfree < navail / 2)
 		return 0;	/* can't take now, leave it in xmit_pending */
 
 	/* Do protocol field compression (XXX this should be optional) */
@@ -1257,14 +1264,19 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 		--len;
 	}
 
-	/* decide on fragment size */
+	/*
+	 * Decide on fragment size.
+	 * We create a fragment for each free channel regardless of
+	 * how small they are (i.e. even 0 length) in order to minimize
+	 * the time that it will take to detect when a channel drops
+	 * a fragment.
+	 */
 	fragsize = len;
-	if (nch > 1) {
-		int maxch = ROUNDUP(len, MIN_FRAG_SIZE);
-		if (nch > maxch)
-			nch = maxch;
-		fragsize = ROUNDUP(fragsize, nch);
-	}
+	if (nfree > 1)
+		fragsize = ROUNDUP(fragsize, nfree);
+	/* nbigger channels get fragsize bytes, the rest get fragsize-1,
+	   except if nbigger==0, then they all get fragsize. */
+	nbigger = len % nfree;
 
 	/* skip to the channel after the one we last used
 	   and start at that one */
@@ -1278,7 +1290,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 
 	/* create a fragment for each channel */
 	bits = B;
-	do {
+	while (nfree > 0 || len > 0) {
 		list = list->next;
 		if (list == &ppp->channels) {
 			i = 0;
@@ -1289,61 +1301,92 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 		if (!pch->avail)
 			continue;
 
+		/*
+		 * Skip this channel if it has a fragment pending already and
+		 * we haven't given a fragment to all of the free channels.
+		 */
+		if (pch->avail == 1) {
+			if (nfree > 0)
+				continue;
+		} else {
+			--nfree;
+			pch->avail = 1;
+		}
+
 		/* check the channel's mtu and whether it is still attached. */
 		spin_lock_bh(&pch->downl);
-		if (pch->chan == 0 || (mtu = pch->chan->mtu) < hdrlen) {
-			/* can't use this channel */
+		if (pch->chan == NULL) {
+			/* can't use this channel, it's being deregistered */
 			spin_unlock_bh(&pch->downl);
 			pch->avail = 0;
-			if (--nch == 0)
+			if (--navail == 0)
 				break;
 			continue;
 		}
 
 		/*
-		 * We have to create multiple fragments for this channel
-		 * if fragsize is greater than the channel's mtu.
+		 * Create a fragment for this channel of
+		 * min(max(mtu+2-hdrlen, 4), fragsize, len) bytes.
+		 * If mtu+2-hdrlen < 4, that is a ridiculously small
+		 * MTU, so we use mtu = 2 + hdrlen.
 		 */
 		if (fragsize > len)
 			fragsize = len;
-		for (flen = fragsize; flen > 0; flen -= fnb) {
-			fnb = flen;
-			if (fnb > mtu + 2 - hdrlen)
-				fnb = mtu + 2 - hdrlen;
-			if (fnb >= len)
-				bits |= E;
-			frag = alloc_skb(fnb + hdrlen, GFP_ATOMIC);
-			if (frag == 0)
-				goto noskb;
-			q = skb_put(frag, fnb + hdrlen);
-			/* make the MP header */
-			q[0] = PPP_MP >> 8;
-			q[1] = PPP_MP;
-			if (ppp->flags & SC_MP_XSHORTSEQ) {
-				q[2] = bits + ((ppp->nxseq >> 8) & 0xf);
-				q[3] = ppp->nxseq;
-			} else {
-				q[2] = bits;
-				q[3] = ppp->nxseq >> 16;
-				q[4] = ppp->nxseq >> 8;
-				q[5] = ppp->nxseq;
-			}
-
-			/* copy the data in */
-			memcpy(q + hdrlen, p, fnb);
-
-			/* try to send it down the channel */
-			chan = pch->chan;
-			if (!chan->ops->start_xmit(chan, frag))
-				skb_queue_tail(&pch->file.xq, frag);
-			pch->had_frag = 1;
-			p += fnb;
-			len -= fnb;
-			++ppp->nxseq;
-			bits = 0;
+		flen = fragsize;
+		mtu = pch->chan->mtu + 2 - hdrlen;
+		if (mtu < 4)
+			mtu = 4;
+		if (flen > mtu)
+			flen = mtu;
+		if (flen == len && nfree == 0)
+			bits |= E;
+		frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC);
+		if (frag == 0)
+			goto noskb;
+		q = skb_put(frag, flen + hdrlen);
+
+		/* make the MP header */
+		q[0] = PPP_MP >> 8;
+		q[1] = PPP_MP;
+		if (ppp->flags & SC_MP_XSHORTSEQ) {
+			q[2] = bits + ((ppp->nxseq >> 8) & 0xf);
+			q[3] = ppp->nxseq;
+		} else {
+			q[2] = bits;
+			q[3] = ppp->nxseq >> 16;
+			q[4] = ppp->nxseq >> 8;
+			q[5] = ppp->nxseq;
 		}
+
+		/*
+		 * Copy the data in.
+		 * Unfortunately there is a bug in older versions of
+		 * the Linux PPP multilink reconstruction code where it
+		 * drops 0-length fragments.  Therefore we make sure the
+		 * fragment has at least one byte of data.  Any bytes
+		 * we add in this situation will end up as padding on the
+		 * end of the reconstructed packet.
+		 */
+		if (flen == 0)
+			*skb_put(frag, 1) = 0;
+		else
+			memcpy(q + hdrlen, p, flen);
+
+		/* try to send it down the channel */
+		chan = pch->chan;
+		if (skb_queue_len(&pch->file.xq)
+		    || !chan->ops->start_xmit(chan, frag))
+			skb_queue_tail(&pch->file.xq, frag);
+		pch->had_frag = 1;
+		p += flen;
+		len -= flen;
+		++ppp->nxseq;
+		bits = 0;
 		spin_unlock_bh(&pch->downl);
-	} while (len > 0);
+
+		if (--nbigger == 0 && fragsize > 0)
+			--fragsize;
+	}
 	ppp->nxchan = i;
 
 	return 1;
@@ -1422,7 +1465,7 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
 		kfree_skb(skb);
 		return;
 	}
-	
+
 	proto = PPP_PROTO(skb);
 	read_lock_bh(&pch->upl);
 	if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) {
@@ -1691,7 +1734,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
 	struct list_head *l;
 	int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
 
-	if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0)
+	if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0)
 		goto err;		/* no good, throw it away */
 
 	/* Decode sequence number and begin/end bits */

+ 252 - 68
drivers/net/r8169.c

@@ -69,7 +69,13 @@ VERSION 2.2LK	<2005/01/25>
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#define RTL8169_VERSION "2.2LK"
+#ifdef CONFIG_R8169_NAPI
+#define NAPI_SUFFIX	"-NAPI"
+#else
+#define NAPI_SUFFIX	""
+#endif
+
+#define RTL8169_VERSION "2.2LK" NAPI_SUFFIX
 #define MODULENAME "r8169"
 #define PFX MODULENAME ": "
 
@@ -85,6 +91,10 @@ VERSION 2.2LK	<2005/01/25>
 #define dprintk(fmt, args...)	do {} while (0)
 #endif /* RTL8169_DEBUG */
 
+#define R8169_MSG_DEFAULT \
+	(NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_IFUP | \
+	 NETIF_MSG_IFDOWN)
+
 #define TX_BUFFS_AVAIL(tp) \
 	(tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1)
 
@@ -174,8 +184,9 @@ const static struct {
 #undef _R
 
 static struct pci_device_id rtl8169_pci_tbl[] = {
-	{0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x1186, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8169), },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK,	0x4300), },
+	{ PCI_DEVICE(0x16ec,			0x0116), },
 	{0,},
 };
 
@@ -183,10 +194,15 @@ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
 
 static int rx_copybreak = 200;
 static int use_dac;
+static struct {
+	u32 msg_enable;
+} debug = { -1 };
 
 enum RTL8169_registers {
 	MAC0 = 0,		/* Ethernet hardware address. */
 	MAR0 = 8,		/* Multicast filter. */
+	CounterAddrLow = 0x10,
+	CounterAddrHigh = 0x14,
 	TxDescStartAddrLow = 0x20,
 	TxDescStartAddrHigh = 0x24,
 	TxHDescStartAddrLow = 0x28,
@@ -328,6 +344,9 @@ enum RTL8169_register_content {
 
 	/* _TBICSRBit */
 	TBILinkOK = 0x02000000,
+
+	/* DumpCounterCommand */
+	CounterDump = 0x8,
 };
 
 enum _DescStatusBit {
@@ -385,6 +404,7 @@ struct rtl8169_private {
 	struct pci_dev *pci_dev;	/* Index of PCI device */
 	struct net_device_stats stats;	/* statistics of net device */
 	spinlock_t lock;		/* spin lock flag */
+	u32 msg_enable;
 	int chipset;
 	int mac_version;
 	int phy_version;
@@ -418,9 +438,13 @@ struct rtl8169_private {
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
 MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
 module_param_array(media, int, &num_media, 0);
+MODULE_PARM_DESC(media, "force phy operation. Deprecated by ethtool (8).");
 module_param(rx_copybreak, int, 0);
+MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
 module_param(use_dac, int, 0);
 MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");
+module_param_named(debug, debug.msg_enable, int, 0);
+MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(RTL8169_VERSION);
 
@@ -433,10 +457,10 @@ static void rtl8169_hw_start(struct net_device *dev);
 static int rtl8169_close(struct net_device *dev);
 static void rtl8169_set_rx_mode(struct net_device *dev);
 static void rtl8169_tx_timeout(struct net_device *dev);
-static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev);
+static struct net_device_stats *rtl8169_get_stats(struct net_device *dev);
 static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *,
 				void __iomem *);
-static int rtl8169_change_mtu(struct net_device *netdev, int new_mtu);
+static int rtl8169_change_mtu(struct net_device *dev, int new_mtu);
 static void rtl8169_down(struct net_device *dev);
 
 #ifdef CONFIG_R8169_NAPI
@@ -543,9 +567,13 @@ static void rtl8169_check_link_status(struct net_device *dev,
 	spin_lock_irqsave(&tp->lock, flags);
 	if (tp->link_ok(ioaddr)) {
 		netif_carrier_on(dev);
-		printk(KERN_INFO PFX "%s: link up\n", dev->name);
-	} else
+		if (netif_msg_ifup(tp))
+			printk(KERN_INFO PFX "%s: link up\n", dev->name);
+	} else {
+		if (netif_msg_ifdown(tp))
+			printk(KERN_INFO PFX "%s: link down\n", dev->name);
 		netif_carrier_off(dev);
+	}
 	spin_unlock_irqrestore(&tp->lock, flags);
 }
 
@@ -569,7 +597,7 @@ static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex)
 	
 	option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff;
 
-	if ((option != 0xff) && !idx)
+	if ((option != 0xff) && !idx && netif_msg_drv(&debug))
 		printk(KERN_WARNING PFX "media option is deprecated.\n");
 
 	for (p = link_settings; p->media != 0xff; p++) {
@@ -611,9 +639,11 @@ static int rtl8169_set_speed_tbi(struct net_device *dev,
 	} else if (autoneg == AUTONEG_ENABLE)
 		RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
 	else {
-		printk(KERN_WARNING PFX
-		       "%s: incorrect speed setting refused in TBI mode\n",
-		       dev->name);
+		if (netif_msg_link(tp)) {
+			printk(KERN_WARNING "%s: "
+			       "incorrect speed setting refused in TBI mode\n",
+			       dev->name);
+		}
 		ret = -EOPNOTSUPP;
 	}
 
@@ -871,12 +901,120 @@ static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
         spin_unlock_irqrestore(&tp->lock, flags);
 }
 
+static u32 rtl8169_get_msglevel(struct net_device *dev)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+
+	return tp->msg_enable;
+}
+
+static void rtl8169_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+
+	tp->msg_enable = value;
+}
+
+static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
+	"tx_packets",
+	"rx_packets",
+	"tx_errors",
+	"rx_errors",
+	"rx_missed",
+	"align_errors",
+	"tx_single_collisions",
+	"tx_multi_collisions",
+	"unicast",
+	"broadcast",
+	"multicast",
+	"tx_aborted",
+	"tx_underrun",
+};
+
+struct rtl8169_counters {
+	u64	tx_packets;
+	u64	rx_packets;
+	u64	tx_errors;
+	u32	rx_errors;
+	u16	rx_missed;
+	u16	align_errors;
+	u32	tx_one_collision;
+	u32	tx_multi_collision;
+	u64	rx_unicast;
+	u64	rx_broadcast;
+	u32	rx_multicast;
+	u16	tx_aborted;
+	u16	tx_underun;
+};
+
+static int rtl8169_get_stats_count(struct net_device *dev)
+{
+	return ARRAY_SIZE(rtl8169_gstrings);
+}
+
+static void rtl8169_get_ethtool_stats(struct net_device *dev,
+				      struct ethtool_stats *stats, u64 *data)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void __iomem *ioaddr = tp->mmio_addr;
+	struct rtl8169_counters *counters;
+	dma_addr_t paddr;
+	u32 cmd;
+
+	ASSERT_RTNL();
+
+	counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr);
+	if (!counters)
+		return;
+
+	RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
+	cmd = (u64)paddr & DMA_32BIT_MASK;
+	RTL_W32(CounterAddrLow, cmd);
+	RTL_W32(CounterAddrLow, cmd | CounterDump);
+
+	while (RTL_R32(CounterAddrLow) & CounterDump) {
+		if (msleep_interruptible(1))
+			break;
+	}
+
+	RTL_W32(CounterAddrLow, 0);
+	RTL_W32(CounterAddrHigh, 0);
+
+	data[0]	= le64_to_cpu(counters->tx_packets);
+	data[1] = le64_to_cpu(counters->rx_packets);
+	data[2] = le64_to_cpu(counters->tx_errors);
+	data[3] = le32_to_cpu(counters->rx_errors);
+	data[4] = le16_to_cpu(counters->rx_missed);
+	data[5] = le16_to_cpu(counters->align_errors);
+	data[6] = le32_to_cpu(counters->tx_one_collision);
+	data[7] = le32_to_cpu(counters->tx_multi_collision);
+	data[8] = le64_to_cpu(counters->rx_unicast);
+	data[9] = le64_to_cpu(counters->rx_broadcast);
+	data[10] = le32_to_cpu(counters->rx_multicast);
+	data[11] = le16_to_cpu(counters->tx_aborted);
+	data[12] = le16_to_cpu(counters->tx_underun);
+
+	pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr);
+}
+
+static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	switch(stringset) {
+	case ETH_SS_STATS:
+		memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
+		break;
+	}
+}
+
+
 static struct ethtool_ops rtl8169_ethtool_ops = {
 	.get_drvinfo		= rtl8169_get_drvinfo,
 	.get_regs_len		= rtl8169_get_regs_len,
 	.get_link		= ethtool_op_get_link,
 	.get_settings		= rtl8169_get_settings,
 	.set_settings		= rtl8169_set_settings,
+	.get_msglevel		= rtl8169_get_msglevel,
+	.set_msglevel		= rtl8169_set_msglevel,
 	.get_rx_csum		= rtl8169_get_rx_csum,
 	.set_rx_csum		= rtl8169_set_rx_csum,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
@@ -886,6 +1024,9 @@ static struct ethtool_ops rtl8169_ethtool_ops = {
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= ethtool_op_set_tso,
 	.get_regs		= rtl8169_get_regs,
+	.get_strings		= rtl8169_get_strings,
+	.get_stats_count	= rtl8169_get_stats_count,
+	.get_ethtool_stats	= rtl8169_get_ethtool_stats,
 };
 
 static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum,
@@ -1091,7 +1232,8 @@ static void rtl8169_phy_timer(unsigned long __opaque)
 	if (tp->link_ok(ioaddr))
 		goto out_unlock;
 
-	printk(KERN_WARNING PFX "%s: PHY reset until link up\n", dev->name);
+	if (netif_msg_link(tp))
+		printk(KERN_WARNING "%s: PHY reset until link up\n", dev->name);
 
 	tp->phy_reset_enable(ioaddr);
 
@@ -1169,18 +1311,23 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 	/* dev zeroed in alloc_etherdev */
 	dev = alloc_etherdev(sizeof (*tp));
 	if (dev == NULL) {
-		printk(KERN_ERR PFX "unable to alloc new ethernet\n");
+		if (netif_msg_drv(&debug))
+			printk(KERN_ERR PFX "unable to alloc new ethernet\n");
 		goto err_out;
 	}
 
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	tp = netdev_priv(dev);
+	tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
 
 	/* enable device (incl. PCI PM wakeup and hotplug setup) */
 	rc = pci_enable_device(pdev);
-	if (rc) {
-		printk(KERN_ERR PFX "%s: enable failure\n", pci_name(pdev));
+	if (rc < 0) {
+		if (netif_msg_probe(tp)) {
+			printk(KERN_ERR PFX "%s: enable failure\n",
+			       pci_name(pdev));
+		}
 		goto err_out_free_dev;
 	}
 
@@ -1196,29 +1343,39 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 		pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
 		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
 	} else {
-		printk(KERN_ERR PFX
-		       "Cannot find PowerManagement capability, aborting.\n");
+		if (netif_msg_probe(tp)) {
+			printk(KERN_ERR PFX
+			       "Cannot find PowerManagement capability. "
+			       "Aborting.\n");
+		}
 		goto err_out_mwi;
 	}
 
 	/* make sure PCI base addr 1 is MMIO */
 	if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
-		printk(KERN_ERR PFX
-		       "region #1 not an MMIO resource, aborting\n");
+		if (netif_msg_probe(tp)) {
+			printk(KERN_ERR PFX
+			       "region #1 not an MMIO resource, aborting\n");
+		}
 		rc = -ENODEV;
 		goto err_out_mwi;
 	}
 	/* check for weird/broken PCI region reporting */
 	if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) {
-		printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
+		if (netif_msg_probe(tp)) {
+			printk(KERN_ERR PFX
+			       "Invalid PCI region size(s), aborting\n");
+		}
 		rc = -ENODEV;
 		goto err_out_mwi;
 	}
 
 	rc = pci_request_regions(pdev, MODULENAME);
-	if (rc) {
-		printk(KERN_ERR PFX "%s: could not request regions.\n",
-		       pci_name(pdev));
+	if (rc < 0) {
+		if (netif_msg_probe(tp)) {
+			printk(KERN_ERR PFX "%s: could not request regions.\n",
+			       pci_name(pdev));
+		}
 		goto err_out_mwi;
 	}
 
@@ -1231,7 +1388,10 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 	} else {
 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc < 0) {
-			printk(KERN_ERR PFX "DMA configuration failed.\n");
+			if (netif_msg_probe(tp)) {
+				printk(KERN_ERR PFX
+				       "DMA configuration failed.\n");
+			}
 			goto err_out_free_res;
 		}
 	}
@@ -1241,7 +1401,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 	/* ioremap MMIO region */
 	ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE);
 	if (ioaddr == NULL) {
-		printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
+		if (netif_msg_probe(tp))
+			printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
 		rc = -EIO;
 		goto err_out_free_res;
 	}
@@ -1272,9 +1433,11 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 	}
 	if (i < 0) {
 		/* Unknown chip: assume array element #0, original RTL-8169 */
-		printk(KERN_DEBUG PFX
-		       "PCI device %s: unknown chip version, assuming %s\n",
-		       pci_name(pdev), rtl_chip_info[0].name);
+		if (netif_msg_probe(tp)) {
+			printk(KERN_DEBUG PFX "PCI device %s: "
+			       "unknown chip version, assuming %s\n",
+			       pci_name(pdev), rtl_chip_info[0].name);
+		}
 		i++;
 	}
 	tp->chipset = i;
@@ -1308,7 +1471,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	struct rtl8169_private *tp;
 	void __iomem *ioaddr = NULL;
 	static int board_idx = -1;
-	static int printed_version = 0;
 	u8 autoneg, duplex;
 	u16 speed;
 	int i, rc;
@@ -1318,10 +1480,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	board_idx++;
 
-	if (!printed_version) {
+	if (netif_msg_drv(&debug)) {
 		printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
 		       MODULENAME, RTL8169_VERSION);
-		printed_version = 1;
 	}
 
 	rc = rtl8169_init_board(pdev, &dev, &ioaddr);
@@ -1366,7 +1527,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 #ifdef CONFIG_R8169_NAPI
 	dev->poll = rtl8169_poll;
 	dev->weight = R8169_NAPI_WEIGHT;
-	printk(KERN_INFO PFX "NAPI enabled\n");
 #endif
 
 #ifdef CONFIG_R8169_VLAN
@@ -1391,20 +1551,24 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		return rc;
 	}
 
-	printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", dev->name,
-	       rtl_chip_info[tp->chipset].name);
+	if (netif_msg_probe(tp)) {
+		printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n",
+		       dev->name, rtl_chip_info[tp->chipset].name);
+	}
 
 	pci_set_drvdata(pdev, dev);
 
-	printk(KERN_INFO "%s: %s at 0x%lx, "
-	       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
-	       "IRQ %d\n",
-	       dev->name,
-	       rtl_chip_info[ent->driver_data].name,
-	       dev->base_addr,
-	       dev->dev_addr[0], dev->dev_addr[1],
-	       dev->dev_addr[2], dev->dev_addr[3],
-	       dev->dev_addr[4], dev->dev_addr[5], dev->irq);
+	if (netif_msg_probe(tp)) {
+		printk(KERN_INFO "%s: %s at 0x%lx, "
+		       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+		       "IRQ %d\n",
+		       dev->name,
+		       rtl_chip_info[ent->driver_data].name,
+		       dev->base_addr,
+		       dev->dev_addr[0], dev->dev_addr[1],
+		       dev->dev_addr[2], dev->dev_addr[3],
+		       dev->dev_addr[4], dev->dev_addr[5], dev->irq);
+	}
 
 	rtl8169_hw_phy_config(dev);
 
@@ -1427,7 +1591,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	rtl8169_set_speed(dev, autoneg, speed, duplex);
 	
-	if (RTL_R8(PHYstatus) & TBI_Enable)
+	if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
 		printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
 
 	return 0;
@@ -1860,8 +2024,13 @@ static void rtl8169_reinit_task(void *_data)
 	ret = rtl8169_open(dev);
 	if (unlikely(ret < 0)) {
 		if (net_ratelimit()) {
-			printk(PFX KERN_ERR "%s: reinit failure (status = %d)."
-			       " Rescheduling.\n", dev->name, ret);
+			struct rtl8169_private *tp = netdev_priv(dev);
+
+			if (netif_msg_drv(tp)) {
+				printk(PFX KERN_ERR
+				       "%s: reinit failure (status = %d)."
+				       " Rescheduling.\n", dev->name, ret);
+			}
 		}
 		rtl8169_schedule_work(dev, rtl8169_reinit_task);
 	}
@@ -1886,8 +2055,12 @@ static void rtl8169_reset_task(void *_data)
 		netif_wake_queue(dev);
 	} else {
 		if (net_ratelimit()) {
-			printk(PFX KERN_EMERG "%s: Rx buffers shortage\n",
-			       dev->name);
+			struct rtl8169_private *tp = netdev_priv(dev);
+
+			if (netif_msg_intr(tp)) {
+				printk(PFX KERN_EMERG
+				       "%s: Rx buffers shortage\n", dev->name);
+			}
 		}
 		rtl8169_schedule_work(dev, rtl8169_reset_task);
 	}
@@ -1973,8 +2146,11 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	int ret = 0;
 	
 	if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
-		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
-		       dev->name);
+		if (netif_msg_drv(tp)) {
+			printk(KERN_ERR
+			       "%s: BUG! Tx Ring full when queue awake!\n",
+			       dev->name);
+		}
 		goto err_stop;
 	}
 
@@ -2049,8 +2225,11 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
 	pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
 	pci_read_config_word(pdev, PCI_STATUS, &pci_status);
 
-	printk(KERN_ERR PFX "%s: PCI error (cmd = 0x%04x, status = 0x%04x).\n",
-	       dev->name, pci_cmd, pci_status);
+	if (netif_msg_intr(tp)) {
+		printk(KERN_ERR
+		       "%s: PCI error (cmd = 0x%04x, status = 0x%04x).\n",
+		       dev->name, pci_cmd, pci_status);
+	}
 
 	/*
 	 * The recovery sequence below admits a very elaborated explanation:
@@ -2069,7 +2248,8 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
 
 	/* The infamous DAC f*ckup only happens at boot time */
 	if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
-		printk(KERN_INFO PFX "%s: disabling PCI DAC.\n", dev->name);
+		if (netif_msg_intr(tp))
+			printk(KERN_INFO "%s: disabling PCI DAC.\n", dev->name);
 		tp->cp_cmd &= ~PCIDAC;
 		RTL_W16(CPlusCmd, tp->cp_cmd);
 		dev->features &= ~NETIF_F_HIGHDMA;
@@ -2180,7 +2360,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 	rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
 	rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
 
-	while (rx_left > 0) {
+	for (; rx_left > 0; rx_left--, cur_rx++) {
 		unsigned int entry = cur_rx % NUM_RX_DESC;
 		struct RxDesc *desc = tp->RxDescArray + entry;
 		u32 status;
@@ -2190,9 +2370,12 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 
 		if (status & DescOwn)
 			break;
-		if (status & RxRES) {
-			printk(KERN_INFO "%s: Rx ERROR. status = %08x\n",
-			       dev->name, status);
+		if (unlikely(status & RxRES)) {
+			if (netif_msg_rx_err(tp)) {
+				printk(KERN_INFO
+				       "%s: Rx ERROR. status = %08x\n",
+				       dev->name, status);
+			}
 			tp->stats.rx_errors++;
 			if (status & (RxRWT | RxRUNT))
 				tp->stats.rx_length_errors++;
@@ -2214,7 +2397,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 				tp->stats.rx_dropped++;
 				tp->stats.rx_length_errors++;
 				rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
-				goto move_on;
+				continue;
 			}
 
 			rtl8169_rx_csum(skb, desc);
@@ -2243,16 +2426,13 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 			tp->stats.rx_bytes += pkt_size;
 			tp->stats.rx_packets++;
 		}
-move_on:		
-		cur_rx++; 
-		rx_left--;
 	}
 
 	count = cur_rx - tp->cur_rx;
 	tp->cur_rx = cur_rx;
 
 	delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
-	if (!delta && count)
+	if (!delta && count && netif_msg_intr(tp))
 		printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name);
 	tp->dirty_rx += delta;
 
@@ -2263,7 +2443,7 @@ move_on:
 	 *   after refill ?
 	 * - how do others driver handle this condition (Uh oh...).
 	 */
-	if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx)
+	if ((tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) && netif_msg_intr(tp))
 		printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name);
 
 	return count;
@@ -2315,7 +2495,7 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 
 		if (likely(netif_rx_schedule_prep(dev)))
 			__netif_rx_schedule(dev);
-		else {
+		else if (netif_msg_intr(tp)) {
 			printk(KERN_INFO "%s: interrupt %04x taken in poll\n",
 			       dev->name, status);	
 		}
@@ -2334,8 +2514,10 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 	} while (boguscnt > 0);
 
 	if (boguscnt <= 0) {
-		printk(KERN_WARNING "%s: Too much work at interrupt!\n",
-		       dev->name);
+		if (net_ratelimit() && netif_msg_intr(tp)) {
+			printk(KERN_WARNING
+			       "%s: Too much work at interrupt!\n", dev->name);
+		}
 		/* Clear all interrupt sources. */
 		RTL_W16(IntrStatus, 0xffff);
 	}
@@ -2458,8 +2640,10 @@ rtl8169_set_rx_mode(struct net_device *dev)
 
 	if (dev->flags & IFF_PROMISC) {
 		/* Unconditionally log net taps. */
-		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
-		       dev->name);
+		if (netif_msg_link(tp)) {
+			printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+			       dev->name);
+		}
 		rx_mode =
 		    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
 		    AcceptAllPhys;

+ 3 - 5
drivers/net/sk98lin/skge.c

@@ -4212,7 +4212,7 @@ SK_BOOL		DualNet;
 			Flags);
 
 		SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_HARD_RST);
-		pAC->dev[Param.Para32[0]]->flags &= ~IFF_RUNNING;
+		netif_carrier_off(pAC->dev[Param.Para32[0]]);
 		spin_unlock_irqrestore(
 			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
 			Flags);
@@ -4355,7 +4355,7 @@ SK_BOOL		DualNet;
 		}
 
 		/* Inform the world that link protocol is up. */
-		pAC->dev[Param.Para32[0]]->flags |= IFF_RUNNING;
+		netif_carrier_on(pAC->dev[Param.Para32[0]]);
 
 		break;
 	case SK_DRV_NET_DOWN:	 /* SK_U32 Reason */
@@ -4368,7 +4368,7 @@ SK_BOOL		DualNet;
 		} else {
 			DoPrintInterfaceChange = SK_TRUE;
 		}
-		pAC->dev[Param.Para32[1]]->flags &= ~IFF_RUNNING;
+		netif_carrier_off(pAC->dev[Param.Para32[1]]);
 		break;
 	case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
@@ -4961,7 +4961,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller =	&SkGePollController;
 #endif
-	dev->flags &= 		~IFF_RUNNING;
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
 
@@ -5035,7 +5034,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
 		dev->set_mac_address    = &SkGeSetMacAddr;
 		dev->do_ioctl           = &SkGeIoctl;
 		dev->change_mtu         = &SkGeChangeMtu;
-		dev->flags             &= ~IFF_RUNNING;
 		SET_NETDEV_DEV(dev, &pdev->dev);
 		SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
 

+ 0 - 2066
drivers/net/sk_g16.c

@@ -1,2066 +0,0 @@
-/*-
- * Copyright (C) 1994 by PJD Weichmann & SWS Bern, Switzerland
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Module         : sk_g16.c
- *
- * Version        : $Revision: 1.1 $
- *
- * Author         : Patrick J.D. Weichmann
- *
- * Date Created   : 94/05/26
- * Last Updated   : $Date: 1994/06/30 16:25:15 $
- *
- * Description    : Schneider & Koch G16 Ethernet Device Driver for
- *                  Linux Kernel >= 1.1.22
- * Update History :
- *                  Paul Gortmaker, 03/97: Fix for v2.1.x to use read{b,w}
- *                  write{b,w} and memcpy -> memcpy_{to,from}io
- *
- *		    Jeff Garzik, 06/2000, Modularize
- *
--*/
-
-static const char rcsid[] = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
-
-/*
- * The Schneider & Koch (SK) G16 Network device driver is based
- * on the 'ni6510' driver from Michael Hipp which can be found at
- * ftp://sunsite.unc.edu/pub/Linux/system/Network/drivers/nidrivers.tar.gz
- * 
- * Sources: 1) ni6510.c by M. Hipp
- *          2) depca.c  by D.C. Davies
- *          3) skeleton.c by D. Becker
- *          4) Am7990 Local Area Network Controller for Ethernet (LANCE),
- *             AMD, Pub. #05698, June 1989
- *
- * Many Thanks for helping me to get things working to: 
- *                 
- *                 A. Cox (A.Cox@swansea.ac.uk)
- *                 M. Hipp (mhipp@student.uni-tuebingen.de)
- *                 R. Bolz (Schneider & Koch, Germany)
- *
- * To Do: 
- *        - Support of SK_G8 and other SK Network Cards.
- *        - Autoset memory mapped RAM. Check for free memory and then
- *          configure RAM correctly. 
- *        - SK_close should really set card in to initial state.
- *        - Test if IRQ 3 is not switched off. Use autoirq() functionality.
- *          (as in /drivers/net/skeleton.c)
- *        - Implement Multicast addressing. At minimum something like
- *          in depca.c. 
- *        - Redo the statistics part.
- *        - Try to find out if the board is in 8 Bit or 16 Bit slot.
- *          If in 8 Bit mode don't use IRQ 11.
- *        - (Try to make it slightly faster.) 
- *	  - Power management support
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/string.h> 
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-
-#include "sk_g16.h"
-
-/* 
- * Schneider & Koch Card Definitions 
- * =================================
- */  
-
-#define SK_NAME   "SK_G16"
-
-/*
- * SK_G16 Configuration
- * --------------------
- */ 
-
-/* 
- * Abbreviations
- * -------------
- *  
- * RAM - used for the 16KB shared memory 
- * Boot_ROM, ROM - are used for referencing the BootEPROM
- *
- * SK_BOOT_ROM and SK_ADDR are symbolic constants used to configure
- * the behaviour of the driver and the SK_G16.
- *
- * ! See sk_g16.install on how to install and configure the driver !   
- *
- * SK_BOOT_ROM defines if the Boot_ROM should be switched off or not.
- *
- * SK_ADDR defines the address where the RAM will be mapped into the real
- *         host memory.
- *         valid addresses are from 0xa0000 to 0xfc000 in 16Kbyte steps.
- */  
- 
-#define SK_BOOT_ROM     1              /* 1=BootROM on 0=off */
-
-#define SK_ADDR         0xcc000
-
-/* 
- * In POS3 are bits A14-A19 of the address bus. These bits can be set
- * to choose the RAM address. That's why we only can choose the RAM address
- * in 16KB steps.
- */
-
-#define POS_ADDR       (rom_addr>>14)  /* Do not change this line */
-
-/* 
- * SK_G16 I/O PORT's + IRQ's + Boot_ROM locations
- * ----------------------------------------------
- */
-
-/* 
- * As nearly every card has also SK_G16 a specified I/O Port region and
- * only a few possible IRQ's.
- * In the Installation Guide from Schneider & Koch is listed a possible
- * Interrupt IRQ2. IRQ2 is always IRQ9 in boards with two cascaded interrupt
- * controllers. So we use in SK_IRQS IRQ9.
- */
-
-/* Don't touch any of the following #defines. */
-
-#define SK_IO_PORTS     { 0x100, 0x180, 0x208, 0x220, 0x288, 0x320, 0x328, 0x390, 0 }
-
-#define SK_IRQS         { 3, 5, 9, 11, 0 }
-
-#define SK_BOOT_ROM_LOCATIONS { 0xc0000, 0xc4000, 0xc8000, 0xcc000, 0xd0000, 0xd4000, 0xd8000, 0xdc000, 0 }
-
-#define SK_BOOT_ROM_ID  { 0x55, 0xaa, 0x10, 0x50, 0x06, 0x33 }
-
-/* 
- * SK_G16 POS REGISTERS 
- * --------------------
- */
-
-/*
- * SK_G16 has a Programmable Option Select (POS) Register.
- * The POS is composed of 8 separate registers (POS0-7) which 
- * are I/O mapped on an address set by the W1 switch.                    
- *
- */
-
-#define SK_POS_SIZE 8           /* 8 I/O Ports are used by SK_G16 */
-
-#define SK_POS0     ioaddr      /* Card-ID Low (R) */
-#define SK_POS1     ioaddr+1    /* Card-ID High (R) */
-#define SK_POS2     ioaddr+2    /* Card-Enable, Boot-ROM Disable (RW) */
-#define SK_POS3     ioaddr+3    /* Base address of RAM */
-#define SK_POS4     ioaddr+4    /* IRQ */
-
-/* POS5 - POS7 are unused */
-
-/* 
- * SK_G16 MAC PREFIX 
- * -----------------
- */
-
-/* 
- * Scheider & Koch manufacturer code (00:00:a5).
- * This must be checked, that we are sure it is a SK card.
- */
-
-#define SK_MAC0         0x00
-#define SK_MAC1         0x00
-#define SK_MAC2         0x5a
-
-/* 
- * SK_G16 ID 
- * ---------
- */ 
-
-/* 
- * If POS0,POS1 contain the following ID, then we know
- * at which I/O Port Address we are. 
- */
-
-#define SK_IDLOW  0xfd 
-#define SK_IDHIGH 0x6a
-
-
-/* 
- * LANCE POS Bit definitions 
- * -------------------------
- */
-
-#define SK_ROM_RAM_ON  (POS2_CARD)
-#define SK_ROM_RAM_OFF (POS2_EPROM)
-#define SK_ROM_ON      (inb(SK_POS2) & POS2_CARD)
-#define SK_ROM_OFF     (inb(SK_POS2) | POS2_EPROM)
-#define SK_RAM_ON      (inb(SK_POS2) | POS2_CARD)
-#define SK_RAM_OFF     (inb(SK_POS2) & POS2_EPROM) 
-
-#define POS2_CARD  0x0001              /* 1 = SK_G16 on      0 = off */
-#define POS2_EPROM 0x0002              /* 1 = Boot EPROM off 0 = on */ 
-
-/* 
- * SK_G16 Memory mapped Registers
- * ------------------------------
- *
- */ 
-
-#define SK_IOREG        (&board->ioreg) /* LANCE data registers.     */ 
-#define SK_PORT         (&board->port)  /* Control, Status register  */
-#define SK_IOCOM        (&board->iocom) /* I/O Command               */
-
-/* 
- * SK_G16 Status/Control Register bits
- * -----------------------------------
- *
- * (C) Controlreg (S) Statusreg 
- */
-
-/* 
- * Register transfer: 0 = no transfer
- *                    1 = transferring data between LANCE and I/O reg 
- */
-#define SK_IORUN        0x20   
-
-/* 
- * LANCE interrupt: 0 = LANCE interrupt occurred	
- *                  1 = no LANCE interrupt occurred
- */
-#define SK_IRQ          0x10   
-			
-#define SK_RESET        0x08   /* Reset SK_CARD: 0 = RESET 1 = normal */
-#define SK_RW           0x02   /* 0 = write to 1 = read from */
-#define SK_ADR          0x01   /* 0 = REG DataPort 1 = RAP Reg addr port */
-
-  
-#define SK_RREG         SK_RW  /* Transferdirection to read from lance */
-#define SK_WREG         0      /* Transferdirection to write to lance */
-#define SK_RAP          SK_ADR /* Destination Register RAP */
-#define SK_RDATA        0      /* Destination Register REG DataPort */
-
-/* 
- * SK_G16 I/O Command 
- * ------------------
- */
-
-/* 
- * Any bitcombination sets the internal I/O bit (transfer will start) 
- * when written to I/O Command
- */
-
-#define SK_DOIO         0x80   /* Do Transfer */ 
- 
-/* 
- * LANCE RAP (Register Address Port). 
- * ---------------------------------
- */
-
-/*   
- * The LANCE internal registers are selected through the RAP. 
- * The Registers are:
- *
- * CSR0 - Status and Control flags 
- * CSR1 - Low order bits of initialize block (bits 15:00)
- * CSR2 - High order bits of initialize block (bits 07:00, 15:08 are reserved)
- * CSR3 - Allows redefinition of the Bus Master Interface.
- *        This register must be set to 0x0002, which means BSWAP = 0,
- *        ACON = 1, BCON = 0;
- *
- */
- 
-#define CSR0            0x00   
-#define CSR1            0x01  
-#define CSR2            0x02 
-#define CSR3            0x03
-
-/* 
- * General Definitions 
- * ===================
- */
-
-/* 
- * Set the number of Tx and Rx buffers, using Log_2(# buffers).
- * We have 16KB RAM which can be accessed by the LANCE. In the 
- * memory are not only the buffers but also the ring descriptors and
- * the initialize block. 
- * Don't change anything unless you really know what you do.
- */
-
-#define LC_LOG_TX_BUFFERS 1               /* (2 == 2^^1) 2 Transmit buffers */
-#define LC_LOG_RX_BUFFERS 3               /* (8 == 2^^3) 8 Receive buffers */
-
-/* Descriptor ring sizes */
-
-#define TMDNUM (1 << (LC_LOG_TX_BUFFERS)) /* 2 Transmit descriptor rings */
-#define RMDNUM (1 << (LC_LOG_RX_BUFFERS)) /* 8 Receive Buffers */
-
-/* Define Mask for setting RMD, TMD length in the LANCE init_block */
-
-#define TMDNUMMASK (LC_LOG_TX_BUFFERS << 29)
-#define RMDNUMMASK (LC_LOG_RX_BUFFERS << 29)
-
-/*
- * Data Buffer size is set to maximum packet length.
- */
-
-#define PKT_BUF_SZ              1518 
-
-/* 
- * The number of low I/O ports used by the ethercard. 
- */
-
-#define ETHERCARD_TOTAL_SIZE    SK_POS_SIZE
-
-/* 
- * SK_DEBUG
- *
- * Here you can choose what level of debugging wanted.
- *
- * If SK_DEBUG and SK_DEBUG2 are undefined, then only the
- *  necessary messages will be printed.
- *
- * If SK_DEBUG is defined, there will be many debugging prints
- *  which can help to find some mistakes in configuration or even
- *  in the driver code.
- *
- * If SK_DEBUG2 is defined, many many messages will be printed 
- *  which normally you don't need. I used this to check the interrupt
- *  routine. 
- *
- * (If you define only SK_DEBUG2 then only the messages for 
- *  checking interrupts will be printed!)
- *
- * Normal way of live is: 
- *
- * For the whole thing get going let both symbolic constants
- * undefined. If you face any problems and you know what's going
- * on (you know something about the card and you can interpret some
- * hex LANCE register output) then define SK_DEBUG
- * 
- */
-
-#undef  SK_DEBUG	/* debugging */
-#undef  SK_DEBUG2	/* debugging with more verbose report */
-
-#ifdef SK_DEBUG
-#define PRINTK(x) printk x
-#else
-#define PRINTK(x) /**/
-#endif
-
-#ifdef SK_DEBUG2
-#define PRINTK2(x) printk x
-#else
-#define PRINTK2(x) /**/
-#endif
-
-/* 
- * SK_G16 RAM
- *
- * The components are memory mapped and can be set in a region from
- * 0x00000 through 0xfc000 in 16KB steps. 
- *
- * The Network components are: dual ported RAM, Prom, I/O Reg, Status-,
- * Controlregister and I/O Command.
- *
- * dual ported RAM: This is the only memory region which the LANCE chip
- *      has access to. From the Lance it is addressed from 0x0000 to
- *      0x3fbf. The host accesses it normally.
- *
- * PROM: The PROM obtains the ETHERNET-MAC-Address. It is realised as a
- *       8-Bit PROM, this means only the 16 even addresses are used of the
- *       32 Byte Address region. Access to an odd address results in invalid
- *       data.
- * 
- * LANCE I/O Reg: The I/O Reg is build of 4 single Registers, Low-Byte Write,
- *       Hi-Byte Write, Low-Byte Read, Hi-Byte Read.
- *       Transfer from or to the LANCE is always in 16Bit so Low and High
- *       registers are always relevant.
- *
- *       The Data from the Readregister is not the data in the Writeregister!!
- *       
- * Port: Status- and Controlregister. 
- *       Two different registers which share the same address, Status is 
- *       read-only, Control is write-only.
- *    
- * I/O Command: 
- *       Any bitcombination written in here starts the transmission between
- *       Host and LANCE.
- */
-
-typedef struct
-{
-	unsigned char  ram[0x3fc0];   /* 16KB dual ported ram */
-	unsigned char  rom[0x0020];   /* 32Byte PROM containing 6Byte MAC */
-	unsigned char  res1[0x0010];  /* reserved */
-	unsigned volatile short ioreg;/* LANCE I/O Register */
-	unsigned volatile char  port; /* Statusregister and Controlregister */
-	unsigned char  iocom;         /* I/O Command Register */
-} SK_RAM;
-
-/* struct  */
-
-/* 
- * This is the structure for the dual ported ram. We
- * have exactly 16 320 Bytes. In here there must be:
- *
- *     - Initialize Block   (starting at a word boundary)
- *     - Receive and Transmit Descriptor Rings (quadword boundary)
- *     - Data Buffers (arbitrary boundary)
- *
- * This is because LANCE has on SK_G16 only access to the dual ported
- * RAM and nowhere else.
- */
-
-struct SK_ram
-{
-    struct init_block ib;
-    struct tmd tmde[TMDNUM];
-    struct rmd rmde[RMDNUM];
-    char tmdbuf[TMDNUM][PKT_BUF_SZ];
-    char rmdbuf[RMDNUM][PKT_BUF_SZ];
-};
-
-/* 
- * Structure where all necessary information is for ring buffer 
- * management and statistics.
- */
-
-struct priv
-{
-    struct SK_ram *ram;  /* dual ported ram structure */
-    struct rmd *rmdhead; /* start of receive ring descriptors */
-    struct tmd *tmdhead; /* start of transmit ring descriptors */
-    int        rmdnum;   /* actual used ring descriptor */
-    int        tmdnum;   /* actual transmit descriptor for transmitting data */
-    int        tmdlast;  /* last sent descriptor used for error handling, etc */
-    void       *rmdbufs[RMDNUM]; /* pointer to the receive buffers */
-    void       *tmdbufs[TMDNUM]; /* pointer to the transmit buffers */
-    struct net_device_stats stats; /* Device driver statistics */
-};
-
-/* global variable declaration */
-
-/* IRQ map used to reserve a IRQ (see SK_open()) */
-
-/* static variables */
-
-static SK_RAM *board;  /* pointer to our memory mapped board components */
-static DEFINE_SPINLOCK(SK_lock);
-
-/* Macros */
-
-
-/* Function Prototypes */
-
-/*
- * Device Driver functions
- * -----------------------
- * See for short explanation of each function its definitions header.
- */
-
-static int   SK_probe(struct net_device *dev, short ioaddr);
-
-static void  SK_timeout(struct net_device *dev);
-static int   SK_open(struct net_device *dev);
-static int   SK_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t SK_interrupt(int irq, void *dev_id, struct pt_regs * regs);
-static void  SK_rxintr(struct net_device *dev);
-static void  SK_txintr(struct net_device *dev);
-static int   SK_close(struct net_device *dev);
-
-static struct net_device_stats *SK_get_stats(struct net_device *dev);
-
-unsigned int SK_rom_addr(void);
-
-static void set_multicast_list(struct net_device *dev);
-
-/*
- * LANCE Functions
- * ---------------
- */
-
-static int SK_lance_init(struct net_device *dev, unsigned short mode);
-void   SK_reset_board(void);
-void   SK_set_RAP(int reg_number);
-int    SK_read_reg(int reg_number);
-int    SK_rread_reg(void);
-void   SK_write_reg(int reg_number, int value);
-
-/* 
- * Debugging functions
- * -------------------
- */
-
-void SK_print_pos(struct net_device *dev, char *text);
-void SK_print_dev(struct net_device *dev, char *text);
-void SK_print_ram(struct net_device *dev);
-
-
-/*-
- * Function       : SK_init
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/26
- *
- * Description    : Check for a SK_G16 network adaptor and initialize it.
- *                  This function gets called by dev_init which initializes
- *                  all Network devices.
- *
- * Parameters     : I : struct net_device *dev - structure preconfigured 
- *                                           from Space.c
- * Return Value   : 0 = Driver Found and initialized 
- * Errors         : ENODEV - no device found
- *                  ENXIO  - not probed
- * Globals        : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-static int io;	/* 0 == probe */
-
-/* 
- * Check for a network adaptor of this type, and return '0' if one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- */
-
-struct net_device * __init SK_init(int unit)
-{
-	int *port, ports[] = SK_IO_PORTS;  /* SK_G16 supported ports */
-	static unsigned version_printed;
-	struct net_device *dev = alloc_etherdev(sizeof(struct priv));
-	int err = -ENODEV;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-		io = dev->base_addr;
-	}
-
-	if (version_printed++ == 0)
-	        PRINTK(("%s: %s", SK_NAME, rcsid));
-
-	if (io > 0xff) {        /* Check a single specified address */
-		err = -EBUSY;
-		/* Check if on specified address is a SK_G16 */
-		if (request_region(io, ETHERCARD_TOTAL_SIZE, "sk_g16")) {
-			err = SK_probe(dev, io);
-			if (!err)
-				goto got_it;
-			release_region(io, ETHERCARD_TOTAL_SIZE);
-		}
-	} else if (io > 0) {       /* Don't probe at all */
-		err = -ENXIO;
-	} else {
-		/* Autoprobe base_addr */
-		for (port = &ports[0]; *port; port++) {
-			io = *port;
-
-			/* Check if I/O Port region is used by another board */
-			if (!request_region(io, ETHERCARD_TOTAL_SIZE, "sk_g16"))
-				continue;       /* Try next Port address */
-
-			/* Check if at ioaddr is a SK_G16 */
-			if (SK_probe(dev, io) == 0)
-				goto got_it;
-
-			release_region(io, ETHERCARD_TOTAL_SIZE);
-		}
-	}
-err_out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-
-got_it:
-	err = register_netdev(dev);
-	if (err) {
-		release_region(dev->base_addr, ETHERCARD_TOTAL_SIZE);
-		goto err_out;
-	}
-	return dev;
-
-} /* End of SK_init */
-
-
-MODULE_AUTHOR("Patrick J.D. Weichmann");
-MODULE_DESCRIPTION("Schneider & Koch G16 Ethernet Device Driver");
-MODULE_LICENSE("GPL");
-MODULE_PARM(io, "i");
-MODULE_PARM_DESC(io, "0 to probe common ports (unsafe), or the I/O base of the board");
-
-
-#ifdef MODULE
-
-static struct net_device *SK_dev;
-
-static int __init SK_init_module (void)
-{
- 	SK_dev = SK_init(-1);
- 	return IS_ERR(SK_dev) ? PTR_ERR(SK_dev) : 0;
-}
-
-static void __exit SK_cleanup_module (void)
-{
- 	unregister_netdev(SK_dev);
- 	release_region(SK_dev->base_addr, ETHERCARD_TOTAL_SIZE);
- 	free_netdev(SK_dev);
-}
-
-module_init(SK_init_module);
-module_exit(SK_cleanup_module);
-#endif
-
-
-/*-
- * Function       : SK_probe
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/26
- *
- * Description    : This function is called by SK_init and 
- *                  does the main part of initialization.
- *                  
- * Parameters     : I : struct net_device *dev - SK_G16 device structure
- *                  I : short ioaddr       - I/O Port address where POS is.
- * Return Value   : 0 = Initialization done             
- * Errors         : ENODEV - No SK_G16 found
- *                  -1     - Configuration problem
- * Globals        : board       - pointer to SK_RAM
- * Update History :
- *     YY/MM/DD  uid  Description
- *     94/06/30  pwe  SK_ADDR now checked and at the correct place
--*/
-
-int __init SK_probe(struct net_device *dev, short ioaddr)
-{
-    int i,j;                /* Counters */
-    int sk_addr_flag = 0;   /* SK ADDR correct? 1 - no, 0 - yes */
-    unsigned int rom_addr;  /* used to store RAM address used for POS_ADDR */
-
-    struct priv *p = netdev_priv(dev);	/* SK_G16 private structure */
-
-    if (inb(SK_POS0) != SK_IDLOW || inb(SK_POS1) != SK_IDHIGH)
-	return -ENODEV;
-    dev->base_addr = ioaddr;
-
-    if (SK_ADDR & 0x3fff || SK_ADDR < 0xa0000)
-    {
-      
-       sk_addr_flag = 1;
-
-       /* 
-        * Now here we could use a routine which searches for a free
-        * place in the ram and set SK_ADDR if found. TODO. 
-        */
-    }
-
-    if (SK_BOOT_ROM)            /* Shall we keep Boot_ROM on ? */
-    {
-        PRINTK(("## %s: SK_BOOT_ROM is set.\n", SK_NAME));
-
-        rom_addr = SK_rom_addr();
-
-	if (rom_addr == 0)      /* No Boot_ROM found */
-	{
-            if (sk_addr_flag)   /* No or Invalid SK_ADDR is defined */ 
-            {
-                printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n",
-                       dev->name, SK_ADDR);
-                return -1;
-            }
-
-	    rom_addr = SK_ADDR; /* assign predefined address */
-
-	    PRINTK(("## %s: NO Bootrom found \n", SK_NAME));
-
-	    outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off */
-	    outb(POS_ADDR, SK_POS3);       /* Set RAM address */
-	    outb(SK_RAM_ON, SK_POS2);      /* enable RAM */
-	}
-	else if (rom_addr == SK_ADDR) 
-	{
-            printk("%s: RAM + ROM are set to the same address %#08x\n"
-                   "   Check configuration. Now switching off Boot_ROM\n",
-                   SK_NAME, rom_addr);
-
-	    outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off*/
-	    outb(POS_ADDR, SK_POS3);       /* Set RAM address */
-	    outb(SK_RAM_ON, SK_POS2);      /* enable RAM */
-	}
-	else
-	{
-            PRINTK(("## %s: Found ROM at %#08x\n", SK_NAME, rom_addr));
-	    PRINTK(("## %s: Keeping Boot_ROM on\n", SK_NAME));
-
-            if (sk_addr_flag)       /* No or Invalid SK_ADDR is defined */ 
-            {
-                printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n",
-                       dev->name, SK_ADDR);
-                return -1;
-            }
-
-	    rom_addr = SK_ADDR;
-
-	    outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off */ 
-	    outb(POS_ADDR, SK_POS3);       /* Set RAM address */
-	    outb(SK_ROM_RAM_ON, SK_POS2);  /* RAM on, BOOT_ROM on */
-	}
-    }
-    else /* Don't keep Boot_ROM */
-    {
-        PRINTK(("## %s: SK_BOOT_ROM is not set.\n", SK_NAME));
-
-        if (sk_addr_flag)           /* No or Invalid SK_ADDR is defined */ 
-        {
-            printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n",
-                   dev->name, SK_ADDR);
-            return -1;
-        }
-
-	rom_addr = SK_rom_addr();          /* Try to find a Boot_ROM */
-
-	/* IF we find a Boot_ROM disable it */
-
-	outb(SK_ROM_RAM_OFF, SK_POS2);     /* Boot_ROM + RAM off */  
-
-        /* We found a Boot_ROM and it's gone. Set RAM address on
-         * Boot_ROM address. 
-         */ 
-
-	if (rom_addr) 
-	{
-            printk("%s: We found Boot_ROM at %#08x. Now setting RAM on"
-                   "that address\n", SK_NAME, rom_addr);
-
-	    outb(POS_ADDR, SK_POS3);       /* Set RAM on Boot_ROM address */
-	}
-	else /* We did not find a Boot_ROM, use predefined SK_ADDR for ram */
-	{
-            if (sk_addr_flag)       /* No or Invalid SK_ADDR is defined */ 
-            {
-                printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n",
-                       dev->name, SK_ADDR);
-                return -1;
-            }
-
-	    rom_addr = SK_ADDR;
-
-	    outb(POS_ADDR, SK_POS3);       /* Set RAM address */ 
-	}
-	outb(SK_RAM_ON, SK_POS2);          /* enable RAM */
-    }
-
-#ifdef SK_DEBUG
-    SK_print_pos(dev, "POS registers after ROM, RAM config");
-#endif
-
-    board = (SK_RAM *) isa_bus_to_virt(rom_addr);
-
-    /* Read in station address */
-    for (i = 0, j = 0; i < ETH_ALEN; i++, j+=2)
-    {
-	dev->dev_addr[i] = readb(board->rom+j);          
-    }
-
-    /* Check for manufacturer code */
-    if (!(dev->dev_addr[0] == SK_MAC0 &&
-	  dev->dev_addr[1] == SK_MAC1 &&
-	  dev->dev_addr[2] == SK_MAC2) )
-    {
-        PRINTK(("## %s: We did not find SK_G16 at RAM location.\n",
-                SK_NAME)); 
-	return -ENODEV;                     /* NO SK_G16 found */
-    }
-
-    printk("%s: %s found at %#3x, HW addr: %#04x:%02x:%02x:%02x:%02x:%02x\n",
-	    dev->name,
-	    "Schneider & Koch Netcard",
-	    (unsigned int) dev->base_addr,
-	    dev->dev_addr[0],
-	    dev->dev_addr[1],
-	    dev->dev_addr[2],
-	    dev->dev_addr[3],
-	    dev->dev_addr[4],
-	    dev->dev_addr[5]);
-
-    memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */
-
-    /* Assign our Device Driver functions */
-
-    dev->open                   = SK_open;
-    dev->stop                   = SK_close;
-    dev->hard_start_xmit        = SK_send_packet;
-    dev->get_stats              = SK_get_stats;
-    dev->set_multicast_list     = set_multicast_list;
-    dev->tx_timeout		= SK_timeout;
-    dev->watchdog_timeo		= HZ/7;
-
-
-    dev->flags &= ~IFF_MULTICAST;
-
-    /* Initialize private structure */
-
-    p->ram = (struct SK_ram *) rom_addr; /* Set dual ported RAM addr */
-    p->tmdhead = &(p->ram)->tmde[0];     /* Set TMD head */
-    p->rmdhead = &(p->ram)->rmde[0];     /* Set RMD head */
-
-    /* Initialize buffer pointers */
-
-    for (i = 0; i < TMDNUM; i++)
-    {
-	p->tmdbufs[i] = &(p->ram)->tmdbuf[i];
-    }
-
-    for (i = 0; i < RMDNUM; i++)
-    {
-	p->rmdbufs[i] = &(p->ram)->rmdbuf[i]; 
-    }
-
-#ifdef SK_DEBUG
-    SK_print_pos(dev, "End of SK_probe");
-    SK_print_ram(dev);
-#endif 
-    return 0;                            /* Initialization done */
-} /* End of SK_probe() */
-
-
-/*- 
- * Function       : SK_open
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/26
- *
- * Description    : This function is called sometimes after booting 
- *                  when ifconfig program is run.
- *
- *                  This function requests an IRQ, sets the correct
- *                  IRQ in the card. Then calls SK_lance_init() to 
- *                  init and start the LANCE chip. Then if everything is 
- *                  ok returns with 0 (OK), which means SK_G16 is now
- *                  opened and operational.
- *
- *                  (Called by dev_open() /net/inet/dev.c)
- *
- * Parameters     : I : struct net_device *dev - SK_G16 device structure
- * Return Value   : 0 - Device opened
- * Errors         : -EAGAIN - Open failed
- * Side Effects   : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-static int SK_open(struct net_device *dev)
-{
-    int i = 0;
-    int irqval = 0;
-    int ioaddr = dev->base_addr;
-
-    int irqtab[] = SK_IRQS; 
-
-    struct priv *p = netdev_priv(dev);
-
-    PRINTK(("## %s: At beginning of SK_open(). CSR0: %#06x\n", 
-           SK_NAME, SK_read_reg(CSR0)));
-
-    if (dev->irq == 0) /* Autoirq */
-    {
-	i = 0;
-
-	/* 
-         * Check if one IRQ out of SK_IRQS is free and install 
-	 * interrupt handler.
-	 * Most done by request_irq(). 
-	 * irqval: 0       - interrupt handler installed for IRQ irqtab[i]
-	 *         -EBUSY  - interrupt busy 
-         *         -EINVAL - irq > 15 or handler = NULL
-	 */
-
-	do
-	{
-	  irqval = request_irq(irqtab[i], &SK_interrupt, 0, "sk_g16", dev);
-	  i++;
-	} while (irqval && irqtab[i]);
-
-	if (irqval) /* We tried every possible IRQ but no success */
-	{
-	    printk("%s: unable to get an IRQ\n", dev->name);
-	    return -EAGAIN;
-	}
-
-	dev->irq = irqtab[--i]; 
-	
-	outb(i<<2, SK_POS4);           /* Set Card on probed IRQ */
-
-    }
-    else if (dev->irq == 2) /* IRQ2 is always IRQ9 */
-    {
-	if (request_irq(9, &SK_interrupt, 0, "sk_g16", dev))
-	{
-	    printk("%s: unable to get IRQ 9\n", dev->name);
-	    return -EAGAIN;
-	} 
-	dev->irq = 9;
-	
-        /* 
-         * Now we set card on IRQ2.
-         * This can be confusing, but remember that IRQ2 on the network
-         * card is in reality IRQ9
-         */
-	outb(0x08, SK_POS4);           /* set card to IRQ2 */
-
-    }
-    else  /* Check IRQ as defined in Space.c */
-    {
-	int i = 0;
-
-	/* check if IRQ free and valid. Then install Interrupt handler */
-
-	if (request_irq(dev->irq, &SK_interrupt, 0, "sk_g16", dev))
-	{
-	    printk("%s: unable to get selected IRQ\n", dev->name);
-	    return -EAGAIN;
-	}
-
-	switch(dev->irq)
-	{
-	    case 3: i = 0;
-		    break;
-	    case 5: i = 1;
-		    break;
-	    case 2: i = 2;
-		    break;
-	    case 11:i = 3;
-		    break;
-	    default: 
-		printk("%s: Preselected IRQ %d is invalid for %s boards",
-		       dev->name,
-		       dev->irq,
-                       SK_NAME);
-		return -EAGAIN;
-	}      
-  
-	outb(i<<2, SK_POS4);           /* Set IRQ on card */
-    }
-
-    printk("%s: Schneider & Koch G16 at %#3x, IRQ %d, shared mem at %#08x\n",
-	    dev->name, (unsigned int)dev->base_addr, 
-	    (int) dev->irq, (unsigned int) p->ram);
-
-    if (!(i = SK_lance_init(dev, 0)))  /* LANCE init OK? */
-    {
-	netif_start_queue(dev);
-
-#ifdef SK_DEBUG
-
-        /* 
-         * This debug block tries to stop LANCE,
-         * reinit LANCE with transmitter and receiver disabled,
-         * then stop again and reinit with NORMAL_MODE
-         */
-
-        printk("## %s: After lance init. CSR0: %#06x\n", 
-               SK_NAME, SK_read_reg(CSR0));
-        SK_write_reg(CSR0, CSR0_STOP);
-        printk("## %s: LANCE stopped. CSR0: %#06x\n", 
-               SK_NAME, SK_read_reg(CSR0));
-        SK_lance_init(dev, MODE_DTX | MODE_DRX);
-        printk("## %s: Reinit with DTX + DRX off. CSR0: %#06x\n", 
-               SK_NAME, SK_read_reg(CSR0));
-        SK_write_reg(CSR0, CSR0_STOP);
-        printk("## %s: LANCE stopped. CSR0: %#06x\n", 
-               SK_NAME, SK_read_reg(CSR0));
-        SK_lance_init(dev, MODE_NORMAL);
-        printk("## %s: LANCE back to normal mode. CSR0: %#06x\n", 
-               SK_NAME, SK_read_reg(CSR0));
-        SK_print_pos(dev, "POS regs before returning OK");
-
-#endif /* SK_DEBUG */
-       
-	return 0;              /* SK_open() is successful */
-    }
-    else /* LANCE init failed */
-    {
-
-	PRINTK(("## %s: LANCE init failed: CSR0: %#06x\n", 
-               SK_NAME, SK_read_reg(CSR0)));
-
-	return -EAGAIN;
-    }
-
-} /* End of SK_open() */
-
-
-/*-
- * Function       : SK_lance_init
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/26
- *
- * Description    : Reset LANCE chip, fill RMD, TMD structures with
- *                  start values and Start LANCE.
- *
- * Parameters     : I : struct net_device *dev - SK_G16 device structure
- *                  I : int mode - put LANCE into "mode" see data-sheet for
- *                                 more info.
- * Return Value   : 0  - Init done
- * Errors         : -1 - Init failed
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-static int SK_lance_init(struct net_device *dev, unsigned short mode)
-{
-    int i;
-    unsigned long flags;
-    struct priv *p = netdev_priv(dev);
-    struct tmd  *tmdp;
-    struct rmd  *rmdp;
-
-    PRINTK(("## %s: At beginning of LANCE init. CSR0: %#06x\n", 
-           SK_NAME, SK_read_reg(CSR0)));
-
-    /* Reset LANCE */
-    SK_reset_board();
-
-    /* Initialize TMD's with start values */
-    p->tmdnum = 0;                   /* First descriptor for transmitting */ 
-    p->tmdlast = 0;                  /* First descriptor for reading stats */
-
-    for (i = 0; i < TMDNUM; i++)     /* Init all TMD's */
-    {
-	tmdp = p->tmdhead + i; 
-   
-	writel((unsigned long) p->tmdbufs[i], tmdp->u.buffer); /* assign buffer */
-	
-	/* Mark TMD as start and end of packet */
-	writeb(TX_STP | TX_ENP, &tmdp->u.s.status);
-    }
-
-
-    /* Initialize RMD's with start values */
-
-    p->rmdnum = 0;                   /* First RMD which will be used */
- 
-    for (i = 0; i < RMDNUM; i++)     /* Init all RMD's */
-    {
-	rmdp = p->rmdhead + i;
-
-	
-	writel((unsigned long) p->rmdbufs[i], rmdp->u.buffer); /* assign buffer */
-	
-	/* 
-         * LANCE must be owner at beginning so that he can fill in 
-	 * receiving packets, set status and release RMD 
-	 */
-
-	writeb(RX_OWN, &rmdp->u.s.status);
-
-	writew(-PKT_BUF_SZ, &rmdp->blen); /* Buffer Size (two's complement) */
-
-	writeb(0, &rmdp->mlen);           /* init message length */       
-	
-    }
-
-    /* Fill LANCE Initialize Block */
-
-    writew(mode, (&((p->ram)->ib.mode))); /* Set operation mode */
-
-    for (i = 0; i < ETH_ALEN; i++)   /* Set physical address */
-    {
-	writeb(dev->dev_addr[i], (&((p->ram)->ib.paddr[i]))); 
-    }
-
-    for (i = 0; i < 8; i++)          /* Set multicast, logical address */
-    {
-	writeb(0, (&((p->ram)->ib.laddr[i]))); /* We do not use logical addressing */
-    } 
-
-    /* Set ring descriptor pointers and set number of descriptors */
-
-    writel((int)p->rmdhead | RMDNUMMASK, (&((p->ram)->ib.rdrp)));
-    writel((int)p->tmdhead | TMDNUMMASK, (&((p->ram)->ib.tdrp)));
-
-    /* Prepare LANCE Control and Status Registers */
-
-    spin_lock_irqsave(&SK_lock, flags);
-
-    SK_write_reg(CSR3, CSR3_ACON);   /* Ale Control !!!THIS MUST BE SET!!!! */
- 
-    /* 
-     * LANCE addresses the RAM from 0x0000 to 0x3fbf and has no access to
-     * PC Memory locations.
-     *
-     * In structure SK_ram is defined that the first thing in ram
-     * is the initialization block. So his address is for LANCE always
-     * 0x0000
-     *
-     * CSR1 contains low order bits 15:0 of initialization block address
-     * CSR2 is built of: 
-     *    7:0  High order bits 23:16 of initialization block address
-     *   15:8  reserved, must be 0
-     */
-    
-    /* Set initialization block address (must be on word boundary) */
-    SK_write_reg(CSR1, 0);          /* Set low order bits 15:0 */
-    SK_write_reg(CSR2, 0);          /* Set high order bits 23:16 */ 
-    
-
-    PRINTK(("## %s: After setting CSR1-3. CSR0: %#06x\n", 
-           SK_NAME, SK_read_reg(CSR0)));
-
-    /* Initialize LANCE */
-
-    /* 
-     * INIT = Initialize, when set, causes the LANCE to begin the
-     * initialization procedure and access the Init Block.
-     */
-
-    SK_write_reg(CSR0, CSR0_INIT); 
-
-    spin_unlock_irqrestore(&SK_lock, flags);
-
-    /* Wait until LANCE finished initialization */
-    
-    SK_set_RAP(CSR0);              /* Register Address Pointer to CSR0 */
-
-    for (i = 0; (i < 100) && !(SK_rread_reg() & CSR0_IDON); i++) 
-	; /* Wait until init done or go ahead if problems (i>=100) */
-
-    if (i >= 100) /* Something is wrong ! */
-    {
-	printk("%s: can't init am7990, status: %04x "
-	       "init_block: %#08x\n", 
-		dev->name, (int) SK_read_reg(CSR0), 
-		(unsigned int) &(p->ram)->ib);
-
-#ifdef SK_DEBUG
-	SK_print_pos(dev, "LANCE INIT failed");
-	SK_print_dev(dev,"Device Structure:");
-#endif
-
-	return -1;                 /* LANCE init failed */
-    }
-
-    PRINTK(("## %s: init done after %d ticks\n", SK_NAME, i));
-
-    /* Clear Initialize done, enable Interrupts, start LANCE */
-
-    SK_write_reg(CSR0, CSR0_IDON | CSR0_INEA | CSR0_STRT);
-
-    PRINTK(("## %s: LANCE started. CSR0: %#06x\n", SK_NAME, 
-            SK_read_reg(CSR0)));
-
-    return 0;                      /* LANCE is up and running */
-
-} /* End of SK_lance_init() */
-
-
-
-/*-
- * Function       : SK_send_packet
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/27
- *
- * Description    : Writes an socket buffer into a transmit descriptor
- *                  and starts transmission.
- *
- * Parameters     : I : struct sk_buff *skb - packet to transfer
- *                  I : struct net_device *dev  - SK_G16 device structure
- * Return Value   : 0 - OK
- *                  1 - Could not transmit (dev_queue_xmit will queue it)
- *                      and try to sent it later
- * Globals        : None
- * Side Effects   : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-static void SK_timeout(struct net_device *dev)
-{
-	printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name);
-	SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */
-	netif_wake_queue(dev);		 /* Clear Transmitter flag */
-	dev->trans_start = jiffies;      /* Mark Start of transmission */
-}
-
-static int SK_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-    struct priv *p = netdev_priv(dev);
-    struct tmd *tmdp;
-    static char pad[64];
-
-    PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n", 
-	    SK_NAME, SK_read_reg(CSR0)));
-
-
-    /* 
-     * Block a timer-based transmit from overlapping. 
-     * This means check if we are already in. 
-     */
-
-    netif_stop_queue (dev);
-
-    {
-
-	/* Evaluate Packet length */
-	short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; 
-       
-	tmdp = p->tmdhead + p->tmdnum; /* Which descriptor for transmitting */
-
-	/* Fill in Transmit Message Descriptor */
-
-	/* Copy data into dual ported ram */
-
-	memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len);
-	if (len != skb->len)
-		memcpy_toio((tmdp->u.buffer & 0x00ffffff) + skb->len, pad, len-skb->len);
-
-	writew(-len, &tmdp->blen);            /* set length to transmit */
-
-	/* 
-	 * Packet start and end is always set because we use the maximum
-	 * packet length as buffer length.
-	 * Relinquish ownership to LANCE
-	 */
-
-	writeb(TX_OWN | TX_STP | TX_ENP, &tmdp->u.s.status);
-	
-	/* Start Demand Transmission */
-	SK_write_reg(CSR0, CSR0_TDMD | CSR0_INEA);
-
-	dev->trans_start = jiffies;   /* Mark start of transmission */
-
-	/* Set pointer to next transmit buffer */
-	p->tmdnum++; 
-	p->tmdnum &= TMDNUM-1; 
-
-	/* Do we own the next transmit buffer ? */
-	if (! (readb(&((p->tmdhead + p->tmdnum)->u.s.status)) & TX_OWN) )
-	{
-	   /* 
-	    * We own next buffer and are ready to transmit, so
-	    * clear busy flag
-	    */
-	   netif_start_queue(dev);
-	}
-
-	p->stats.tx_bytes += skb->len;
-
-    }
-
-    dev_kfree_skb(skb);
-    return 0;  
-} /* End of SK_send_packet */
-
-
-/*-
- * Function       : SK_interrupt
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/27
- *
- * Description    : SK_G16 interrupt handler which checks for LANCE
- *                  Errors, handles transmit and receive interrupts
- *
- * Parameters     : I : int irq, void *dev_id, struct pt_regs * regs -
- * Return Value   : None
- * Errors         : None
- * Globals        : None
- * Side Effects   : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-static irqreturn_t SK_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-    int csr0;
-    struct net_device *dev = dev_id;
-    struct priv *p = netdev_priv(dev);
-
-
-    PRINTK2(("## %s: SK_interrupt(). status: %#06x\n", 
-            SK_NAME, SK_read_reg(CSR0)));
-
-    if (dev == NULL)
-    {
-	printk("SK_interrupt(): IRQ %d for unknown device.\n", irq);
-    }
-    
-    spin_lock (&SK_lock);
-
-    csr0 = SK_read_reg(CSR0);      /* store register for checking */
-
-    /* 
-     * Acknowledge all of the current interrupt sources, disable      
-     * Interrupts (INEA = 0) 
-     */
-
-    SK_write_reg(CSR0, csr0 & CSR0_CLRALL); 
-
-    if (csr0 & CSR0_ERR) /* LANCE Error */
-    {
-	printk("%s: error: %04x\n", dev->name, csr0);
-      
-        if (csr0 & CSR0_MISS)      /* No place to store packet ? */
-        { 
-            p->stats.rx_dropped++;
-        }
-    }
-
-    if (csr0 & CSR0_RINT)          /* Receive Interrupt (packet arrived) */ 
-    {
-	SK_rxintr(dev); 
-    }
-
-    if (csr0 & CSR0_TINT)          /* Transmit interrupt (packet sent) */
-    {
-	SK_txintr(dev);
-    }
-
-    SK_write_reg(CSR0, CSR0_INEA); /* Enable Interrupts */
-
-    spin_unlock (&SK_lock);
-    return IRQ_HANDLED;
-} /* End of SK_interrupt() */ 
-
-
-/*-
- * Function       : SK_txintr
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/27
- *
- * Description    : After sending a packet we check status, update
- *                  statistics and relinquish ownership of transmit 
- *                  descriptor ring.
- *
- * Parameters     : I : struct net_device *dev - SK_G16 device structure
- * Return Value   : None
- * Errors         : None
- * Globals        : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-static void SK_txintr(struct net_device *dev)
-{
-    int tmdstat;
-    struct tmd *tmdp;
-    struct priv *p = netdev_priv(dev);
-
-
-    PRINTK2(("## %s: SK_txintr() status: %#06x\n", 
-            SK_NAME, SK_read_reg(CSR0)));
-
-    tmdp = p->tmdhead + p->tmdlast;     /* Which buffer we sent at last ? */
-
-    /* Set next buffer */
-    p->tmdlast++;
-    p->tmdlast &= TMDNUM-1;
-
-    tmdstat = readb(&tmdp->u.s.status);
-
-    /* 
-     * We check status of transmitted packet.
-     * see LANCE data-sheet for error explanation
-     */
-    if (tmdstat & TX_ERR) /* Error occurred */
-    {
-	int stat2 = readw(&tmdp->status2);
-
-	printk("%s: TX error: %04x %04x\n", dev->name, tmdstat, stat2);
-
-	if (stat2 & TX_TDR)    /* TDR problems? */
-	{
-	    printk("%s: tdr-problems \n", dev->name);
-	}
-
-	if (stat2 & TX_RTRY)   /* Failed in 16 attempts to transmit ? */
-            p->stats.tx_aborted_errors++;   
-        if (stat2 & TX_LCOL)   /* Late collision ? */
-            p->stats.tx_window_errors++; 
-	if (stat2 & TX_LCAR)   /* Loss of Carrier ? */  
-            p->stats.tx_carrier_errors++;
-        if (stat2 & TX_UFLO)   /* Underflow error ? */
-        {
-            p->stats.tx_fifo_errors++;
-
-            /* 
-             * If UFLO error occurs it will turn transmitter of.
-             * So we must reinit LANCE
-             */
-
-            SK_lance_init(dev, MODE_NORMAL);
-        }
-	
-	p->stats.tx_errors++;
-
-	writew(0, &tmdp->status2);             /* Clear error flags */
-    }
-    else if (tmdstat & TX_MORE)        /* Collisions occurred ? */
-    {
-        /* 
-         * Here I have a problem.
-         * I only know that there must be one or up to 15 collisions.
-         * That's why TX_MORE is set, because after 16 attempts TX_RTRY
-         * will be set which means couldn't send packet aborted transfer.
-         *
-         * First I did not have this in but then I thought at minimum
-         * we see that something was not ok.
-         * If anyone knows something better than this to handle this
-         * please report it.
-         */ 
-
-        p->stats.collisions++; 
-    }
-    else   /* Packet sent without any problems */
-    {
-        p->stats.tx_packets++; 
-    }
-
-    /* 
-     * We mark transmitter not busy anymore, because now we have a free
-     * transmit descriptor which can be filled by SK_send_packet and
-     * afterwards sent by the LANCE
-     * 
-     * The function which do handle slow IRQ parts is do_bottom_half()
-     * which runs at normal kernel priority, that means all interrupt are
-     * enabled. (see kernel/irq.c)
-     *  
-     * net_bh does something like this:
-     *  - check if already in net_bh
-     *  - try to transmit something from the send queue
-     *  - if something is in the receive queue send it up to higher 
-     *    levels if it is a known protocol
-     *  - try to transmit something from the send queue
-     */
-
-    netif_wake_queue(dev);
-
-} /* End of SK_txintr() */
-
-
-/*-
- * Function       : SK_rxintr
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/27
- *
- * Description    : Buffer sent, check for errors, relinquish ownership
- *                  of the receive message descriptor. 
- *
- * Parameters     : I : SK_G16 device structure
- * Return Value   : None
- * Globals        : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-static void SK_rxintr(struct net_device *dev)
-{
-
-    struct rmd *rmdp;
-    int rmdstat;
-    struct priv *p = netdev_priv(dev);
-
-    PRINTK2(("## %s: SK_rxintr(). CSR0: %#06x\n", 
-            SK_NAME, SK_read_reg(CSR0)));
-
-    rmdp = p->rmdhead + p->rmdnum;
-
-    /* As long as we own the next entry, check status and send
-     * it up to higher layer 
-     */
-
-    while (!( (rmdstat = readb(&rmdp->u.s.status)) & RX_OWN))
-    {
-	/* 
-         * Start and end of packet must be set, because we use 
-	 * the ethernet maximum packet length (1518) as buffer size.
-	 * 
-	 * Because our buffers are at maximum OFLO and BUFF errors are
-	 * not to be concerned (see Data sheet)
-	 */
-
-	if ((rmdstat & (RX_STP | RX_ENP)) != (RX_STP | RX_ENP))
-	{
-	    /* Start of a frame > 1518 Bytes ? */
-
-	    if (rmdstat & RX_STP) 
-	    {
-		p->stats.rx_errors++;        /* bad packet received */
-		p->stats.rx_length_errors++; /* packet too long */
-
-		printk("%s: packet too long\n", dev->name);
-	    }
-	    
-	    /* 
-             * All other packets will be ignored until a new frame with
-	     * start (RX_STP) set follows.
-	     * 
-	     * What we do is just give descriptor free for new incoming
-	     * packets. 
-	     */
-
-	    writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ 
-
-	}
-	else if (rmdstat & RX_ERR)          /* Receive Error ? */
-	{
-	    printk("%s: RX error: %04x\n", dev->name, (int) rmdstat);
-	    
-	    p->stats.rx_errors++;
-
-	    if (rmdstat & RX_FRAM) p->stats.rx_frame_errors++;
-	    if (rmdstat & RX_CRC)  p->stats.rx_crc_errors++;
-
-	    writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */
-
-	}
-	else /* We have a packet which can be queued for the upper layers */
-	{
-
-	    int len = readw(&rmdp->mlen) & 0x0fff;  /* extract message length from receive buffer */
-	    struct sk_buff *skb;
-
-	    skb = dev_alloc_skb(len+2); /* allocate socket buffer */ 
-
-	    if (skb == NULL)                /* Could not get mem ? */
-	    {
-    
-		/* 
-                 * Couldn't allocate sk_buffer so we give descriptor back
-		 * to Lance, update statistics and go ahead.
-		 */
-
-		writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */
-		printk("%s: Couldn't allocate sk_buff, deferring packet.\n",
-		       dev->name);
-		p->stats.rx_dropped++;
-
-		break;                      /* Jump out */
-	    }
-	    
-	    /* Prepare sk_buff to queue for upper layers */
-
-	    skb->dev = dev;
-	    skb_reserve(skb,2);		/* Align IP header on 16 byte boundary */
-	    
-	    /* 
-             * Copy data out of our receive descriptor into sk_buff.
-	     *
-	     * (rmdp->u.buffer & 0x00ffffff) -> get address of buffer and 
-	     * ignore status fields) 
-	     */
-
-	    memcpy_fromio(skb_put(skb,len), (rmdp->u.buffer & 0x00ffffff), len);
-
-
-	    /* 
-             * Notify the upper protocol layers that there is another packet
-	     * to handle
-	     *
-	     * netif_rx() always succeeds. see /net/inet/dev.c for more.
-	     */
-
-	    skb->protocol=eth_type_trans(skb,dev);
-	    netif_rx(skb);                 /* queue packet and mark it for processing */
-	   
-	    /* 
-             * Packet is queued and marked for processing so we
-	     * free our descriptor and update statistics 
-	     */
-
-	    writeb(RX_OWN, &rmdp->u.s.status);
-	    dev->last_rx = jiffies;
-	    p->stats.rx_packets++;
-	    p->stats.rx_bytes += len;
-
-
-	    p->rmdnum++;
-	    p->rmdnum %= RMDNUM;
-
-	    rmdp = p->rmdhead + p->rmdnum;
-	}
-    }
-} /* End of SK_rxintr() */
-
-
-/*-
- * Function       : SK_close
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/26
- *
- * Description    : close gets called from dev_close() and should
- *                  deinstall the card (free_irq, mem etc).
- *
- * Parameters     : I : struct net_device *dev - our device structure
- * Return Value   : 0 - closed device driver
- * Errors         : None
- * Globals        : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-/* I have tried to set BOOT_ROM on and RAM off but then, after a 'ifconfig
- * down' the system stops. So I don't shut set card to init state.
- */
-
-static int SK_close(struct net_device *dev)
-{
-
-    PRINTK(("## %s: SK_close(). CSR0: %#06x\n", 
-           SK_NAME, SK_read_reg(CSR0)));
-
-    netif_stop_queue(dev);	   /* Transmitter busy */
-
-    printk("%s: Shutting %s down CSR0 %#06x\n", dev->name, SK_NAME, 
-           (int) SK_read_reg(CSR0));
-
-    SK_write_reg(CSR0, CSR0_STOP); /* STOP the LANCE */
-
-    free_irq(dev->irq, dev);      /* Free IRQ */
-
-    return 0; /* always succeed */
-    
-} /* End of SK_close() */
-
-
-/*-
- * Function       : SK_get_stats
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/26
- *
- * Description    : Return current status structure to upper layers.
- *                  It is called by sprintf_stats (dev.c).
- *
- * Parameters     : I : struct net_device *dev   - our device structure
- * Return Value   : struct net_device_stats * - our current statistics
- * Errors         : None
- * Side Effects   : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-static struct net_device_stats *SK_get_stats(struct net_device *dev)
-{
-
-    struct priv *p = netdev_priv(dev);
-
-    PRINTK(("## %s: SK_get_stats(). CSR0: %#06x\n", 
-           SK_NAME, SK_read_reg(CSR0)));
-
-    return &p->stats;             /* Return Device status */
-
-} /* End of SK_get_stats() */
-
-
-/*-
- * Function       : set_multicast_list
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/26
- *
- * Description    : This function gets called when a program performs
- *                  a SIOCSIFFLAGS call. Ifconfig does this if you call
- *                  'ifconfig [-]allmulti' which enables or disables the
- *                  Promiscuous mode.
- *                  Promiscuous mode is when the Network card accepts all
- *                  packets, not only the packets which match our MAC 
- *                  Address. It is useful for writing a network monitor,
- *                  but it is also a security problem. You have to remember
- *                  that all information on the net is not encrypted.
- *
- * Parameters     : I : struct net_device *dev - SK_G16 device Structure
- * Return Value   : None
- * Errors         : None
- * Globals        : None
- * Update History :
- *     YY/MM/DD  uid  Description
- *     95/10/18  ACox  New multicast calling scheme
--*/
-
-
-/* Set or clear the multicast filter for SK_G16.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-
-    if (dev->flags&IFF_PROMISC)
-    {
-	/* Reinitialize LANCE with MODE_PROM set */
-	SK_lance_init(dev, MODE_PROM);
-    }
-    else if (dev->mc_count==0 && !(dev->flags&IFF_ALLMULTI))
-    {
-	/* Reinitialize LANCE without MODE_PROM */
-	SK_lance_init(dev, MODE_NORMAL);
-    }
-    else
-    {
-	/* Multicast with logical address filter on */
-	/* Reinitialize LANCE without MODE_PROM */
-	SK_lance_init(dev, MODE_NORMAL);
-	
-	/* Not implemented yet. */
-    }
-} /* End of set_multicast_list() */
-
-
-
-/*-
- * Function       : SK_rom_addr
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/06/01
- *
- * Description    : Try to find a Boot_ROM at all possible locations
- *
- * Parameters     : None
- * Return Value   : Address where Boot_ROM is
- * Errors         : 0 - Did not find Boot_ROM
- * Globals        : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-unsigned int __init SK_rom_addr(void)
-{
-    int i,j;
-    int rom_found = 0;
-    unsigned int rom_location[] = SK_BOOT_ROM_LOCATIONS;
-    unsigned char rom_id[] = SK_BOOT_ROM_ID;
-    unsigned char test_byte;
-
-    /* Autodetect Boot_ROM */
-    PRINTK(("## %s: Autodetection of Boot_ROM\n", SK_NAME));
-
-    for (i = 0; (rom_location[i] != 0) && (rom_found == 0); i++)
-    {
-	
-	PRINTK(("##   Trying ROM location %#08x", rom_location[i]));
-	
-	rom_found = 1; 
-	for (j = 0; j < 6; j++)
-	{
-	    test_byte = readb(rom_location[i]+j);
-	    PRINTK((" %02x ", *test_byte));
-
-	    if(test_byte != rom_id[j])
-	    {
-		rom_found = 0;
-	    } 
-	}
-	PRINTK(("\n"));
-    }
-
-    if (rom_found == 1)
-    {
-	PRINTK(("## %s: Boot_ROM found at %#08x\n", 
-               SK_NAME, rom_location[(i-1)]));
-
-	return (rom_location[--i]);
-    }
-    else
-    {
-	PRINTK(("%s: No Boot_ROM found\n", SK_NAME));
-	return 0;
-    }
-} /* End of SK_rom_addr() */
-
-
-
-/* LANCE access functions 
- *
- * ! CSR1-3 can only be accessed when in CSR0 the STOP bit is set !
- */
-
-
-/*-
- * Function       : SK_reset_board
- *
- * Author         : Patrick J.D. Weichmann
- *
- * Date Created   : 94/05/25
- *
- * Description    : This function resets SK_G16 and all components, but
- *                  POS registers are not changed
- *
- * Parameters     : None
- * Return Value   : None
- * Errors         : None
- * Globals        : SK_RAM *board - SK_RAM structure pointer
- *
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-void SK_reset_board(void)
-{
-    writeb(0x00, SK_PORT);       /* Reset active */
-    mdelay(5);                /* Delay min 5ms */
-    writeb(SK_RESET, SK_PORT);   /* Set back to normal operation */
-
-} /* End of SK_reset_board() */
-
-
-/*-
- * Function       : SK_set_RAP
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/25
- *
- * Description    : Set LANCE Register Address Port to register
- *                  for later data transfer.
- *
- * Parameters     : I : reg_number - which CSR to read/write from/to
- * Return Value   : None
- * Errors         : None
- * Globals        : SK_RAM *board - SK_RAM structure pointer
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-void SK_set_RAP(int reg_number)
-{
-    writew(reg_number, SK_IOREG);
-    writeb(SK_RESET | SK_RAP | SK_WREG, SK_PORT);
-    writeb(SK_DOIO, SK_IOCOM);
-
-    while (readb(SK_PORT) & SK_IORUN) 
-	barrier();
-} /* End of SK_set_RAP() */
-
-
-/*-
- * Function       : SK_read_reg
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/25
- *
- * Description    : Set RAP and read data from a LANCE CSR register
- *
- * Parameters     : I : reg_number - which CSR to read from
- * Return Value   : Register contents
- * Errors         : None
- * Globals        : SK_RAM *board - SK_RAM structure pointer
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-int SK_read_reg(int reg_number)
-{
-    SK_set_RAP(reg_number);
-
-    writeb(SK_RESET | SK_RDATA | SK_RREG, SK_PORT);
-    writeb(SK_DOIO, SK_IOCOM);
-
-    while (readb(SK_PORT) & SK_IORUN)
-	barrier();
-    return (readw(SK_IOREG));
-
-} /* End of SK_read_reg() */
-
-
-/*-
- * Function       : SK_rread_reg
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/28
- *
- * Description    : Read data from preseted register.
- *                  This function requires that you know which
- *                  Register is actually set. Be aware that CSR1-3
- *                  can only be accessed when in CSR0 STOP is set.
- *
- * Return Value   : Register contents
- * Errors         : None
- * Globals        : SK_RAM *board - SK_RAM structure pointer
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-int SK_rread_reg(void)
-{
-    writeb(SK_RESET | SK_RDATA | SK_RREG, SK_PORT);
-
-    writeb(SK_DOIO, SK_IOCOM);
-
-    while (readb(SK_PORT) & SK_IORUN)
-	barrier();
-    return (readw(SK_IOREG));
-
-} /* End of SK_rread_reg() */
-
-
-/*-
- * Function       : SK_write_reg
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/25
- *
- * Description    : This function sets the RAP then fills in the
- *                  LANCE I/O Reg and starts Transfer to LANCE.
- *                  It waits until transfer has ended which is max. 7 ms
- *                  and then it returns.
- *
- * Parameters     : I : reg_number - which CSR to write to
- *                  I : value      - what value to fill into register 
- * Return Value   : None
- * Errors         : None
- * Globals        : SK_RAM *board - SK_RAM structure pointer
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-void SK_write_reg(int reg_number, int value)
-{
-    SK_set_RAP(reg_number);
-
-    writew(value, SK_IOREG);
-    writeb(SK_RESET | SK_RDATA | SK_WREG, SK_PORT);
-    writeb(SK_DOIO, SK_IOCOM);
-
-    while (readb(SK_PORT) & SK_IORUN)
-	barrier();
-} /* End of SK_write_reg */
-
-
-
-/* 
- * Debugging functions
- * -------------------
- */
-
-/*-
- * Function       : SK_print_pos
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/25
- *
- * Description    : This function prints out the 4 POS (Programmable
- *                  Option Select) Registers. Used mainly to debug operation.
- *
- * Parameters     : I : struct net_device *dev - SK_G16 device structure
- *                  I : char * - Text which will be printed as title
- * Return Value   : None
- * Errors         : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-void SK_print_pos(struct net_device *dev, char *text)
-{
-    int ioaddr = dev->base_addr;
-
-    unsigned char pos0 = inb(SK_POS0),
-		  pos1 = inb(SK_POS1),
-		  pos2 = inb(SK_POS2),
-		  pos3 = inb(SK_POS3),
-		  pos4 = inb(SK_POS4);
-
-
-    printk("## %s: %s.\n"
-           "##   pos0=%#4x pos1=%#4x pos2=%#04x pos3=%#08x pos4=%#04x\n",
-           SK_NAME, text, pos0, pos1, pos2, (pos3<<14), pos4);
-
-} /* End of SK_print_pos() */
-
-
-
-/*-
- * Function       : SK_print_dev
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/05/25
- *
- * Description    : This function simply prints out the important fields
- *                  of the device structure.
- *
- * Parameters     : I : struct net_device *dev  - SK_G16 device structure
- *                  I : char *text - Title for printing
- * Return Value   : None
- * Errors         : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-void SK_print_dev(struct net_device *dev, char *text)
-{
-    if (dev == NULL)
-    {
-	printk("## %s: Device Structure. %s\n", SK_NAME, text);
-	printk("## DEVICE == NULL\n");
-    }
-    else
-    {
-	printk("## %s: Device Structure. %s\n", SK_NAME, text);
-	printk("## Device Name: %s Base Address: %#06lx IRQ: %d\n", 
-               dev->name, dev->base_addr, dev->irq);
-	       
-	printk("## next device: %#08x init function: %#08x\n", 
-              (int) dev->next, (int) dev->init);
-    }
-
-} /* End of SK_print_dev() */
-
-
-
-/*-
- * Function       : SK_print_ram
- * Author         : Patrick J.D. Weichmann
- * Date Created   : 94/06/02
- *
- * Description    : This function is used to check how are things set up
- *                  in the 16KB RAM. Also the pointers to the receive and 
- *                  transmit descriptor rings and rx and tx buffers locations.
- *                  It contains a minor bug in printing, but has no effect to the values
- *                  only newlines are not correct.
- *
- * Parameters     : I : struct net_device *dev - SK_G16 device structure
- * Return Value   : None
- * Errors         : None
- * Globals        : None
- * Update History :
- *     YY/MM/DD  uid  Description
--*/
-
-void __init SK_print_ram(struct net_device *dev)
-{
-
-    int i;    
-    struct priv *p = netdev_priv(dev);
-
-    printk("## %s: RAM Details.\n"
-           "##   RAM at %#08x tmdhead: %#08x rmdhead: %#08x initblock: %#08x\n",
-           SK_NAME, 
-           (unsigned int) p->ram,
-           (unsigned int) p->tmdhead, 
-           (unsigned int) p->rmdhead, 
-           (unsigned int) &(p->ram)->ib);
-           
-    printk("##   ");
-
-    for(i = 0; i < TMDNUM; i++)
-    {
-           if (!(i % 3)) /* Every third line do a newline */
-           {
-               printk("\n##   ");
-           }
-        printk("tmdbufs%d: %#08x ", (i+1), (int) p->tmdbufs[i]);
-    }
-    printk("##   ");
-
-    for(i = 0; i < RMDNUM; i++)
-    {
-         if (!(i % 3)) /* Every third line do a newline */
-           {
-               printk("\n##   ");
-           }
-        printk("rmdbufs%d: %#08x ", (i+1), (int) p->rmdbufs[i]);
-    } 
-    printk("\n");
-
-} /* End of SK_print_ram() */
-

+ 0 - 165
drivers/net/sk_g16.h

@@ -1,165 +0,0 @@
-/*-
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Module         : sk_g16.h
- * Version        : $Revision$  
- *
- * Author         : M.Hipp (mhipp@student.uni-tuebingen.de)
- * changes by     : Patrick J.D. Weichmann
- *
- * Date Created   : 94/05/25
- *
- * Description    : In here are all necessary definitions of  
- *                  the am7990 (LANCE) chip used for writing a
- *                  network device driver which uses this chip 
- *
- * $Log$
--*/
-
-#ifndef SK_G16_H
-
-#define SK_G16_H
-
-
-/*
- * 	Control and Status Register 0 (CSR0) bit definitions
- *
- * (R=Readable) (W=Writeable) (S=Set on write) (C-Clear on write)
- *
- */
-
-#define CSR0_ERR	0x8000	/* Error summary (R) */
-#define CSR0_BABL	0x4000	/* Babble transmitter timeout error (RC) */
-#define CSR0_CERR	0x2000	/* Collision Error (RC) */
-#define CSR0_MISS	0x1000	/* Missed packet (RC) */
-#define CSR0_MERR	0x0800	/* Memory Error  (RC) */ 
-#define CSR0_RINT	0x0400	/* Receiver Interrupt (RC) */
-#define CSR0_TINT       0x0200	/* Transmit Interrupt (RC) */ 
-#define CSR0_IDON	0x0100	/* Initialization Done (RC) */
-#define CSR0_INTR	0x0080	/* Interrupt Flag (R) */
-#define CSR0_INEA	0x0040	/* Interrupt Enable (RW) */
-#define CSR0_RXON	0x0020	/* Receiver on (R) */
-#define CSR0_TXON	0x0010  /* Transmitter on (R) */
-#define CSR0_TDMD	0x0008	/* Transmit Demand (RS) */
-#define CSR0_STOP	0x0004 	/* Stop (RS) */
-#define CSR0_STRT	0x0002	/* Start (RS) */
-#define CSR0_INIT	0x0001	/* Initialize (RS) */
-
-#define CSR0_CLRALL     0x7f00  /* mask for all clearable bits */
-
-/*
- *    Control and Status Register 3 (CSR3) bit definitions
- *
- */
-
-#define CSR3_BSWAP	0x0004	/* Byte Swap (RW) */
-#define CSR3_ACON	0x0002  /* ALE Control (RW) */
-#define CSR3_BCON	0x0001	/* Byte Control (RW) */
-
-/*
- *	Initialization Block Mode operation Bit Definitions.
- */
-
-#define MODE_PROM	0x8000	/* Promiscuous Mode */
-#define MODE_INTL	0x0040  /* Internal Loopback */
-#define MODE_DRTY	0x0020  /* Disable Retry */ 
-#define MODE_COLL	0x0010	/* Force Collision */
-#define MODE_DTCR	0x0008	/* Disable Transmit CRC) */
-#define MODE_LOOP	0x0004	/* Loopback */
-#define MODE_DTX	0x0002	/* Disable the Transmitter */ 
-#define MODE_DRX	0x0001  /* Disable the Receiver */
-
-#define MODE_NORMAL 	0x0000  /* Normal operation mode */
-
-/*
- * 	Receive message descriptor status bit definitions.
- */
-
-#define RX_OWN		0x80	/* Owner bit 0 = host, 1 = lance */
-#define RX_ERR		0x40	/* Error Summary */
-#define RX_FRAM		0x20	/* Framing Error */
-#define RX_OFLO		0x10	/* Overflow Error */
-#define RX_CRC		0x08	/* CRC Error */ 
-#define RX_BUFF		0x04	/* Buffer Error */
-#define RX_STP		0x02	/* Start of Packet */
-#define RX_ENP		0x01	/* End of Packet */
-
-
-/*
- *	Transmit message descriptor status bit definitions.
- */
-
-#define TX_OWN		0x80	/* Owner bit 0 = host, 1 = lance */
-#define TX_ERR		0x40    /* Error Summary */
-#define TX_MORE		0x10	/* More the 1 retry needed to Xmit */
-#define TX_ONE		0x08	/* One retry needed to Xmit */
-#define TX_DEF		0x04	/* Deferred */
-#define TX_STP 		0x02	/* Start of Packet */
-#define TX_ENP		0x01	/* End of Packet */
-
-/*
- *      Transmit status (2) (valid if TX_ERR == 1)
- */
-
-#define TX_BUFF 	0x8000  /* Buffering error (no ENP) */
-#define TX_UFLO 	0x4000  /* Underflow (late memory) */
-#define TX_LCOL 	0x1000  /* Late collision */
-#define TX_LCAR 	0x0400  /* Loss of Carrier */
-#define TX_RTRY 	0x0200  /* Failed after 16 retransmissions  */
-#define TX_TDR          0x003f  /* Time-domain-reflectometer-value */
-
-
-/* 
- * Structures used for Communication with the LANCE 
- */
-
-/* LANCE Initialize Block */
-
-struct init_block 
-{
-  unsigned short mode;     /* Mode Register */
-  unsigned char  paddr[6]; /* Physical Address (MAC) */
-  unsigned char  laddr[8]; /* Logical Filter Address (not used) */
-  unsigned int   rdrp;     /* Receive Descriptor Ring pointer */
-  unsigned int   tdrp;     /* Transmit Descriptor Ring pointer */
-};
-
-
-/* Receive Message Descriptor Entry */
-
-struct rmd 
-{ 
-  union
-  {
-    unsigned long buffer;     /* Address of buffer */
-    struct 
-    {
-      unsigned char unused[3]; 
-      unsigned volatile char status;   /* Status Bits */
-    } s;
-  } u;
-  volatile short blen;        /* Buffer Length (two's complement) */
-  unsigned short mlen;        /* Message Byte Count */
-};
-
-
-/* Transmit Message Descriptor Entry */
-
-struct tmd   
-{
-  union 
-  {
-    unsigned long  buffer;    /* Address of buffer */
-    struct 
-    {
-      unsigned char unused[3];
-      unsigned volatile char status;   /* Status Bits */
-    } s;
-  } u;
-  unsigned short blen;             /* Buffer Length (two's complement) */
-  unsigned volatile short status2; /* Error Status Bits */
-};
-
-#endif /* End of SK_G16_H */

+ 3386 - 0
drivers/net/skge.c

@@ -0,0 +1,3386 @@
+/*
+ * New driver for Marvell Yukon chipset and SysKonnect Gigabit
+ * Ethernet adapters. Based on earlier sk98lin, e100 and
+ * FreeBSD if_sk drivers.
+ *
+ * This driver intentionally does not support all the features
+ * of the original driver such as link fail-over and link management because
+ * those should be done at higher levels.
+ *
+ * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
+#include <asm/irq.h>
+
+#include "skge.h"
+
+#define DRV_NAME		"skge"
+#define DRV_VERSION		"0.6"
+#define PFX			DRV_NAME " "
+
+#define DEFAULT_TX_RING_SIZE	128
+#define DEFAULT_RX_RING_SIZE	512
+#define MAX_TX_RING_SIZE	1024
+#define MAX_RX_RING_SIZE	4096
+#define PHY_RETRIES	        1000
+#define ETH_JUMBO_MTU		9000
+#define TX_WATCHDOG		(5 * HZ)
+#define NAPI_WEIGHT		64
+#define BLINK_HZ		(HZ/4)
+#define LINK_POLL_HZ		(HZ/10)
+
+MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
+MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+static const u32 default_msg
+	= NETIF_MSG_DRV| NETIF_MSG_PROBE| NETIF_MSG_LINK
+	  | NETIF_MSG_IFUP| NETIF_MSG_IFDOWN;
+
+static int debug = -1;	/* defaults above */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+static const struct pci_device_id skge_id_table[] = {
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_SYSKONNECT, 0x9E00, /* SK-9Exx  */
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_MARVELL, 0x4320, /* Gigabit Ethernet Controller */
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_MARVELL, 0x5005, /* Marvell (11ab), Belkin */
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, skge_id_table);
+
+static int skge_up(struct net_device *dev);
+static int skge_down(struct net_device *dev);
+static void skge_tx_clean(struct skge_port *skge);
+static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static void genesis_get_stats(struct skge_port *skge, u64 *data);
+static void yukon_get_stats(struct skge_port *skge, u64 *data);
+static void yukon_init(struct skge_hw *hw, int port);
+static void yukon_reset(struct skge_hw *hw, int port);
+static void genesis_mac_init(struct skge_hw *hw, int port);
+static void genesis_reset(struct skge_hw *hw, int port);
+
+static const int txqaddr[] = { Q_XA1, Q_XA2 };
+static const int rxqaddr[] = { Q_R1, Q_R2 };
+static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F };
+static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F };
+
+/* Don't need to look at whole 16K.
+ * last interesting register is descriptor poll timer.
+ */
+#define SKGE_REGS_LEN	(29*128)
+
+static int skge_get_regs_len(struct net_device *dev)
+{
+	return SKGE_REGS_LEN;
+}
+
+/*
+ * Returns copy of control register region
+ * I/O region is divided into banks and certain regions are unreadable
+ */
+static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+			  void *p)
+{
+	const struct skge_port *skge = netdev_priv(dev);
+	unsigned long offs;
+	const void __iomem *io = skge->hw->regs;
+	static const unsigned long bankmap
+		= (1<<0) | (1<<2) | (1<<8) | (1<<9)
+		  | (1<<12) | (1<<13) | (1<<14) | (1<<15) | (1<<16)
+		  | (1<<17) | (1<<20) | (1<<21) | (1<<22) | (1<<23)
+		  | (1<<24)  | (1<<25) | (1<<26) | (1<<27) | (1<<28);
+
+	regs->version = 1;
+	for (offs = 0; offs < regs->len; offs += 128) {
+		u32 len = min_t(u32, 128, regs->len - offs);
+
+		if (bankmap & (1<<(offs/128)))
+			memcpy_fromio(p + offs, io + offs, len);
+		else
+			memset(p + offs, 0, len);
+	}
+}
+
+/* Wake on Lan only supported on Yukon chps with rev 1 or above */
+static int wol_supported(const struct skge_hw *hw)
+{
+	return !((hw->chip_id == CHIP_ID_GENESIS ||
+		  (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0)));
+}
+
+static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	wol->supported = wol_supported(skge->hw) ? WAKE_MAGIC : 0;
+	wol->wolopts = skge->wol ? WAKE_MAGIC : 0;
+}
+
+static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+
+	if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+		return -EOPNOTSUPP;
+
+	if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
+		return -EOPNOTSUPP;
+
+	skge->wol = wol->wolopts == WAKE_MAGIC;
+
+	if (skge->wol) {
+		memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN);
+
+		skge_write16(hw, WOL_CTRL_STAT,
+			     WOL_CTL_ENA_PME_ON_MAGIC_PKT |
+			     WOL_CTL_ENA_MAGIC_PKT_UNIT);
+	} else
+		skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT);
+
+	return 0;
+}
+
+
+static int skge_get_settings(struct net_device *dev,
+			     struct ethtool_cmd *ecmd)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+
+	ecmd->transceiver = XCVR_INTERNAL;
+
+	if (iscopper(hw)) {
+		if (hw->chip_id == CHIP_ID_GENESIS)
+			ecmd->supported = SUPPORTED_1000baseT_Full
+				| SUPPORTED_1000baseT_Half
+				| SUPPORTED_Autoneg | SUPPORTED_TP;
+		else {
+			ecmd->supported = SUPPORTED_10baseT_Half
+				| SUPPORTED_10baseT_Full
+				| SUPPORTED_100baseT_Half
+				| SUPPORTED_100baseT_Full
+				| SUPPORTED_1000baseT_Half
+				| SUPPORTED_1000baseT_Full
+				| SUPPORTED_Autoneg| SUPPORTED_TP;
+
+			if (hw->chip_id == CHIP_ID_YUKON)
+				ecmd->supported &= ~SUPPORTED_1000baseT_Half;
+
+			else if (hw->chip_id == CHIP_ID_YUKON_FE)
+				ecmd->supported &= ~(SUPPORTED_1000baseT_Half
+						     | SUPPORTED_1000baseT_Full);
+		}
+
+		ecmd->port = PORT_TP;
+		ecmd->phy_address = hw->phy_addr;
+	} else {
+		ecmd->supported = SUPPORTED_1000baseT_Full
+			| SUPPORTED_FIBRE
+			| SUPPORTED_Autoneg;
+
+		ecmd->port = PORT_FIBRE;
+	}
+
+	ecmd->advertising = skge->advertising;
+	ecmd->autoneg = skge->autoneg;
+	ecmd->speed = skge->speed;
+	ecmd->duplex = skge->duplex;
+	return 0;
+}
+
+static u32 skge_modes(const struct skge_hw *hw)
+{
+	u32 modes = ADVERTISED_Autoneg
+		| ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half
+		| ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half
+		| ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half;
+
+	if (iscopper(hw)) {
+		modes |= ADVERTISED_TP;
+		switch(hw->chip_id) {
+		case CHIP_ID_GENESIS:
+			modes &= ~(ADVERTISED_100baseT_Full
+				   | ADVERTISED_100baseT_Half
+				   | ADVERTISED_10baseT_Full
+				   | ADVERTISED_10baseT_Half);
+			break;
+
+		case CHIP_ID_YUKON:
+			modes &= ~ADVERTISED_1000baseT_Half;
+			break;
+
+		case CHIP_ID_YUKON_FE:
+			modes &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+			break;
+		}
+	} else {
+		modes |= ADVERTISED_FIBRE;
+		modes &= ~ADVERTISED_1000baseT_Half;
+	}
+	return modes;
+}
+
+static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	const struct skge_hw *hw = skge->hw;
+
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+		if (ecmd->advertising & skge_modes(hw))
+			return -EINVAL;
+	} else {
+		switch(ecmd->speed) {
+		case SPEED_1000:
+			if (hw->chip_id == CHIP_ID_YUKON_FE)
+				return -EINVAL;
+			break;
+		case SPEED_100:
+		case SPEED_10:
+			if (iscopper(hw) || hw->chip_id == CHIP_ID_GENESIS)
+				return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	skge->autoneg = ecmd->autoneg;
+	skge->speed = ecmd->speed;
+	skge->duplex = ecmd->duplex;
+	skge->advertising = ecmd->advertising;
+
+	if (netif_running(dev)) {
+		skge_down(dev);
+		skge_up(dev);
+	}
+	return (0);
+}
+
+static void skge_get_drvinfo(struct net_device *dev,
+			     struct ethtool_drvinfo *info)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->fw_version, "N/A");
+	strcpy(info->bus_info, pci_name(skge->hw->pdev));
+}
+
+static const struct skge_stat {
+	char 	   name[ETH_GSTRING_LEN];
+	u16	   xmac_offset;
+	u16	   gma_offset;
+} skge_stats[] = {
+	{ "tx_bytes",		XM_TXO_OK_HI,  GM_TXO_OK_HI },
+	{ "rx_bytes",		XM_RXO_OK_HI,  GM_RXO_OK_HI },
+
+	{ "tx_broadcast",	XM_TXF_BC_OK,  GM_TXF_BC_OK },
+	{ "rx_broadcast",	XM_RXF_BC_OK,  GM_RXF_BC_OK },
+	{ "tx_multicast",	XM_TXF_MC_OK,  GM_TXF_MC_OK },
+	{ "rx_multicast",	XM_RXF_MC_OK,  GM_RXF_MC_OK },
+	{ "tx_unicast",		XM_TXF_UC_OK,  GM_TXF_UC_OK },
+	{ "rx_unicast",		XM_RXF_UC_OK,  GM_RXF_UC_OK },
+	{ "tx_mac_pause",	XM_TXF_MPAUSE, GM_TXF_MPAUSE },
+	{ "rx_mac_pause",	XM_RXF_MPAUSE, GM_RXF_MPAUSE },
+
+	{ "collisions",		XM_TXF_SNG_COL, GM_TXF_SNG_COL },
+	{ "multi_collisions",	XM_TXF_MUL_COL, GM_TXF_MUL_COL },
+	{ "aborted",		XM_TXF_ABO_COL, GM_TXF_ABO_COL },
+	{ "late_collision",	XM_TXF_LAT_COL, GM_TXF_LAT_COL },
+	{ "fifo_underrun",	XM_TXE_FIFO_UR, GM_TXE_FIFO_UR },
+	{ "fifo_overflow",	XM_RXE_FIFO_OV, GM_RXE_FIFO_OV },
+
+	{ "rx_toolong",		XM_RXF_LNG_ERR, GM_RXF_LNG_ERR },
+	{ "rx_jabber",		XM_RXF_JAB_PKT, GM_RXF_JAB_PKT },
+	{ "rx_runt",		XM_RXE_RUNT, 	GM_RXE_FRAG },
+	{ "rx_too_long",	XM_RXF_LNG_ERR, GM_RXF_LNG_ERR },
+	{ "rx_fcs_error",	XM_RXF_FCS_ERR, GM_RXF_FCS_ERR },
+};
+
+static int skge_get_stats_count(struct net_device *dev)
+{
+	return ARRAY_SIZE(skge_stats);
+}
+
+static void skge_get_ethtool_stats(struct net_device *dev,
+				   struct ethtool_stats *stats, u64 *data)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	if (skge->hw->chip_id == CHIP_ID_GENESIS)
+		genesis_get_stats(skge, data);
+	else
+		yukon_get_stats(skge, data);
+}
+
+/* Use hardware MIB variables for critical path statistics and
+ * transmit feedback not reported at interrupt.
+ * Other errors are accounted for in interrupt handler.
+ */
+static struct net_device_stats *skge_get_stats(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	u64 data[ARRAY_SIZE(skge_stats)];
+
+	if (skge->hw->chip_id == CHIP_ID_GENESIS)
+		genesis_get_stats(skge, data);
+	else
+		yukon_get_stats(skge, data);
+
+	skge->net_stats.tx_bytes = data[0];
+	skge->net_stats.rx_bytes = data[1];
+	skge->net_stats.tx_packets = data[2] + data[4] + data[6];
+	skge->net_stats.rx_packets = data[3] + data[5] + data[7];
+	skge->net_stats.multicast = data[5] + data[7];
+	skge->net_stats.collisions = data[10];
+	skge->net_stats.tx_aborted_errors = data[12];
+
+	return &skge->net_stats;
+}
+
+static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	int i;
+
+	switch(stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < ARRAY_SIZE(skge_stats); i++)
+			memcpy(data + i * ETH_GSTRING_LEN,
+			       skge_stats[i].name, ETH_GSTRING_LEN);
+		break;
+	}
+}
+
+static void skge_get_ring_param(struct net_device *dev,
+				struct ethtool_ringparam *p)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	p->rx_max_pending = MAX_RX_RING_SIZE;
+	p->tx_max_pending = MAX_TX_RING_SIZE;
+	p->rx_mini_max_pending = 0;
+	p->rx_jumbo_max_pending = 0;
+
+	p->rx_pending = skge->rx_ring.count;
+	p->tx_pending = skge->tx_ring.count;
+	p->rx_mini_pending = 0;
+	p->rx_jumbo_pending = 0;
+}
+
+static int skge_set_ring_param(struct net_device *dev,
+			       struct ethtool_ringparam *p)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	if (p->rx_pending == 0 || p->rx_pending > MAX_RX_RING_SIZE ||
+	    p->tx_pending == 0 || p->tx_pending > MAX_TX_RING_SIZE)
+		return -EINVAL;
+
+	skge->rx_ring.count = p->rx_pending;
+	skge->tx_ring.count = p->tx_pending;
+
+	if (netif_running(dev)) {
+		skge_down(dev);
+		skge_up(dev);
+	}
+
+	return 0;
+}
+
+static u32 skge_get_msglevel(struct net_device *netdev)
+{
+	struct skge_port *skge = netdev_priv(netdev);
+	return skge->msg_enable;
+}
+
+static void skge_set_msglevel(struct net_device *netdev, u32 value)
+{
+	struct skge_port *skge = netdev_priv(netdev);
+	skge->msg_enable = value;
+}
+
+static int skge_nway_reset(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	if (skge->autoneg != AUTONEG_ENABLE || !netif_running(dev))
+		return -EINVAL;
+
+	spin_lock_bh(&hw->phy_lock);
+	if (hw->chip_id == CHIP_ID_GENESIS) {
+		genesis_reset(hw, port);
+		genesis_mac_init(hw, port);
+	} else {
+		yukon_reset(hw, port);
+		yukon_init(hw, port);
+	}
+	spin_unlock_bh(&hw->phy_lock);
+	return 0;
+}
+
+static int skge_set_sg(struct net_device *dev, u32 data)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+
+	if (hw->chip_id == CHIP_ID_GENESIS && data)
+		return -EOPNOTSUPP;
+	return ethtool_op_set_sg(dev, data);
+}
+
+static int skge_set_tx_csum(struct net_device *dev, u32 data)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+
+	if (hw->chip_id == CHIP_ID_GENESIS && data)
+		return -EOPNOTSUPP;
+
+	return ethtool_op_set_tx_csum(dev, data);
+}
+
+static u32 skge_get_rx_csum(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	return skge->rx_csum;
+}
+
+/* Only Yukon supports checksum offload. */
+static int skge_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	if (skge->hw->chip_id == CHIP_ID_GENESIS && data)
+		return -EOPNOTSUPP;
+
+	skge->rx_csum = data;
+	return 0;
+}
+
+/* Only Yukon II supports TSO (not implemented yet) */
+static int skge_set_tso(struct net_device *dev, u32 data)
+{
+	if (data)
+		return -EOPNOTSUPP;
+	return 0;
+}
+
+static void skge_get_pauseparam(struct net_device *dev,
+				struct ethtool_pauseparam *ecmd)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	ecmd->tx_pause = (skge->flow_control == FLOW_MODE_LOC_SEND)
+		|| (skge->flow_control == FLOW_MODE_SYMMETRIC);
+	ecmd->rx_pause = (skge->flow_control == FLOW_MODE_REM_SEND)
+		|| (skge->flow_control == FLOW_MODE_SYMMETRIC);
+
+	ecmd->autoneg = skge->autoneg;
+}
+
+static int skge_set_pauseparam(struct net_device *dev,
+			       struct ethtool_pauseparam *ecmd)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	skge->autoneg = ecmd->autoneg;
+	if (ecmd->rx_pause && ecmd->tx_pause)
+		skge->flow_control = FLOW_MODE_SYMMETRIC;
+	else if(ecmd->rx_pause && !ecmd->tx_pause)
+		skge->flow_control = FLOW_MODE_REM_SEND;
+	else if(!ecmd->rx_pause && ecmd->tx_pause)
+		skge->flow_control = FLOW_MODE_LOC_SEND;
+	else
+		skge->flow_control = FLOW_MODE_NONE;
+
+	if (netif_running(dev)) {
+		skge_down(dev);
+		skge_up(dev);
+	}
+	return 0;
+}
+
+/* Chip internal frequency for clock calculations */
+static inline u32 hwkhz(const struct skge_hw *hw)
+{
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		return 53215; /* or:  53.125 MHz */
+	else if (hw->chip_id == CHIP_ID_YUKON_EC)
+		return 125000; /* or: 125.000 MHz */
+	else
+		return 78215; /* or:  78.125 MHz */
+}
+
+/* Chip hz to microseconds */
+static inline u32 skge_clk2usec(const struct skge_hw *hw, u32 ticks)
+{
+	return (ticks * 1000) / hwkhz(hw);
+}
+
+/* Microseconds to chip hz */
+static inline u32 skge_usecs2clk(const struct skge_hw *hw, u32 usec)
+{
+	return hwkhz(hw) * usec / 1000;
+}
+
+static int skge_get_coalesce(struct net_device *dev,
+			     struct ethtool_coalesce *ecmd)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	ecmd->rx_coalesce_usecs = 0;
+	ecmd->tx_coalesce_usecs = 0;
+
+	if (skge_read32(hw, B2_IRQM_CTRL) & TIM_START) {
+		u32 delay = skge_clk2usec(hw, skge_read32(hw, B2_IRQM_INI));
+		u32 msk = skge_read32(hw, B2_IRQM_MSK);
+
+		if (msk & rxirqmask[port])
+			ecmd->rx_coalesce_usecs = delay;
+		if (msk & txirqmask[port])
+			ecmd->tx_coalesce_usecs = delay;
+	}
+
+	return 0;
+}
+
+/* Note: interrupt timer is per board, but can turn on/off per port */
+static int skge_set_coalesce(struct net_device *dev,
+			     struct ethtool_coalesce *ecmd)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u32 msk = skge_read32(hw, B2_IRQM_MSK);
+	u32 delay = 25;
+
+	if (ecmd->rx_coalesce_usecs == 0)
+		msk &= ~rxirqmask[port];
+	else if (ecmd->rx_coalesce_usecs < 25 ||
+		 ecmd->rx_coalesce_usecs > 33333)
+		return -EINVAL;
+	else {
+		msk |= rxirqmask[port];
+		delay = ecmd->rx_coalesce_usecs;
+	}
+
+	if (ecmd->tx_coalesce_usecs == 0)
+		msk &= ~txirqmask[port];
+	else if (ecmd->tx_coalesce_usecs < 25 ||
+		 ecmd->tx_coalesce_usecs > 33333)
+		return -EINVAL;
+	else {
+		msk |= txirqmask[port];
+		delay = min(delay, ecmd->rx_coalesce_usecs);
+	}
+
+	skge_write32(hw, B2_IRQM_MSK, msk);
+	if (msk == 0)
+		skge_write32(hw, B2_IRQM_CTRL, TIM_STOP);
+	else {
+		skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, delay));
+		skge_write32(hw, B2_IRQM_CTRL, TIM_START);
+	}
+	return 0;
+}
+
+static void skge_led_on(struct skge_hw *hw, int port)
+{
+	if (hw->chip_id == CHIP_ID_GENESIS) {
+		skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON);
+		skge_write8(hw, B0_LED, LED_STAT_ON);
+
+		skge_write8(hw, SKGEMAC_REG(port, RX_LED_TST), LED_T_ON);
+		skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 100);
+		skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START);
+
+		switch (hw->phy_type) {
+		case SK_PHY_BCOM:
+			skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
+					  PHY_B_PEC_LED_ON);
+			break;
+		case SK_PHY_LONE:
+			skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG,
+					  0x0800);
+			break;
+		default:
+			skge_write8(hw, SKGEMAC_REG(port, TX_LED_TST), LED_T_ON);
+			skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 100);
+			skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START);
+		}
+	} else {
+		skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+		skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+				  PHY_M_LED_MO_DUP(MO_LED_ON)  |
+				  PHY_M_LED_MO_10(MO_LED_ON)   |
+				  PHY_M_LED_MO_100(MO_LED_ON)  |
+				  PHY_M_LED_MO_1000(MO_LED_ON) |
+				  PHY_M_LED_MO_RX(MO_LED_ON));
+	}
+}
+
+static void skge_led_off(struct skge_hw *hw, int port)
+{
+	if (hw->chip_id == CHIP_ID_GENESIS) {
+		skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_OFF);
+		skge_write8(hw, B0_LED, LED_STAT_OFF);
+
+		skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 0);
+		skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_T_OFF);
+
+		switch (hw->phy_type) {
+		case SK_PHY_BCOM:
+			skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
+					  PHY_B_PEC_LED_OFF);
+			break;
+		case SK_PHY_LONE:
+			skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG,
+					  PHY_L_LC_LEDT);
+			break;
+		default:
+			skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 0);
+			skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_T_OFF);
+		}
+	} else {
+		skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+		skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+				  PHY_M_LED_MO_DUP(MO_LED_OFF)  |
+				  PHY_M_LED_MO_10(MO_LED_OFF)   |
+				  PHY_M_LED_MO_100(MO_LED_OFF)  |
+				  PHY_M_LED_MO_1000(MO_LED_OFF) |
+				  PHY_M_LED_MO_RX(MO_LED_OFF));
+	}
+}
+
+static void skge_blink_timer(unsigned long data)
+{
+	struct skge_port *skge = (struct skge_port *) data;
+	struct skge_hw *hw = skge->hw;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hw->phy_lock, flags);
+	if (skge->blink_on)
+		skge_led_on(hw, skge->port);
+	else
+		skge_led_off(hw, skge->port);
+	spin_unlock_irqrestore(&hw->phy_lock, flags);
+
+	skge->blink_on = !skge->blink_on;
+	mod_timer(&skge->led_blink, jiffies + BLINK_HZ);
+}
+
+/* blink LED's for finding board */
+static int skge_phys_id(struct net_device *dev, u32 data)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+		data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+	/* start blinking */
+	skge->blink_on = 1;
+	mod_timer(&skge->led_blink, jiffies+1);
+
+	msleep_interruptible(data * 1000);
+	del_timer_sync(&skge->led_blink);
+
+	skge_led_off(skge->hw, skge->port);
+
+	return 0;
+}
+
+static struct ethtool_ops skge_ethtool_ops = {
+	.get_settings	= skge_get_settings,
+	.set_settings	= skge_set_settings,
+	.get_drvinfo	= skge_get_drvinfo,
+	.get_regs_len	= skge_get_regs_len,
+	.get_regs	= skge_get_regs,
+	.get_wol	= skge_get_wol,
+	.set_wol	= skge_set_wol,
+	.get_msglevel	= skge_get_msglevel,
+	.set_msglevel	= skge_set_msglevel,
+	.nway_reset	= skge_nway_reset,
+	.get_link	= ethtool_op_get_link,
+	.get_ringparam	= skge_get_ring_param,
+	.set_ringparam	= skge_set_ring_param,
+	.get_pauseparam = skge_get_pauseparam,
+	.set_pauseparam = skge_set_pauseparam,
+	.get_coalesce	= skge_get_coalesce,
+	.set_coalesce	= skge_set_coalesce,
+	.get_tso	= ethtool_op_get_tso,
+	.set_tso	= skge_set_tso,
+	.get_sg		= ethtool_op_get_sg,
+	.set_sg		= skge_set_sg,
+	.get_tx_csum	= ethtool_op_get_tx_csum,
+	.set_tx_csum	= skge_set_tx_csum,
+	.get_rx_csum	= skge_get_rx_csum,
+	.set_rx_csum	= skge_set_rx_csum,
+	.get_strings	= skge_get_strings,
+	.phys_id	= skge_phys_id,
+	.get_stats_count = skge_get_stats_count,
+	.get_ethtool_stats = skge_get_ethtool_stats,
+};
+
+/*
+ * Allocate ring elements and chain them together
+ * One-to-one association of board descriptors with ring elements
+ */
+static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
+{
+	struct skge_tx_desc *d;
+	struct skge_element *e;
+	int i;
+
+	ring->start = kmalloc(sizeof(*e)*ring->count, GFP_KERNEL);
+	if (!ring->start)
+		return -ENOMEM;
+
+	for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) {
+		e->desc = d;
+		if (i == ring->count - 1) {
+			e->next = ring->start;
+			d->next_offset = base;
+		} else {
+			e->next = e + 1;
+			d->next_offset = base + (i+1) * sizeof(*d);
+		}
+	}
+	ring->to_use = ring->to_clean = ring->start;
+
+	return 0;
+}
+
+/* Setup buffer for receiving */
+static inline int skge_rx_alloc(struct skge_port *skge,
+				struct skge_element *e)
+{
+	unsigned long bufsize = skge->netdev->mtu + ETH_HLEN; /* VLAN? */
+	struct skge_rx_desc *rd = e->desc;
+	struct sk_buff *skb;
+	u64 map;
+
+	skb = dev_alloc_skb(bufsize + NET_IP_ALIGN);
+	if (unlikely(!skb)) {
+		printk(KERN_DEBUG PFX "%s: out of memory for receive\n",
+		       skge->netdev->name);
+		return -ENOMEM;
+	}
+
+	skb->dev = skge->netdev;
+	skb_reserve(skb, NET_IP_ALIGN);
+
+	map = pci_map_single(skge->hw->pdev, skb->data, bufsize,
+			     PCI_DMA_FROMDEVICE);
+
+	rd->dma_lo = map;
+	rd->dma_hi = map >> 32;
+	e->skb = skb;
+	rd->csum1_start = ETH_HLEN;
+	rd->csum2_start = ETH_HLEN;
+	rd->csum1 = 0;
+	rd->csum2 = 0;
+
+	wmb();
+
+	rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize;
+	pci_unmap_addr_set(e, mapaddr, map);
+	pci_unmap_len_set(e, maplen, bufsize);
+	return 0;
+}
+
+/* Free all unused buffers in receive ring, assumes receiver stopped */
+static void skge_rx_clean(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	struct skge_ring *ring = &skge->rx_ring;
+	struct skge_element *e;
+
+	for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+		struct skge_rx_desc *rd = e->desc;
+		rd->control = 0;
+
+		pci_unmap_single(hw->pdev,
+				 pci_unmap_addr(e, mapaddr),
+				 pci_unmap_len(e, maplen),
+				 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb(e->skb);
+		e->skb = NULL;
+	}
+	ring->to_clean = e;
+}
+
+/* Allocate buffers for receive ring
+ * For receive: to_use   is refill location
+ *              to_clean is next received frame.
+ *
+ * if (to_use == to_clean)
+ *	 then ring all frames in ring need buffers
+ * if (to_use->next == to_clean)
+ *	 then ring all frames in ring have buffers
+ */
+static int skge_rx_fill(struct skge_port *skge)
+{
+	struct skge_ring *ring = &skge->rx_ring;
+	struct skge_element *e;
+	int ret = 0;
+
+	for (e = ring->to_use; e->next != ring->to_clean; e = e->next) {
+		if (skge_rx_alloc(skge, e)) {
+			ret = 1;
+			break;
+		}
+
+	}
+	ring->to_use = e;
+
+	return ret;
+}
+
+static void skge_link_up(struct skge_port *skge)
+{
+	netif_carrier_on(skge->netdev);
+	if (skge->tx_avail > MAX_SKB_FRAGS + 1)
+		netif_wake_queue(skge->netdev);
+
+	if (netif_msg_link(skge))
+		printk(KERN_INFO PFX
+		       "%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
+		       skge->netdev->name, skge->speed,
+		       skge->duplex == DUPLEX_FULL ? "full" : "half",
+		       (skge->flow_control == FLOW_MODE_NONE) ? "none" :
+		       (skge->flow_control == FLOW_MODE_LOC_SEND) ? "tx only" :
+		       (skge->flow_control == FLOW_MODE_REM_SEND) ? "rx only" :
+		       (skge->flow_control == FLOW_MODE_SYMMETRIC) ? "tx and rx" :
+		       "unknown");
+}
+
+static void skge_link_down(struct skge_port *skge)
+{
+	netif_carrier_off(skge->netdev);
+	netif_stop_queue(skge->netdev);
+
+	if (netif_msg_link(skge))
+		printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
+}
+
+static u16 skge_xm_phy_read(struct skge_hw *hw, int port,  u16 reg)
+{
+	int i;
+	u16 v;
+
+	skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+	v = skge_xm_read16(hw, port, XM_PHY_DATA);
+	if (hw->phy_type != SK_PHY_XMAC) {
+		for (i = 0; i < PHY_RETRIES; i++) {
+			udelay(1);
+			if (skge_xm_read16(hw, port, XM_MMU_CMD)
+			    & XM_MMU_PHY_RDY)
+				goto ready;
+		}
+
+		printk(KERN_WARNING PFX "%s: phy read timed out\n",
+		       hw->dev[port]->name);
+		return 0;
+	ready:
+		v = skge_xm_read16(hw, port, XM_PHY_DATA);
+	}
+
+	return v;
+}
+
+static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+{
+	int i;
+
+	skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+	for (i = 0; i < PHY_RETRIES; i++) {
+		if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+			goto ready;
+		cpu_relax();
+	}
+	printk(KERN_WARNING PFX "%s: phy write failed to come ready\n",
+	       hw->dev[port]->name);
+
+
+ ready:
+	skge_xm_write16(hw, port, XM_PHY_DATA, val);
+	for (i = 0; i < PHY_RETRIES; i++) {
+		udelay(1);
+		if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+			return;
+	}
+	printk(KERN_WARNING PFX "%s: phy write timed out\n",
+		       hw->dev[port]->name);
+}
+
+static void genesis_init(struct skge_hw *hw)
+{
+	/* set blink source counter */
+	skge_write32(hw, B2_BSC_INI, (SK_BLK_DUR * SK_FACT_53) / 100);
+	skge_write8(hw, B2_BSC_CTRL, BSC_START);
+
+	/* configure mac arbiter */
+	skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR);
+
+	/* configure mac arbiter timeout values */
+	skge_write8(hw, B3_MA_TOINI_RX1, SK_MAC_TO_53);
+	skge_write8(hw, B3_MA_TOINI_RX2, SK_MAC_TO_53);
+	skge_write8(hw, B3_MA_TOINI_TX1, SK_MAC_TO_53);
+	skge_write8(hw, B3_MA_TOINI_TX2, SK_MAC_TO_53);
+
+	skge_write8(hw, B3_MA_RCINI_RX1, 0);
+	skge_write8(hw, B3_MA_RCINI_RX2, 0);
+	skge_write8(hw, B3_MA_RCINI_TX1, 0);
+	skge_write8(hw, B3_MA_RCINI_TX2, 0);
+
+	/* configure packet arbiter timeout */
+	skge_write16(hw, B3_PA_CTRL, PA_RST_CLR);
+	skge_write16(hw, B3_PA_TOINI_RX1, SK_PKT_TO_MAX);
+	skge_write16(hw, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
+	skge_write16(hw, B3_PA_TOINI_RX2, SK_PKT_TO_MAX);
+	skge_write16(hw, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);
+}
+
+static void genesis_reset(struct skge_hw *hw, int port)
+{
+	int i;
+	u64 zero = 0;
+
+	/* reset the statistics module */
+	skge_xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
+	skge_xm_write16(hw, port, XM_IMSK, 0xffff);	/* disable XMAC IRQs */
+	skge_xm_write32(hw, port, XM_MODE, 0);		/* clear Mode Reg */
+	skge_xm_write16(hw, port, XM_TX_CMD, 0);	/* reset TX CMD Reg */
+	skge_xm_write16(hw, port, XM_RX_CMD, 0);	/* reset RX CMD Reg */
+
+	/* disable all PHY IRQs */
+	if  (hw->phy_type == SK_PHY_BCOM)
+		skge_xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+
+	skge_xm_outhash(hw, port, XM_HSM, (u8 *) &zero);
+	for (i = 0; i < 15; i++)
+		skge_xm_outaddr(hw, port, XM_EXM(i), (u8 *) &zero);
+	skge_xm_outhash(hw, port, XM_SRC_CHK, (u8 *) &zero);
+}
+
+
+static void genesis_mac_init(struct skge_hw *hw, int port)
+{
+	struct skge_port *skge = netdev_priv(hw->dev[port]);
+	int i;
+	u32 r;
+	u16 id1;
+	u16 ctrl1, ctrl2, ctrl3, ctrl4, ctrl5;
+
+	/* magic workaround patterns for Broadcom */
+	static const struct {
+		u16 reg;
+		u16 val;
+	} A1hack[] = {
+		{ 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 },
+		{ 0x17, 0x0013 }, { 0x15, 0x0404 }, { 0x17, 0x8006 },
+		{ 0x15, 0x0132 }, { 0x17, 0x8006 }, { 0x15, 0x0232 },
+		{ 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
+	}, C0hack[] = {
+		{ 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 },
+		{ 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 },
+	};
+
+
+	/* initialize Rx, Tx and Link LED */
+	skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON);
+	skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON);
+
+	skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START);
+	skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START);
+
+	/* Unreset the XMAC. */
+	skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+
+	/*
+	 * Perform additional initialization for external PHYs,
+	 * namely for the 1000baseTX cards that use the XMAC's
+	 * GMII mode.
+	 */
+	spin_lock_bh(&hw->phy_lock);
+	if (hw->phy_type != SK_PHY_XMAC) {
+		/* Take PHY out of reset. */
+		r = skge_read32(hw, B2_GP_IO);
+		if (port == 0)
+			r |= GP_DIR_0|GP_IO_0;
+		else
+			r |= GP_DIR_2|GP_IO_2;
+
+		skge_write32(hw, B2_GP_IO, r);
+		skge_read32(hw, B2_GP_IO);
+
+		/* Enable GMII mode on the XMAC. */
+		skge_xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
+
+		id1 = skge_xm_phy_read(hw, port, PHY_XMAC_ID1);
+
+		/* Optimize MDIO transfer by suppressing preamble. */
+		skge_xm_write16(hw, port, XM_MMU_CMD,
+				skge_xm_read16(hw, port, XM_MMU_CMD)
+				| XM_MMU_NO_PRE);
+
+		if (id1 == PHY_BCOM_ID1_C0) {
+			/*
+			 * Workaround BCOM Errata for the C0 type.
+			 * Write magic patterns to reserved registers.
+			 */
+			for (i = 0; i < ARRAY_SIZE(C0hack); i++)
+				skge_xm_phy_write(hw, port,
+					  C0hack[i].reg, C0hack[i].val);
+
+		} else if (id1 == PHY_BCOM_ID1_A1) {
+			/*
+			 * Workaround BCOM Errata for the A1 type.
+			 * Write magic patterns to reserved registers.
+			 */
+			for (i = 0; i < ARRAY_SIZE(A1hack); i++)
+				skge_xm_phy_write(hw, port,
+					  A1hack[i].reg, A1hack[i].val);
+		}
+
+		/*
+		 * Workaround BCOM Errata (#10523) for all BCom PHYs.
+		 * Disable Power Management after reset.
+		 */
+		r = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
+		skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r | PHY_B_AC_DIS_PM);
+	}
+
+	/* Dummy read */
+	skge_xm_read16(hw, port, XM_ISRC);
+
+	r = skge_xm_read32(hw, port, XM_MODE);
+	skge_xm_write32(hw, port, XM_MODE, r|XM_MD_CSA);
+
+	/* We don't need the FCS appended to the packet. */
+	r = skge_xm_read16(hw, port, XM_RX_CMD);
+	skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_STRIP_FCS);
+
+	/* We want short frames padded to 60 bytes. */
+	r = skge_xm_read16(hw, port, XM_TX_CMD);
+	skge_xm_write16(hw, port, XM_TX_CMD, r | XM_TX_AUTO_PAD);
+
+	/*
+	 * Enable the reception of all error frames. This is is
+	 * a necessary evil due to the design of the XMAC. The
+	 * XMAC's receive FIFO is only 8K in size, however jumbo
+	 * frames can be up to 9000 bytes in length. When bad
+	 * frame filtering is enabled, the XMAC's RX FIFO operates
+	 * in 'store and forward' mode. For this to work, the
+	 * entire frame has to fit into the FIFO, but that means
+	 * that jumbo frames larger than 8192 bytes will be
+	 * truncated. Disabling all bad frame filtering causes
+	 * the RX FIFO to operate in streaming mode, in which
+	 * case the XMAC will start transfering frames out of the
+	 * RX FIFO as soon as the FIFO threshold is reached.
+	 */
+	r = skge_xm_read32(hw, port, XM_MODE);
+	skge_xm_write32(hw, port, XM_MODE,
+		     XM_MD_RX_CRCE|XM_MD_RX_LONG|XM_MD_RX_RUNT|
+		     XM_MD_RX_ERR|XM_MD_RX_IRLE);
+
+	skge_xm_outaddr(hw, port, XM_SA, hw->dev[port]->dev_addr);
+	skge_xm_outaddr(hw, port, XM_EXM(0), hw->dev[port]->dev_addr);
+
+	/*
+	 * Bump up the transmit threshold. This helps hold off transmit
+	 * underruns when we're blasting traffic from both ports at once.
+	 */
+	skge_xm_write16(hw, port, XM_TX_THR, 512);
+
+	/* Configure MAC arbiter */
+	skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR);
+
+	/* configure timeout values */
+	skge_write8(hw, B3_MA_TOINI_RX1, 72);
+	skge_write8(hw, B3_MA_TOINI_RX2, 72);
+	skge_write8(hw, B3_MA_TOINI_TX1, 72);
+	skge_write8(hw, B3_MA_TOINI_TX2, 72);
+
+	skge_write8(hw, B3_MA_RCINI_RX1, 0);
+	skge_write8(hw, B3_MA_RCINI_RX2, 0);
+	skge_write8(hw, B3_MA_RCINI_TX1, 0);
+	skge_write8(hw, B3_MA_RCINI_TX2, 0);
+
+	/* Configure Rx MAC FIFO */
+	skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_CLR);
+	skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT);
+	skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+	/* Configure Tx MAC FIFO */
+	skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_CLR);
+	skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+	skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+
+	if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+		/* Enable frame flushing if jumbo frames used */
+		skge_write16(hw, SKGEMAC_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
+	} else {
+		/* enable timeout timers if normal frames */
+		skge_write16(hw, B3_PA_CTRL,
+			     port == 0 ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
+	}
+
+
+	r = skge_xm_read16(hw, port, XM_RX_CMD);
+	if (hw->dev[port]->mtu > ETH_DATA_LEN)
+		skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_BIG_PK_OK);
+	else
+		skge_xm_write16(hw, port, XM_RX_CMD, r & ~(XM_RX_BIG_PK_OK));
+
+	switch (hw->phy_type) {
+	case SK_PHY_XMAC:
+		if (skge->autoneg == AUTONEG_ENABLE) {
+			ctrl1 = PHY_X_AN_FD | PHY_X_AN_HD;
+
+			switch (skge->flow_control) {
+			case FLOW_MODE_NONE:
+				ctrl1 |= PHY_X_P_NO_PAUSE;
+				break;
+			case FLOW_MODE_LOC_SEND:
+				ctrl1 |= PHY_X_P_ASYM_MD;
+				break;
+			case FLOW_MODE_SYMMETRIC:
+				ctrl1 |= PHY_X_P_SYM_MD;
+				break;
+			case FLOW_MODE_REM_SEND:
+				ctrl1 |= PHY_X_P_BOTH_MD;
+				break;
+			}
+
+			skge_xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl1);
+			ctrl2 = PHY_CT_ANE | PHY_CT_RE_CFG;
+		} else {
+			ctrl2 = 0;
+			if (skge->duplex == DUPLEX_FULL)
+				ctrl2 |= PHY_CT_DUP_MD;
+		}
+
+		skge_xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl2);
+		break;
+
+	case SK_PHY_BCOM:
+		ctrl1 = PHY_CT_SP1000;
+		ctrl2 = 0;
+		ctrl3 = PHY_SEL_TYPE;
+		ctrl4 = PHY_B_PEC_EN_LTR;
+		ctrl5 = PHY_B_AC_TX_TST;
+
+		if (skge->autoneg == AUTONEG_ENABLE) {
+			/*
+			 * Workaround BCOM Errata #1 for the C5 type.
+			 * 1000Base-T Link Acquisition Failure in Slave Mode
+			 * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+			 */
+			ctrl2 |= PHY_B_1000C_RD;
+			if (skge->advertising & ADVERTISED_1000baseT_Half)
+				ctrl2 |= PHY_B_1000C_AHD;
+			if (skge->advertising & ADVERTISED_1000baseT_Full)
+				ctrl2 |= PHY_B_1000C_AFD;
+
+			/* Set Flow-control capabilities */
+			switch (skge->flow_control) {
+			case FLOW_MODE_NONE:
+				ctrl3 |= PHY_B_P_NO_PAUSE;
+				break;
+			case FLOW_MODE_LOC_SEND:
+				ctrl3 |= PHY_B_P_ASYM_MD;
+				break;
+			case FLOW_MODE_SYMMETRIC:
+				ctrl3 |= PHY_B_P_SYM_MD;
+				break;
+			case FLOW_MODE_REM_SEND:
+				ctrl3 |= PHY_B_P_BOTH_MD;
+				break;
+			}
+
+			/* Restart Auto-negotiation */
+			ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
+		} else {
+			if (skge->duplex == DUPLEX_FULL)
+				ctrl1 |= PHY_CT_DUP_MD;
+
+			ctrl2 |= PHY_B_1000C_MSE;	/* set it to Slave */
+		}
+
+		skge_xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, ctrl2);
+		skge_xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, ctrl3);
+
+		if (skge->netdev->mtu > ETH_DATA_LEN) {
+			ctrl4 |= PHY_B_PEC_HIGH_LA;
+			ctrl5 |= PHY_B_AC_LONG_PACK;
+
+			skge_xm_phy_write(hw, port,PHY_BCOM_AUX_CTRL, ctrl5);
+		}
+
+		skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ctrl4);
+		skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl1);
+		break;
+	}
+	spin_unlock_bh(&hw->phy_lock);
+
+	/* Clear MIB counters */
+	skge_xm_write16(hw, port, XM_STAT_CMD,
+			XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+	/* Clear two times according to Errata #3 */
+	skge_xm_write16(hw, port, XM_STAT_CMD,
+			XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+
+	/* Start polling for link status */
+	mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
+}
+
+static void genesis_stop(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	/* Clear Tx packet arbiter timeout IRQ */
+	skge_write16(hw, B3_PA_CTRL,
+		     port == 0 ? PA_CLR_TO_TX1 : PA_CLR_TO_TX2);
+
+	/*
+	 * If the transfer stucks at the MAC the STOP command will not
+	 * terminate if we don't flush the XMAC's transmit FIFO !
+	 */
+	skge_xm_write32(hw, port, XM_MODE,
+			skge_xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
+
+
+	/* Reset the MAC */
+	skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+
+	/* For external PHYs there must be special handling */
+	if (hw->phy_type != SK_PHY_XMAC) {
+		u32 reg = skge_read32(hw, B2_GP_IO);
+
+		if (port == 0) {
+			reg |= GP_DIR_0;
+			reg &= ~GP_IO_0;
+		} else {
+			reg |= GP_DIR_2;
+			reg &= ~GP_IO_2;
+		}
+		skge_write32(hw, B2_GP_IO, reg);
+		skge_read32(hw, B2_GP_IO);
+	}
+
+	skge_xm_write16(hw, port, XM_MMU_CMD,
+			skge_xm_read16(hw, port, XM_MMU_CMD)
+			& ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
+
+	skge_xm_read16(hw, port, XM_MMU_CMD);
+}
+
+
+static void genesis_get_stats(struct skge_port *skge, u64 *data)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	int i;
+	unsigned long timeout = jiffies + HZ;
+
+	skge_xm_write16(hw, port,
+			XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
+
+	/* wait for update to complete */
+	while (skge_xm_read16(hw, port, XM_STAT_CMD)
+	       & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) {
+		if (time_after(jiffies, timeout))
+			break;
+		udelay(10);
+	}
+
+	/* special case for 64 bit octet counter */
+	data[0] = (u64) skge_xm_read32(hw, port, XM_TXO_OK_HI) << 32
+		| skge_xm_read32(hw, port, XM_TXO_OK_LO);
+	data[1] = (u64) skge_xm_read32(hw, port, XM_RXO_OK_HI) << 32
+		| skge_xm_read32(hw, port, XM_RXO_OK_LO);
+
+	for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
+		data[i] = skge_xm_read32(hw, port, skge_stats[i].xmac_offset);
+}
+
+static void genesis_mac_intr(struct skge_hw *hw, int port)
+{
+	struct skge_port *skge = netdev_priv(hw->dev[port]);
+	u16 status = skge_xm_read16(hw, port, XM_ISRC);
+
+	pr_debug("genesis_intr status %x\n", status);
+	if (hw->phy_type == SK_PHY_XMAC) {
+		/* LInk down, start polling for state change */
+		if (status & XM_IS_INP_ASS) {
+			skge_xm_write16(hw, port, XM_IMSK,
+					skge_xm_read16(hw, port, XM_IMSK) | XM_IS_INP_ASS);
+			mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
+		}
+		else if (status & XM_IS_AND)
+			mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
+	}
+
+	if (status & XM_IS_TXF_UR) {
+		skge_xm_write32(hw, port, XM_MODE, XM_MD_FTF);
+		++skge->net_stats.tx_fifo_errors;
+	}
+	if (status & XM_IS_RXF_OV) {
+		skge_xm_write32(hw, port, XM_MODE, XM_MD_FRF);
+		++skge->net_stats.rx_fifo_errors;
+	}
+}
+
+static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+{
+	int i;
+
+	skge_gma_write16(hw, port, GM_SMI_DATA, val);
+	skge_gma_write16(hw, port, GM_SMI_CTRL,
+			 GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg));
+	for (i = 0; i < PHY_RETRIES; i++) {
+		udelay(1);
+
+		if (!(skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
+			break;
+	}
+}
+
+static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg)
+{
+	int i;
+
+	skge_gma_write16(hw, port, GM_SMI_CTRL,
+			 GM_SMI_CT_PHY_AD(hw->phy_addr)
+			 | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
+
+	for (i = 0; i < PHY_RETRIES; i++) {
+		udelay(1);
+		if (skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
+			goto ready;
+	}
+
+	printk(KERN_WARNING PFX "%s: phy read timeout\n",
+	       hw->dev[port]->name);
+	return 0;
+ ready:
+	return skge_gma_read16(hw, port, GM_SMI_DATA);
+}
+
+static void genesis_link_down(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	pr_debug("genesis_link_down\n");
+
+	skge_xm_write16(hw, port, XM_MMU_CMD,
+			skge_xm_read16(hw, port, XM_MMU_CMD)
+			& ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
+
+	/* dummy read to ensure writing */
+	(void) skge_xm_read16(hw, port, XM_MMU_CMD);
+
+	skge_link_down(skge);
+}
+
+static void genesis_link_up(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u16 cmd;
+	u32 mode, msk;
+
+	pr_debug("genesis_link_up\n");
+	cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
+
+	/*
+	 * enabling pause frame reception is required for 1000BT
+	 * because the XMAC is not reset if the link is going down
+	 */
+	if (skge->flow_control == FLOW_MODE_NONE ||
+	    skge->flow_control == FLOW_MODE_LOC_SEND)
+		cmd |= XM_MMU_IGN_PF;
+	else
+		/* Enable Pause Frame Reception */
+		cmd &= ~XM_MMU_IGN_PF;
+
+	skge_xm_write16(hw, port, XM_MMU_CMD, cmd);
+
+	mode = skge_xm_read32(hw, port, XM_MODE);
+	if (skge->flow_control == FLOW_MODE_SYMMETRIC ||
+	    skge->flow_control == FLOW_MODE_LOC_SEND) {
+		/*
+		 * Configure Pause Frame Generation
+		 * Use internal and external Pause Frame Generation.
+		 * Sending pause frames is edge triggered.
+		 * Send a Pause frame with the maximum pause time if
+		 * internal oder external FIFO full condition occurs.
+		 * Send a zero pause time frame to re-start transmission.
+		 */
+		/* XM_PAUSE_DA = '010000C28001' (default) */
+		/* XM_MAC_PTIME = 0xffff (maximum) */
+		/* remember this value is defined in big endian (!) */
+		skge_xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
+
+		mode |= XM_PAUSE_MODE;
+		skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
+	} else {
+		/*
+		 * disable pause frame generation is required for 1000BT
+		 * because the XMAC is not reset if the link is going down
+		 */
+		/* Disable Pause Mode in Mode Register */
+		mode &= ~XM_PAUSE_MODE;
+
+		skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+	}
+
+	skge_xm_write32(hw, port, XM_MODE, mode);
+
+	msk = XM_DEF_MSK;
+	if (hw->phy_type != SK_PHY_XMAC)
+		msk |= XM_IS_INP_ASS;	/* disable GP0 interrupt bit */
+
+	skge_xm_write16(hw, port, XM_IMSK, msk);
+	skge_xm_read16(hw, port, XM_ISRC);
+
+	/* get MMU Command Reg. */
+	cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
+	if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
+		cmd |= XM_MMU_GMII_FD;
+
+	if (hw->phy_type == SK_PHY_BCOM) {
+		/*
+		 * Workaround BCOM Errata (#10523) for all BCom Phys
+		 * Enable Power Management after link up
+		 */
+		skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+				  skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
+				  & ~PHY_B_AC_DIS_PM);
+		skge_xm_phy_write(hw, port, PHY_BCOM_INT_MASK,
+				  PHY_B_DEF_MSK);
+	}
+
+	/* enable Rx/Tx */
+	skge_xm_write16(hw, port, XM_MMU_CMD,
+			cmd | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+	skge_link_up(skge);
+}
+
+
+static void genesis_bcom_intr(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u16 stat = skge_xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+
+	pr_debug("genesis_bcom intr stat=%x\n", stat);
+
+	/* Workaround BCom Errata:
+	 *	enable and disable loopback mode if "NO HCD" occurs.
+	 */
+	if (stat & PHY_B_IS_NO_HDCL) {
+		u16 ctrl = skge_xm_phy_read(hw, port, PHY_BCOM_CTRL);
+		skge_xm_phy_write(hw, port, PHY_BCOM_CTRL,
+				  ctrl | PHY_CT_LOOP);
+		skge_xm_phy_write(hw, port, PHY_BCOM_CTRL,
+				  ctrl & ~PHY_CT_LOOP);
+	}
+
+	stat = skge_xm_phy_read(hw, port, PHY_BCOM_STAT);
+	if (stat & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) {
+		u16 aux = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
+		if ( !(aux & PHY_B_AS_LS) && netif_carrier_ok(skge->netdev))
+			genesis_link_down(skge);
+
+		else if (stat & PHY_B_IS_LST_CHANGE) {
+			if (aux & PHY_B_AS_AN_C) {
+				switch (aux & PHY_B_AS_AN_RES_MSK) {
+				case PHY_B_RES_1000FD:
+					skge->duplex = DUPLEX_FULL;
+					break;
+				case PHY_B_RES_1000HD:
+					skge->duplex = DUPLEX_HALF;
+					break;
+				}
+
+				switch (aux & PHY_B_AS_PAUSE_MSK) {
+				case PHY_B_AS_PAUSE_MSK:
+					skge->flow_control = FLOW_MODE_SYMMETRIC;
+					break;
+				case PHY_B_AS_PRR:
+					skge->flow_control = FLOW_MODE_REM_SEND;
+					break;
+				case PHY_B_AS_PRT:
+					skge->flow_control = FLOW_MODE_LOC_SEND;
+					break;
+				default:
+					skge->flow_control = FLOW_MODE_NONE;
+				}
+				skge->speed = SPEED_1000;
+			}
+			genesis_link_up(skge);
+		}
+		else
+			mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
+	}
+}
+
+/* Perodic poll of phy status to check for link transistion  */
+static void skge_link_timer(unsigned long __arg)
+{
+	struct skge_port *skge = (struct skge_port *) __arg;
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	if (hw->chip_id != CHIP_ID_GENESIS || !netif_running(skge->netdev))
+		return;
+
+	spin_lock_bh(&hw->phy_lock);
+	if (hw->phy_type == SK_PHY_BCOM)
+		genesis_bcom_intr(skge);
+	else {
+		int i;
+		for (i = 0; i < 3; i++)
+			if (skge_xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
+				break;
+
+		if (i == 3)
+			mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
+		else
+			genesis_link_up(skge);
+	}
+	spin_unlock_bh(&hw->phy_lock);
+}
+
+/* Marvell Phy Initailization */
+static void yukon_init(struct skge_hw *hw, int port)
+{
+	struct skge_port *skge = netdev_priv(hw->dev[port]);
+	u16 ctrl, ct1000, adv;
+	u16 ledctrl, ledover;
+
+	pr_debug("yukon_init\n");
+	if (skge->autoneg == AUTONEG_ENABLE) {
+		u16 ectrl = skge_gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
+
+		ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
+			  PHY_M_EC_MAC_S_MSK);
+		ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
+
+		/* on PHY 88E1111 there is a change for downshift control */
+		if (hw->chip_id == CHIP_ID_YUKON_EC)
+			ectrl |= PHY_M_EC_M_DSC_2(0) | PHY_M_EC_DOWN_S_ENA;
+		else
+			ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+
+		skge_gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
+	}
+
+	ctrl = skge_gm_phy_read(hw, port, PHY_MARV_CTRL);
+	if (skge->autoneg == AUTONEG_DISABLE)
+		ctrl &= ~PHY_CT_ANE;
+
+	ctrl |= PHY_CT_RESET;
+	skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+
+	ctrl = 0;
+	ct1000 = 0;
+	adv = PHY_SEL_TYPE;
+
+	if (skge->autoneg == AUTONEG_ENABLE) {
+		if (iscopper(hw)) {
+			if (skge->advertising & ADVERTISED_1000baseT_Full)
+				ct1000 |= PHY_M_1000C_AFD;
+			if (skge->advertising & ADVERTISED_1000baseT_Half)
+				ct1000 |= PHY_M_1000C_AHD;
+			if (skge->advertising & ADVERTISED_100baseT_Full)
+				adv |= PHY_M_AN_100_FD;
+			if (skge->advertising & ADVERTISED_100baseT_Half)
+				adv |= PHY_M_AN_100_HD;
+			if (skge->advertising & ADVERTISED_10baseT_Full)
+				adv |= PHY_M_AN_10_FD;
+			if (skge->advertising & ADVERTISED_10baseT_Half)
+				adv |= PHY_M_AN_10_HD;
+
+			/* Set Flow-control capabilities */
+			switch (skge->flow_control) {
+			case FLOW_MODE_NONE:
+				adv |= PHY_B_P_NO_PAUSE;
+				break;
+			case FLOW_MODE_LOC_SEND:
+				adv |= PHY_B_P_ASYM_MD;
+				break;
+			case FLOW_MODE_SYMMETRIC:
+				adv |= PHY_B_P_SYM_MD;
+				break;
+			case FLOW_MODE_REM_SEND:
+				adv |= PHY_B_P_BOTH_MD;
+				break;
+			}
+		} else {	/* special defines for FIBER (88E1011S only) */
+			adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
+
+			/* Set Flow-control capabilities */
+			switch (skge->flow_control) {
+			case FLOW_MODE_NONE:
+				adv |= PHY_M_P_NO_PAUSE_X;
+				break;
+			case FLOW_MODE_LOC_SEND:
+				adv |= PHY_M_P_ASYM_MD_X;
+				break;
+			case FLOW_MODE_SYMMETRIC:
+				adv |= PHY_M_P_SYM_MD_X;
+				break;
+			case FLOW_MODE_REM_SEND:
+				adv |= PHY_M_P_BOTH_MD_X;
+				break;
+			}
+		}
+		/* Restart Auto-negotiation */
+		ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+	} else {
+		/* forced speed/duplex settings */
+		ct1000 = PHY_M_1000C_MSE;
+
+		if (skge->duplex == DUPLEX_FULL)
+			ctrl |= PHY_CT_DUP_MD;
+
+		switch (skge->speed) {
+		case SPEED_1000:
+			ctrl |= PHY_CT_SP1000;
+			break;
+		case SPEED_100:
+			ctrl |= PHY_CT_SP100;
+			break;
+		}
+
+		ctrl |= PHY_CT_RESET;
+	}
+
+	if (hw->chip_id != CHIP_ID_YUKON_FE)
+		skge_gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
+
+	skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
+	skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+
+	/* Setup Phy LED's */
+	ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS);
+	ledover = 0;
+
+	if (hw->chip_id == CHIP_ID_YUKON_FE) {
+		/* on 88E3082 these bits are at 11..9 (shifted left) */
+		ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1;
+
+		skge_gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR,
+				  ((skge_gm_phy_read(hw, port, PHY_MARV_FE_LED_PAR)
+
+				    & ~PHY_M_FELP_LED1_MSK)
+				   | PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL)));
+	} else {
+		/* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
+		ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
+
+		/* turn off the Rx LED (LED_RX) */
+		ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
+	}
+
+	/* disable blink mode (LED_DUPLEX) on collisions */
+	ctrl |= PHY_M_LEDC_DP_CTRL;
+	skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
+
+	if (skge->autoneg == AUTONEG_DISABLE || skge->speed == SPEED_100) {
+		/* turn on 100 Mbps LED (LED_LINK100) */
+		ledover |= PHY_M_LED_MO_100(MO_LED_ON);
+	}
+
+	if (ledover)
+		skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
+
+	/* Enable phy interrupt on autonegotiation complete (or link up) */
+	if (skge->autoneg == AUTONEG_ENABLE)
+		skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
+	else
+		skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+}
+
+static void yukon_reset(struct skge_hw *hw, int port)
+{
+	skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */
+	skge_gma_write16(hw, port, GM_MC_ADDR_H1, 0);	/* clear MC hash */
+	skge_gma_write16(hw, port, GM_MC_ADDR_H2, 0);
+	skge_gma_write16(hw, port, GM_MC_ADDR_H3, 0);
+	skge_gma_write16(hw, port, GM_MC_ADDR_H4, 0);
+
+	skge_gma_write16(hw, port, GM_RX_CTRL,
+			 skge_gma_read16(hw, port, GM_RX_CTRL)
+			 | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+}
+
+static void yukon_mac_init(struct skge_hw *hw, int port)
+{
+	struct skge_port *skge = netdev_priv(hw->dev[port]);
+	int i;
+	u32 reg;
+	const u8 *addr = hw->dev[port]->dev_addr;
+
+	/* WA code for COMA mode -- set PHY reset */
+	if (hw->chip_id == CHIP_ID_YUKON_LITE &&
+	    chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+		skge_write32(hw, B2_GP_IO,
+			     (skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9));
+
+	/* hard reset */
+	skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), GPC_RST_SET);
+	skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_RST_SET);
+
+	/* WA code for COMA mode -- clear PHY reset */
+	if (hw->chip_id == CHIP_ID_YUKON_LITE &&
+	    chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+		skge_write32(hw, B2_GP_IO,
+			     (skge_read32(hw, B2_GP_IO) | GP_DIR_9)
+			     & ~GP_IO_9);
+
+	/* Set hardware config mode */
+	reg = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
+		GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE;
+	reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB;
+
+	/* Clear GMC reset */
+	skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
+	skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_CLR);
+	skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+	if (skge->autoneg == AUTONEG_DISABLE) {
+		reg = GM_GPCR_AU_ALL_DIS;
+		skge_gma_write16(hw, port, GM_GP_CTRL,
+				 skge_gma_read16(hw, port, GM_GP_CTRL) | reg);
+
+		switch (skge->speed) {
+		case SPEED_1000:
+			reg |= GM_GPCR_SPEED_1000;
+			/* fallthru */
+		case SPEED_100:
+			reg |= GM_GPCR_SPEED_100;
+		}
+
+		if (skge->duplex == DUPLEX_FULL)
+			reg |= GM_GPCR_DUP_FULL;
+	} else
+		reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
+	switch (skge->flow_control) {
+	case FLOW_MODE_NONE:
+		skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+		reg |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+		break;
+	case FLOW_MODE_LOC_SEND:
+		/* disable Rx flow-control */
+		reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+	}
+
+	skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+	skge_read16(hw, GMAC_IRQ_SRC);
+
+	spin_lock_bh(&hw->phy_lock);
+	yukon_init(hw, port);
+	spin_unlock_bh(&hw->phy_lock);
+
+	/* MIB clear */
+	reg = skge_gma_read16(hw, port, GM_PHY_ADDR);
+	skge_gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
+
+	for (i = 0; i < GM_MIB_CNT_SIZE; i++)
+		skge_gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
+	skge_gma_write16(hw, port, GM_PHY_ADDR, reg);
+
+	/* transmit control */
+	skge_gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
+
+	/* receive control reg: unicast + multicast + no FCS  */
+	skge_gma_write16(hw, port, GM_RX_CTRL,
+			 GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA);
+
+	/* transmit flow control */
+	skge_gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
+
+	/* transmit parameter */
+	skge_gma_write16(hw, port, GM_TX_PARAM,
+			 TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) |
+			 TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) |
+			 TX_IPG_JAM_DATA(TX_IPG_JAM_DEF));
+
+	/* serial mode register */
+	reg = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
+	if (hw->dev[port]->mtu > 1500)
+		reg |= GM_SMOD_JUMBO_ENA;
+
+	skge_gma_write16(hw, port, GM_SERIAL_MODE, reg);
+
+	/* physical address: used for pause frames */
+	skge_gm_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
+	/* virtual address for data */
+	skge_gm_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
+
+	/* enable interrupt mask for counter overflows */
+	skge_gma_write16(hw, port, GM_TX_IRQ_MSK, 0);
+	skge_gma_write16(hw, port, GM_RX_IRQ_MSK, 0);
+	skge_gma_write16(hw, port, GM_TR_IRQ_MSK, 0);
+
+	/* Initialize Mac Fifo */
+
+	/* Configure Rx MAC FIFO */
+	skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK);
+	reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+	if (hw->chip_id == CHIP_ID_YUKON_LITE &&
+	    chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+		reg &= ~GMF_RX_F_FL_ON;
+	skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
+	skge_write16(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), reg);
+	skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
+
+	/* Configure Tx MAC FIFO */
+	skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
+	skge_write16(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
+}
+
+static void yukon_stop(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	if (hw->chip_id == CHIP_ID_YUKON_LITE &&
+	    chip_rev(hw) == CHIP_REV_YU_LITE_A3) {
+		skge_write32(hw, B2_GP_IO,
+			     skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9);
+	}
+
+	skge_gma_write16(hw, port, GM_GP_CTRL,
+			 skge_gma_read16(hw, port, GM_GP_CTRL)
+			 & ~(GM_GPCR_RX_ENA|GM_GPCR_RX_ENA));
+	skge_gma_read16(hw, port, GM_GP_CTRL);
+
+	/* set GPHY Control reset */
+	skge_gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET);
+	skge_gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET);
+}
+
+static void yukon_get_stats(struct skge_port *skge, u64 *data)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	int i;
+
+	data[0] = (u64) skge_gma_read32(hw, port, GM_TXO_OK_HI) << 32
+		| skge_gma_read32(hw, port, GM_TXO_OK_LO);
+	data[1] = (u64) skge_gma_read32(hw, port, GM_RXO_OK_HI) << 32
+		| skge_gma_read32(hw, port, GM_RXO_OK_LO);
+
+	for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
+		data[i] = skge_gma_read32(hw, port,
+					  skge_stats[i].gma_offset);
+}
+
+static void yukon_mac_intr(struct skge_hw *hw, int port)
+{
+	struct skge_port *skge = netdev_priv(hw->dev[port]);
+	u8 status = skge_read8(hw, SKGEMAC_REG(port, GMAC_IRQ_SRC));
+
+	pr_debug("yukon_intr status %x\n", status);
+	if (status & GM_IS_RX_FF_OR) {
+		++skge->net_stats.rx_fifo_errors;
+		skge_gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO);
+	}
+	if (status & GM_IS_TX_FF_UR) {
+		++skge->net_stats.tx_fifo_errors;
+		skge_gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU);
+	}
+
+}
+
+static u16 yukon_speed(const struct skge_hw *hw, u16 aux)
+{
+	if (hw->chip_id == CHIP_ID_YUKON_FE)
+		return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10;
+
+	switch(aux & PHY_M_PS_SPEED_MSK) {
+	case PHY_M_PS_SPEED_1000:
+		return SPEED_1000;
+	case PHY_M_PS_SPEED_100:
+		return SPEED_100;
+	default:
+		return SPEED_10;
+	}
+}
+
+static void yukon_link_up(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u16 reg;
+
+	pr_debug("yukon_link_up\n");
+
+	/* Enable Transmit FIFO Underrun */
+	skge_write8(hw, GMAC_IRQ_MSK, GMAC_DEF_MSK);
+
+	reg = skge_gma_read16(hw, port, GM_GP_CTRL);
+	if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE)
+		reg |= GM_GPCR_DUP_FULL;
+
+	/* enable Rx/Tx */
+	reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
+	skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+
+	skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+	skge_link_up(skge);
+}
+
+static void yukon_link_down(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	pr_debug("yukon_link_down\n");
+	skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);
+	skge_gm_phy_write(hw, port, GM_GP_CTRL,
+			  skge_gm_phy_read(hw, port, GM_GP_CTRL)
+			  & ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA));
+
+	if (hw->chip_id != CHIP_ID_YUKON_FE &&
+	    skge->flow_control == FLOW_MODE_REM_SEND) {
+		/* restore Asymmetric Pause bit */
+		skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
+				  skge_gm_phy_read(hw, port,
+						   PHY_MARV_AUNE_ADV)
+				  | PHY_M_AN_ASP);
+
+	}
+
+	yukon_reset(hw, port);
+	skge_link_down(skge);
+
+	yukon_init(hw, port);
+}
+
+static void yukon_phy_intr(struct skge_port *skge)
+{
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	const char *reason = NULL;
+	u16 istatus, phystat;
+
+	istatus = skge_gm_phy_read(hw, port, PHY_MARV_INT_STAT);
+	phystat = skge_gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
+	pr_debug("yukon phy intr istat=%x phy_stat=%x\n", istatus, phystat);
+
+	if (istatus & PHY_M_IS_AN_COMPL) {
+		if (skge_gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
+		    & PHY_M_AN_RF) {
+			reason = "remote fault";
+			goto failed;
+		}
+
+		if (!(hw->chip_id == CHIP_ID_YUKON_FE || hw->chip_id == CHIP_ID_YUKON_EC)
+		    && (skge_gm_phy_read(hw, port, PHY_MARV_1000T_STAT)
+			& PHY_B_1000S_MSF)) {
+			reason = "master/slave fault";
+			goto failed;
+		}
+
+		if (!(phystat & PHY_M_PS_SPDUP_RES)) {
+			reason = "speed/duplex";
+			goto failed;
+		}
+
+		skge->duplex = (phystat & PHY_M_PS_FULL_DUP)
+			? DUPLEX_FULL : DUPLEX_HALF;
+		skge->speed = yukon_speed(hw, phystat);
+
+		/* Tx & Rx Pause Enabled bits are at 9..8 */
+		if (hw->chip_id == CHIP_ID_YUKON_XL)
+			phystat >>= 6;
+
+		/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+		switch (phystat & PHY_M_PS_PAUSE_MSK) {
+		case PHY_M_PS_PAUSE_MSK:
+			skge->flow_control = FLOW_MODE_SYMMETRIC;
+			break;
+		case PHY_M_PS_RX_P_EN:
+			skge->flow_control = FLOW_MODE_REM_SEND;
+			break;
+		case PHY_M_PS_TX_P_EN:
+			skge->flow_control = FLOW_MODE_LOC_SEND;
+			break;
+		default:
+			skge->flow_control = FLOW_MODE_NONE;
+		}
+
+		if (skge->flow_control == FLOW_MODE_NONE ||
+		    (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF))
+			skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+		else
+			skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+		yukon_link_up(skge);
+		return;
+	}
+
+	if (istatus & PHY_M_IS_LSP_CHANGE)
+		skge->speed = yukon_speed(hw, phystat);
+
+	if (istatus & PHY_M_IS_DUP_CHANGE)
+		skge->duplex = (phystat & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
+	if (istatus & PHY_M_IS_LST_CHANGE) {
+		if (phystat & PHY_M_PS_LINK_UP)
+			yukon_link_up(skge);
+		else
+			yukon_link_down(skge);
+	}
+	return;
+ failed:
+	printk(KERN_ERR PFX "%s: autonegotiation failed (%s)\n",
+	       skge->netdev->name, reason);
+
+	/* XXX restart autonegotiation? */
+}
+
+static void skge_ramset(struct skge_hw *hw, u16 q, u32 start, size_t len)
+{
+	u32 end;
+
+	start /= 8;
+	len /= 8;
+	end = start + len - 1;
+
+	skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR);
+	skge_write32(hw, RB_ADDR(q, RB_START), start);
+	skge_write32(hw, RB_ADDR(q, RB_WP), start);
+	skge_write32(hw, RB_ADDR(q, RB_RP), start);
+	skge_write32(hw, RB_ADDR(q, RB_END), end);
+
+	if (q == Q_R1 || q == Q_R2) {
+		/* Set thresholds on receive queue's */
+		skge_write32(hw, RB_ADDR(q, RB_RX_UTPP),
+			     start + (2*len)/3);
+		skge_write32(hw, RB_ADDR(q, RB_RX_LTPP),
+			     start + (len/3));
+	} else {
+		/* Enable store & forward on Tx queue's because
+		 * Tx FIFO is only 4K on Genesis and 1K on Yukon
+		 */
+		skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_STFWD);
+	}
+
+	skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_OP_MD);
+}
+
+/* Setup Bus Memory Interface */
+static void skge_qset(struct skge_port *skge, u16 q,
+		      const struct skge_element *e)
+{
+	struct skge_hw *hw = skge->hw;
+	u32 watermark = 0x600;
+	u64 base = skge->dma + (e->desc - skge->mem);
+
+	/* optimization to reduce window on 32bit/33mhz */
+	if ((skge_read16(hw, B0_CTST) & (CS_BUS_CLOCK | CS_BUS_SLOT_SZ)) == 0)
+		watermark /= 2;
+
+	skge_write32(hw, Q_ADDR(q, Q_CSR), CSR_CLR_RESET);
+	skge_write32(hw, Q_ADDR(q, Q_F), watermark);
+	skge_write32(hw, Q_ADDR(q, Q_DA_H), (u32)(base >> 32));
+	skge_write32(hw, Q_ADDR(q, Q_DA_L), (u32)base);
+}
+
+static int skge_up(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	u32 chunk, ram_addr;
+	size_t rx_size, tx_size;
+	int err;
+
+	if (netif_msg_ifup(skge))
+		printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
+
+	rx_size = skge->rx_ring.count * sizeof(struct skge_rx_desc);
+	tx_size = skge->tx_ring.count * sizeof(struct skge_tx_desc);
+	skge->mem_size = tx_size + rx_size;
+	skge->mem = pci_alloc_consistent(hw->pdev, skge->mem_size, &skge->dma);
+	if (!skge->mem)
+		return -ENOMEM;
+
+	memset(skge->mem, 0, skge->mem_size);
+
+	if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma)))
+		goto free_pci_mem;
+
+	if (skge_rx_fill(skge))
+		goto free_rx_ring;
+
+	if ((err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size,
+				   skge->dma + rx_size)))
+		goto free_rx_ring;
+
+	skge->tx_avail = skge->tx_ring.count - 1;
+
+	/* Initialze MAC */
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		genesis_mac_init(hw, port);
+	else
+		yukon_mac_init(hw, port);
+
+	/* Configure RAMbuffers */
+	chunk = hw->ram_size / (isdualport(hw) ? 4 : 2);
+	ram_addr = hw->ram_offset + 2 * chunk * port;
+
+	skge_ramset(hw, rxqaddr[port], ram_addr, chunk);
+	skge_qset(skge, rxqaddr[port], skge->rx_ring.to_clean);
+
+	BUG_ON(skge->tx_ring.to_use != skge->tx_ring.to_clean);
+	skge_ramset(hw, txqaddr[port], ram_addr+chunk, chunk);
+	skge_qset(skge, txqaddr[port], skge->tx_ring.to_use);
+
+	/* Start receiver BMU */
+	wmb();
+	skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F);
+
+	pr_debug("skge_up completed\n");
+	return 0;
+
+ free_rx_ring:
+	skge_rx_clean(skge);
+	kfree(skge->rx_ring.start);
+ free_pci_mem:
+	pci_free_consistent(hw->pdev, skge->mem_size, skge->mem, skge->dma);
+
+	return err;
+}
+
+static int skge_down(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+
+	if (netif_msg_ifdown(skge))
+		printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
+
+	netif_stop_queue(dev);
+
+	del_timer_sync(&skge->led_blink);
+	del_timer_sync(&skge->link_check);
+
+	/* Stop transmitter */
+	skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP);
+	skge_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL),
+		     RB_RST_SET|RB_DIS_OP_MD);
+
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		genesis_stop(skge);
+	else
+		yukon_stop(skge);
+
+	/* Disable Force Sync bit and Enable Alloc bit */
+	skge_write8(hw, SKGEMAC_REG(port, TXA_CTRL),
+		    TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+
+	/* Stop Interval Timer and Limit Counter of Tx Arbiter */
+	skge_write32(hw, SKGEMAC_REG(port, TXA_ITI_INI), 0L);
+	skge_write32(hw, SKGEMAC_REG(port, TXA_LIM_INI), 0L);
+
+	/* Reset PCI FIFO */
+	skge_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_SET_RESET);
+	skge_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET);
+
+	/* Reset the RAM Buffer async Tx queue */
+	skge_write8(hw, RB_ADDR(port == 0 ? Q_XA1 : Q_XA2, RB_CTRL), RB_RST_SET);
+	/* stop receiver */
+	skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_STOP);
+	skge_write32(hw, RB_ADDR(port ? Q_R2 : Q_R1, RB_CTRL),
+		     RB_RST_SET|RB_DIS_OP_MD);
+	skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET);
+
+	if (hw->chip_id == CHIP_ID_GENESIS) {
+		skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_SET);
+		skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_SET);
+		skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_STOP);
+		skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_STOP);
+	} else {
+		skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+		skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
+	}
+
+	/* turn off led's */
+	skge_write16(hw, B0_LED, LED_STAT_OFF);
+
+	skge_tx_clean(skge);
+	skge_rx_clean(skge);
+
+	kfree(skge->rx_ring.start);
+	kfree(skge->tx_ring.start);
+	pci_free_consistent(hw->pdev, skge->mem_size, skge->mem, skge->dma);
+	return 0;
+}
+
+static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	struct skge_ring *ring = &skge->tx_ring;
+	struct skge_element *e;
+	struct skge_tx_desc *td;
+	int i;
+	u32 control, len;
+	u64 map;
+	unsigned long flags;
+
+	skb = skb_padto(skb, ETH_ZLEN);
+	if (!skb)
+		return NETDEV_TX_OK;
+
+	local_irq_save(flags);
+	if (!spin_trylock(&skge->tx_lock)) {
+ 		/* Collision - tell upper layer to requeue */ 
+ 		local_irq_restore(flags); 
+ 		return NETDEV_TX_LOCKED; 
+ 	} 
+
+	if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) {
+		netif_stop_queue(dev);
+		spin_unlock_irqrestore(&skge->tx_lock, flags);
+
+		printk(KERN_WARNING PFX "%s: ring full when queue awake!\n",
+		       dev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	e = ring->to_use;
+	td = e->desc;
+	e->skb = skb;
+	len = skb_headlen(skb);
+	map = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	pci_unmap_addr_set(e, mapaddr, map);
+	pci_unmap_len_set(e, maplen, len);
+
+	td->dma_lo = map;
+	td->dma_hi = map >> 32;
+
+	if (skb->ip_summed == CHECKSUM_HW) {
+		const struct iphdr *ip
+			= (const struct iphdr *) (skb->data + ETH_HLEN);
+		int offset = skb->h.raw - skb->data;
+
+		/* This seems backwards, but it is what the sk98lin
+		 * does.  Looks like hardware is wrong?
+		 */
+		if (ip->protocol == IPPROTO_UDP
+	            && chip_rev(hw) == 0 && hw->chip_id == CHIP_ID_YUKON)
+			control = BMU_TCP_CHECK;
+		else
+			control = BMU_UDP_CHECK;
+
+		td->csum_offs = 0;
+		td->csum_start = offset;
+		td->csum_write = offset + skb->csum;
+	} else
+		control = BMU_CHECK;
+
+	if (!skb_shinfo(skb)->nr_frags) /* single buffer i.e. no fragments */
+		control |= BMU_EOF| BMU_IRQ_EOF;
+	else {
+		struct skge_tx_desc *tf = td;
+
+		control |= BMU_STFWD;
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+			map = pci_map_page(hw->pdev, frag->page, frag->page_offset,
+					   frag->size, PCI_DMA_TODEVICE);
+
+			e = e->next;
+			e->skb = NULL;
+			tf = e->desc;
+			tf->dma_lo = map;
+			tf->dma_hi = (u64) map >> 32;
+			pci_unmap_addr_set(e, mapaddr, map);
+			pci_unmap_len_set(e, maplen, frag->size);
+
+			tf->control = BMU_OWN | BMU_SW | control | frag->size;
+		}
+		tf->control |= BMU_EOF | BMU_IRQ_EOF;
+	}
+	/* Make sure all the descriptors written */
+	wmb();
+	td->control = BMU_OWN | BMU_SW | BMU_STF | control | len;
+	wmb();
+
+	skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_START);
+
+	if (netif_msg_tx_queued(skge))
+		printk(KERN_DEBUG "%s: tx queued, slot %td, len %d\n",
+		       dev->name, e - ring->start, skb->len);
+
+	ring->to_use = e->next;
+	skge->tx_avail -= skb_shinfo(skb)->nr_frags + 1;
+	if (skge->tx_avail <= MAX_SKB_FRAGS + 1) {
+		pr_debug("%s: transmit queue full\n", dev->name);
+		netif_stop_queue(dev);
+	}
+
+	dev->trans_start = jiffies;
+	spin_unlock_irqrestore(&skge->tx_lock, flags);
+
+	return NETDEV_TX_OK;
+}
+
+static inline void skge_tx_free(struct skge_hw *hw, struct skge_element *e)
+{
+	if (e->skb) {
+		pci_unmap_single(hw->pdev,
+			       pci_unmap_addr(e, mapaddr),
+			       pci_unmap_len(e, maplen),
+			       PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(e->skb);
+		e->skb = NULL;
+	} else {
+		pci_unmap_page(hw->pdev,
+			       pci_unmap_addr(e, mapaddr),
+			       pci_unmap_len(e, maplen),
+			       PCI_DMA_TODEVICE);
+	}
+}
+
+static void skge_tx_clean(struct skge_port *skge)
+{
+	struct skge_ring *ring = &skge->tx_ring;
+	struct skge_element *e;
+	unsigned long flags;
+
+	spin_lock_irqsave(&skge->tx_lock, flags);
+	for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+		++skge->tx_avail;
+		skge_tx_free(skge->hw, e);
+	}
+	ring->to_clean = e;
+	spin_unlock_irqrestore(&skge->tx_lock, flags);
+}
+
+static void skge_tx_timeout(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	if (netif_msg_timer(skge))
+		printk(KERN_DEBUG PFX "%s: tx timeout\n", dev->name);
+
+	skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_STOP);
+	skge_tx_clean(skge);
+}
+
+static int skge_change_mtu(struct net_device *dev, int new_mtu)
+{
+	int err = 0;
+
+	if(new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+
+	if (netif_running(dev)) {
+		skge_down(dev);
+		skge_up(dev);
+	}
+
+	return err;
+}
+
+static void genesis_set_multicast(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	int i, count = dev->mc_count;
+	struct dev_mc_list *list = dev->mc_list;
+	u32 mode;
+	u8 filter[8];
+
+	mode = skge_xm_read32(hw, port, XM_MODE);
+	mode |= XM_MD_ENA_HASH;
+	if (dev->flags & IFF_PROMISC)
+		mode |= XM_MD_ENA_PROM;
+	else
+		mode &= ~XM_MD_ENA_PROM;
+
+	if (dev->flags & IFF_ALLMULTI)
+		memset(filter, 0xff, sizeof(filter));
+	else {
+		memset(filter, 0, sizeof(filter));
+		for(i = 0; list && i < count; i++, list = list->next) {
+			u32 crc = crc32_le(~0, list->dmi_addr, ETH_ALEN);
+			u8 bit = 63 - (crc & 63);
+
+			filter[bit/8] |= 1 << (bit%8);
+		}
+	}
+
+	skge_xm_outhash(hw, port, XM_HSM, filter);
+
+	skge_xm_write32(hw, port, XM_MODE, mode);
+}
+
+static void yukon_set_multicast(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	int port = skge->port;
+	struct dev_mc_list *list = dev->mc_list;
+	u16 reg;
+	u8 filter[8];
+
+	memset(filter, 0, sizeof(filter));
+
+	reg = skge_gma_read16(hw, port, GM_RX_CTRL);
+	reg |= GM_RXCR_UCF_ENA;
+
+	if (dev->flags & IFF_PROMISC) 		/* promiscious */
+		reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+	else if (dev->flags & IFF_ALLMULTI)	/* all multicast */
+		memset(filter, 0xff, sizeof(filter));
+	else if (dev->mc_count == 0)		/* no multicast */
+		reg &= ~GM_RXCR_MCF_ENA;
+	else {
+		int i;
+		reg |= GM_RXCR_MCF_ENA;
+
+		for(i = 0; list && i < dev->mc_count; i++, list = list->next) {
+			u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f;
+			filter[bit/8] |= 1 << (bit%8);
+		}
+	}
+
+
+	skge_gma_write16(hw, port, GM_MC_ADDR_H1,
+			 (u16)filter[0] | ((u16)filter[1] << 8));
+	skge_gma_write16(hw, port, GM_MC_ADDR_H2,
+			 (u16)filter[2] | ((u16)filter[3] << 8));
+	skge_gma_write16(hw, port, GM_MC_ADDR_H3,
+			 (u16)filter[4] | ((u16)filter[5] << 8));
+	skge_gma_write16(hw, port, GM_MC_ADDR_H4,
+			 (u16)filter[6] | ((u16)filter[7] << 8));
+
+	skge_gma_write16(hw, port, GM_RX_CTRL, reg);
+}
+
+static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
+{
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		return (status & (XMR_FS_ERR | XMR_FS_2L_VLAN)) != 0;
+	else
+		return (status & GMR_FS_ANY_ERR) ||
+			(status & GMR_FS_RX_OK) == 0;
+}
+
+static void skge_rx_error(struct skge_port *skge, int slot,
+			  u32 control, u32 status)
+{
+	if (netif_msg_rx_err(skge))
+		printk(KERN_DEBUG PFX "%s: rx err, slot %d control 0x%x status 0x%x\n",
+		       skge->netdev->name, slot, control, status);
+
+	if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
+	    || (control & BMU_BBC) > skge->netdev->mtu + VLAN_ETH_HLEN)
+		skge->net_stats.rx_length_errors++;
+	else {
+		if (skge->hw->chip_id == CHIP_ID_GENESIS) {
+			if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
+				skge->net_stats.rx_length_errors++;
+			if (status & XMR_FS_FRA_ERR)
+				skge->net_stats.rx_frame_errors++;
+			if (status & XMR_FS_FCS_ERR)
+				skge->net_stats.rx_crc_errors++;
+		} else {
+			if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
+				skge->net_stats.rx_length_errors++;
+			if (status & GMR_FS_FRAGMENT)
+				skge->net_stats.rx_frame_errors++;
+			if (status & GMR_FS_CRC_ERR)
+				skge->net_stats.rx_crc_errors++;
+		}
+	}
+}
+
+static int skge_poll(struct net_device *dev, int *budget)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	struct skge_ring *ring = &skge->rx_ring;
+	struct skge_element *e;
+	unsigned int to_do = min(dev->quota, *budget);
+	unsigned int work_done = 0;
+	int done;
+	static const u32 irqmask[] = { IS_PORT_1, IS_PORT_2 };
+
+	for (e = ring->to_clean; e != ring->to_use && work_done < to_do;
+	     e = e->next) {
+		struct skge_rx_desc *rd = e->desc;
+		struct sk_buff *skb = e->skb;
+		u32 control, len, status;
+
+		rmb();
+		control = rd->control;
+		if (control & BMU_OWN)
+			break;
+
+		len = control & BMU_BBC;
+		e->skb = NULL;
+
+		pci_unmap_single(hw->pdev,
+				 pci_unmap_addr(e, mapaddr),
+				 pci_unmap_len(e, maplen),
+				 PCI_DMA_FROMDEVICE);
+
+		status = rd->status;
+		if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
+		     || len > dev->mtu + VLAN_ETH_HLEN
+		     || bad_phy_status(hw, status)) {
+			skge_rx_error(skge, e - ring->start, control, status);
+			dev_kfree_skb(skb);
+			continue;
+		}
+
+		if (netif_msg_rx_status(skge))
+		    printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
+			   dev->name, e - ring->start, rd->status, len);
+
+		skb_put(skb, len);
+		skb->protocol = eth_type_trans(skb, dev);
+
+		if (skge->rx_csum) {
+			skb->csum = le16_to_cpu(rd->csum2);
+			skb->ip_summed = CHECKSUM_HW;
+		}
+
+		dev->last_rx = jiffies;
+		netif_receive_skb(skb);
+
+		++work_done;
+	}
+	ring->to_clean = e;
+
+	*budget -= work_done;
+	dev->quota -= work_done;
+	done = work_done < to_do;
+
+	if (skge_rx_fill(skge))
+		done = 0;
+
+	/* restart receiver */
+	wmb();
+	skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR),
+		    CSR_START | CSR_IRQ_CL_F);
+
+	if (done) {
+		local_irq_disable();
+		hw->intr_mask |= irqmask[skge->port];
+		/* Order is important since data can get interrupted */
+		skge_write32(hw, B0_IMSK, hw->intr_mask);
+		__netif_rx_complete(dev);
+		local_irq_enable();
+	}
+
+	return !done;
+}
+
+static inline void skge_tx_intr(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct skge_hw *hw = skge->hw;
+	struct skge_ring *ring = &skge->tx_ring;
+	struct skge_element *e;
+
+	spin_lock(&skge->tx_lock);
+	for(e = ring->to_clean; e != ring->to_use; e = e->next) {
+		struct skge_tx_desc *td = e->desc;
+		u32 control;
+
+		rmb();
+		control = td->control;
+		if (control & BMU_OWN)
+			break;
+
+		if (unlikely(netif_msg_tx_done(skge)))
+			printk(KERN_DEBUG PFX "%s: tx done slot %td status 0x%x\n",
+			       dev->name, e - ring->start, td->status);
+
+		skge_tx_free(hw, e);
+		e->skb = NULL;
+		++skge->tx_avail;
+	}
+	ring->to_clean = e;
+	skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
+
+	if (skge->tx_avail > MAX_SKB_FRAGS + 1)
+		netif_wake_queue(dev);
+
+	spin_unlock(&skge->tx_lock);
+}
+
+static void skge_mac_parity(struct skge_hw *hw, int port)
+{
+	printk(KERN_ERR PFX "%s: mac data parity error\n",
+	       hw->dev[port] ? hw->dev[port]->name
+	       : (port == 0 ? "(port A)": "(port B"));
+
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1),
+			     MFF_CLR_PERR);
+	else
+		/* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
+		skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T),
+			    (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0)
+			    ? GMF_CLI_TX_FC : GMF_CLI_TX_PE);
+}
+
+static void skge_pci_clear(struct skge_hw *hw)
+{
+	u16 status;
+
+	status = skge_read16(hw, SKGEPCI_REG(PCI_STATUS));
+	skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	skge_write16(hw, SKGEPCI_REG(PCI_STATUS),
+		     status | PCI_STATUS_ERROR_BITS);
+	skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+}
+
+static void skge_mac_intr(struct skge_hw *hw, int port)
+{
+	if (hw->chip_id == CHIP_ID_GENESIS) 
+		genesis_mac_intr(hw, port);
+	else
+		yukon_mac_intr(hw, port);
+}
+
+/* Handle device specific framing and timeout interrupts */
+static void skge_error_irq(struct skge_hw *hw)
+{
+	u32 hwstatus = skge_read32(hw, B0_HWE_ISRC);
+
+	if (hw->chip_id == CHIP_ID_GENESIS) {
+		/* clear xmac errors */
+		if (hwstatus & (IS_NO_STAT_M1|IS_NO_TIST_M1))
+			skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+		if (hwstatus & (IS_NO_STAT_M2|IS_NO_TIST_M2))
+			skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT);
+	} else {
+		/* Timestamp (unused) overflow */
+		if (hwstatus & IS_IRQ_TIST_OV)
+			skge_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
+
+		if (hwstatus & IS_IRQ_SENSOR) {
+			/* no sensors on 32-bit Yukon */
+			if (!(skge_read16(hw, B0_CTST) & CS_BUS_SLOT_SZ)) {
+				printk(KERN_ERR PFX "ignoring bogus sensor interrups\n");
+				skge_write32(hw, B0_HWE_IMSK,
+					     IS_ERR_MSK & ~IS_IRQ_SENSOR);
+			} else
+				printk(KERN_WARNING PFX "sensor interrupt\n");
+		}
+
+
+	}
+
+	if (hwstatus & IS_RAM_RD_PAR) {
+		printk(KERN_ERR PFX "Ram read data parity error\n");
+		skge_write16(hw, B3_RI_CTRL, RI_CLR_RD_PERR);
+	}
+
+	if (hwstatus & IS_RAM_WR_PAR) {
+		printk(KERN_ERR PFX "Ram write data parity error\n");
+		skge_write16(hw, B3_RI_CTRL, RI_CLR_WR_PERR);
+	}
+
+	if (hwstatus & IS_M1_PAR_ERR)
+		skge_mac_parity(hw, 0);
+
+	if (hwstatus & IS_M2_PAR_ERR)
+		skge_mac_parity(hw, 1);
+
+	if (hwstatus & IS_R1_PAR_ERR)
+		skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P);
+
+	if (hwstatus & IS_R2_PAR_ERR)
+		skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P);
+
+	if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) {
+		printk(KERN_ERR PFX "hardware error detected (status 0x%x)\n",
+		       hwstatus);
+
+		skge_pci_clear(hw);
+
+		hwstatus = skge_read32(hw, B0_HWE_ISRC);
+		if (hwstatus & IS_IRQ_STAT) {
+			printk(KERN_WARNING PFX "IRQ status %x: still set ignoring hardware errors\n",
+			       hwstatus);
+			hw->intr_mask &= ~IS_HW_ERR;
+		}
+	}
+}
+
+/*
+ * Interrrupt from PHY are handled in tasklet (soft irq)
+ * because accessing phy registers requires spin wait which might
+ * cause excess interrupt latency.
+ */
+static void skge_extirq(unsigned long data)
+{
+	struct skge_hw *hw = (struct skge_hw *) data;
+	int port;
+
+	spin_lock(&hw->phy_lock);
+	for (port = 0; port < 2; port++) {
+		struct net_device *dev = hw->dev[port];
+
+		if (dev && netif_running(dev)) {
+			struct skge_port *skge = netdev_priv(dev);
+
+			if (hw->chip_id != CHIP_ID_GENESIS)
+				yukon_phy_intr(skge);
+			else if (hw->phy_type == SK_PHY_BCOM)
+				genesis_bcom_intr(skge);
+		}
+	}
+	spin_unlock(&hw->phy_lock);
+
+	local_irq_disable();
+	hw->intr_mask |= IS_EXT_REG;
+	skge_write32(hw, B0_IMSK, hw->intr_mask);
+	local_irq_enable();
+}
+
+static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct skge_hw *hw = dev_id;
+	u32 status = skge_read32(hw, B0_SP_ISRC);
+
+	if (status == 0 || status == ~0) /* hotplug or shared irq */
+		return IRQ_NONE;
+
+	status &= hw->intr_mask;
+
+	if ((status & IS_R1_F) && netif_rx_schedule_prep(hw->dev[0])) {
+		status &= ~IS_R1_F;
+		hw->intr_mask &= ~IS_R1_F;
+		skge_write32(hw, B0_IMSK, hw->intr_mask);
+		__netif_rx_schedule(hw->dev[0]);
+	}
+
+	if ((status & IS_R2_F) && netif_rx_schedule_prep(hw->dev[1])) {
+		status &= ~IS_R2_F;
+		hw->intr_mask &= ~IS_R2_F;
+		skge_write32(hw, B0_IMSK, hw->intr_mask);
+		__netif_rx_schedule(hw->dev[1]);
+	}
+
+	if (status & IS_XA1_F)
+		skge_tx_intr(hw->dev[0]);
+
+	if (status & IS_XA2_F)
+		skge_tx_intr(hw->dev[1]);
+
+	if (status & IS_MAC1)
+		skge_mac_intr(hw, 0);
+	
+	if (status & IS_MAC2)
+		skge_mac_intr(hw, 1);
+
+	if (status & IS_HW_ERR)
+		skge_error_irq(hw);
+
+	if (status & IS_EXT_REG) {
+		hw->intr_mask &= ~IS_EXT_REG;
+		tasklet_schedule(&hw->ext_tasklet);
+	}
+
+	if (status)
+		skge_write32(hw, B0_IMSK, hw->intr_mask);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void skge_netpoll(struct net_device *dev)
+{
+	struct skge_port *skge = netdev_priv(dev);
+
+	disable_irq(dev->irq);
+	skge_intr(dev->irq, skge->hw, NULL);
+	enable_irq(dev->irq);
+}
+#endif
+
+static int skge_set_mac_address(struct net_device *dev, void *p)
+{
+	struct skge_port *skge = netdev_priv(dev);
+	struct sockaddr *addr = p;
+	int err = 0;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	skge_down(dev);
+	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+	memcpy_toio(skge->hw->regs + B2_MAC_1 + skge->port*8,
+		    dev->dev_addr, ETH_ALEN);
+	memcpy_toio(skge->hw->regs + B2_MAC_2 + skge->port*8,
+		    dev->dev_addr, ETH_ALEN);
+	if (dev->flags & IFF_UP)
+		err = skge_up(dev);
+	return err;
+}
+
+static const struct {
+	u8 id;
+	const char *name;
+} skge_chips[] = {
+	{ CHIP_ID_GENESIS,	"Genesis" },
+	{ CHIP_ID_YUKON,	 "Yukon" },
+	{ CHIP_ID_YUKON_LITE,	 "Yukon-Lite"},
+	{ CHIP_ID_YUKON_LP,	 "Yukon-LP"},
+	{ CHIP_ID_YUKON_XL,	 "Yukon-2 XL"},
+	{ CHIP_ID_YUKON_EC,	 "YUKON-2 EC"},
+	{ CHIP_ID_YUKON_FE,	 "YUKON-2 FE"},
+};
+
+static const char *skge_board_name(const struct skge_hw *hw)
+{
+	int i;
+	static char buf[16];
+
+	for (i = 0; i < ARRAY_SIZE(skge_chips); i++)
+		if (skge_chips[i].id == hw->chip_id)
+			return skge_chips[i].name;
+
+	snprintf(buf, sizeof buf, "chipid 0x%x", hw->chip_id);
+	return buf;
+}
+
+
+/*
+ * Setup the board data structure, but don't bring up
+ * the port(s)
+ */
+static int skge_reset(struct skge_hw *hw)
+{
+	u16 ctst;
+	u8 t8;
+	int i, ports;
+
+	ctst = skge_read16(hw, B0_CTST);
+
+	/* do a SW reset */
+	skge_write8(hw, B0_CTST, CS_RST_SET);
+	skge_write8(hw, B0_CTST, CS_RST_CLR);
+
+	/* clear PCI errors, if any */
+	skge_pci_clear(hw);
+
+	skge_write8(hw, B0_CTST, CS_MRST_CLR);
+
+	/* restore CLK_RUN bits (for Yukon-Lite) */
+	skge_write16(hw, B0_CTST,
+		     ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA));
+
+	hw->chip_id = skge_read8(hw, B2_CHIP_ID);
+	hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
+	hw->pmd_type = skge_read8(hw, B2_PMD_TYP);
+
+	switch(hw->chip_id) {
+	case CHIP_ID_GENESIS:
+		switch (hw->phy_type) {
+		case SK_PHY_XMAC:
+			hw->phy_addr = PHY_ADDR_XMAC;
+			break;
+		case SK_PHY_BCOM:
+			hw->phy_addr = PHY_ADDR_BCOM;
+			break;
+		default:
+			printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
+			       pci_name(hw->pdev), hw->phy_type);
+			return -EOPNOTSUPP;
+		}
+		break;
+
+	case CHIP_ID_YUKON:
+	case CHIP_ID_YUKON_LITE:
+	case CHIP_ID_YUKON_LP:
+		if (hw->phy_type < SK_PHY_MARV_COPPER && hw->pmd_type != 'S')
+			hw->phy_type = SK_PHY_MARV_COPPER;
+
+		hw->phy_addr = PHY_ADDR_MARV;
+		if (!iscopper(hw))
+			hw->phy_type = SK_PHY_MARV_FIBER;
+
+		break;
+
+	default:
+		printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
+		       pci_name(hw->pdev), hw->chip_id);
+		return -EOPNOTSUPP;
+	}
+
+	hw->mac_cfg = skge_read8(hw, B2_MAC_CFG);
+	ports = isdualport(hw) ? 2 : 1;
+
+	/* read the adapters RAM size */
+	t8 = skge_read8(hw, B2_E_0);
+	if (hw->chip_id == CHIP_ID_GENESIS) {
+		if (t8 == 3) {
+			/* special case: 4 x 64k x 36, offset = 0x80000 */
+			hw->ram_size = 0x100000;
+			hw->ram_offset = 0x80000;
+		} else
+			hw->ram_size = t8 * 512;
+	}
+	else if (t8 == 0)
+		hw->ram_size = 0x20000;
+	else
+		hw->ram_size = t8 * 4096;
+
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		genesis_init(hw);
+	else {
+		/* switch power to VCC (WA for VAUX problem) */
+		skge_write8(hw, B0_POWER_CTRL,
+			    PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
+		for (i = 0; i < ports; i++) {
+			skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+			skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+		}
+	}
+
+	/* turn off hardware timer (unused) */
+	skge_write8(hw, B2_TI_CTRL, TIM_STOP);
+	skge_write8(hw, B2_TI_CTRL, TIM_CLR_IRQ);
+	skge_write8(hw, B0_LED, LED_STAT_ON);
+
+	/* enable the Tx Arbiters */
+	for (i = 0; i < ports; i++)
+		skge_write8(hw, SKGEMAC_REG(i, TXA_CTRL), TXA_ENA_ARB);
+
+	/* Initialize ram interface */
+	skge_write16(hw, B3_RI_CTRL, RI_RST_CLR);
+
+	skge_write8(hw, B3_RI_WTO_R1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_XA1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_XS1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_R1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_XA1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_XS1, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_R2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_XA2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_WTO_XS2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_R2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_XA2, SK_RI_TO_53);
+	skge_write8(hw, B3_RI_RTO_XS2, SK_RI_TO_53);
+
+	skge_write32(hw, B0_HWE_IMSK, IS_ERR_MSK);
+
+	/* Set interrupt moderation for Transmit only
+	 * Receive interrupts avoided by NAPI
+	 */
+	skge_write32(hw, B2_IRQM_MSK, IS_XA1_F|IS_XA2_F);
+	skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
+	skge_write32(hw, B2_IRQM_CTRL, TIM_START);
+
+	hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
+	if (isdualport(hw))
+		hw->intr_mask |= IS_PORT_2;
+	skge_write32(hw, B0_IMSK, hw->intr_mask);
+
+	if (hw->chip_id != CHIP_ID_GENESIS)
+		skge_write8(hw, GMAC_IRQ_MSK, 0);
+
+	spin_lock_bh(&hw->phy_lock);
+	for (i = 0; i < ports; i++) {
+		if (hw->chip_id == CHIP_ID_GENESIS)
+			genesis_reset(hw, i);
+		else
+			yukon_reset(hw, i);
+	}
+	spin_unlock_bh(&hw->phy_lock);
+
+	return 0;
+}
+
+/* Initialize network device */
+static struct net_device *skge_devinit(struct skge_hw *hw, int port)
+{
+	struct skge_port *skge;
+	struct net_device *dev = alloc_etherdev(sizeof(*skge));
+
+	if (!dev) {
+		printk(KERN_ERR "skge etherdev alloc failed");
+		return NULL;
+	}
+
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &hw->pdev->dev);
+	dev->open = skge_up;
+	dev->stop = skge_down;
+	dev->hard_start_xmit = skge_xmit_frame;
+	dev->get_stats = skge_get_stats;
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		dev->set_multicast_list = genesis_set_multicast;
+	else
+		dev->set_multicast_list = yukon_set_multicast;
+
+	dev->set_mac_address = skge_set_mac_address;
+	dev->change_mtu = skge_change_mtu;
+	SET_ETHTOOL_OPS(dev, &skge_ethtool_ops);
+	dev->tx_timeout = skge_tx_timeout;
+	dev->watchdog_timeo = TX_WATCHDOG;
+	dev->poll = skge_poll;
+	dev->weight = NAPI_WEIGHT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = skge_netpoll;
+#endif
+	dev->irq = hw->pdev->irq;
+	dev->features = NETIF_F_LLTX;
+
+	skge = netdev_priv(dev);
+	skge->netdev = dev;
+	skge->hw = hw;
+	skge->msg_enable = netif_msg_init(debug, default_msg);
+	skge->tx_ring.count = DEFAULT_TX_RING_SIZE;
+	skge->rx_ring.count = DEFAULT_RX_RING_SIZE;
+
+	/* Auto speed and flow control */
+	skge->autoneg = AUTONEG_ENABLE;
+	skge->flow_control = FLOW_MODE_SYMMETRIC;
+	skge->duplex = -1;
+	skge->speed = -1;
+	skge->advertising = skge_modes(hw);
+
+	hw->dev[port] = dev;
+
+	skge->port = port;
+
+	spin_lock_init(&skge->tx_lock);
+
+	init_timer(&skge->link_check);
+	skge->link_check.function = skge_link_timer;
+	skge->link_check.data = (unsigned long) skge;
+
+	init_timer(&skge->led_blink);
+	skge->led_blink.function = skge_blink_timer;
+	skge->led_blink.data = (unsigned long) skge;
+
+	if (hw->chip_id != CHIP_ID_GENESIS) {
+		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+		skge->rx_csum = 1;
+	}
+
+	/* read the mac address */
+	memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
+
+	/* device is off until link detection */
+	netif_carrier_off(dev);
+	netif_stop_queue(dev);
+
+	return dev;
+}
+
+static void __devinit skge_show_addr(struct net_device *dev)
+{
+	const struct skge_port *skge = netdev_priv(dev);
+
+	if (netif_msg_probe(skge))
+		printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       dev->name,
+		       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+}
+
+static int __devinit skge_probe(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
+{
+	struct net_device *dev, *dev1;
+	struct skge_hw *hw;
+	int err, using_dac = 0;
+
+	if ((err = pci_enable_device(pdev))) {
+		printk(KERN_ERR PFX "%s cannot enable PCI device\n",
+		       pci_name(pdev));
+		goto err_out;
+	}
+
+	if ((err = pci_request_regions(pdev, DRV_NAME))) {
+		printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
+		       pci_name(pdev));
+		goto err_out_disable_pdev;
+	}
+
+	pci_set_master(pdev);
+
+	if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)))
+		using_dac = 1;
+	else if (!(err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+		printk(KERN_ERR PFX "%s no usable DMA configuration\n",
+		       pci_name(pdev));
+		goto err_out_free_regions;
+	}
+
+#ifdef __BIG_ENDIAN
+	/* byte swap decriptors in hardware */
+	{
+		u32 reg;
+
+		pci_read_config_dword(pdev, PCI_DEV_REG2, &reg);
+		reg |= PCI_REV_DESC;
+		pci_write_config_dword(pdev, PCI_DEV_REG2, reg);
+	}
+#endif
+
+	err = -ENOMEM;
+	hw = kmalloc(sizeof(*hw), GFP_KERNEL);
+	if (!hw) {
+		printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
+		       pci_name(pdev));
+		goto err_out_free_regions;
+	}
+
+	memset(hw, 0, sizeof(*hw));
+	hw->pdev = pdev;
+	spin_lock_init(&hw->phy_lock);
+	tasklet_init(&hw->ext_tasklet, skge_extirq, (unsigned long) hw);
+
+	hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
+	if (!hw->regs) {
+		printk(KERN_ERR PFX "%s: cannot map device registers\n",
+		       pci_name(pdev));
+		goto err_out_free_hw;
+	}
+
+	if ((err = request_irq(pdev->irq, skge_intr, SA_SHIRQ, DRV_NAME, hw))) {
+		printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+		       pci_name(pdev), pdev->irq);
+		goto err_out_iounmap;
+	}
+	pci_set_drvdata(pdev, hw);
+
+	err = skge_reset(hw);
+	if (err)
+		goto err_out_free_irq;
+
+	printk(KERN_INFO PFX "addr 0x%lx irq %d chip %s rev %d\n",
+	       pci_resource_start(pdev, 0), pdev->irq,
+	       skge_board_name(hw), chip_rev(hw));
+
+	if ((dev = skge_devinit(hw, 0)) == NULL)
+		goto err_out_led_off;
+
+	if (using_dac)
+		dev->features |= NETIF_F_HIGHDMA;
+
+	if ((err = register_netdev(dev))) {
+		printk(KERN_ERR PFX "%s: cannot register net device\n",
+		       pci_name(pdev));
+		goto err_out_free_netdev;
+	}
+
+	skge_show_addr(dev);
+
+	if (isdualport(hw) && (dev1 = skge_devinit(hw, 1))) {
+		if (using_dac)
+			dev1->features |= NETIF_F_HIGHDMA;
+
+		if (register_netdev(dev1) == 0)
+			skge_show_addr(dev1);
+		else {
+			/* Failure to register second port need not be fatal */
+			printk(KERN_WARNING PFX "register of second port failed\n");
+			hw->dev[1] = NULL;
+			free_netdev(dev1);
+		}
+	}
+
+	return 0;
+
+err_out_free_netdev:
+	free_netdev(dev);
+err_out_led_off:
+	skge_write16(hw, B0_LED, LED_STAT_OFF);
+err_out_free_irq:
+	free_irq(pdev->irq, hw);
+err_out_iounmap:
+	iounmap(hw->regs);
+err_out_free_hw:
+	kfree(hw);
+err_out_free_regions:
+	pci_release_regions(pdev);
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+err_out:
+	return err;
+}
+
+static void __devexit skge_remove(struct pci_dev *pdev)
+{
+	struct skge_hw *hw  = pci_get_drvdata(pdev);
+	struct net_device *dev0, *dev1;
+
+	if(!hw)
+		return;
+
+	if ((dev1 = hw->dev[1]))
+		unregister_netdev(dev1);
+	dev0 = hw->dev[0];
+	unregister_netdev(dev0);
+
+	tasklet_kill(&hw->ext_tasklet);
+
+	free_irq(pdev->irq, hw);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	if (dev1)
+		free_netdev(dev1);
+	free_netdev(dev0);
+	skge_write16(hw, B0_LED, LED_STAT_OFF);
+	iounmap(hw->regs);
+	kfree(hw);
+	pci_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int skge_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct skge_hw *hw  = pci_get_drvdata(pdev);
+	int i, wol = 0;
+
+	for(i = 0; i < 2; i++) {
+		struct net_device *dev = hw->dev[i];
+
+		if (dev) {
+			struct skge_port *skge = netdev_priv(dev);
+			if (netif_running(dev)) {
+				netif_carrier_off(dev);
+				skge_down(dev);
+			}
+			netif_device_detach(dev);
+			wol |= skge->wol;
+		}
+	}
+
+	pci_save_state(pdev);
+	pci_enable_wake(pdev, state, wol);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static int skge_resume(struct pci_dev *pdev)
+{
+	struct skge_hw *hw  = pci_get_drvdata(pdev);
+	int i;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	pci_enable_wake(pdev, PCI_D0, 0);
+
+	skge_reset(hw);
+
+	for(i = 0; i < 2; i++) {
+		struct net_device *dev = hw->dev[i];
+		if (dev) {
+			netif_device_attach(dev);
+			if(netif_running(dev))
+				skge_up(dev);
+		}
+	}
+	return 0;
+}
+#endif
+
+static struct pci_driver skge_driver = {
+	.name =         DRV_NAME,
+	.id_table =     skge_id_table,
+	.probe =        skge_probe,
+	.remove =       __devexit_p(skge_remove),
+#ifdef CONFIG_PM
+	.suspend = 	skge_suspend,
+	.resume = 	skge_resume,
+#endif
+};
+
+static int __init skge_init_module(void)
+{
+	return pci_module_init(&skge_driver);
+}
+
+static void __exit skge_cleanup_module(void)
+{
+	pci_unregister_driver(&skge_driver);
+}
+
+module_init(skge_init_module);
+module_exit(skge_cleanup_module);

+ 3005 - 0
drivers/net/skge.h

@@ -0,0 +1,3005 @@
+/*
+ * Definitions for the new Marvell Yukon / SysKonenct driver.
+ */
+#ifndef _SKGE_H
+#define _SKGE_H
+
+/* PCI config registers */
+#define PCI_DEV_REG1	0x40
+#define PCI_DEV_REG2	0x44
+#ifndef PCI_VPD
+#define PCI_VPD		0x50
+#endif
+
+/*	PCI_OUR_REG_2		32 bit	Our Register 2 */
+enum {
+	PCI_VPD_WR_THR  = 0xff<<24, /* Bit 31..24:	VPD Write Threshold */
+	PCI_DEV_SEL	= 0x7f<<17, /* Bit 23..17:	EEPROM Device Select */
+	PCI_VPD_ROM_SZ  = 7   <<14, /* Bit 16..14:	VPD ROM Size	*/
+ 				    /* Bit 13..12:	reserved	*/
+	PCI_EN_DUMMY_RD = 1<<3, /* Enable Dummy Read */
+	PCI_REV_DESC    = 1<<2, /* Reverse Desc. Bytes */
+	PCI_USEDATA64   = 1<<0, /* Use 64Bit Data bus ext */
+};
+
+/*	PCI_VPD_ADR_REG		16 bit	VPD Address Register */
+enum {
+	PCI_VPD_FLAG	= 1<<15,  /* starts VPD rd/wr cycle */
+	PCI_VPD_ADR_MSK =0x7fffL, /* Bit 14.. 0:	VPD Address Mask */
+	VPD_RES_ID	= 0x82,
+	VPD_RES_READ	= 0x90,
+	VPD_RES_WRITE	= 0x81,
+	VPD_RES_END	= 0x78,
+};
+
+
+#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
+			       PCI_STATUS_SIG_SYSTEM_ERROR | \
+			       PCI_STATUS_REC_MASTER_ABORT | \
+			       PCI_STATUS_REC_TARGET_ABORT | \
+			       PCI_STATUS_PARITY)
+
+
+enum csr_regs {
+	B0_RAP	= 0x0000,
+	B0_CTST	= 0x0004,
+	B0_LED	= 0x0006,
+	B0_POWER_CTRL	= 0x0007,
+	B0_ISRC	= 0x0008,
+	B0_IMSK	= 0x000c,
+	B0_HWE_ISRC	= 0x0010,
+	B0_HWE_IMSK	= 0x0014,
+	B0_SP_ISRC	= 0x0018,
+	B0_XM1_IMSK	= 0x0020,
+	B0_XM1_ISRC	= 0x0028,
+	B0_XM1_PHY_ADDR	= 0x0030,
+	B0_XM1_PHY_DATA	= 0x0034,
+	B0_XM2_IMSK	= 0x0040,
+	B0_XM2_ISRC	= 0x0048,
+	B0_XM2_PHY_ADDR	= 0x0050,
+	B0_XM2_PHY_DATA	= 0x0054,
+	B0_R1_CSR	= 0x0060,
+	B0_R2_CSR	= 0x0064,
+	B0_XS1_CSR	= 0x0068,
+	B0_XA1_CSR	= 0x006c,
+	B0_XS2_CSR	= 0x0070,
+	B0_XA2_CSR	= 0x0074,
+
+	B2_MAC_1	= 0x0100,
+	B2_MAC_2	= 0x0108,
+	B2_MAC_3	= 0x0110,
+	B2_CONN_TYP	= 0x0118,
+	B2_PMD_TYP	= 0x0119,
+	B2_MAC_CFG	= 0x011a,
+	B2_CHIP_ID	= 0x011b,
+	B2_E_0		= 0x011c,
+	B2_E_1		= 0x011d,
+	B2_E_2		= 0x011e,
+	B2_E_3		= 0x011f,
+	B2_FAR		= 0x0120,
+	B2_FDP		= 0x0124,
+	B2_LD_CTRL	= 0x0128,
+	B2_LD_TEST	= 0x0129,
+	B2_TI_INI	= 0x0130,
+	B2_TI_VAL	= 0x0134,
+	B2_TI_CTRL	= 0x0138,
+	B2_TI_TEST	= 0x0139,
+	B2_IRQM_INI	= 0x0140,
+	B2_IRQM_VAL	= 0x0144,
+	B2_IRQM_CTRL	= 0x0148,
+	B2_IRQM_TEST	= 0x0149,
+	B2_IRQM_MSK	= 0x014c,
+	B2_IRQM_HWE_MSK	= 0x0150,
+	B2_TST_CTRL1	= 0x0158,
+	B2_TST_CTRL2	= 0x0159,
+	B2_GP_IO	= 0x015c,
+	B2_I2C_CTRL	= 0x0160,
+	B2_I2C_DATA	= 0x0164,
+	B2_I2C_IRQ	= 0x0168,
+	B2_I2C_SW	= 0x016c,
+	B2_BSC_INI	= 0x0170,
+	B2_BSC_VAL	= 0x0174,
+	B2_BSC_CTRL	= 0x0178,
+	B2_BSC_STAT	= 0x0179,
+	B2_BSC_TST	= 0x017a,
+
+	B3_RAM_ADDR	= 0x0180,
+	B3_RAM_DATA_LO	= 0x0184,
+	B3_RAM_DATA_HI	= 0x0188,
+	B3_RI_WTO_R1	= 0x0190,
+	B3_RI_WTO_XA1	= 0x0191,
+	B3_RI_WTO_XS1	= 0x0192,
+	B3_RI_RTO_R1	= 0x0193,
+	B3_RI_RTO_XA1	= 0x0194,
+	B3_RI_RTO_XS1	= 0x0195,
+	B3_RI_WTO_R2	= 0x0196,
+	B3_RI_WTO_XA2	= 0x0197,
+	B3_RI_WTO_XS2	= 0x0198,
+	B3_RI_RTO_R2	= 0x0199,
+	B3_RI_RTO_XA2	= 0x019a,
+	B3_RI_RTO_XS2	= 0x019b,
+	B3_RI_TO_VAL	= 0x019c,
+	B3_RI_CTRL	= 0x01a0,
+	B3_RI_TEST	= 0x01a2,
+	B3_MA_TOINI_RX1	= 0x01b0,
+	B3_MA_TOINI_RX2	= 0x01b1,
+	B3_MA_TOINI_TX1	= 0x01b2,
+	B3_MA_TOINI_TX2	= 0x01b3,
+	B3_MA_TOVAL_RX1	= 0x01b4,
+	B3_MA_TOVAL_RX2	= 0x01b5,
+	B3_MA_TOVAL_TX1	= 0x01b6,
+	B3_MA_TOVAL_TX2	= 0x01b7,
+	B3_MA_TO_CTRL	= 0x01b8,
+	B3_MA_TO_TEST	= 0x01ba,
+	B3_MA_RCINI_RX1	= 0x01c0,
+	B3_MA_RCINI_RX2	= 0x01c1,
+	B3_MA_RCINI_TX1	= 0x01c2,
+	B3_MA_RCINI_TX2	= 0x01c3,
+	B3_MA_RCVAL_RX1	= 0x01c4,
+	B3_MA_RCVAL_RX2	= 0x01c5,
+	B3_MA_RCVAL_TX1	= 0x01c6,
+	B3_MA_RCVAL_TX2	= 0x01c7,
+	B3_MA_RC_CTRL	= 0x01c8,
+	B3_MA_RC_TEST	= 0x01ca,
+	B3_PA_TOINI_RX1	= 0x01d0,
+	B3_PA_TOINI_RX2	= 0x01d4,
+	B3_PA_TOINI_TX1	= 0x01d8,
+	B3_PA_TOINI_TX2	= 0x01dc,
+	B3_PA_TOVAL_RX1	= 0x01e0,
+	B3_PA_TOVAL_RX2	= 0x01e4,
+	B3_PA_TOVAL_TX1	= 0x01e8,
+	B3_PA_TOVAL_TX2	= 0x01ec,
+	B3_PA_CTRL	= 0x01f0,
+	B3_PA_TEST	= 0x01f2,
+};
+
+/*	B0_CTST			16 bit	Control/Status register */
+enum {
+	CS_CLK_RUN_HOT	= 1<<13,/* CLK_RUN hot m. (YUKON-Lite only) */
+	CS_CLK_RUN_RST	= 1<<12,/* CLK_RUN reset  (YUKON-Lite only) */
+	CS_CLK_RUN_ENA	= 1<<11,/* CLK_RUN enable (YUKON-Lite only) */
+	CS_VAUX_AVAIL	= 1<<10,/* VAUX available (YUKON only) */
+	CS_BUS_CLOCK	= 1<<9,	/* Bus Clock 0/1 = 33/66 MHz */
+	CS_BUS_SLOT_SZ	= 1<<8,	/* Slot Size 0/1 = 32/64 bit slot */
+	CS_ST_SW_IRQ	= 1<<7,	/* Set IRQ SW Request */
+	CS_CL_SW_IRQ	= 1<<6,	/* Clear IRQ SW Request */
+	CS_STOP_DONE	= 1<<5,	/* Stop Master is finished */
+	CS_STOP_MAST	= 1<<4,	/* Command Bit to stop the master */
+	CS_MRST_CLR	= 1<<3,	/* Clear Master reset	*/
+	CS_MRST_SET	= 1<<2,	/* Set Master reset	*/
+	CS_RST_CLR	= 1<<1,	/* Clear Software reset	*/
+	CS_RST_SET	= 1,	/* Set   Software reset	*/
+
+/*	B0_LED			 8 Bit	LED register */
+/* Bit  7.. 2:	reserved */
+	LED_STAT_ON	= 1<<1,	/* Status LED on	*/
+	LED_STAT_OFF	= 1,		/* Status LED off	*/
+
+/*	B0_POWER_CTRL	 8 Bit	Power Control reg (YUKON only) */
+	PC_VAUX_ENA	= 1<<7,	/* Switch VAUX Enable  */
+	PC_VAUX_DIS	= 1<<6,	/* Switch VAUX Disable */
+	PC_VCC_ENA	= 1<<5,	/* Switch VCC Enable  */
+	PC_VCC_DIS	= 1<<4,	/* Switch VCC Disable */
+	PC_VAUX_ON	= 1<<3,	/* Switch VAUX On  */
+	PC_VAUX_OFF	= 1<<2,	/* Switch VAUX Off */
+	PC_VCC_ON	= 1<<1,	/* Switch VCC On  */
+	PC_VCC_OFF	= 1<<0,	/* Switch VCC Off */
+};
+
+/*	B2_IRQM_MSK 	32 bit	IRQ Moderation Mask */
+enum {
+	IS_ALL_MSK	= 0xbffffffful,	/* All Interrupt bits */
+	IS_HW_ERR	= 1<<31,	/* Interrupt HW Error */
+					/* Bit 30:	reserved */
+	IS_PA_TO_RX1	= 1<<29,	/* Packet Arb Timeout Rx1 */
+	IS_PA_TO_RX2	= 1<<28,	/* Packet Arb Timeout Rx2 */
+	IS_PA_TO_TX1	= 1<<27,	/* Packet Arb Timeout Tx1 */
+	IS_PA_TO_TX2	= 1<<26,	/* Packet Arb Timeout Tx2 */
+	IS_I2C_READY	= 1<<25,	/* IRQ on end of I2C Tx */
+	IS_IRQ_SW	= 1<<24,	/* SW forced IRQ	*/
+	IS_EXT_REG	= 1<<23,	/* IRQ from LM80 or PHY (GENESIS only) */
+					/* IRQ from PHY (YUKON only) */
+	IS_TIMINT	= 1<<22,	/* IRQ from Timer	*/
+	IS_MAC1		= 1<<21,	/* IRQ from MAC 1	*/
+	IS_LNK_SYNC_M1	= 1<<20,	/* Link Sync Cnt wrap MAC 1 */
+	IS_MAC2		= 1<<19,	/* IRQ from MAC 2	*/
+	IS_LNK_SYNC_M2	= 1<<18,	/* Link Sync Cnt wrap MAC 2 */
+/* Receive Queue 1 */
+	IS_R1_B		= 1<<17,	/* Q_R1 End of Buffer */
+	IS_R1_F		= 1<<16,	/* Q_R1 End of Frame */
+	IS_R1_C		= 1<<15,	/* Q_R1 Encoding Error */
+/* Receive Queue 2 */
+	IS_R2_B		= 1<<14,	/* Q_R2 End of Buffer */
+	IS_R2_F		= 1<<13,	/* Q_R2 End of Frame */
+	IS_R2_C		= 1<<12,	/* Q_R2 Encoding Error */
+/* Synchronous Transmit Queue 1 */
+	IS_XS1_B	= 1<<11,	/* Q_XS1 End of Buffer */
+	IS_XS1_F	= 1<<10,	/* Q_XS1 End of Frame */
+	IS_XS1_C	= 1<<9,		/* Q_XS1 Encoding Error */
+/* Asynchronous Transmit Queue 1 */
+	IS_XA1_B	= 1<<8,		/* Q_XA1 End of Buffer */
+	IS_XA1_F	= 1<<7,		/* Q_XA1 End of Frame */
+	IS_XA1_C	= 1<<6,		/* Q_XA1 Encoding Error */
+/* Synchronous Transmit Queue 2 */
+	IS_XS2_B	= 1<<5,		/* Q_XS2 End of Buffer */
+	IS_XS2_F	= 1<<4,		/* Q_XS2 End of Frame */
+	IS_XS2_C	= 1<<3,		/* Q_XS2 Encoding Error */
+/* Asynchronous Transmit Queue 2 */
+	IS_XA2_B	= 1<<2,		/* Q_XA2 End of Buffer */
+	IS_XA2_F	= 1<<1,		/* Q_XA2 End of Frame */
+	IS_XA2_C	= 1<<0,		/* Q_XA2 Encoding Error */
+
+	IS_PORT_1	= IS_XA1_F| IS_R1_F| IS_MAC1,
+	IS_PORT_2	= IS_XA2_F| IS_R2_F| IS_MAC2,
+};
+
+
+/*	B2_IRQM_HWE_MSK	32 bit	IRQ Moderation HW Error Mask */
+enum {
+	IS_ERR_MSK	= 0x00003fff,/* 		All Error bits */
+
+	IS_IRQ_TIST_OV	= 1<<13, /* Time Stamp Timer Overflow (YUKON only) */
+	IS_IRQ_SENSOR	= 1<<12, /* IRQ from Sensor (YUKON only) */
+	IS_IRQ_MST_ERR	= 1<<11, /* IRQ master error detected */
+	IS_IRQ_STAT	= 1<<10, /* IRQ status exception */
+	IS_NO_STAT_M1	= 1<<9,	/* No Rx Status from MAC 1 */
+	IS_NO_STAT_M2	= 1<<8,	/* No Rx Status from MAC 2 */
+	IS_NO_TIST_M1	= 1<<7,	/* No Time Stamp from MAC 1 */
+	IS_NO_TIST_M2	= 1<<6,	/* No Time Stamp from MAC 2 */
+	IS_RAM_RD_PAR	= 1<<5,	/* RAM Read  Parity Error */
+	IS_RAM_WR_PAR	= 1<<4,	/* RAM Write Parity Error */
+	IS_M1_PAR_ERR	= 1<<3,	/* MAC 1 Parity Error */
+	IS_M2_PAR_ERR	= 1<<2,	/* MAC 2 Parity Error */
+	IS_R1_PAR_ERR	= 1<<1,	/* Queue R1 Parity Error */
+	IS_R2_PAR_ERR	= 1<<0,	/* Queue R2 Parity Error */
+};
+
+/*	B2_TST_CTRL1	 8 bit	Test Control Register 1 */
+enum {
+	TST_FRC_DPERR_MR = 1<<7, /* force DATAPERR on MST RD */
+	TST_FRC_DPERR_MW = 1<<6, /* force DATAPERR on MST WR */
+	TST_FRC_DPERR_TR = 1<<5, /* force DATAPERR on TRG RD */
+	TST_FRC_DPERR_TW = 1<<4, /* force DATAPERR on TRG WR */
+	TST_FRC_APERR_M	 = 1<<3, /* force ADDRPERR on MST */
+	TST_FRC_APERR_T	 = 1<<2, /* force ADDRPERR on TRG */
+	TST_CFG_WRITE_ON = 1<<1, /* Enable  Config Reg WR */
+	TST_CFG_WRITE_OFF= 1<<0, /* Disable Config Reg WR */
+};
+
+/*	B2_MAC_CFG		 8 bit	MAC Configuration / Chip Revision */
+enum {
+	CFG_CHIP_R_MSK	  = 0xf<<4,	/* Bit 7.. 4: Chip Revision */
+					/* Bit 3.. 2:	reserved */
+	CFG_DIS_M2_CLK	  = 1<<1,	/* Disable Clock for 2nd MAC */
+	CFG_SNG_MAC	  = 1<<0,	/* MAC Config: 0=2 MACs / 1=1 MAC*/
+};
+
+/*	B2_CHIP_ID		 8 bit 	Chip Identification Number */
+enum {
+	CHIP_ID_GENESIS	   = 0x0a, /* Chip ID for GENESIS */
+	CHIP_ID_YUKON	   = 0xb0, /* Chip ID for YUKON */
+	CHIP_ID_YUKON_LITE = 0xb1, /* Chip ID for YUKON-Lite (Rev. A1-A3) */
+	CHIP_ID_YUKON_LP   = 0xb2, /* Chip ID for YUKON-LP */
+	CHIP_ID_YUKON_XL   = 0xb3, /* Chip ID for YUKON-2 XL */
+	CHIP_ID_YUKON_EC   = 0xb6, /* Chip ID for YUKON-2 EC */
+ 	CHIP_ID_YUKON_FE   = 0xb7, /* Chip ID for YUKON-2 FE */
+
+	CHIP_REV_YU_LITE_A1  = 3,	/* Chip Rev. for YUKON-Lite A1,A2 */
+	CHIP_REV_YU_LITE_A3  = 7,	/* Chip Rev. for YUKON-Lite A3 */
+};
+
+/*	B2_LD_TEST		 8 bit	EPROM loader test register */
+enum {
+	LD_T_ON		= 1<<3,	/* Loader Test mode on */
+	LD_T_OFF	= 1<<2,	/* Loader Test mode off */
+	LD_T_STEP	= 1<<1,	/* Decrement FPROM addr. Counter */
+	LD_START	= 1<<0,	/* Start loading FPROM */
+};
+
+/*	B2_TI_CTRL		 8 bit	Timer control */
+/*	B2_IRQM_CTRL	 8 bit	IRQ Moderation Timer Control */
+enum {
+	TIM_START	= 1<<2,	/* Start Timer */
+	TIM_STOP	= 1<<1,	/* Stop  Timer */
+	TIM_CLR_IRQ	= 1<<0,	/* Clear Timer IRQ (!IRQM) */
+};
+
+/*	B2_TI_TEST		 8 Bit	Timer Test */
+/*	B2_IRQM_TEST	 8 bit	IRQ Moderation Timer Test */
+/*	B28_DPT_TST		 8 bit	Descriptor Poll Timer Test Reg */
+enum {
+	TIM_T_ON	= 1<<2,	/* Test mode on */
+	TIM_T_OFF	= 1<<1,	/* Test mode off */
+	TIM_T_STEP	= 1<<0,	/* Test step */
+};
+
+/*	B28_DPT_INI	32 bit	Descriptor Poll Timer Init Val */
+/*	B28_DPT_VAL	32 bit	Descriptor Poll Timer Curr Val */
+/*	B28_DPT_CTRL	 8 bit	Descriptor Poll Timer Ctrl Reg */
+enum {
+	DPT_MSK	= 0x00ffffffL,	/* Bit 23.. 0:	Desc Poll Timer Bits */
+
+	DPT_START	= 1<<1,	/* Start Descriptor Poll Timer */
+	DPT_STOP	= 1<<0,	/* Stop  Descriptor Poll Timer */
+};
+
+/*	B2_GP_IO		32 bit	General Purpose I/O Register */
+enum {
+	GP_DIR_9 = 1<<25, /* IO_9 direct, 0=In/1=Out */
+	GP_DIR_8 = 1<<24, /* IO_8 direct, 0=In/1=Out */
+	GP_DIR_7 = 1<<23, /* IO_7 direct, 0=In/1=Out */
+	GP_DIR_6 = 1<<22, /* IO_6 direct, 0=In/1=Out */
+	GP_DIR_5 = 1<<21, /* IO_5 direct, 0=In/1=Out */
+	GP_DIR_4 = 1<<20, /* IO_4 direct, 0=In/1=Out */
+	GP_DIR_3 = 1<<19, /* IO_3 direct, 0=In/1=Out */
+	GP_DIR_2 = 1<<18, /* IO_2 direct, 0=In/1=Out */
+	GP_DIR_1 = 1<<17, /* IO_1 direct, 0=In/1=Out */
+	GP_DIR_0 = 1<<16, /* IO_0 direct, 0=In/1=Out */
+
+	GP_IO_9	= 1<<9,	/* IO_9 pin */
+	GP_IO_8	= 1<<8,	/* IO_8 pin */
+	GP_IO_7	= 1<<7,	/* IO_7 pin */
+	GP_IO_6	= 1<<6,	/* IO_6 pin */
+	GP_IO_5	= 1<<5,	/* IO_5 pin */
+	GP_IO_4	= 1<<4,	/* IO_4 pin */
+	GP_IO_3	= 1<<3,	/* IO_3 pin */
+	GP_IO_2	= 1<<2,	/* IO_2 pin */
+	GP_IO_1	= 1<<1,	/* IO_1 pin */
+	GP_IO_0	= 1<<0,	/* IO_0 pin */
+};
+
+/* Rx/Tx Path related Arbiter Test Registers */
+/*	B3_MA_TO_TEST	16 bit	MAC Arbiter Timeout Test Reg */
+/*	B3_MA_RC_TEST	16 bit	MAC Arbiter Recovery Test Reg */
+/*	B3_PA_TEST		16 bit	Packet Arbiter Test Register */
+/*			Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
+enum {
+	TX2_T_EV	= 1<<15,/* TX2 Timeout/Recv Event occured */
+	TX2_T_ON	= 1<<14,/* TX2 Timeout/Recv Timer Test On */
+	TX2_T_OFF	= 1<<13,/* TX2 Timeout/Recv Timer Tst Off */
+	TX2_T_STEP	= 1<<12,/* TX2 Timeout/Recv Timer Step */
+	TX1_T_EV	= 1<<11,/* TX1 Timeout/Recv Event occured */
+	TX1_T_ON	= 1<<10,/* TX1 Timeout/Recv Timer Test On */
+	TX1_T_OFF	= 1<<9,	/* TX1 Timeout/Recv Timer Tst Off */
+	TX1_T_STEP	= 1<<8,	/* TX1 Timeout/Recv Timer Step */
+	RX2_T_EV	= 1<<7,	/* RX2 Timeout/Recv Event occured */
+	RX2_T_ON	= 1<<6,	/* RX2 Timeout/Recv Timer Test On */
+	RX2_T_OFF	= 1<<5,	/* RX2 Timeout/Recv Timer Tst Off */
+	RX2_T_STEP	= 1<<4,	/* RX2 Timeout/Recv Timer Step */
+	RX1_T_EV	= 1<<3,	/* RX1 Timeout/Recv Event occured */
+	RX1_T_ON	= 1<<2,	/* RX1 Timeout/Recv Timer Test On */
+	RX1_T_OFF	= 1<<1,	/* RX1 Timeout/Recv Timer Tst Off */
+	RX1_T_STEP	= 1<<0,	/* RX1 Timeout/Recv Timer Step */
+};
+
+/* Descriptor Bit Definition */
+/*	TxCtrl		Transmit Buffer Control Field */
+/*	RxCtrl		Receive  Buffer Control Field */
+enum {
+	BMU_OWN		= 1<<31, /* OWN bit: 0=host/1=BMU */
+	BMU_STF		= 1<<30, /* Start of Frame */
+	BMU_EOF		= 1<<29, /* End of Frame */
+	BMU_IRQ_EOB	= 1<<28, /* Req "End of Buffer" IRQ */
+	BMU_IRQ_EOF	= 1<<27, /* Req "End of Frame" IRQ */
+				/* TxCtrl specific bits */
+	BMU_STFWD	= 1<<26, /* (Tx)	Store & Forward Frame */
+	BMU_NO_FCS	= 1<<25, /* (Tx) Disable MAC FCS (CRC) generation */
+	BMU_SW	= 1<<24, /* (Tx)	1 bit res. for SW use */
+				/* RxCtrl specific bits */
+	BMU_DEV_0	= 1<<26, /* (Rx)	Transfer data to Dev0 */
+	BMU_STAT_VAL	= 1<<25, /* (Rx)	Rx Status Valid */
+	BMU_TIST_VAL	= 1<<24, /* (Rx)	Rx TimeStamp Valid */
+			/* Bit 23..16:	BMU Check Opcodes */
+	BMU_CHECK	= 0x55<<16, /* Default BMU check */
+	BMU_TCP_CHECK	= 0x56<<16, /* Descr with TCP ext */
+	BMU_UDP_CHECK	= 0x57<<16, /* Descr with UDP ext (YUKON only) */
+	BMU_BBC		= 0xffffL, /* Bit 15.. 0:	Buffer Byte Counter */
+};
+
+/*	B2_BSC_CTRL		 8 bit	Blink Source Counter Control */
+enum {
+	 BSC_START	= 1<<1,	/* Start Blink Source Counter */
+	 BSC_STOP	= 1<<0,	/* Stop  Blink Source Counter */
+};
+
+/*	B2_BSC_STAT		 8 bit	Blink Source Counter Status */
+enum {
+	BSC_SRC		= 1<<0,	/* Blink Source, 0=Off / 1=On */
+};
+
+/*	B2_BSC_TST		16 bit	Blink Source Counter Test Reg */
+enum {
+	BSC_T_ON	= 1<<2,	/* Test mode on */
+	BSC_T_OFF	= 1<<1,	/* Test mode off */
+	BSC_T_STEP	= 1<<0,	/* Test step */
+};
+
+/*	B3_RAM_ADDR		32 bit	RAM Address, to read or write */
+					/* Bit 31..19:	reserved */
+#define RAM_ADR_RAN	0x0007ffffL	/* Bit 18.. 0:	RAM Address Range */
+/* RAM Interface Registers */
+
+/*	B3_RI_CTRL		16 bit	RAM Iface Control Register */
+enum {
+	RI_CLR_RD_PERR	= 1<<9,	/* Clear IRQ RAM Read Parity Err */
+	RI_CLR_WR_PERR	= 1<<8,	/* Clear IRQ RAM Write Parity Err*/
+
+	RI_RST_CLR	= 1<<1,	/* Clear RAM Interface Reset */
+	RI_RST_SET	= 1<<0,	/* Set   RAM Interface Reset */
+};
+
+/*	B3_RI_TEST		 8 bit	RAM Iface Test Register */
+enum {
+	RI_T_EV	= 1<<3,	/* Timeout Event occured */
+	RI_T_ON	= 1<<2,	/* Timeout Timer Test On */
+	RI_T_OFF	= 1<<1,	/* Timeout Timer Test Off */
+	RI_T_STEP	= 1<<0,	/* Timeout Timer Step */
+};
+
+/* MAC Arbiter Registers */
+/*	B3_MA_TO_CTRL	16 bit	MAC Arbiter Timeout Ctrl Reg */
+enum {
+	MA_FOE_ON	= 1<<3,	/* XMAC Fast Output Enable ON */
+	MA_FOE_OFF	= 1<<2,	/* XMAC Fast Output Enable OFF */
+	MA_RST_CLR	= 1<<1,	/* Clear MAC Arbiter Reset */
+	MA_RST_SET	= 1<<0,	/* Set   MAC Arbiter Reset */
+
+};
+
+/* Timeout values */
+#define SK_MAC_TO_53	72		/* MAC arbiter timeout */
+#define SK_PKT_TO_53	0x2000		/* Packet arbiter timeout */
+#define SK_PKT_TO_MAX	0xffff		/* Maximum value */
+#define SK_RI_TO_53	36		/* RAM interface timeout */
+
+
+/*	B3_MA_RC_CTRL	16 bit	MAC Arbiter Recovery Ctrl Reg */
+enum {
+	MA_ENA_REC_TX2	= 1<<7,	/* Enable  Recovery Timer TX2 */
+	MA_DIS_REC_TX2	= 1<<6,	/* Disable Recovery Timer TX2 */
+	MA_ENA_REC_TX1	= 1<<5,	/* Enable  Recovery Timer TX1 */
+	MA_DIS_REC_TX1	= 1<<4,	/* Disable Recovery Timer TX1 */
+	MA_ENA_REC_RX2	= 1<<3,	/* Enable  Recovery Timer RX2 */
+	MA_DIS_REC_RX2	= 1<<2,	/* Disable Recovery Timer RX2 */
+	MA_ENA_REC_RX1	= 1<<1,	/* Enable  Recovery Timer RX1 */
+	MA_DIS_REC_RX1	= 1<<0,	/* Disable Recovery Timer RX1 */
+};
+
+/* Packet Arbiter Registers */
+/*	B3_PA_CTRL		16 bit	Packet Arbiter Ctrl Register */
+enum {
+	PA_CLR_TO_TX2	= 1<<13,	/* Clear IRQ Packet Timeout TX2 */
+	PA_CLR_TO_TX1	= 1<<12,	/* Clear IRQ Packet Timeout TX1 */
+	PA_CLR_TO_RX2	= 1<<11,	/* Clear IRQ Packet Timeout RX2 */
+	PA_CLR_TO_RX1	= 1<<10,	/* Clear IRQ Packet Timeout RX1 */
+	PA_ENA_TO_TX2	= 1<<9,	/* Enable  Timeout Timer TX2 */
+	PA_DIS_TO_TX2	= 1<<8,	/* Disable Timeout Timer TX2 */
+	PA_ENA_TO_TX1	= 1<<7,	/* Enable  Timeout Timer TX1 */
+	PA_DIS_TO_TX1	= 1<<6,	/* Disable Timeout Timer TX1 */
+	PA_ENA_TO_RX2	= 1<<5,	/* Enable  Timeout Timer RX2 */
+	PA_DIS_TO_RX2	= 1<<4,	/* Disable Timeout Timer RX2 */
+	PA_ENA_TO_RX1	= 1<<3,	/* Enable  Timeout Timer RX1 */
+	PA_DIS_TO_RX1	= 1<<2,	/* Disable Timeout Timer RX1 */
+	PA_RST_CLR	= 1<<1,	/* Clear MAC Arbiter Reset */
+	PA_RST_SET	= 1<<0,	/* Set   MAC Arbiter Reset */
+};
+
+#define PA_ENA_TO_ALL	(PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\
+						PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
+
+
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/*	TXA_ITI_INI		32 bit	Tx Arb Interval Timer Init Val */
+/*	TXA_ITI_VAL		32 bit	Tx Arb Interval Timer Value */
+/*	TXA_LIM_INI		32 bit	Tx Arb Limit Counter Init Val */
+/*	TXA_LIM_VAL		32 bit	Tx Arb Limit Counter Value */
+
+#define TXA_MAX_VAL	0x00ffffffUL	/* Bit 23.. 0:	Max TXA Timer/Cnt Val */
+
+/*	TXA_CTRL		 8 bit	Tx Arbiter Control Register */
+enum {
+	TXA_ENA_FSYNC	= 1<<7,	/* Enable  force of sync Tx queue */
+	TXA_DIS_FSYNC	= 1<<6,	/* Disable force of sync Tx queue */
+	TXA_ENA_ALLOC	= 1<<5,	/* Enable  alloc of free bandwidth */
+	TXA_DIS_ALLOC	= 1<<4,	/* Disable alloc of free bandwidth */
+	TXA_START_RC	= 1<<3,	/* Start sync Rate Control */
+	TXA_STOP_RC	= 1<<2,	/* Stop  sync Rate Control */
+	TXA_ENA_ARB	= 1<<1,	/* Enable  Tx Arbiter */
+	TXA_DIS_ARB	= 1<<0,	/* Disable Tx Arbiter */
+};
+
+/*
+ *	Bank 4 - 5
+ */
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+enum {
+	TXA_ITI_INI	= 0x0200,/* 32 bit	Tx Arb Interval Timer Init Val*/
+	TXA_ITI_VAL	= 0x0204,/* 32 bit	Tx Arb Interval Timer Value */
+	TXA_LIM_INI	= 0x0208,/* 32 bit	Tx Arb Limit Counter Init Val */
+	TXA_LIM_VAL	= 0x020c,/* 32 bit	Tx Arb Limit Counter Value */
+	TXA_CTRL	= 0x0210,/*  8 bit	Tx Arbiter Control Register */
+	TXA_TEST	= 0x0211,/*  8 bit	Tx Arbiter Test Register */
+	TXA_STAT	= 0x0212,/*  8 bit	Tx Arbiter Status Register */
+};
+
+
+enum {
+	B6_EXT_REG	= 0x0300,/* External registers (GENESIS only) */
+	B7_CFG_SPC	= 0x0380,/* copy of the Configuration register */
+	B8_RQ1_REGS	= 0x0400,/* Receive Queue 1 */
+	B8_RQ2_REGS	= 0x0480,/* Receive Queue 2 */
+	B8_TS1_REGS	= 0x0600,/* Transmit sync queue 1 */
+	B8_TA1_REGS	= 0x0680,/* Transmit async queue 1 */
+	B8_TS2_REGS	= 0x0700,/* Transmit sync queue 2 */
+	B8_TA2_REGS	= 0x0780,/* Transmit sync queue 2 */
+	B16_RAM_REGS	= 0x0800,/* RAM Buffer Registers */
+};
+
+/* Queue Register Offsets, use Q_ADDR() to access */
+enum {
+	B8_Q_REGS = 0x0400, /* base of Queue registers */	
+	Q_D	= 0x00,	/* 8*32	bit	Current Descriptor */
+	Q_DA_L	= 0x20,	/* 32 bit	Current Descriptor Address Low dWord */
+	Q_DA_H	= 0x24,	/* 32 bit	Current Descriptor Address High dWord */
+	Q_AC_L	= 0x28,	/* 32 bit	Current Address Counter Low dWord */
+	Q_AC_H	= 0x2c,	/* 32 bit	Current Address Counter High dWord */
+	Q_BC	= 0x30,	/* 32 bit	Current Byte Counter */
+	Q_CSR	= 0x34,	/* 32 bit	BMU Control/Status Register */
+	Q_F	= 0x38,	/* 32 bit	Flag Register */
+	Q_T1	= 0x3c,	/* 32 bit	Test Register 1 */
+	Q_T1_TR	= 0x3c,	/*  8 bit	Test Register 1 Transfer SM */
+	Q_T1_WR	= 0x3d,	/*  8 bit	Test Register 1 Write Descriptor SM */
+	Q_T1_RD	= 0x3e,	/*  8 bit	Test Register 1 Read Descriptor SM */
+	Q_T1_SV	= 0x3f,	/*  8 bit	Test Register 1 Supervisor SM */
+	Q_T2	= 0x40,	/* 32 bit	Test Register 2	*/
+	Q_T3	= 0x44,	/* 32 bit	Test Register 3	*/
+
+/* Yukon-2 */
+	Q_DONE	= 0x24,	/* 16 bit	Done Index 		(Yukon-2 only) */
+	Q_WM	= 0x40,	/* 16 bit	FIFO Watermark */
+	Q_AL	= 0x42,	/*  8 bit	FIFO Alignment */
+	Q_RSP	= 0x44,	/* 16 bit	FIFO Read Shadow Pointer */
+	Q_RSL	= 0x46,	/*  8 bit	FIFO Read Shadow Level */
+	Q_RP	= 0x48,	/*  8 bit	FIFO Read Pointer */
+	Q_RL	= 0x4a,	/*  8 bit	FIFO Read Level */
+	Q_WP	= 0x4c,	/*  8 bit	FIFO Write Pointer */
+	Q_WSP	= 0x4d,	/*  8 bit	FIFO Write Shadow Pointer */
+	Q_WL	= 0x4e,	/*  8 bit	FIFO Write Level */
+	Q_WSL	= 0x4f,	/*  8 bit	FIFO Write Shadow Level */
+};
+#define Q_ADDR(reg, offs) (B8_Q_REGS + (reg) + (offs))
+
+/* RAM Buffer Register Offsets */
+enum {
+
+	RB_START	= 0x00,/* 32 bit	RAM Buffer Start Address */
+	RB_END	= 0x04,/* 32 bit	RAM Buffer End Address */
+	RB_WP	= 0x08,/* 32 bit	RAM Buffer Write Pointer */
+	RB_RP	= 0x0c,/* 32 bit	RAM Buffer Read Pointer */
+	RB_RX_UTPP	= 0x10,/* 32 bit	Rx Upper Threshold, Pause Packet */
+	RB_RX_LTPP	= 0x14,/* 32 bit	Rx Lower Threshold, Pause Packet */
+	RB_RX_UTHP	= 0x18,/* 32 bit	Rx Upper Threshold, High Prio */
+	RB_RX_LTHP	= 0x1c,/* 32 bit	Rx Lower Threshold, High Prio */
+	/* 0x10 - 0x1f:	reserved at Tx RAM Buffer Registers */
+	RB_PC	= 0x20,/* 32 bit	RAM Buffer Packet Counter */
+	RB_LEV	= 0x24,/* 32 bit	RAM Buffer Level Register */
+	RB_CTRL	= 0x28,/* 32 bit	RAM Buffer Control Register */
+	RB_TST1	= 0x29,/*  8 bit	RAM Buffer Test Register 1 */
+	RB_TST2	= 0x2a,/*  8 bit	RAM Buffer Test Register 2 */
+};
+
+/* Receive and Transmit Queues */
+enum {
+	Q_R1	= 0x0000,	/* Receive Queue 1 */
+	Q_R2	= 0x0080,	/* Receive Queue 2 */
+	Q_XS1	= 0x0200,	/* Synchronous Transmit Queue 1 */
+	Q_XA1	= 0x0280,	/* Asynchronous Transmit Queue 1 */
+	Q_XS2	= 0x0300,	/* Synchronous Transmit Queue 2 */
+	Q_XA2	= 0x0380,	/* Asynchronous Transmit Queue 2 */
+};
+
+/* Different MAC Types */
+enum {
+	SK_MAC_XMAC =	0,	/* Xaqti XMAC II */
+	SK_MAC_GMAC =	1,	/* Marvell GMAC */
+};
+
+/* Different PHY Types */
+enum {
+	SK_PHY_XMAC	= 0,/* integrated in XMAC II */
+	SK_PHY_BCOM	= 1,/* Broadcom BCM5400 */
+	SK_PHY_LONE	= 2,/* Level One LXT1000  [not supported]*/
+	SK_PHY_NAT	= 3,/* National DP83891  [not supported] */
+	SK_PHY_MARV_COPPER= 4,/* Marvell 88E1011S */
+	SK_PHY_MARV_FIBER = 5,/* Marvell 88E1011S working on fiber */
+};
+
+/* PHY addresses (bits 12..8 of PHY address reg) */
+enum {
+	PHY_ADDR_XMAC	= 0<<8,
+	PHY_ADDR_BCOM	= 1<<8,
+	PHY_ADDR_LONE	= 3<<8,
+	PHY_ADDR_NAT	= 0<<8,
+/* GPHY address (bits 15..11 of SMI control reg) */
+	PHY_ADDR_MARV	= 0,
+};
+
+#define RB_ADDR(offs, queue) (B16_RAM_REGS + (queue) + (offs))
+
+/* Receive MAC FIFO, Receive LED, and Link_Sync regs (GENESIS only) */
+enum {
+	RX_MFF_EA	= 0x0c00,/* 32 bit	Receive MAC FIFO End Address */
+	RX_MFF_WP	= 0x0c04,/* 32 bit	Receive MAC FIFO Write Pointer */
+
+	RX_MFF_RP	= 0x0c0c,/* 32 bit	Receive MAC FIFO Read Pointer */
+	RX_MFF_PC	= 0x0c10,/* 32 bit	Receive MAC FIFO Packet Cnt */
+	RX_MFF_LEV	= 0x0c14,/* 32 bit	Receive MAC FIFO Level */
+	RX_MFF_CTRL1	= 0x0c18,/* 16 bit	Receive MAC FIFO Control Reg 1*/
+	RX_MFF_STAT_TO	= 0x0c1a,/*  8 bit	Receive MAC Status Timeout */
+	RX_MFF_TIST_TO	= 0x0c1b,/*  8 bit	Receive MAC Time Stamp Timeout */
+	RX_MFF_CTRL2	= 0x0c1c,/*  8 bit	Receive MAC FIFO Control Reg 2*/
+	RX_MFF_TST1	= 0x0c1d,/*  8 bit	Receive MAC FIFO Test Reg 1 */
+	RX_MFF_TST2	= 0x0c1e,/*  8 bit	Receive MAC FIFO Test Reg 2 */
+
+	RX_LED_INI	= 0x0c20,/* 32 bit	Receive LED Cnt Init Value */
+	RX_LED_VAL	= 0x0c24,/* 32 bit	Receive LED Cnt Current Value */
+	RX_LED_CTRL	= 0x0c28,/*  8 bit	Receive LED Cnt Control Reg */
+	RX_LED_TST	= 0x0c29,/*  8 bit	Receive LED Cnt Test Register */
+
+	LNK_SYNC_INI	= 0x0c30,/* 32 bit	Link Sync Cnt Init Value */
+	LNK_SYNC_VAL	= 0x0c34,/* 32 bit	Link Sync Cnt Current Value */
+	LNK_SYNC_CTRL	= 0x0c38,/*  8 bit	Link Sync Cnt Control Register */
+	LNK_SYNC_TST	= 0x0c39,/*  8 bit	Link Sync Cnt Test Register */
+	LNK_LED_REG	= 0x0c3c,/*  8 bit	Link LED Register */
+};
+
+/* Receive and Transmit MAC FIFO Registers (GENESIS only) */
+/*	RX_MFF_CTRL1	16 bit	Receive MAC FIFO Control Reg 1 */
+enum {
+	MFF_ENA_RDY_PAT	= 1<<13,	/* Enable  Ready Patch */
+	MFF_DIS_RDY_PAT	= 1<<12,	/* Disable Ready Patch */
+	MFF_ENA_TIM_PAT	= 1<<11,	/* Enable  Timing Patch */
+	MFF_DIS_TIM_PAT	= 1<<10,	/* Disable Timing Patch */
+	MFF_ENA_ALM_FUL	= 1<<9,	/* Enable  AlmostFull Sign */
+	MFF_DIS_ALM_FUL	= 1<<8,	/* Disable AlmostFull Sign */
+	MFF_ENA_PAUSE	= 1<<7,	/* Enable  Pause Signaling */
+	MFF_DIS_PAUSE	= 1<<6,	/* Disable Pause Signaling */
+	MFF_ENA_FLUSH	= 1<<5,	/* Enable  Frame Flushing */
+	MFF_DIS_FLUSH	= 1<<4,	/* Disable Frame Flushing */
+	MFF_ENA_TIST	= 1<<3,	/* Enable  Time Stamp Gener */
+	MFF_DIS_TIST	= 1<<2,	/* Disable Time Stamp Gener */
+	MFF_CLR_INTIST	= 1<<1,	/* Clear IRQ No Time Stamp */
+	MFF_CLR_INSTAT	= 1<<0,	/* Clear IRQ No Status */
+#define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT
+};
+
+/*	TX_MFF_CTRL1	16 bit	Transmit MAC FIFO Control Reg 1 */
+enum {
+	MFF_CLR_PERR	= 1<<15,	/* Clear Parity Error IRQ */
+								/* Bit 14:	reserved */
+	MFF_ENA_PKT_REC	= 1<<13,	/* Enable  Packet Recovery */
+	MFF_DIS_PKT_REC	= 1<<12,	/* Disable Packet Recovery */
+
+	MFF_ENA_W4E	= 1<<7,	/* Enable  Wait for Empty */
+	MFF_DIS_W4E	= 1<<6,	/* Disable Wait for Empty */
+
+	MFF_ENA_LOOPB	= 1<<3,	/* Enable  Loopback */
+	MFF_DIS_LOOPB	= 1<<2,	/* Disable Loopback */
+	MFF_CLR_MAC_RST	= 1<<1,	/* Clear XMAC Reset */
+	MFF_SET_MAC_RST	= 1<<0,	/* Set   XMAC Reset */
+};
+
+#define MFF_TX_CTRL_DEF	(MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH)
+
+/*	RX_MFF_TST2	 	 8 bit	Receive MAC FIFO Test Register 2 */
+/*	TX_MFF_TST2	 	 8 bit	Transmit MAC FIFO Test Register 2 */
+enum {
+	MFF_WSP_T_ON	= 1<<6,	/* Tx: Write Shadow Ptr TestOn */
+	MFF_WSP_T_OFF	= 1<<5,	/* Tx: Write Shadow Ptr TstOff */
+	MFF_WSP_INC	= 1<<4,	/* Tx: Write Shadow Ptr Increment */
+	MFF_PC_DEC	= 1<<3,	/* Packet Counter Decrement */
+	MFF_PC_T_ON	= 1<<2,	/* Packet Counter Test On */
+	MFF_PC_T_OFF	= 1<<1,	/* Packet Counter Test Off */
+	MFF_PC_INC	= 1<<0,	/* Packet Counter Increment */
+};
+
+/*	RX_MFF_TST1	 	 8 bit	Receive MAC FIFO Test Register 1 */
+/*	TX_MFF_TST1	 	 8 bit	Transmit MAC FIFO Test Register 1 */
+enum {
+	MFF_WP_T_ON	= 1<<6,	/* Write Pointer Test On */
+	MFF_WP_T_OFF	= 1<<5,	/* Write Pointer Test Off */
+	MFF_WP_INC	= 1<<4,	/* Write Pointer Increm */
+
+	MFF_RP_T_ON	= 1<<2,	/* Read Pointer Test On */
+	MFF_RP_T_OFF	= 1<<1,	/* Read Pointer Test Off */
+	MFF_RP_DEC	= 1<<0,	/* Read Pointer Decrement */
+};
+
+/*	RX_MFF_CTRL2	 8 bit	Receive MAC FIFO Control Reg 2 */
+/*	TX_MFF_CTRL2	 8 bit	Transmit MAC FIFO Control Reg 2 */
+enum {
+	MFF_ENA_OP_MD	= 1<<3,	/* Enable  Operation Mode */
+	MFF_DIS_OP_MD	= 1<<2,	/* Disable Operation Mode */
+	MFF_RST_CLR	= 1<<1,	/* Clear MAC FIFO Reset */
+	MFF_RST_SET	= 1<<0,	/* Set   MAC FIFO Reset */
+};
+
+
+/*	Link LED Counter Registers (GENESIS only) */
+
+/*	RX_LED_CTRL		 8 bit	Receive LED Cnt Control Reg */
+/*	TX_LED_CTRL		 8 bit	Transmit LED Cnt Control Reg */
+/*	LNK_SYNC_CTRL	 8 bit	Link Sync Cnt Control Register */
+enum {
+	LED_START	= 1<<2,	/* Start Timer */
+	LED_STOP	= 1<<1,	/* Stop Timer */
+	LED_STATE	= 1<<0,	/* Rx/Tx: LED State, 1=LED on */
+};
+
+/*	RX_LED_TST		 8 bit	Receive LED Cnt Test Register */
+/*	TX_LED_TST		 8 bit	Transmit LED Cnt Test Register */
+/*	LNK_SYNC_TST	 8 bit	Link Sync Cnt Test Register */
+enum {
+	LED_T_ON	= 1<<2,	/* LED Counter Test mode On */
+	LED_T_OFF	= 1<<1,	/* LED Counter Test mode Off */
+	LED_T_STEP	= 1<<0,	/* LED Counter Step */
+};
+
+/*	LNK_LED_REG	 	 8 bit	Link LED Register */
+enum {
+	LED_BLK_ON	= 1<<5,	/* Link LED Blinking On */
+	LED_BLK_OFF	= 1<<4,	/* Link LED Blinking Off */
+	LED_SYNC_ON	= 1<<3,	/* Use Sync Wire to switch LED */
+	LED_SYNC_OFF	= 1<<2,	/* Disable Sync Wire Input */
+	LED_ON	= 1<<1,	/* switch LED on */
+	LED_OFF	= 1<<0,	/* switch LED off */
+};
+
+/* Receive GMAC FIFO (YUKON and Yukon-2) */
+enum {
+	RX_GMF_EA	= 0x0c40,/* 32 bit	Rx GMAC FIFO End Address */
+	RX_GMF_AF_THR	= 0x0c44,/* 32 bit	Rx GMAC FIFO Almost Full Thresh. */
+	RX_GMF_CTRL_T	= 0x0c48,/* 32 bit	Rx GMAC FIFO Control/Test */
+	RX_GMF_FL_MSK	= 0x0c4c,/* 32 bit	Rx GMAC FIFO Flush Mask */
+	RX_GMF_FL_THR	= 0x0c50,/* 32 bit	Rx GMAC FIFO Flush Threshold */
+	RX_GMF_TR_THR	= 0x0c54,/* 32 bit	Rx Truncation Threshold (Yukon-2) */
+
+	RX_GMF_VLAN	= 0x0c5c,/* 32 bit	Rx VLAN Type Register (Yukon-2) */
+	RX_GMF_WP	= 0x0c60,/* 32 bit	Rx GMAC FIFO Write Pointer */
+
+	RX_GMF_WLEV	= 0x0c68,/* 32 bit	Rx GMAC FIFO Write Level */
+
+	RX_GMF_RP	= 0x0c70,/* 32 bit	Rx GMAC FIFO Read Pointer */
+
+	RX_GMF_RLEV	= 0x0c78,/* 32 bit	Rx GMAC FIFO Read Level */
+};
+
+
+/*	TXA_TEST		 8 bit	Tx Arbiter Test Register */
+enum {
+	TXA_INT_T_ON	= 1<<5,	/* Tx Arb Interval Timer Test On */
+	TXA_INT_T_OFF	= 1<<4,	/* Tx Arb Interval Timer Test Off */
+	TXA_INT_T_STEP	= 1<<3,	/* Tx Arb Interval Timer Step */
+	TXA_LIM_T_ON	= 1<<2,	/* Tx Arb Limit Timer Test On */
+	TXA_LIM_T_OFF	= 1<<1,	/* Tx Arb Limit Timer Test Off */
+	TXA_LIM_T_STEP	= 1<<0,	/* Tx Arb Limit Timer Step */
+};
+
+/*	TXA_STAT		 8 bit	Tx Arbiter Status Register */
+enum {
+	TXA_PRIO_XS	= 1<<0,	/* sync queue has prio to send */
+};
+
+
+/*	Q_BC			32 bit	Current Byte Counter */
+
+/* BMU Control Status Registers */
+/*	B0_R1_CSR		32 bit	BMU Ctrl/Stat Rx Queue 1 */
+/*	B0_R2_CSR		32 bit	BMU Ctrl/Stat Rx Queue 2 */
+/*	B0_XA1_CSR		32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+/*	B0_XS1_CSR		32 bit	BMU Ctrl/Stat Async Tx Queue 1 */
+/*	B0_XA2_CSR		32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+/*	B0_XS2_CSR		32 bit	BMU Ctrl/Stat Async Tx Queue 2 */
+/*	Q_CSR			32 bit	BMU Control/Status Register */
+
+enum {
+	CSR_SV_IDLE	= 1<<24,	/* BMU SM Idle */
+
+	CSR_DESC_CLR	= 1<<21,	/* Clear Reset for Descr */
+	CSR_DESC_SET	= 1<<20,	/* Set   Reset for Descr */
+	CSR_FIFO_CLR	= 1<<19,	/* Clear Reset for FIFO */
+	CSR_FIFO_SET	= 1<<18,	/* Set   Reset for FIFO */
+	CSR_HPI_RUN	= 1<<17,	/* Release HPI SM */
+	CSR_HPI_RST	= 1<<16,	/* Reset   HPI SM to Idle */
+	CSR_SV_RUN	= 1<<15,	/* Release Supervisor SM */
+	CSR_SV_RST	= 1<<14,	/* Reset   Supervisor SM */
+	CSR_DREAD_RUN	= 1<<13,	/* Release Descr Read SM */
+	CSR_DREAD_RST	= 1<<12,	/* Reset   Descr Read SM */
+	CSR_DWRITE_RUN	= 1<<11,	/* Release Descr Write SM */
+	CSR_DWRITE_RST	= 1<<10,	/* Reset   Descr Write SM */
+	CSR_TRANS_RUN	= 1<<9,		/* Release Transfer SM */
+	CSR_TRANS_RST	= 1<<8,		/* Reset   Transfer SM */
+	CSR_ENA_POL	= 1<<7,		/* Enable  Descr Polling */
+	CSR_DIS_POL	= 1<<6,		/* Disable Descr Polling */
+	CSR_STOP	= 1<<5,		/* Stop  Rx/Tx Queue */
+	CSR_START	= 1<<4,		/* Start Rx/Tx Queue */
+	CSR_IRQ_CL_P	= 1<<3,		/* (Rx)	Clear Parity IRQ */
+	CSR_IRQ_CL_B	= 1<<2,		/* Clear EOB IRQ */
+	CSR_IRQ_CL_F	= 1<<1,		/* Clear EOF IRQ */
+	CSR_IRQ_CL_C	= 1<<0,		/* Clear ERR IRQ */
+};
+
+#define CSR_SET_RESET	(CSR_DESC_SET | CSR_FIFO_SET | CSR_HPI_RST |\
+			CSR_SV_RST | CSR_DREAD_RST | CSR_DWRITE_RST |\
+			CSR_TRANS_RST)
+#define CSR_CLR_RESET	(CSR_DESC_CLR | CSR_FIFO_CLR | CSR_HPI_RUN |\
+			CSR_SV_RUN | CSR_DREAD_RUN | CSR_DWRITE_RUN |\
+			CSR_TRANS_RUN)
+
+/*	Q_F				32 bit	Flag Register */
+enum {
+	F_ALM_FULL	= 1<<27,	/* Rx FIFO: almost full */
+	F_EMPTY		= 1<<27,	/* Tx FIFO: empty flag */
+	F_FIFO_EOF	= 1<<26,	/* Tag (EOF Flag) bit in FIFO */
+	F_WM_REACHED	= 1<<25,	/* Watermark reached */
+
+	F_FIFO_LEVEL	= 0x1fL<<16,	/* Bit 23..16:	# of Qwords in FIFO */
+	F_WATER_MARK	= 0x0007ffL,	/* Bit 10.. 0:	Watermark */
+};
+
+/* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */
+/*	RB_START		32 bit	RAM Buffer Start Address */
+/*	RB_END			32 bit	RAM Buffer End Address */
+/*	RB_WP			32 bit	RAM Buffer Write Pointer */
+/*	RB_RP			32 bit	RAM Buffer Read Pointer */
+/*	RB_RX_UTPP		32 bit	Rx Upper Threshold, Pause Pack */
+/*	RB_RX_LTPP		32 bit	Rx Lower Threshold, Pause Pack */
+/*	RB_RX_UTHP		32 bit	Rx Upper Threshold, High Prio */
+/*	RB_RX_LTHP		32 bit	Rx Lower Threshold, High Prio */
+/*	RB_PC			32 bit	RAM Buffer Packet Counter */
+/*	RB_LEV			32 bit	RAM Buffer Level Register */
+
+#define RB_MSK	0x0007ffff	/* Bit 18.. 0:	RAM Buffer Pointer Bits */
+/*	RB_TST2			 8 bit	RAM Buffer Test Register 2 */
+/*	RB_TST1			 8 bit	RAM Buffer Test Register 1 */
+
+/*	RB_CTRL			 8 bit	RAM Buffer Control Register */
+enum {
+	RB_ENA_STFWD	= 1<<5,	/* Enable  Store & Forward */
+	RB_DIS_STFWD	= 1<<4,	/* Disable Store & Forward */
+	RB_ENA_OP_MD	= 1<<3,	/* Enable  Operation Mode */
+	RB_DIS_OP_MD	= 1<<2,	/* Disable Operation Mode */
+	RB_RST_CLR	= 1<<1,	/* Clear RAM Buf STM Reset */
+	RB_RST_SET	= 1<<0,	/* Set   RAM Buf STM Reset */
+};
+
+/* Transmit MAC FIFO and Transmit LED Registers (GENESIS only), */
+enum {
+	TX_MFF_EA	= 0x0d00,/* 32 bit	Transmit MAC FIFO End Address */
+	TX_MFF_WP	= 0x0d04,/* 32 bit	Transmit MAC FIFO WR Pointer */
+	TX_MFF_WSP	= 0x0d08,/* 32 bit	Transmit MAC FIFO WR Shadow Ptr */
+	TX_MFF_RP	= 0x0d0c,/* 32 bit	Transmit MAC FIFO RD Pointer */
+	TX_MFF_PC	= 0x0d10,/* 32 bit	Transmit MAC FIFO Packet Cnt */
+	TX_MFF_LEV	= 0x0d14,/* 32 bit	Transmit MAC FIFO Level */
+	TX_MFF_CTRL1	= 0x0d18,/* 16 bit	Transmit MAC FIFO Ctrl Reg 1 */
+	TX_MFF_WAF	= 0x0d1a,/*  8 bit	Transmit MAC Wait after flush */
+
+	TX_MFF_CTRL2	= 0x0d1c,/*  8 bit	Transmit MAC FIFO Ctrl Reg 2 */
+	TX_MFF_TST1	= 0x0d1d,/*  8 bit	Transmit MAC FIFO Test Reg 1 */
+	TX_MFF_TST2	= 0x0d1e,/*  8 bit	Transmit MAC FIFO Test Reg 2 */
+
+	TX_LED_INI	= 0x0d20,/* 32 bit	Transmit LED Cnt Init Value */
+	TX_LED_VAL	= 0x0d24,/* 32 bit	Transmit LED Cnt Current Val */
+	TX_LED_CTRL	= 0x0d28,/*  8 bit	Transmit LED Cnt Control Reg */
+	TX_LED_TST	= 0x0d29,/*  8 bit	Transmit LED Cnt Test Reg */
+};
+
+/* Counter and Timer constants, for a host clock of 62.5 MHz */
+#define SK_XMIT_DUR		0x002faf08UL	/*  50 ms */
+#define SK_BLK_DUR		0x01dcd650UL	/* 500 ms */
+
+#define SK_DPOLL_DEF	0x00ee6b28UL	/* 250 ms at 62.5 MHz */
+
+#define SK_DPOLL_MAX	0x00ffffffUL	/* 268 ms at 62.5 MHz */
+					/* 215 ms at 78.12 MHz */
+
+#define SK_FACT_62		100	/* is given in percent */
+#define SK_FACT_53		 85     /* on GENESIS:	53.12 MHz */
+#define SK_FACT_78		125	/* on YUKON:	78.12 MHz */
+
+
+/* Transmit GMAC FIFO (YUKON only) */
+enum {
+	TX_GMF_EA	= 0x0d40,/* 32 bit	Tx GMAC FIFO End Address */
+	TX_GMF_AE_THR	= 0x0d44,/* 32 bit	Tx GMAC FIFO Almost Empty Thresh.*/
+	TX_GMF_CTRL_T	= 0x0d48,/* 32 bit	Tx GMAC FIFO Control/Test */
+
+	TX_GMF_WP	= 0x0d60,/* 32 bit 	Tx GMAC FIFO Write Pointer */
+	TX_GMF_WSP	= 0x0d64,/* 32 bit 	Tx GMAC FIFO Write Shadow Ptr. */
+	TX_GMF_WLEV	= 0x0d68,/* 32 bit 	Tx GMAC FIFO Write Level */
+
+	TX_GMF_RP	= 0x0d70,/* 32 bit 	Tx GMAC FIFO Read Pointer */
+	TX_GMF_RSTP	= 0x0d74,/* 32 bit 	Tx GMAC FIFO Restart Pointer */
+	TX_GMF_RLEV	= 0x0d78,/* 32 bit 	Tx GMAC FIFO Read Level */
+
+	/* Descriptor Poll Timer Registers */
+	B28_DPT_INI	= 0x0e00,/* 24 bit	Descriptor Poll Timer Init Val */
+	B28_DPT_VAL	= 0x0e04,/* 24 bit	Descriptor Poll Timer Curr Val */
+	B28_DPT_CTRL	= 0x0e08,/*  8 bit	Descriptor Poll Timer Ctrl Reg */
+
+	B28_DPT_TST	= 0x0e0a,/*  8 bit	Descriptor Poll Timer Test Reg */
+
+	/* Time Stamp Timer Registers (YUKON only) */
+	GMAC_TI_ST_VAL	= 0x0e14,/* 32 bit	Time Stamp Timer Curr Val */
+	GMAC_TI_ST_CTRL	= 0x0e18,/*  8 bit	Time Stamp Timer Ctrl Reg */
+	GMAC_TI_ST_TST	= 0x0e1a,/*  8 bit	Time Stamp Timer Test Reg */
+};
+
+/* Status BMU Registers (Yukon-2 only)*/
+enum {
+	STAT_CTRL	= 0x0e80,/* 32 bit	Status BMU Control Reg */
+	STAT_LAST_IDX	= 0x0e84,/* 16 bit	Status BMU Last Index */
+	/* 0x0e85 - 0x0e86:	reserved */
+	STAT_LIST_ADDR_LO	= 0x0e88,/* 32 bit	Status List Start Addr (low) */
+	STAT_LIST_ADDR_HI	= 0x0e8c,/* 32 bit	Status List Start Addr (high) */
+	STAT_TXA1_RIDX	= 0x0e90,/* 16 bit	Status TxA1 Report Index Reg */
+	STAT_TXS1_RIDX	= 0x0e92,/* 16 bit	Status TxS1 Report Index Reg */
+	STAT_TXA2_RIDX	= 0x0e94,/* 16 bit	Status TxA2 Report Index Reg */
+	STAT_TXS2_RIDX	= 0x0e96,/* 16 bit	Status TxS2 Report Index Reg */
+	STAT_TX_IDX_TH	= 0x0e98,/* 16 bit	Status Tx Index Threshold Reg */
+	STAT_PUT_IDX	= 0x0e9c,/* 16 bit	Status Put Index Reg */
+
+/* FIFO Control/Status Registers (Yukon-2 only)*/
+	STAT_FIFO_WP	= 0x0ea0,/*  8 bit	Status FIFO Write Pointer Reg */
+	STAT_FIFO_RP	= 0x0ea4,/*  8 bit	Status FIFO Read Pointer Reg */
+	STAT_FIFO_RSP	= 0x0ea6,/*  8 bit	Status FIFO Read Shadow Ptr */
+	STAT_FIFO_LEVEL	= 0x0ea8,/*  8 bit	Status FIFO Level Reg */
+	STAT_FIFO_SHLVL	= 0x0eaa,/*  8 bit	Status FIFO Shadow Level Reg */
+	STAT_FIFO_WM	= 0x0eac,/*  8 bit	Status FIFO Watermark Reg */
+	STAT_FIFO_ISR_WM	= 0x0ead,/*  8 bit	Status FIFO ISR Watermark Reg */
+
+/* Level and ISR Timer Registers (Yukon-2 only)*/
+	STAT_LEV_TIMER_INI	= 0x0eb0,/* 32 bit	Level Timer Init. Value Reg */
+	STAT_LEV_TIMER_CNT	= 0x0eb4,/* 32 bit	Level Timer Counter Reg */
+	STAT_LEV_TIMER_CTRL	= 0x0eb8,/*  8 bit	Level Timer Control Reg */
+	STAT_LEV_TIMER_TEST	= 0x0eb9,/*  8 bit	Level Timer Test Reg */
+	STAT_TX_TIMER_INI	= 0x0ec0,/* 32 bit	Tx Timer Init. Value Reg */
+	STAT_TX_TIMER_CNT	= 0x0ec4,/* 32 bit	Tx Timer Counter Reg */
+	STAT_TX_TIMER_CTRL	= 0x0ec8,/*  8 bit	Tx Timer Control Reg */
+	STAT_TX_TIMER_TEST	= 0x0ec9,/*  8 bit	Tx Timer Test Reg */
+	STAT_ISR_TIMER_INI	= 0x0ed0,/* 32 bit	ISR Timer Init. Value Reg */
+	STAT_ISR_TIMER_CNT	= 0x0ed4,/* 32 bit	ISR Timer Counter Reg */
+	STAT_ISR_TIMER_CTRL	= 0x0ed8,/*  8 bit	ISR Timer Control Reg */
+	STAT_ISR_TIMER_TEST	= 0x0ed9,/*  8 bit	ISR Timer Test Reg */
+
+	ST_LAST_IDX_MASK	= 0x007f,/* Last Index Mask */
+	ST_TXRP_IDX_MASK	= 0x0fff,/* Tx Report Index Mask */
+	ST_TXTH_IDX_MASK	= 0x0fff,/* Tx Threshold Index Mask */
+	ST_WM_IDX_MASK	= 0x3f,/* FIFO Watermark Index Mask */
+};
+
+enum {
+	LINKLED_OFF 	     = 0x01,
+	LINKLED_ON  	     = 0x02,
+	LINKLED_LINKSYNC_OFF = 0x04,
+	LINKLED_LINKSYNC_ON  = 0x08,
+	LINKLED_BLINK_OFF    = 0x10,
+	LINKLED_BLINK_ON     = 0x20,
+};
+	
+/* GMAC and GPHY Control Registers (YUKON only) */
+enum {
+	GMAC_CTRL	= 0x0f00,/* 32 bit	GMAC Control Reg */
+	GPHY_CTRL	= 0x0f04,/* 32 bit	GPHY Control Reg */
+	GMAC_IRQ_SRC	= 0x0f08,/*  8 bit	GMAC Interrupt Source Reg */
+	GMAC_IRQ_MSK	= 0x0f0c,/*  8 bit	GMAC Interrupt Mask Reg */
+	GMAC_LINK_CTRL	= 0x0f10,/* 16 bit	Link Control Reg */
+
+/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
+
+	WOL_REG_OFFS	= 0x20,/* HW-Bug: Address is + 0x20 against spec. */
+
+	WOL_CTRL_STAT	= 0x0f20,/* 16 bit	WOL Control/Status Reg */
+	WOL_MATCH_CTL	= 0x0f22,/*  8 bit	WOL Match Control Reg */
+	WOL_MATCH_RES	= 0x0f23,/*  8 bit	WOL Match Result Reg */
+	WOL_MAC_ADDR	= 0x0f24,/* 32 bit	WOL MAC Address */
+	WOL_PATT_PME	= 0x0f2a,/*  8 bit	WOL PME Match Enable (Yukon-2) */
+	WOL_PATT_ASFM	= 0x0f2b,/*  8 bit	WOL ASF Match Enable (Yukon-2) */
+	WOL_PATT_RPTR	= 0x0f2c,/*  8 bit	WOL Pattern Read Pointer */
+
+/* WOL Pattern Length Registers (YUKON only) */
+
+	WOL_PATT_LEN_LO	= 0x0f30,/* 32 bit	WOL Pattern Length 3..0 */
+	WOL_PATT_LEN_HI	= 0x0f34,/* 24 bit	WOL Pattern Length 6..4 */
+
+/* WOL Pattern Counter Registers (YUKON only) */
+
+	WOL_PATT_CNT_0	= 0x0f38,/* 32 bit	WOL Pattern Counter 3..0 */
+	WOL_PATT_CNT_4	= 0x0f3c,/* 24 bit	WOL Pattern Counter 6..4 */
+};
+
+enum {
+	WOL_PATT_RAM_1	= 0x1000,/*  WOL Pattern RAM Link 1 */
+	WOL_PATT_RAM_2	= 0x1400,/*  WOL Pattern RAM Link 2 */
+};
+
+enum {
+	BASE_XMAC_1	= 0x2000,/* XMAC 1 registers */
+	BASE_GMAC_1	= 0x2800,/* GMAC 1 registers */
+	BASE_XMAC_2	= 0x3000,/* XMAC 2 registers */
+	BASE_GMAC_2	= 0x3800,/* GMAC 2 registers */
+};
+
+/*
+ * Receive Frame Status Encoding
+ */
+enum {
+	XMR_FS_LEN	= 0x3fff<<18,	/* Bit 31..18:	Rx Frame Length */
+	XMR_FS_2L_VLAN	= 1<<17, /* Bit 17:	tagged wh 2Lev VLAN ID*/
+	XMR_FS_1_VLAN	= 1<<16, /* Bit 16:	tagged wh 1ev VLAN ID*/
+	XMR_FS_BC	= 1<<15, /* Bit 15:	Broadcast Frame */
+	XMR_FS_MC	= 1<<14, /* Bit 14:	Multicast Frame */
+	XMR_FS_UC	= 1<<13, /* Bit 13:	Unicast Frame */
+
+	XMR_FS_BURST	= 1<<11, /* Bit 11:	Burst Mode */
+	XMR_FS_CEX_ERR	= 1<<10, /* Bit 10:	Carrier Ext. Error */
+	XMR_FS_802_3	= 1<<9, /* Bit  9:	802.3 Frame */
+	XMR_FS_COL_ERR	= 1<<8, /* Bit  8:	Collision Error */
+	XMR_FS_CAR_ERR	= 1<<7, /* Bit  7:	Carrier Event Error */
+	XMR_FS_LEN_ERR	= 1<<6, /* Bit  6:	In-Range Length Error */
+	XMR_FS_FRA_ERR	= 1<<5, /* Bit  5:	Framing Error */
+	XMR_FS_RUNT	= 1<<4, /* Bit  4:	Runt Frame */
+	XMR_FS_LNG_ERR	= 1<<3, /* Bit  3:	Giant (Jumbo) Frame */
+	XMR_FS_FCS_ERR	= 1<<2, /* Bit  2:	Frame Check Sequ Err */
+	XMR_FS_ERR	= 1<<1, /* Bit  1:	Frame Error */
+	XMR_FS_MCTRL	= 1<<0, /* Bit  0:	MAC Control Packet */
+
+/*
+ * XMR_FS_ERR will be set if
+ *	XMR_FS_FCS_ERR, XMR_FS_LNG_ERR, XMR_FS_RUNT,
+ *	XMR_FS_FRA_ERR, XMR_FS_LEN_ERR, or XMR_FS_CEX_ERR
+ * is set. XMR_FS_LNG_ERR and XMR_FS_LEN_ERR will issue
+ * XMR_FS_ERR unless the corresponding bit in the Receive Command
+ * Register is set.
+ */
+};
+
+/*
+,* XMAC-PHY Registers, indirect addressed over the XMAC
+ */
+enum {
+	PHY_XMAC_CTRL		= 0x00,/* 16 bit r/w	PHY Control Register */
+	PHY_XMAC_STAT		= 0x01,/* 16 bit r/w	PHY Status Register */
+	PHY_XMAC_ID0		= 0x02,/* 16 bit r/o	PHY ID0 Register */
+	PHY_XMAC_ID1		= 0x03,/* 16 bit r/o	PHY ID1 Register */
+	PHY_XMAC_AUNE_ADV	= 0x04,/* 16 bit r/w	Auto-Neg. Advertisement */
+	PHY_XMAC_AUNE_LP	= 0x05,/* 16 bit r/o	Link Partner Abi Reg */
+	PHY_XMAC_AUNE_EXP	= 0x06,/* 16 bit r/o	Auto-Neg. Expansion Reg */
+	PHY_XMAC_NEPG	= 0x07,/* 16 bit r/w	Next Page Register */
+	PHY_XMAC_NEPG_LP	= 0x08,/* 16 bit r/o	Next Page Link Partner */
+
+	PHY_XMAC_EXT_STAT	= 0x0f,/* 16 bit r/o	Ext Status Register */
+	PHY_XMAC_RES_ABI	= 0x10,/* 16 bit r/o	PHY Resolved Ability */
+};
+/*
+ * Broadcom-PHY Registers, indirect addressed over XMAC
+ */
+enum {
+	PHY_BCOM_CTRL		= 0x00,/* 16 bit r/w	PHY Control Register */
+	PHY_BCOM_STAT		= 0x01,/* 16 bit r/o	PHY Status Register */
+	PHY_BCOM_ID0		= 0x02,/* 16 bit r/o	PHY ID0 Register */
+	PHY_BCOM_ID1		= 0x03,/* 16 bit r/o	PHY ID1 Register */
+	PHY_BCOM_AUNE_ADV	= 0x04,/* 16 bit r/w	Auto-Neg. Advertisement */
+	PHY_BCOM_AUNE_LP	= 0x05,/* 16 bit r/o	Link Part Ability Reg */
+	PHY_BCOM_AUNE_EXP	= 0x06,/* 16 bit r/o	Auto-Neg. Expansion Reg */
+	PHY_BCOM_NEPG		= 0x07,/* 16 bit r/w	Next Page Register */
+	PHY_BCOM_NEPG_LP	= 0x08,/* 16 bit r/o	Next Page Link Partner */
+	/* Broadcom-specific registers */
+	PHY_BCOM_1000T_CTRL	= 0x09,/* 16 bit r/w	1000Base-T Control Reg */
+	PHY_BCOM_1000T_STAT	= 0x0a,/* 16 bit r/o	1000Base-T Status Reg */
+	PHY_BCOM_EXT_STAT	= 0x0f,/* 16 bit r/o	Extended Status Reg */
+	PHY_BCOM_P_EXT_CTRL	= 0x10,/* 16 bit r/w	PHY Extended Ctrl Reg */
+	PHY_BCOM_P_EXT_STAT	= 0x11,/* 16 bit r/o	PHY Extended Stat Reg */
+	PHY_BCOM_RE_CTR		= 0x12,/* 16 bit r/w	Receive Error Counter */
+	PHY_BCOM_FC_CTR		= 0x13,/* 16 bit r/w	False Carrier Sense Cnt */
+	PHY_BCOM_RNO_CTR	= 0x14,/* 16 bit r/w	Receiver NOT_OK Cnt */
+
+	PHY_BCOM_AUX_CTRL	= 0x18,/* 16 bit r/w	Auxiliary Control Reg */
+	PHY_BCOM_AUX_STAT	= 0x19,/* 16 bit r/o	Auxiliary Stat Summary */
+	PHY_BCOM_INT_STAT	= 0x1a,/* 16 bit r/o	Interrupt Status Reg */
+	PHY_BCOM_INT_MASK	= 0x1b,/* 16 bit r/w	Interrupt Mask Reg */
+};
+
+/*
+ * Marvel-PHY Registers, indirect addressed over GMAC
+ */
+enum {
+	PHY_MARV_CTRL		= 0x00,/* 16 bit r/w	PHY Control Register */
+	PHY_MARV_STAT		= 0x01,/* 16 bit r/o	PHY Status Register */
+	PHY_MARV_ID0		= 0x02,/* 16 bit r/o	PHY ID0 Register */
+	PHY_MARV_ID1		= 0x03,/* 16 bit r/o	PHY ID1 Register */
+	PHY_MARV_AUNE_ADV	= 0x04,/* 16 bit r/w	Auto-Neg. Advertisement */
+	PHY_MARV_AUNE_LP	= 0x05,/* 16 bit r/o	Link Part Ability Reg */
+	PHY_MARV_AUNE_EXP	= 0x06,/* 16 bit r/o	Auto-Neg. Expansion Reg */
+	PHY_MARV_NEPG		= 0x07,/* 16 bit r/w	Next Page Register */
+	PHY_MARV_NEPG_LP	= 0x08,/* 16 bit r/o	Next Page Link Partner */
+	/* Marvel-specific registers */
+	PHY_MARV_1000T_CTRL	= 0x09,/* 16 bit r/w	1000Base-T Control Reg */
+	PHY_MARV_1000T_STAT	= 0x0a,/* 16 bit r/o	1000Base-T Status Reg */
+	PHY_MARV_EXT_STAT	= 0x0f,/* 16 bit r/o	Extended Status Reg */
+	PHY_MARV_PHY_CTRL	= 0x10,/* 16 bit r/w	PHY Specific Ctrl Reg */
+	PHY_MARV_PHY_STAT	= 0x11,/* 16 bit r/o	PHY Specific Stat Reg */
+	PHY_MARV_INT_MASK	= 0x12,/* 16 bit r/w	Interrupt Mask Reg */
+	PHY_MARV_INT_STAT	= 0x13,/* 16 bit r/o	Interrupt Status Reg */
+	PHY_MARV_EXT_CTRL	= 0x14,/* 16 bit r/w	Ext. PHY Specific Ctrl */
+	PHY_MARV_RXE_CNT	= 0x15,/* 16 bit r/w	Receive Error Counter */
+	PHY_MARV_EXT_ADR	= 0x16,/* 16 bit r/w	Ext. Ad. for Cable Diag. */
+	PHY_MARV_PORT_IRQ	= 0x17,/* 16 bit r/o	Port 0 IRQ (88E1111 only) */
+	PHY_MARV_LED_CTRL	= 0x18,/* 16 bit r/w	LED Control Reg */
+	PHY_MARV_LED_OVER	= 0x19,/* 16 bit r/w	Manual LED Override Reg */
+	PHY_MARV_EXT_CTRL_2	= 0x1a,/* 16 bit r/w	Ext. PHY Specific Ctrl 2 */
+	PHY_MARV_EXT_P_STAT	= 0x1b,/* 16 bit r/w	Ext. PHY Spec. Stat Reg */
+	PHY_MARV_CABLE_DIAG	= 0x1c,/* 16 bit r/o	Cable Diagnostic Reg */
+	PHY_MARV_PAGE_ADDR	= 0x1d,/* 16 bit r/w	Extended Page Address Reg */
+	PHY_MARV_PAGE_DATA	= 0x1e,/* 16 bit r/w	Extended Page Data Reg */
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+	PHY_MARV_FE_LED_PAR	= 0x16,/* 16 bit r/w	LED Parallel Select Reg. */
+	PHY_MARV_FE_LED_SER	= 0x17,/* 16 bit r/w	LED Stream Select S. LED */
+	PHY_MARV_FE_VCT_TX	= 0x1a,/* 16 bit r/w	VCT Reg. for TXP/N Pins */
+	PHY_MARV_FE_VCT_RX	= 0x1b,/* 16 bit r/o	VCT Reg. for RXP/N Pins */
+	PHY_MARV_FE_SPEC_2	= 0x1c,/* 16 bit r/w	Specific Control Reg. 2 */
+};
+
+/* Level One-PHY Registers, indirect addressed over XMAC */
+enum {
+	PHY_LONE_CTRL		= 0x00,/* 16 bit r/w	PHY Control Register */
+	PHY_LONE_STAT		= 0x01,/* 16 bit r/o	PHY Status Register */
+	PHY_LONE_ID0		= 0x02,/* 16 bit r/o	PHY ID0 Register */
+	PHY_LONE_ID1		= 0x03,/* 16 bit r/o	PHY ID1 Register */
+	PHY_LONE_AUNE_ADV	= 0x04,/* 16 bit r/w	Auto-Neg. Advertisement */
+	PHY_LONE_AUNE_LP	= 0x05,/* 16 bit r/o	Link Part Ability Reg */
+	PHY_LONE_AUNE_EXP	= 0x06,/* 16 bit r/o	Auto-Neg. Expansion Reg */
+	PHY_LONE_NEPG		= 0x07,/* 16 bit r/w	Next Page Register */
+	PHY_LONE_NEPG_LP	= 0x08,/* 16 bit r/o	Next Page Link Partner */
+	/* Level One-specific registers */
+	PHY_LONE_1000T_CTRL	= 0x09,/* 16 bit r/w	1000Base-T Control Reg */
+	PHY_LONE_1000T_STAT	= 0x0a,/* 16 bit r/o	1000Base-T Status Reg */
+	PHY_LONE_EXT_STAT	= 0x0f,/* 16 bit r/o	Extended Status Reg */
+	PHY_LONE_PORT_CFG	= 0x10,/* 16 bit r/w	Port Configuration Reg*/
+	PHY_LONE_Q_STAT		= 0x11,/* 16 bit r/o	Quick Status Reg */
+	PHY_LONE_INT_ENAB	= 0x12,/* 16 bit r/w	Interrupt Enable Reg */
+	PHY_LONE_INT_STAT	= 0x13,/* 16 bit r/o	Interrupt Status Reg */
+	PHY_LONE_LED_CFG	= 0x14,/* 16 bit r/w	LED Configuration Reg */
+	PHY_LONE_PORT_CTRL	= 0x15,/* 16 bit r/w	Port Control Reg */
+	PHY_LONE_CIM		= 0x16,/* 16 bit r/o	CIM Reg */
+};
+
+/* National-PHY Registers, indirect addressed over XMAC */
+enum {
+	PHY_NAT_CTRL		= 0x00,/* 16 bit r/w	PHY Control Register */
+	PHY_NAT_STAT		= 0x01,/* 16 bit r/w	PHY Status Register */
+	PHY_NAT_ID0		= 0x02,/* 16 bit r/o	PHY ID0 Register */
+	PHY_NAT_ID1		= 0x03,/* 16 bit r/o	PHY ID1 Register */
+	PHY_NAT_AUNE_ADV	= 0x04,/* 16 bit r/w	Auto-Neg. Advertisement */
+	PHY_NAT_AUNE_LP		= 0x05,/* 16 bit r/o	Link Partner Ability Reg */
+	PHY_NAT_AUNE_EXP	= 0x06,/* 16 bit r/o	Auto-Neg. Expansion Reg */
+	PHY_NAT_NEPG		= 0x07,/* 16 bit r/w	Next Page Register */
+	PHY_NAT_NEPG_LP		= 0x08,/* 16 bit r/o	Next Page Link Partner Reg */
+	/* National-specific registers */
+	PHY_NAT_1000T_CTRL	= 0x09,/* 16 bit r/w	1000Base-T Control Reg */
+	PHY_NAT_1000T_STAT	= 0x0a,/* 16 bit r/o	1000Base-T Status Reg */
+	PHY_NAT_EXT_STAT	= 0x0f,/* 16 bit r/o	Extended Status Register */
+	PHY_NAT_EXT_CTRL1	= 0x10,/* 16 bit r/o	Extended Control Reg1 */
+	PHY_NAT_Q_STAT1		= 0x11,/* 16 bit r/o	Quick Status Reg1 */
+	PHY_NAT_10B_OP		= 0x12,/* 16 bit r/o	10Base-T Operations Reg */
+	PHY_NAT_EXT_CTRL2	= 0x13,/* 16 bit r/o	Extended Control Reg1 */
+	PHY_NAT_Q_STAT2		= 0x14,/* 16 bit r/o	Quick Status Reg2 */
+
+	PHY_NAT_PHY_ADDR	= 0x19,/* 16 bit r/o	PHY Address Register */
+};
+
+enum {
+	PHY_CT_RESET	= 1<<15, /* Bit 15: (sc)	clear all PHY related regs */
+	PHY_CT_LOOP	= 1<<14, /* Bit 14:	enable Loopback over PHY */
+	PHY_CT_SPS_LSB	= 1<<13, /* Bit 13:	Speed select, lower bit */
+	PHY_CT_ANE	= 1<<12, /* Bit 12:	Auto-Negotiation Enabled */
+	PHY_CT_PDOWN	= 1<<11, /* Bit 11:	Power Down Mode */
+	PHY_CT_ISOL	= 1<<10, /* Bit 10:	Isolate Mode */
+	PHY_CT_RE_CFG	= 1<<9, /* Bit  9:	(sc) Restart Auto-Negotiation */
+	PHY_CT_DUP_MD	= 1<<8, /* Bit  8:	Duplex Mode */
+	PHY_CT_COL_TST	= 1<<7, /* Bit  7:	Collision Test enabled */
+	PHY_CT_SPS_MSB	= 1<<6, /* Bit  6:	Speed select, upper bit */
+};
+
+enum {
+	PHY_CT_SP1000	= PHY_CT_SPS_MSB, /* enable speed of 1000 Mbps */
+	PHY_CT_SP100	= PHY_CT_SPS_LSB, /* enable speed of  100 Mbps */
+	PHY_CT_SP10	= 0,		  /* enable speed of   10 Mbps */
+};
+
+enum {
+	PHY_ST_EXT_ST	= 1<<8, /* Bit  8:	Extended Status Present */
+
+	PHY_ST_PRE_SUP	= 1<<6, /* Bit  6:	Preamble Suppression */
+	PHY_ST_AN_OVER	= 1<<5, /* Bit  5:	Auto-Negotiation Over */
+	PHY_ST_REM_FLT	= 1<<4, /* Bit  4:	Remote Fault Condition Occured */
+	PHY_ST_AN_CAP	= 1<<3, /* Bit  3:	Auto-Negotiation Capability */
+	PHY_ST_LSYNC	= 1<<2, /* Bit  2:	Link Synchronized */
+	PHY_ST_JAB_DET	= 1<<1, /* Bit  1:	Jabber Detected */
+	PHY_ST_EXT_REG	= 1<<0, /* Bit  0:	Extended Register available */
+};
+
+enum {
+	PHY_I1_OUI_MSK	= 0x3f<<10, /* Bit 15..10:	Organization Unique ID */
+	PHY_I1_MOD_NUM	= 0x3f<<4, /* Bit  9.. 4:	Model Number */
+	PHY_I1_REV_MSK	= 0xf, /* Bit  3.. 0:	Revision Number */
+};
+
+/* different Broadcom PHY Ids */
+enum {
+	PHY_BCOM_ID1_A1	= 0x6041,
+	PHY_BCOM_ID1_B2 = 0x6043,
+	PHY_BCOM_ID1_C0	= 0x6044,
+	PHY_BCOM_ID1_C5	= 0x6047,
+};
+
+/* different Marvell PHY Ids */
+enum {
+	PHY_MARV_ID0_VAL= 0x0141, /* Marvell Unique Identifier */
+	PHY_MARV_ID1_B0	= 0x0C23, /* Yukon (PHY 88E1011) */
+	PHY_MARV_ID1_B2	= 0x0C25, /* Yukon-Plus (PHY 88E1011) */
+	PHY_MARV_ID1_C2	= 0x0CC2, /* Yukon-EC (PHY 88E1111) */
+	PHY_MARV_ID1_Y2	= 0x0C91, /* Yukon-2 (PHY 88E1112) */
+};
+
+enum {
+	PHY_AN_NXT_PG	= 1<<15, /* Bit 15:	Request Next Page */
+	PHY_X_AN_ACK	= 1<<14, /* Bit 14:	(ro) Acknowledge Received */
+	PHY_X_AN_RFB	= 3<<12,/* Bit 13..12:	Remote Fault Bits */
+
+	PHY_X_AN_PAUSE	= 3<<7,/* Bit  8.. 7:	Pause Bits */
+	PHY_X_AN_HD	= 1<<6, /* Bit  6:	Half Duplex */
+	PHY_X_AN_FD	= 1<<5, /* Bit  5:	Full Duplex */
+};
+
+enum {
+	PHY_B_AN_RF	= 1<<13, /* Bit 13:	Remote Fault */
+
+	PHY_B_AN_ASP	= 1<<11, /* Bit 11:	Asymmetric Pause */
+	PHY_B_AN_PC	= 1<<10, /* Bit 10:	Pause Capable */
+	PHY_B_AN_SEL	= 0x1f, /* Bit 4..0:	Selector Field, 00001=Ethernet*/
+};
+
+enum {
+	PHY_L_AN_RF	= 1<<13, /* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
+	PHY_L_AN_ASP	= 1<<11, /* Bit 11:	Asymmetric Pause */
+	PHY_L_AN_PC	= 1<<10, /* Bit 10:	Pause Capable */
+
+	PHY_L_AN_SEL	= 0x1f, /* Bit 4..0:	Selector Field, 00001=Ethernet*/
+};
+
+/*  PHY_NAT_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement */
+/*  PHY_NAT_AUNE_LP	16 bit r/o	Link Partner Ability Reg *****/
+/*  PHY_AN_NXT_PG	(see XMAC) Bit 15:	Request Next Page */
+enum {
+	PHY_N_AN_RF	= 1<<13, /* Bit 13:	Remote Fault */
+
+	PHY_N_AN_100F	= 1<<11, /* Bit 11:	100Base-T2 FD Support */
+	PHY_N_AN_100H	= 1<<10, /* Bit 10:	100Base-T2 HD Support */
+
+	PHY_N_AN_SEL	= 0x1f, /* Bit 4..0:	Selector Field, 00001=Ethernet*/
+};
+
+/* field type definition for PHY_x_AN_SEL */
+enum {
+	PHY_SEL_TYPE	 = 1,	/* 00001 = Ethernet */
+};
+
+enum {
+	PHY_ANE_LP_NP	= 1<<3, /* Bit  3:	Link Partner can Next Page */
+	PHY_ANE_LOC_NP	= 1<<2, /* Bit  2:	Local PHY can Next Page */
+	PHY_ANE_RX_PG	= 1<<1, /* Bit  1:	Page Received */
+};
+
+enum {
+	PHY_ANE_PAR_DF	= 1<<4, /* Bit  4:	Parallel Detection Fault */
+
+	PHY_ANE_LP_CAP	= 1<<0, /* Bit  0:	Link Partner Auto-Neg. Cap. */ 	
+};
+
+enum {
+	PHY_NP_MORE	= 1<<15, /* Bit 15:	More, Next Pages to follow */
+	PHY_NP_ACK1	= 1<<14, /* Bit 14: (ro)	Ack1, for receiving a message */
+	PHY_NP_MSG_VAL	= 1<<13, /* Bit 13:	Message Page valid */
+	PHY_NP_ACK2	= 1<<12, /* Bit 12:	Ack2, comply with msg content */
+	PHY_NP_TOG	= 1<<11, /* Bit 11:	Toggle Bit, ensure sync */
+	PHY_NP_MSG	= 0x07ff, /* Bit 10..0:	Message from/to Link Partner */
+};
+
+enum {
+	PHY_X_EX_FD	= 1<<15, /* Bit 15:	Device Supports Full Duplex */
+	PHY_X_EX_HD	= 1<<14, /* Bit 14:	Device Supports Half Duplex */
+};
+
+enum {
+	PHY_X_RS_PAUSE	= 3<<7,/* Bit  8..7:	selected Pause Mode */
+	PHY_X_RS_HD	= 1<<6, /* Bit  6:	Half Duplex Mode selected */
+	PHY_X_RS_FD	= 1<<5, /* Bit  5:	Full Duplex Mode selected */
+	PHY_X_RS_ABLMIS	= 1<<4, /* Bit  4:	duplex or pause cap mismatch */
+	PHY_X_RS_PAUMIS	= 1<<3, /* Bit  3:	pause capability mismatch */
+};
+
+/** Remote Fault Bits (PHY_X_AN_RFB) encoding  */
+enum {
+	X_RFB_OK	= 0<<12,/* Bit 13..12	No errors, Link OK */
+	X_RFB_LF	= 1<<12, /* Bit 13..12	Link Failure */
+	X_RFB_OFF	= 2<<12,/* Bit 13..12	Offline */
+	X_RFB_AN_ERR	= 3<<12,/* Bit 13..12	Auto-Negotiation Error */
+};
+
+/* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */
+enum {
+	PHY_X_P_NO_PAUSE	= 0<<7,/* Bit  8..7:	no Pause Mode */
+	PHY_X_P_SYM_MD	= 1<<7, /* Bit  8..7:	symmetric Pause Mode */
+	PHY_X_P_ASYM_MD	= 2<<7,/* Bit  8..7:	asymmetric Pause Mode */
+	PHY_X_P_BOTH_MD	= 3<<7,/* Bit  8..7:	both Pause Mode */
+};
+
+
+/* Broadcom-Specific */
+/*****  PHY_BCOM_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+enum {
+	PHY_B_1000C_TEST	= 7<<13,/* Bit 15..13:	Test Modes */
+	PHY_B_1000C_MSE	= 1<<12, /* Bit 12:	Master/Slave Enable */
+	PHY_B_1000C_MSC	= 1<<11, /* Bit 11:	M/S Configuration */
+	PHY_B_1000C_RD	= 1<<10, /* Bit 10:	Repeater/DTE */
+	PHY_B_1000C_AFD	= 1<<9, /* Bit  9:	Advertise Full Duplex */
+	PHY_B_1000C_AHD	= 1<<8, /* Bit  8:	Advertise Half Duplex */
+};
+
+/*****  PHY_BCOM_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+/*****  PHY_MARV_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+enum {
+	PHY_B_1000S_MSF	= 1<<15, /* Bit 15:	Master/Slave Fault */
+	PHY_B_1000S_MSR	= 1<<14, /* Bit 14:	Master/Slave Result */
+	PHY_B_1000S_LRS	= 1<<13, /* Bit 13:	Local Receiver Status */
+	PHY_B_1000S_RRS	= 1<<12, /* Bit 12:	Remote Receiver Status */
+	PHY_B_1000S_LP_FD	= 1<<11, /* Bit 11:	Link Partner can FD */
+	PHY_B_1000S_LP_HD	= 1<<10, /* Bit 10:	Link Partner can HD */
+									/* Bit  9..8:	reserved */
+	PHY_B_1000S_IEC	= 0xff, /* Bit  7..0:	Idle Error Count */
+};
+
+/*****  PHY_BCOM_EXT_STAT	16 bit r/o	Extended Status Register *****/
+enum {
+	PHY_B_ES_X_FD_CAP	= 1<<15, /* Bit 15:	1000Base-X FD capable */
+	PHY_B_ES_X_HD_CAP	= 1<<14, /* Bit 14:	1000Base-X HD capable */
+	PHY_B_ES_T_FD_CAP	= 1<<13, /* Bit 13:	1000Base-T FD capable */
+	PHY_B_ES_T_HD_CAP	= 1<<12, /* Bit 12:	1000Base-T HD capable */
+};
+
+/*****  PHY_BCOM_P_EXT_CTRL	16 bit r/w	PHY Extended Control Reg *****/
+enum {
+	PHY_B_PEC_MAC_PHY	= 1<<15, /* Bit 15:	10BIT/GMI-Interface */
+	PHY_B_PEC_DIS_CROSS	= 1<<14, /* Bit 14:	Disable MDI Crossover */
+	PHY_B_PEC_TX_DIS	= 1<<13, /* Bit 13:	Tx output Disabled */
+	PHY_B_PEC_INT_DIS	= 1<<12, /* Bit 12:	Interrupts Disabled */
+	PHY_B_PEC_F_INT	= 1<<11, /* Bit 11:	Force Interrupt */
+	PHY_B_PEC_BY_45	= 1<<10, /* Bit 10:	Bypass 4B5B-Decoder */
+	PHY_B_PEC_BY_SCR	= 1<<9, /* Bit  9:	Bypass Scrambler */
+	PHY_B_PEC_BY_MLT3	= 1<<8, /* Bit  8:	Bypass MLT3 Encoder */
+	PHY_B_PEC_BY_RXA	= 1<<7, /* Bit  7:	Bypass Rx Alignm. */
+	PHY_B_PEC_RES_SCR	= 1<<6, /* Bit  6:	Reset Scrambler */
+	PHY_B_PEC_EN_LTR	= 1<<5, /* Bit  5:	Ena LED Traffic Mode */
+	PHY_B_PEC_LED_ON	= 1<<4, /* Bit  4:	Force LED's on */
+	PHY_B_PEC_LED_OFF	= 1<<3, /* Bit  3:	Force LED's off */
+	PHY_B_PEC_EX_IPG	= 1<<2, /* Bit  2:	Extend Tx IPG Mode */
+	PHY_B_PEC_3_LED	= 1<<1, /* Bit  1:	Three Link LED mode */
+	PHY_B_PEC_HIGH_LA	= 1<<0, /* Bit  0:	GMII FIFO Elasticy */
+};
+
+/*****  PHY_BCOM_P_EXT_STAT	16 bit r/o	PHY Extended Status Reg *****/
+enum {
+	PHY_B_PES_CROSS_STAT	= 1<<13, /* Bit 13:	MDI Crossover Status */
+	PHY_B_PES_INT_STAT	= 1<<12, /* Bit 12:	Interrupt Status */
+	PHY_B_PES_RRS	= 1<<11, /* Bit 11:	Remote Receiver Stat. */
+	PHY_B_PES_LRS	= 1<<10, /* Bit 10:	Local Receiver Stat. */
+	PHY_B_PES_LOCKED	= 1<<9, /* Bit  9:	Locked */
+	PHY_B_PES_LS	= 1<<8, /* Bit  8:	Link Status */
+	PHY_B_PES_RF	= 1<<7, /* Bit  7:	Remote Fault */
+	PHY_B_PES_CE_ER	= 1<<6, /* Bit  6:	Carrier Ext Error */
+	PHY_B_PES_BAD_SSD	= 1<<5, /* Bit  5:	Bad SSD */
+	PHY_B_PES_BAD_ESD	= 1<<4, /* Bit  4:	Bad ESD */
+	PHY_B_PES_RX_ER	= 1<<3, /* Bit  3:	Receive Error */
+	PHY_B_PES_TX_ER	= 1<<2, /* Bit  2:	Transmit Error */
+	PHY_B_PES_LOCK_ER	= 1<<1, /* Bit  1:	Lock Error */
+	PHY_B_PES_MLT3_ER	= 1<<0, /* Bit  0:	MLT3 code Error */
+};
+
+/*****  PHY_BCOM_FC_CTR		16 bit r/w	False Carrier Counter *****/
+enum {
+	PHY_B_FC_CTR	= 0xff, /* Bit  7..0:	False Carrier Counter */
+
+/*****  PHY_BCOM_RNO_CTR	16 bit r/w	Receive NOT_OK Counter *****/
+	PHY_B_RC_LOC_MSK	= 0xff00, /* Bit 15..8:	Local Rx NOT_OK cnt */
+	PHY_B_RC_REM_MSK	= 0x00ff, /* Bit  7..0:	Remote Rx NOT_OK cnt */
+
+/*****  PHY_BCOM_AUX_CTRL	16 bit r/w	Auxiliary Control Reg *****/
+	PHY_B_AC_L_SQE		= 1<<15, /* Bit 15:	Low Squelch */
+	PHY_B_AC_LONG_PACK	= 1<<14, /* Bit 14:	Rx Long Packets */
+	PHY_B_AC_ER_CTRL	= 3<<12,/* Bit 13..12:	Edgerate Control */
+									/* Bit 11:	reserved */
+	PHY_B_AC_TX_TST	= 1<<10, /* Bit 10:	Tx test bit, always 1 */
+									/* Bit  9.. 8:	reserved */
+	PHY_B_AC_DIS_PRF	= 1<<7, /* Bit  7:	dis part resp filter */
+									/* Bit  6:	reserved */
+	PHY_B_AC_DIS_PM	= 1<<5, /* Bit  5:	dis power management */
+									/* Bit  4:	reserved */
+	PHY_B_AC_DIAG	= 1<<3, /* Bit  3:	Diagnostic Mode */
+};
+
+/*****  PHY_BCOM_AUX_STAT	16 bit r/o	Auxiliary Status Reg *****/
+enum {
+	PHY_B_AS_AN_C	= 1<<15, /* Bit 15:	AutoNeg complete */
+	PHY_B_AS_AN_CA	= 1<<14, /* Bit 14:	AN Complete Ack */
+	PHY_B_AS_ANACK_D	= 1<<13, /* Bit 13:	AN Ack Detect */
+	PHY_B_AS_ANAB_D	= 1<<12, /* Bit 12:	AN Ability Detect */
+	PHY_B_AS_NPW	= 1<<11, /* Bit 11:	AN Next Page Wait */
+	PHY_B_AS_AN_RES_MSK	= 7<<8,/* Bit 10..8:	AN HDC */
+	PHY_B_AS_PDF	= 1<<7, /* Bit  7:	Parallel Detect. Fault */
+	PHY_B_AS_RF	= 1<<6, /* Bit  6:	Remote Fault */
+	PHY_B_AS_ANP_R	= 1<<5, /* Bit  5:	AN Page Received */
+	PHY_B_AS_LP_ANAB	= 1<<4, /* Bit  4:	LP AN Ability */
+	PHY_B_AS_LP_NPAB	= 1<<3, /* Bit  3:	LP Next Page Ability */
+	PHY_B_AS_LS	= 1<<2, /* Bit  2:	Link Status */
+	PHY_B_AS_PRR	= 1<<1, /* Bit  1:	Pause Resolution-Rx */
+	PHY_B_AS_PRT	= 1<<0, /* Bit  0:	Pause Resolution-Tx */
+};
+#define PHY_B_AS_PAUSE_MSK	(PHY_B_AS_PRR | PHY_B_AS_PRT)
+
+/*****  PHY_BCOM_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+/*****  PHY_BCOM_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
+enum {
+	PHY_B_IS_PSE	= 1<<14, /* Bit 14:	Pair Swap Error */
+	PHY_B_IS_MDXI_SC	= 1<<13, /* Bit 13:	MDIX Status Change */
+	PHY_B_IS_HCT	= 1<<12, /* Bit 12:	counter above 32k */
+	PHY_B_IS_LCT	= 1<<11, /* Bit 11:	counter above 128 */
+	PHY_B_IS_AN_PR	= 1<<10, /* Bit 10:	Page Received */
+	PHY_B_IS_NO_HDCL	= 1<<9, /* Bit  9:	No HCD Link */
+	PHY_B_IS_NO_HDC	= 1<<8, /* Bit  8:	No HCD */
+	PHY_B_IS_NEG_USHDC	= 1<<7, /* Bit  7:	Negotiated Unsup. HCD */
+	PHY_B_IS_SCR_S_ER	= 1<<6, /* Bit  6:	Scrambler Sync Error */
+	PHY_B_IS_RRS_CHANGE	= 1<<5, /* Bit  5:	Remote Rx Stat Change */
+	PHY_B_IS_LRS_CHANGE	= 1<<4, /* Bit  4:	Local Rx Stat Change */
+	PHY_B_IS_DUP_CHANGE	= 1<<3, /* Bit  3:	Duplex Mode Change */
+	PHY_B_IS_LSP_CHANGE	= 1<<2, /* Bit  2:	Link Speed Change */
+	PHY_B_IS_LST_CHANGE	= 1<<1, /* Bit  1:	Link Status Changed */
+	PHY_B_IS_CRC_ER	= 1<<0, /* Bit  0:	CRC Error */
+};
+#define PHY_B_DEF_MSK	(~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+
+/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
+enum {
+	PHY_B_P_NO_PAUSE	= 0<<10,/* Bit 11..10:	no Pause Mode */
+	PHY_B_P_SYM_MD	= 1<<10, /* Bit 11..10:	symmetric Pause Mode */
+	PHY_B_P_ASYM_MD	= 2<<10,/* Bit 11..10:	asymmetric Pause Mode */
+	PHY_B_P_BOTH_MD	= 3<<10,/* Bit 11..10:	both Pause Mode */
+};
+/*
+ * Resolved Duplex mode and Capabilities (Aux Status Summary Reg)
+ */
+enum {
+	PHY_B_RES_1000FD	= 7<<8,/* Bit 10..8:	1000Base-T Full Dup. */
+	PHY_B_RES_1000HD	= 6<<8,/* Bit 10..8:	1000Base-T Half Dup. */
+};
+
+/*
+ * Level One-Specific
+ */
+/*****  PHY_LONE_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+enum {
+	PHY_L_1000C_TEST	= 7<<13,/* Bit 15..13:	Test Modes */
+	PHY_L_1000C_MSE	= 1<<12, /* Bit 12:	Master/Slave Enable */
+	PHY_L_1000C_MSC	= 1<<11, /* Bit 11:	M/S Configuration */
+	PHY_L_1000C_RD	= 1<<10, /* Bit 10:	Repeater/DTE */
+	PHY_L_1000C_AFD	= 1<<9, /* Bit  9:	Advertise Full Duplex */
+	PHY_L_1000C_AHD	= 1<<8, /* Bit  8:	Advertise Half Duplex */
+};
+
+/*****  PHY_LONE_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+enum {
+	PHY_L_1000S_MSF	= 1<<15, /* Bit 15:	Master/Slave Fault */
+	PHY_L_1000S_MSR	= 1<<14, /* Bit 14:	Master/Slave Result */
+	PHY_L_1000S_LRS	= 1<<13, /* Bit 13:	Local Receiver Status */
+	PHY_L_1000S_RRS	= 1<<12, /* Bit 12:	Remote Receiver Status */
+	PHY_L_1000S_LP_FD = 1<<11, /* Bit 11:	Link Partner can FD */
+	PHY_L_1000S_LP_HD = 1<<10, /* Bit 10:	Link Partner can HD */
+
+	PHY_L_1000S_IEC	 = 0xff, /* Bit  7..0:	Idle Error Count */
+
+/*****  PHY_LONE_EXT_STAT	16 bit r/o	Extended Status Register *****/
+	PHY_L_ES_X_FD_CAP = 1<<15, /* Bit 15:	1000Base-X FD capable */
+	PHY_L_ES_X_HD_CAP = 1<<14, /* Bit 14:	1000Base-X HD capable */
+	PHY_L_ES_T_FD_CAP = 1<<13, /* Bit 13:	1000Base-T FD capable */
+	PHY_L_ES_T_HD_CAP = 1<<12, /* Bit 12:	1000Base-T HD capable */
+};
+
+/*****  PHY_LONE_PORT_CFG	16 bit r/w	Port Configuration Reg *****/
+enum {
+	PHY_L_PC_REP_MODE	= 1<<15, /* Bit 15:	Repeater Mode */
+
+	PHY_L_PC_TX_DIS	= 1<<13, /* Bit 13:	Tx output Disabled */
+	PHY_L_PC_BY_SCR	= 1<<12, /* Bit 12:	Bypass Scrambler */
+	PHY_L_PC_BY_45	= 1<<11, /* Bit 11:	Bypass 4B5B-Decoder */
+	PHY_L_PC_JAB_DIS	= 1<<10, /* Bit 10:	Jabber Disabled */
+	PHY_L_PC_SQE	= 1<<9, /* Bit  9:	Enable Heartbeat */
+	PHY_L_PC_TP_LOOP	= 1<<8, /* Bit  8:	TP Loopback */
+	PHY_L_PC_SSS	= 1<<7, /* Bit  7:	Smart Speed Selection */
+	PHY_L_PC_FIFO_SIZE	= 1<<6, /* Bit  6:	FIFO Size */
+	PHY_L_PC_PRE_EN	= 1<<5, /* Bit  5:	Preamble Enable */
+	PHY_L_PC_CIM	= 1<<4, /* Bit  4:	Carrier Integrity Mon */
+	PHY_L_PC_10_SER	= 1<<3, /* Bit  3:	Use Serial Output */
+	PHY_L_PC_ANISOL	= 1<<2, /* Bit  2:	Unisolate Port */
+	PHY_L_PC_TEN_BIT	= 1<<1, /* Bit  1:	10bit iface mode on */
+	PHY_L_PC_ALTCLOCK	= 1<<0, /* Bit  0: (ro)	ALTCLOCK Mode on */
+};
+
+/*****  PHY_LONE_Q_STAT		16 bit r/o	Quick Status Reg *****/
+enum {
+	PHY_L_QS_D_RATE	= 3<<14,/* Bit 15..14:	Data Rate */
+	PHY_L_QS_TX_STAT	= 1<<13, /* Bit 13:	Transmitting */
+	PHY_L_QS_RX_STAT	= 1<<12, /* Bit 12:	Receiving */
+	PHY_L_QS_COL_STAT	= 1<<11, /* Bit 11:	Collision */
+	PHY_L_QS_L_STAT	= 1<<10, /* Bit 10:	Link is up */
+	PHY_L_QS_DUP_MOD	= 1<<9, /* Bit  9:	Full/Half Duplex */
+	PHY_L_QS_AN	= 1<<8, /* Bit  8:	AutoNeg is On */
+	PHY_L_QS_AN_C	= 1<<7, /* Bit  7:	AN is Complete */
+	PHY_L_QS_LLE	= 7<<4,/* Bit  6..4:	Line Length Estim. */
+	PHY_L_QS_PAUSE	= 1<<3, /* Bit  3:	LP advertised Pause */
+	PHY_L_QS_AS_PAUSE	= 1<<2, /* Bit  2:	LP adv. asym. Pause */
+	PHY_L_QS_ISOLATE	= 1<<1, /* Bit  1:	CIM Isolated */
+	PHY_L_QS_EVENT	= 1<<0, /* Bit  0:	Event has occurred */
+};
+
+/*****  PHY_LONE_INT_ENAB	16 bit r/w	Interrupt Enable Reg *****/
+/*****  PHY_LONE_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+enum {
+	PHY_L_IS_AN_F	= 1<<13, /* Bit 13:	Auto-Negotiation fault */
+	PHY_L_IS_CROSS	= 1<<11, /* Bit 11:	Crossover used */
+	PHY_L_IS_POL	= 1<<10, /* Bit 10:	Polarity correct. used */
+	PHY_L_IS_SS	= 1<<9, /* Bit  9:	Smart Speed Downgrade */
+	PHY_L_IS_CFULL	= 1<<8, /* Bit  8:	Counter Full */
+	PHY_L_IS_AN_C	= 1<<7, /* Bit  7:	AutoNeg Complete */
+	PHY_L_IS_SPEED	= 1<<6, /* Bit  6:	Speed Changed */
+	PHY_L_IS_DUP	= 1<<5, /* Bit  5:	Duplex Changed */
+	PHY_L_IS_LS	= 1<<4, /* Bit  4:	Link Status Changed */
+	PHY_L_IS_ISOL	= 1<<3, /* Bit  3:	Isolate Occured */
+	PHY_L_IS_MDINT	= 1<<2, /* Bit  2: (ro)	STAT: MII Int Pending */
+	PHY_L_IS_INTEN	= 1<<1, /* Bit  1:	ENAB: Enable IRQs */
+	PHY_L_IS_FORCE	= 1<<0, /* Bit  0:	ENAB: Force Interrupt */
+};
+
+/* int. mask */
+#define PHY_L_DEF_MSK	(PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN)
+
+/*****  PHY_LONE_LED_CFG	16 bit r/w	LED Configuration Reg *****/
+enum {
+	PHY_L_LC_LEDC	= 3<<14,/* Bit 15..14:	Col/Blink/On/Off */
+	PHY_L_LC_LEDR	= 3<<12,/* Bit 13..12:	Rx/Blink/On/Off */
+	PHY_L_LC_LEDT	= 3<<10,/* Bit 11..10:	Tx/Blink/On/Off */
+	PHY_L_LC_LEDG	= 3<<8,/* Bit  9..8:	Giga/Blink/On/Off */
+	PHY_L_LC_LEDS	= 3<<6,/* Bit  7..6:	10-100/Blink/On/Off */
+	PHY_L_LC_LEDL	= 3<<4,/* Bit  5..4:	Link/Blink/On/Off */
+	PHY_L_LC_LEDF	= 3<<2,/* Bit  3..2:	Duplex/Blink/On/Off */
+	PHY_L_LC_PSTRECH= 1<<1, /* Bit  1:	Strech LED Pulses */
+	PHY_L_LC_FREQ	= 1<<0, /* Bit  0:	30/100 ms */
+};
+
+/*****  PHY_LONE_PORT_CTRL	16 bit r/w	Port Control Reg *****/
+enum {
+	PHY_L_PC_TX_TCLK = 1<<15, /* Bit 15:	Enable TX_TCLK */
+	PHY_L_PC_ALT_NP	 = 1<<13, /* Bit 14:	Alternate Next Page */
+	PHY_L_PC_GMII_ALT= 1<<12, /* Bit 13:	Alternate GMII driver */
+	PHY_L_PC_TEN_CRS = 1<<10, /* Bit 10:	Extend CRS*/
+};
+
+/*****  PHY_LONE_CIM		16 bit r/o	CIM Reg *****/
+enum {
+	PHY_L_CIM_ISOL	    = 0xff<<8,/* Bit 15..8:	Isolate Count */
+	PHY_L_CIM_FALSE_CAR = 0xff,   /* Bit  7..0:	False Carrier Count */
+};
+
+/*
+ * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
+ */
+enum {
+	PHY_L_P_NO_PAUSE= 0<<10,/* Bit 11..10:	no Pause Mode */
+	PHY_L_P_SYM_MD	= 1<<10, /* Bit 11..10:	symmetric Pause Mode */
+	PHY_L_P_ASYM_MD	= 2<<10,/* Bit 11..10:	asymmetric Pause Mode */
+	PHY_L_P_BOTH_MD	= 3<<10,/* Bit 11..10:	both Pause Mode */
+};
+
+/*
+ * National-Specific
+ */
+/*****  PHY_NAT_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+enum {
+	PHY_N_1000C_TEST= 7<<13,/* Bit 15..13:	Test Modes */
+	PHY_N_1000C_MSE	= 1<<12, /* Bit 12:	Master/Slave Enable */
+	PHY_N_1000C_MSC	= 1<<11, /* Bit 11:	M/S Configuration */
+	PHY_N_1000C_RD	= 1<<10, /* Bit 10:	Repeater/DTE */
+	PHY_N_1000C_AFD	= 1<<9, /* Bit  9:	Advertise Full Duplex */
+	PHY_N_1000C_AHD	= 1<<8, /* Bit  8:	Advertise Half Duplex */
+	PHY_N_1000C_APC	= 1<<7, /* Bit  7:	Asymmetric Pause Cap. */};
+
+
+/*****  PHY_NAT_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+enum {
+	PHY_N_1000S_MSF	= 1<<15, /* Bit 15:	Master/Slave Fault */
+	PHY_N_1000S_MSR	= 1<<14, /* Bit 14:	Master/Slave Result */
+	PHY_N_1000S_LRS	= 1<<13, /* Bit 13:	Local Receiver Status */
+	PHY_N_1000S_RRS	= 1<<12, /* Bit 12:	Remote Receiver Status*/
+	PHY_N_1000S_LP_FD= 1<<11, /* Bit 11:	Link Partner can FD */
+	PHY_N_1000S_LP_HD= 1<<10, /* Bit 10:	Link Partner can HD */
+	PHY_N_1000C_LP_APC= 1<<9, /* Bit  9:	LP Asym. Pause Cap. */
+	PHY_N_1000S_IEC	= 0xff, /* Bit  7..0:	Idle Error Count */
+};
+
+/*****  PHY_NAT_EXT_STAT	16 bit r/o	Extended Status Register *****/
+enum {
+	PHY_N_ES_X_FD_CAP= 1<<15, /* Bit 15:	1000Base-X FD capable */
+	PHY_N_ES_X_HD_CAP= 1<<14, /* Bit 14:	1000Base-X HD capable */
+	PHY_N_ES_T_FD_CAP= 1<<13, /* Bit 13:	1000Base-T FD capable */
+	PHY_N_ES_T_HD_CAP= 1<<12, /* Bit 12:	1000Base-T HD capable */
+};
+
+/** Marvell-Specific */
+enum {
+	PHY_M_AN_NXT_PG	= 1<<15, /* Request Next Page */
+	PHY_M_AN_ACK	= 1<<14, /* (ro)	Acknowledge Received */
+	PHY_M_AN_RF	= 1<<13, /* Remote Fault */
+
+	PHY_M_AN_ASP	= 1<<11, /* Asymmetric Pause */
+	PHY_M_AN_PC	= 1<<10, /* MAC Pause implemented */
+	PHY_M_AN_100_T4	= 1<<9, /* Not cap. 100Base-T4 (always 0) */
+	PHY_M_AN_100_FD	= 1<<8, /* Advertise 100Base-TX Full Duplex */
+	PHY_M_AN_100_HD	= 1<<7, /* Advertise 100Base-TX Half Duplex */
+	PHY_M_AN_10_FD	= 1<<6, /* Advertise 10Base-TX Full Duplex */
+	PHY_M_AN_10_HD	= 1<<5, /* Advertise 10Base-TX Half Duplex */
+	PHY_M_AN_SEL_MSK =0x1f<<4,	/* Bit  4.. 0: Selector Field Mask */
+};
+
+/* special defines for FIBER (88E1011S only) */
+enum {
+	PHY_M_AN_ASP_X	= 1<<8, /* Asymmetric Pause */
+	PHY_M_AN_PC_X	= 1<<7, /* MAC Pause implemented */
+	PHY_M_AN_1000X_AHD	= 1<<6, /* Advertise 10000Base-X Half Duplex */
+	PHY_M_AN_1000X_AFD	= 1<<5, /* Advertise 10000Base-X Full Duplex */
+};
+
+/* Pause Bits (PHY_M_AN_ASP_X and PHY_M_AN_PC_X) encoding */
+enum {
+	PHY_M_P_NO_PAUSE_X	= 0<<7,/* Bit  8.. 7:	no Pause Mode */
+	PHY_M_P_SYM_MD_X	= 1<<7, /* Bit  8.. 7:	symmetric Pause Mode */
+	PHY_M_P_ASYM_MD_X	= 2<<7,/* Bit  8.. 7:	asymmetric Pause Mode */
+	PHY_M_P_BOTH_MD_X	= 3<<7,/* Bit  8.. 7:	both Pause Mode */
+};
+
+/*****  PHY_MARV_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+enum {
+	PHY_M_1000C_TEST	= 7<<13,/* Bit 15..13:	Test Modes */
+	PHY_M_1000C_MSE	= 1<<12, /* Manual Master/Slave Enable */
+	PHY_M_1000C_MSC	= 1<<11, /* M/S Configuration (1=Master) */
+	PHY_M_1000C_MPD	= 1<<10, /* Multi-Port Device */
+	PHY_M_1000C_AFD	= 1<<9, /* Advertise Full Duplex */
+	PHY_M_1000C_AHD	= 1<<8, /* Advertise Half Duplex */
+};
+
+/*****  PHY_MARV_PHY_CTRL	16 bit r/w	PHY Specific Ctrl Reg *****/
+enum {
+	PHY_M_PC_TX_FFD_MSK	= 3<<14,/* Bit 15..14: Tx FIFO Depth Mask */
+	PHY_M_PC_RX_FFD_MSK	= 3<<12,/* Bit 13..12: Rx FIFO Depth Mask */
+	PHY_M_PC_ASS_CRS_TX	= 1<<11, /* Assert CRS on Transmit */
+	PHY_M_PC_FL_GOOD	= 1<<10, /* Force Link Good */
+	PHY_M_PC_EN_DET_MSK	= 3<<8,/* Bit  9.. 8: Energy Detect Mask */
+	PHY_M_PC_ENA_EXT_D	= 1<<7, /* Enable Ext. Distance (10BT) */
+	PHY_M_PC_MDIX_MSK	= 3<<5,/* Bit  6.. 5: MDI/MDIX Config. Mask */
+	PHY_M_PC_DIS_125CLK	= 1<<4, /* Disable 125 CLK */
+	PHY_M_PC_MAC_POW_UP	= 1<<3, /* MAC Power up */
+	PHY_M_PC_SQE_T_ENA	= 1<<2, /* SQE Test Enabled */
+	PHY_M_PC_POL_R_DIS	= 1<<1, /* Polarity Reversal Disabled */
+	PHY_M_PC_DIS_JABBER	= 1<<0, /* Disable Jabber */
+};
+
+enum {
+	PHY_M_PC_EN_DET		= 2<<8,	/* Energy Detect (Mode 1) */
+	PHY_M_PC_EN_DET_PLUS	= 3<<8, /* Energy Detect Plus (Mode 2) */
+};
+
+#define PHY_M_PC_MDI_XMODE(x)	(((x)<<5) & PHY_M_PC_MDIX_MSK)	
+
+enum {
+	PHY_M_PC_MAN_MDI	= 0, /* 00 = Manual MDI configuration */
+	PHY_M_PC_MAN_MDIX	= 1, /* 01 = Manual MDIX configuration */
+	PHY_M_PC_ENA_AUTO	= 3, /* 11 = Enable Automatic Crossover */
+};
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+enum {
+	PHY_M_PC_ENA_DTE_DT	= 1<<15, /* Enable Data Terminal Equ. (DTE) Detect */
+	PHY_M_PC_ENA_ENE_DT	= 1<<14, /* Enable Energy Detect (sense & pulse) */
+	PHY_M_PC_DIS_NLP_CK	= 1<<13, /* Disable Normal Link Puls (NLP) Check */
+	PHY_M_PC_ENA_LIP_NP	= 1<<12, /* Enable Link Partner Next Page Reg. */
+	PHY_M_PC_DIS_NLP_GN	= 1<<11, /* Disable Normal Link Puls Generation */
+
+	PHY_M_PC_DIS_SCRAMB	= 1<<9, /* Disable Scrambler */
+	PHY_M_PC_DIS_FEFI	= 1<<8, /* Disable Far End Fault Indic. (FEFI) */
+
+	PHY_M_PC_SH_TP_SEL	= 1<<6, /* Shielded Twisted Pair Select */
+	PHY_M_PC_RX_FD_MSK	= 3<<2,/* Bit  3.. 2: Rx FIFO Depth Mask */
+};
+
+/*****  PHY_MARV_PHY_STAT	16 bit r/o	PHY Specific Status Reg *****/
+enum {
+	PHY_M_PS_SPEED_MSK	= 3<<14, /* Bit 15..14: Speed Mask */
+	PHY_M_PS_SPEED_1000	= 1<<15, /*		10 = 1000 Mbps */
+	PHY_M_PS_SPEED_100	= 1<<14, /*		01 =  100 Mbps */
+	PHY_M_PS_SPEED_10	= 0,	 /*		00 =   10 Mbps */
+	PHY_M_PS_FULL_DUP	= 1<<13, /* Full Duplex */
+	PHY_M_PS_PAGE_REC	= 1<<12, /* Page Received */
+	PHY_M_PS_SPDUP_RES	= 1<<11, /* Speed & Duplex Resolved */
+	PHY_M_PS_LINK_UP	= 1<<10, /* Link Up */
+	PHY_M_PS_CABLE_MSK	= 7<<7,  /* Bit  9.. 7: Cable Length Mask */
+	PHY_M_PS_MDI_X_STAT	= 1<<6,  /* MDI Crossover Stat (1=MDIX) */
+	PHY_M_PS_DOWNS_STAT	= 1<<5,  /* Downshift Status (1=downsh.) */
+	PHY_M_PS_ENDET_STAT	= 1<<4,  /* Energy Detect Status (1=act) */
+	PHY_M_PS_TX_P_EN	= 1<<3,  /* Tx Pause Enabled */
+	PHY_M_PS_RX_P_EN	= 1<<2,  /* Rx Pause Enabled */
+	PHY_M_PS_POL_REV	= 1<<1,  /* Polarity Reversed */
+	PHY_M_PS_JABBER		= 1<<0,  /* Jabber */
+};
+
+#define PHY_M_PS_PAUSE_MSK	(PHY_M_PS_TX_P_EN | PHY_M_PS_RX_P_EN)
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+enum {
+	PHY_M_PS_DTE_DETECT	= 1<<15, /* Data Terminal Equipment (DTE) Detected */
+	PHY_M_PS_RES_SPEED	= 1<<14, /* Resolved Speed (1=100 Mbps, 0=10 Mbps */
+};
+
+enum {
+	PHY_M_IS_AN_ERROR	= 1<<15, /* Auto-Negotiation Error */
+	PHY_M_IS_LSP_CHANGE	= 1<<14, /* Link Speed Changed */
+	PHY_M_IS_DUP_CHANGE	= 1<<13, /* Duplex Mode Changed */
+	PHY_M_IS_AN_PR		= 1<<12, /* Page Received */
+	PHY_M_IS_AN_COMPL	= 1<<11, /* Auto-Negotiation Completed */
+	PHY_M_IS_LST_CHANGE	= 1<<10, /* Link Status Changed */
+	PHY_M_IS_SYMB_ERROR	= 1<<9, /* Symbol Error */
+	PHY_M_IS_FALSE_CARR	= 1<<8, /* False Carrier */
+	PHY_M_IS_FIFO_ERROR	= 1<<7, /* FIFO Overflow/Underrun Error */
+	PHY_M_IS_MDI_CHANGE	= 1<<6, /* MDI Crossover Changed */
+	PHY_M_IS_DOWNSH_DET	= 1<<5, /* Downshift Detected */
+	PHY_M_IS_END_CHANGE	= 1<<4, /* Energy Detect Changed */
+
+	PHY_M_IS_DTE_CHANGE	= 1<<2, /* DTE Power Det. Status Changed */
+	PHY_M_IS_POL_CHANGE	= 1<<1, /* Polarity Changed */
+	PHY_M_IS_JABBER		= 1<<0, /* Jabber */
+};
+
+#define PHY_M_DEF_MSK	( PHY_M_IS_AN_ERROR | PHY_M_IS_LSP_CHANGE | \
+			  PHY_M_IS_LST_CHANGE | PHY_M_IS_FIFO_ERROR)
+
+/*****  PHY_MARV_EXT_CTRL	16 bit r/w	Ext. PHY Specific Ctrl *****/
+enum {
+	PHY_M_EC_ENA_BC_EXT = 1<<15, /* Enable Block Carr. Ext. (88E1111 only) */
+	PHY_M_EC_ENA_LIN_LB = 1<<14, /* Enable Line Loopback (88E1111 only) */
+
+	PHY_M_EC_DIS_LINK_P = 1<<12, /* Disable Link Pulses (88E1111 only) */
+	PHY_M_EC_M_DSC_MSK  = 3<<10, /* Bit 11..10:	Master Downshift Counter */
+					/* (88E1011 only) */
+	PHY_M_EC_S_DSC_MSK	= 3<<8,/* Bit  9.. 8:	Slave  Downshift Counter */
+				       /* (88E1011 only) */
+	PHY_M_EC_M_DSC_MSK2	= 7<<9,/* Bit 11.. 9:	Master Downshift Counter */
+					/* (88E1111 only) */
+	PHY_M_EC_DOWN_S_ENA	= 1<<8, /* Downshift Enable (88E1111 only) */
+					/* !!! Errata in spec. (1 = disable) */
+	PHY_M_EC_RX_TIM_CT	= 1<<7, /* RGMII Rx Timing Control*/
+	PHY_M_EC_MAC_S_MSK	= 7<<4,/* Bit  6.. 4:	Def. MAC interface speed */
+	PHY_M_EC_FIB_AN_ENA	= 1<<3, /* Fiber Auto-Neg. Enable (88E1011S only) */
+	PHY_M_EC_DTE_D_ENA	= 1<<2, /* DTE Detect Enable (88E1111 only) */
+	PHY_M_EC_TX_TIM_CT	= 1<<1, /* RGMII Tx Timing Control */
+	PHY_M_EC_TRANS_DIS	= 1<<0, /* Transmitter Disable (88E1111 only) */};
+
+#define PHY_M_EC_M_DSC(x)	((x)<<10) /* 00=1x; 01=2x; 10=3x; 11=4x */
+#define PHY_M_EC_S_DSC(x)	((x)<<8) /* 00=dis; 01=1x; 10=2x; 11=3x */
+#define PHY_M_EC_MAC_S(x)	((x)<<4) /* 01X=0; 110=2.5; 111=25 (MHz) */
+
+#define PHY_M_EC_M_DSC_2(x)	((x)<<9) /* 000=1x; 001=2x; 010=3x; 011=4x */
+											/* 100=5x; 101=6x; 110=7x; 111=8x */
+enum {
+	MAC_TX_CLK_0_MHZ	= 2,
+	MAC_TX_CLK_2_5_MHZ	= 6,
+	MAC_TX_CLK_25_MHZ 	= 7,
+};
+
+/*****  PHY_MARV_LED_CTRL	16 bit r/w	LED Control Reg *****/
+enum {
+	PHY_M_LEDC_DIS_LED	= 1<<15, /* Disable LED */
+	PHY_M_LEDC_PULS_MSK	= 7<<12,/* Bit 14..12: Pulse Stretch Mask */
+	PHY_M_LEDC_F_INT	= 1<<11, /* Force Interrupt */
+	PHY_M_LEDC_BL_R_MSK	= 7<<8,/* Bit 10.. 8: Blink Rate Mask */
+	PHY_M_LEDC_DP_C_LSB	= 1<<7, /* Duplex Control (LSB, 88E1111 only) */
+	PHY_M_LEDC_TX_C_LSB	= 1<<6, /* Tx Control (LSB, 88E1111 only) */
+	PHY_M_LEDC_LK_C_MSK	= 7<<3,/* Bit  5.. 3: Link Control Mask */
+					/* (88E1111 only) */
+};
+
+enum {
+	PHY_M_LEDC_LINK_MSK	= 3<<3,/* Bit  4.. 3: Link Control Mask */
+									/* (88E1011 only) */
+	PHY_M_LEDC_DP_CTRL	= 1<<2, /* Duplex Control */
+	PHY_M_LEDC_DP_C_MSB	= 1<<2, /* Duplex Control (MSB, 88E1111 only) */
+	PHY_M_LEDC_RX_CTRL	= 1<<1, /* Rx Activity / Link */
+	PHY_M_LEDC_TX_CTRL	= 1<<0, /* Tx Activity / Link */
+	PHY_M_LEDC_TX_C_MSB	= 1<<0, /* Tx Control (MSB, 88E1111 only) */
+};
+
+#define PHY_M_LED_PULS_DUR(x)	(	((x)<<12) & PHY_M_LEDC_PULS_MSK)
+
+enum {
+	PULS_NO_STR	= 0,/* no pulse stretching */
+	PULS_21MS	= 1,/* 21 ms to 42 ms */
+	PULS_42MS	= 2,/* 42 ms to 84 ms */
+	PULS_84MS	= 3,/* 84 ms to 170 ms */
+	PULS_170MS	= 4,/* 170 ms to 340 ms */
+	PULS_340MS	= 5,/* 340 ms to 670 ms */
+	PULS_670MS	= 6,/* 670 ms to 1.3 s */
+	PULS_1300MS	= 7,/* 1.3 s to 2.7 s */
+};
+
+#define PHY_M_LED_BLINK_RT(x)	(	((x)<<8) & PHY_M_LEDC_BL_R_MSK)
+
+enum {
+	BLINK_42MS	= 0,/* 42 ms */
+	BLINK_84MS	= 1,/* 84 ms */
+	BLINK_170MS	= 2,/* 170 ms */
+	BLINK_340MS	= 3,/* 340 ms */
+	BLINK_670MS	= 4,/* 670 ms */
+};
+
+/*****  PHY_MARV_LED_OVER	16 bit r/w	Manual LED Override Reg *****/
+#define PHY_M_LED_MO_SGMII(x)	((x)<<14) /* Bit 15..14:  SGMII AN Timer */
+										/* Bit 13..12:	reserved */
+#define PHY_M_LED_MO_DUP(x)	((x)<<10) /* Bit 11..10:  Duplex */
+#define PHY_M_LED_MO_10(x)	((x)<<8) /* Bit  9.. 8:  Link 10 */
+#define PHY_M_LED_MO_100(x)	((x)<<6) /* Bit  7.. 6:  Link 100 */
+#define PHY_M_LED_MO_1000(x)	((x)<<4) /* Bit  5.. 4:  Link 1000 */
+#define PHY_M_LED_MO_RX(x)	((x)<<2) /* Bit  3.. 2:  Rx */
+#define PHY_M_LED_MO_TX(x)	((x)<<0) /* Bit  1.. 0:  Tx */
+
+enum {
+	MO_LED_NORM	= 0,
+	MO_LED_BLINK	= 1,
+	MO_LED_OFF	= 2,
+	MO_LED_ON	= 3,
+};
+
+/*****  PHY_MARV_EXT_CTRL_2	16 bit r/w	Ext. PHY Specific Ctrl 2 *****/
+enum {
+	PHY_M_EC2_FI_IMPED	= 1<<6, /* Fiber Input  Impedance */
+	PHY_M_EC2_FO_IMPED	= 1<<5, /* Fiber Output Impedance */
+	PHY_M_EC2_FO_M_CLK	= 1<<4, /* Fiber Mode Clock Enable */
+	PHY_M_EC2_FO_BOOST	= 1<<3, /* Fiber Output Boost */
+	PHY_M_EC2_FO_AM_MSK	= 7,/* Bit  2.. 0:	Fiber Output Amplitude */
+};
+
+/*****  PHY_MARV_EXT_P_STAT 16 bit r/w	Ext. PHY Specific Status *****/
+enum {
+	PHY_M_FC_AUTO_SEL	= 1<<15, /* Fiber/Copper Auto Sel. Dis. */
+	PHY_M_FC_AN_REG_ACC	= 1<<14, /* Fiber/Copper AN Reg. Access */
+	PHY_M_FC_RESOLUTION	= 1<<13, /* Fiber/Copper Resolution */
+	PHY_M_SER_IF_AN_BP	= 1<<12, /* Ser. IF AN Bypass Enable */
+	PHY_M_SER_IF_BP_ST	= 1<<11, /* Ser. IF AN Bypass Status */
+	PHY_M_IRQ_POLARITY	= 1<<10, /* IRQ polarity */
+	PHY_M_DIS_AUT_MED	= 1<<9, /* Disable Aut. Medium Reg. Selection */
+									/* (88E1111 only) */
+								/* Bit  9.. 4: reserved (88E1011 only) */
+	PHY_M_UNDOC1	= 1<<7, /* undocumented bit !! */
+	PHY_M_DTE_POW_STAT	= 1<<4, /* DTE Power Status (88E1111 only) */
+	PHY_M_MODE_MASK	= 0xf, /* Bit  3.. 0: copy of HWCFG MODE[3:0] */
+};
+
+/*****  PHY_MARV_CABLE_DIAG	16 bit r/o	Cable Diagnostic Reg *****/
+enum {
+	PHY_M_CABD_ENA_TEST	= 1<<15, /* Enable Test (Page 0) */
+	PHY_M_CABD_DIS_WAIT	= 1<<15, /* Disable Waiting Period (Page 1) */
+					/* (88E1111 only) */
+	PHY_M_CABD_STAT_MSK	= 3<<13, /* Bit 14..13: Status Mask */
+	PHY_M_CABD_AMPL_MSK	= 0x1f<<8,/* Bit 12.. 8: Amplitude Mask */
+					/* (88E1111 only) */
+	PHY_M_CABD_DIST_MSK	= 0xff, /* Bit  7.. 0: Distance Mask */
+};
+
+/* values for Cable Diagnostic Status (11=fail; 00=OK; 10=open; 01=short) */
+enum {
+	CABD_STAT_NORMAL= 0,
+	CABD_STAT_SHORT	= 1,
+	CABD_STAT_OPEN	= 2,
+	CABD_STAT_FAIL	= 3,
+};
+
+/* for 10/100 Fast Ethernet PHY (88E3082 only) */
+/*****  PHY_MARV_FE_LED_PAR		16 bit r/w	LED Parallel Select Reg. *****/
+									/* Bit 15..12: reserved (used internally) */
+enum {
+	PHY_M_FELP_LED2_MSK = 0xf<<8,	/* Bit 11.. 8: LED2 Mask (LINK) */
+	PHY_M_FELP_LED1_MSK = 0xf<<4,	/* Bit  7.. 4: LED1 Mask (ACT) */
+	PHY_M_FELP_LED0_MSK = 0xf, /* Bit  3.. 0: LED0 Mask (SPEED) */
+};
+
+#define PHY_M_FELP_LED2_CTRL(x)	(	((x)<<8) & PHY_M_FELP_LED2_MSK)
+#define PHY_M_FELP_LED1_CTRL(x)	(	((x)<<4) & PHY_M_FELP_LED1_MSK)
+#define PHY_M_FELP_LED0_CTRL(x)	(	((x)<<0) & PHY_M_FELP_LED0_MSK)
+
+enum {
+	LED_PAR_CTRL_COLX	= 0x00,
+	LED_PAR_CTRL_ERROR	= 0x01,
+	LED_PAR_CTRL_DUPLEX	= 0x02,
+	LED_PAR_CTRL_DP_COL	= 0x03,
+	LED_PAR_CTRL_SPEED	= 0x04,
+	LED_PAR_CTRL_LINK	= 0x05,
+	LED_PAR_CTRL_TX		= 0x06,
+	LED_PAR_CTRL_RX		= 0x07,
+	LED_PAR_CTRL_ACT	= 0x08,
+	LED_PAR_CTRL_LNK_RX	= 0x09,
+	LED_PAR_CTRL_LNK_AC	= 0x0a,
+	LED_PAR_CTRL_ACT_BL	= 0x0b,
+	LED_PAR_CTRL_TX_BL	= 0x0c,
+	LED_PAR_CTRL_RX_BL	= 0x0d,
+	LED_PAR_CTRL_COL_BL	= 0x0e,
+	LED_PAR_CTRL_INACT	= 0x0f
+};
+
+/*****,PHY_MARV_FE_SPEC_2		16 bit r/w	Specific Control Reg. 2 *****/
+enum {
+	PHY_M_FESC_DIS_WAIT	= 1<<2, /* Disable TDR Waiting Period */
+	PHY_M_FESC_ENA_MCLK	= 1<<1, /* Enable MAC Rx Clock in sleep mode */
+	PHY_M_FESC_SEL_CL_A	= 1<<0, /* Select Class A driver (100B-TX) */
+};
+
+/* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */
+/*****  PHY_MARV_PHY_CTRL (page 2)		16 bit r/w	MAC Specific Ctrl *****/
+enum {
+	PHY_M_MAC_MD_MSK	= 7<<7, /* Bit  9.. 7: Mode Select Mask */
+	PHY_M_MAC_MD_AUTO	= 3,/* Auto Copper/1000Base-X */
+	PHY_M_MAC_MD_COPPER	= 5,/* Copper only */
+	PHY_M_MAC_MD_1000BX	= 7,/* 1000Base-X only */
+};
+#define PHY_M_MAC_MODE_SEL(x)	(	((x)<<7) & PHY_M_MAC_MD_MSK)
+
+/*****  PHY_MARV_PHY_CTRL (page 3)		16 bit r/w	LED Control Reg. *****/
+enum {
+	PHY_M_LEDC_LOS_MSK	= 0xf<<12,/* Bit 15..12: LOS LED Ctrl. Mask */
+	PHY_M_LEDC_INIT_MSK	= 0xf<<8, /* Bit 11.. 8: INIT LED Ctrl. Mask */
+	PHY_M_LEDC_STA1_MSK	= 0xf<<4,/* Bit  7.. 4: STAT1 LED Ctrl. Mask */
+	PHY_M_LEDC_STA0_MSK	= 0xf, /* Bit  3.. 0: STAT0 LED Ctrl. Mask */
+};
+
+#define PHY_M_LEDC_LOS_CTRL(x)	(	((x)<<12) & PHY_M_LEDC_LOS_MSK)
+#define PHY_M_LEDC_INIT_CTRL(x)	(	((x)<<8) & PHY_M_LEDC_INIT_MSK)
+#define PHY_M_LEDC_STA1_CTRL(x)	(	((x)<<4) & PHY_M_LEDC_STA1_MSK)
+#define PHY_M_LEDC_STA0_CTRL(x)	(	((x)<<0) & PHY_M_LEDC_STA0_MSK)
+
+/* GMAC registers  */
+/* Port Registers */
+enum {
+	GM_GP_STAT	= 0x0000,	/* 16 bit r/o	General Purpose Status */
+	GM_GP_CTRL	= 0x0004,	/* 16 bit r/w	General Purpose Control */
+	GM_TX_CTRL	= 0x0008,	/* 16 bit r/w	Transmit Control Reg. */
+	GM_RX_CTRL	= 0x000c,	/* 16 bit r/w	Receive Control Reg. */
+	GM_TX_FLOW_CTRL	= 0x0010,	/* 16 bit r/w	Transmit Flow-Control */
+	GM_TX_PARAM	= 0x0014,	/* 16 bit r/w	Transmit Parameter Reg. */
+	GM_SERIAL_MODE	= 0x0018,	/* 16 bit r/w	Serial Mode Register */
+/* Source Address Registers */
+	GM_SRC_ADDR_1L	= 0x001c,	/* 16 bit r/w	Source Address 1 (low) */
+	GM_SRC_ADDR_1M	= 0x0020,	/* 16 bit r/w	Source Address 1 (middle) */
+	GM_SRC_ADDR_1H	= 0x0024,	/* 16 bit r/w	Source Address 1 (high) */
+	GM_SRC_ADDR_2L	= 0x0028,	/* 16 bit r/w	Source Address 2 (low) */
+	GM_SRC_ADDR_2M	= 0x002c,	/* 16 bit r/w	Source Address 2 (middle) */
+	GM_SRC_ADDR_2H	= 0x0030,	/* 16 bit r/w	Source Address 2 (high) */
+
+/* Multicast Address Hash Registers */
+	GM_MC_ADDR_H1	= 0x0034,	/* 16 bit r/w	Multicast Address Hash 1 */
+	GM_MC_ADDR_H2	= 0x0038,	/* 16 bit r/w	Multicast Address Hash 2 */
+	GM_MC_ADDR_H3	= 0x003c,	/* 16 bit r/w	Multicast Address Hash 3 */
+	GM_MC_ADDR_H4	= 0x0040,	/* 16 bit r/w	Multicast Address Hash 4 */
+
+/* Interrupt Source Registers */
+	GM_TX_IRQ_SRC	= 0x0044,	/* 16 bit r/o	Tx Overflow IRQ Source */
+	GM_RX_IRQ_SRC	= 0x0048,	/* 16 bit r/o	Rx Overflow IRQ Source */
+	GM_TR_IRQ_SRC	= 0x004c,	/* 16 bit r/o	Tx/Rx Over. IRQ Source */
+
+/* Interrupt Mask Registers */
+	GM_TX_IRQ_MSK	= 0x0050,	/* 16 bit r/w	Tx Overflow IRQ Mask */
+	GM_RX_IRQ_MSK	= 0x0054,	/* 16 bit r/w	Rx Overflow IRQ Mask */
+	GM_TR_IRQ_MSK	= 0x0058,	/* 16 bit r/w	Tx/Rx Over. IRQ Mask */
+
+/* Serial Management Interface (SMI) Registers */
+	GM_SMI_CTRL	= 0x0080,	/* 16 bit r/w	SMI Control Register */
+	GM_SMI_DATA	= 0x0084,	/* 16 bit r/w	SMI Data Register */
+	GM_PHY_ADDR	= 0x0088,	/* 16 bit r/w	GPHY Address Register */
+};
+
+/* MIB Counters */
+#define GM_MIB_CNT_BASE	0x0100		/* Base Address of MIB Counters */
+#define GM_MIB_CNT_SIZE	44		/* Number of MIB Counters */
+
+/*
+ * MIB Counters base address definitions (low word) -
+ * use offset 4 for access to high word	(32 bit r/o)
+ */
+enum {
+	GM_RXF_UC_OK  = GM_MIB_CNT_BASE + 0,	/* Unicast Frames Received OK */
+	GM_RXF_BC_OK	= GM_MIB_CNT_BASE + 8,	/* Broadcast Frames Received OK */
+	GM_RXF_MPAUSE	= GM_MIB_CNT_BASE + 16,	/* Pause MAC Ctrl Frames Received */
+	GM_RXF_MC_OK	= GM_MIB_CNT_BASE + 24,	/* Multicast Frames Received OK */
+	GM_RXF_FCS_ERR	= GM_MIB_CNT_BASE + 32,	/* Rx Frame Check Seq. Error */
+	/* GM_MIB_CNT_BASE + 40:	reserved */
+	GM_RXO_OK_LO	= GM_MIB_CNT_BASE + 48,	/* Octets Received OK Low */
+	GM_RXO_OK_HI	= GM_MIB_CNT_BASE + 56,	/* Octets Received OK High */
+	GM_RXO_ERR_LO	= GM_MIB_CNT_BASE + 64,	/* Octets Received Invalid Low */
+	GM_RXO_ERR_HI	= GM_MIB_CNT_BASE + 72,	/* Octets Received Invalid High */
+	GM_RXF_SHT	= GM_MIB_CNT_BASE + 80,	/* Frames <64 Byte Received OK */
+	GM_RXE_FRAG	= GM_MIB_CNT_BASE + 88,	/* Frames <64 Byte Received with FCS Err */
+	GM_RXF_64B	= GM_MIB_CNT_BASE + 96,	/* 64 Byte Rx Frame */
+	GM_RXF_127B	= GM_MIB_CNT_BASE + 104,	/* 65-127 Byte Rx Frame */
+	GM_RXF_255B	= GM_MIB_CNT_BASE + 112,	/* 128-255 Byte Rx Frame */
+	GM_RXF_511B	= GM_MIB_CNT_BASE + 120,	/* 256-511 Byte Rx Frame */
+	GM_RXF_1023B	= GM_MIB_CNT_BASE + 128,	/* 512-1023 Byte Rx Frame */
+	GM_RXF_1518B	= GM_MIB_CNT_BASE + 136,	/* 1024-1518 Byte Rx Frame */
+	GM_RXF_MAX_SZ	= GM_MIB_CNT_BASE + 144,	/* 1519-MaxSize Byte Rx Frame */
+	GM_RXF_LNG_ERR	= GM_MIB_CNT_BASE + 152,	/* Rx Frame too Long Error */
+	GM_RXF_JAB_PKT	= GM_MIB_CNT_BASE + 160,	/* Rx Jabber Packet Frame */
+	/* GM_MIB_CNT_BASE + 168:	reserved */
+	GM_RXE_FIFO_OV	= GM_MIB_CNT_BASE + 176,	/* Rx FIFO overflow Event */
+	/* GM_MIB_CNT_BASE + 184:	reserved */
+	GM_TXF_UC_OK	= GM_MIB_CNT_BASE + 192,	/* Unicast Frames Xmitted OK */
+	GM_TXF_BC_OK	= GM_MIB_CNT_BASE + 200,	/* Broadcast Frames Xmitted OK */
+	GM_TXF_MPAUSE	= GM_MIB_CNT_BASE + 208,	/* Pause MAC Ctrl Frames Xmitted */
+	GM_TXF_MC_OK	= GM_MIB_CNT_BASE + 216,	/* Multicast Frames Xmitted OK */
+	GM_TXO_OK_LO	= GM_MIB_CNT_BASE + 224,	/* Octets Transmitted OK Low */
+	GM_TXO_OK_HI	= GM_MIB_CNT_BASE + 232,	/* Octets Transmitted OK High */
+	GM_TXF_64B	= GM_MIB_CNT_BASE + 240,	/* 64 Byte Tx Frame */
+	GM_TXF_127B	= GM_MIB_CNT_BASE + 248,	/* 65-127 Byte Tx Frame */
+	GM_TXF_255B	= GM_MIB_CNT_BASE + 256,	/* 128-255 Byte Tx Frame */
+	GM_TXF_511B	= GM_MIB_CNT_BASE + 264,	/* 256-511 Byte Tx Frame */
+	GM_TXF_1023B	= GM_MIB_CNT_BASE + 272,	/* 512-1023 Byte Tx Frame */
+	GM_TXF_1518B	= GM_MIB_CNT_BASE + 280,	/* 1024-1518 Byte Tx Frame */
+	GM_TXF_MAX_SZ	= GM_MIB_CNT_BASE + 288,	/* 1519-MaxSize Byte Tx Frame */
+
+	GM_TXF_COL	= GM_MIB_CNT_BASE + 304,	/* Tx Collision */
+	GM_TXF_LAT_COL	= GM_MIB_CNT_BASE + 312,	/* Tx Late Collision */
+	GM_TXF_ABO_COL	= GM_MIB_CNT_BASE + 320,	/* Tx aborted due to Exces. Col. */
+	GM_TXF_MUL_COL	= GM_MIB_CNT_BASE + 328,	/* Tx Multiple Collision */
+	GM_TXF_SNG_COL	= GM_MIB_CNT_BASE + 336,	/* Tx Single Collision */
+	GM_TXE_FIFO_UR	= GM_MIB_CNT_BASE + 344,	/* Tx FIFO Underrun Event */
+};
+
+/* GMAC Bit Definitions */
+/*	GM_GP_STAT	16 bit r/o	General Purpose Status Register */
+enum {
+	GM_GPSR_SPEED		= 1<<15, /* Bit 15:	Port Speed (1 = 100 Mbps) */
+	GM_GPSR_DUPLEX		= 1<<14, /* Bit 14:	Duplex Mode (1 = Full) */
+	GM_GPSR_FC_TX_DIS	= 1<<13, /* Bit 13:	Tx Flow-Control Mode Disabled */
+	GM_GPSR_LINK_UP		= 1<<12, /* Bit 12:	Link Up Status */
+	GM_GPSR_PAUSE		= 1<<11, /* Bit 11:	Pause State */
+	GM_GPSR_TX_ACTIVE	= 1<<10, /* Bit 10:	Tx in Progress */
+	GM_GPSR_EXC_COL		= 1<<9,	/* Bit  9:	Excessive Collisions Occured */
+	GM_GPSR_LAT_COL		= 1<<8,	/* Bit  8:	Late Collisions Occured */
+
+	GM_GPSR_PHY_ST_CH	= 1<<5,	/* Bit  5:	PHY Status Change */
+	GM_GPSR_GIG_SPEED	= 1<<4,	/* Bit  4:	Gigabit Speed (1 = 1000 Mbps) */
+	GM_GPSR_PART_MODE	= 1<<3,	/* Bit  3:	Partition mode */
+	GM_GPSR_FC_RX_DIS	= 1<<2,	/* Bit  2:	Rx Flow-Control Mode Disabled */
+	GM_GPSR_PROM_EN		= 1<<1,	/* Bit  1:	Promiscuous Mode Enabled */
+};
+	
+/*	GM_GP_CTRL	16 bit r/w	General Purpose Control Register */
+enum {
+	GM_GPCR_PROM_ENA	= 1<<14,	/* Bit 14:	Enable Promiscuous Mode */
+	GM_GPCR_FC_TX_DIS	= 1<<13, /* Bit 13:	Disable Tx Flow-Control Mode */
+	GM_GPCR_TX_ENA		= 1<<12, /* Bit 12:	Enable Transmit */
+	GM_GPCR_RX_ENA		= 1<<11, /* Bit 11:	Enable Receive */
+	GM_GPCR_BURST_ENA	= 1<<10, /* Bit 10:	Enable Burst Mode */
+	GM_GPCR_LOOP_ENA	= 1<<9,	/* Bit  9:	Enable MAC Loopback Mode */
+	GM_GPCR_PART_ENA	= 1<<8,	/* Bit  8:	Enable Partition Mode */
+	GM_GPCR_GIGS_ENA	= 1<<7,	/* Bit  7:	Gigabit Speed (1000 Mbps) */
+	GM_GPCR_FL_PASS		= 1<<6,	/* Bit  6:	Force Link Pass */
+	GM_GPCR_DUP_FULL	= 1<<5,	/* Bit  5:	Full Duplex Mode */
+	GM_GPCR_FC_RX_DIS	= 1<<4,	/* Bit  4:	Disable Rx Flow-Control Mode */
+	GM_GPCR_SPEED_100	= 1<<3,   /* Bit  3:	Port Speed 100 Mbps */
+	GM_GPCR_AU_DUP_DIS	= 1<<2,	/* Bit  2:	Disable Auto-Update Duplex */
+	GM_GPCR_AU_FCT_DIS	= 1<<1,	/* Bit  1:	Disable Auto-Update Flow-C. */
+	GM_GPCR_AU_SPD_DIS	= 1<<0,	/* Bit  0:	Disable Auto-Update Speed */
+};
+
+#define GM_GPCR_SPEED_1000	(GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
+#define GM_GPCR_AU_ALL_DIS	(GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS)
+	
+/*	GM_TX_CTRL			16 bit r/w	Transmit Control Register */
+enum {
+	GM_TXCR_FORCE_JAM	= 1<<15, /* Bit 15:	Force Jam / Flow-Control */
+	GM_TXCR_CRC_DIS		= 1<<14, /* Bit 14:	Disable insertion of CRC */
+	GM_TXCR_PAD_DIS		= 1<<13, /* Bit 13:	Disable padding of packets */
+	GM_TXCR_COL_THR_MSK	= 1<<10, /* Bit 12..10:	Collision Threshold */
+};
+
+#define TX_COL_THR(x)		(((x)<<10) & GM_TXCR_COL_THR_MSK)
+#define TX_COL_DEF		0x04
+	
+/*	GM_RX_CTRL			16 bit r/w	Receive Control Register */
+enum {
+	GM_RXCR_UCF_ENA	= 1<<15, /* Bit 15:	Enable Unicast filtering */
+	GM_RXCR_MCF_ENA	= 1<<14, /* Bit 14:	Enable Multicast filtering */
+	GM_RXCR_CRC_DIS	= 1<<13, /* Bit 13:	Remove 4-byte CRC */
+	GM_RXCR_PASS_FC	= 1<<12, /* Bit 12:	Pass FC packets to FIFO */
+};
+	
+/*	GM_TX_PARAM		16 bit r/w	Transmit Parameter Register */
+enum {
+	GM_TXPA_JAMLEN_MSK	= 0x03<<14,	/* Bit 15..14:	Jam Length */
+	GM_TXPA_JAMIPG_MSK	= 0x1f<<9,	/* Bit 13..9:	Jam IPG */
+	GM_TXPA_JAMDAT_MSK	= 0x1f<<4,	/* Bit  8..4:	IPG Jam to Data */
+
+	TX_JAM_LEN_DEF		= 0x03,
+	TX_JAM_IPG_DEF		= 0x0b,
+	TX_IPG_JAM_DEF		= 0x1c,
+};
+
+#define TX_JAM_LEN_VAL(x)	(((x)<<14) & GM_TXPA_JAMLEN_MSK)
+#define TX_JAM_IPG_VAL(x)	(((x)<<9)  & GM_TXPA_JAMIPG_MSK)
+#define TX_IPG_JAM_DATA(x)	(((x)<<4)  & GM_TXPA_JAMDAT_MSK)
+
+
+/*	GM_SERIAL_MODE			16 bit r/w	Serial Mode Register */
+enum {
+	GM_SMOD_DATABL_MSK	= 0x1f<<11, /* Bit 15..11:	Data Blinder (r/o) */
+	GM_SMOD_LIMIT_4		= 1<<10, /* Bit 10:	4 consecutive Tx trials */
+	GM_SMOD_VLAN_ENA	= 1<<9,	/* Bit  9:	Enable VLAN  (Max. Frame Len) */
+	GM_SMOD_JUMBO_ENA	= 1<<8,	/* Bit  8:	Enable Jumbo (Max. Frame Len) */
+	 GM_SMOD_IPG_MSK	= 0x1f	/* Bit 4..0:	Inter-Packet Gap (IPG) */
+};
+	
+#define DATA_BLIND_VAL(x)	(((x)<<11) & GM_SMOD_DATABL_MSK)
+#define DATA_BLIND_DEF		0x04
+
+#define IPG_DATA_VAL(x)		(x & GM_SMOD_IPG_MSK)
+#define IPG_DATA_DEF		0x1e
+
+/*	GM_SMI_CTRL			16 bit r/w	SMI Control Register */
+enum {
+	GM_SMI_CT_PHY_A_MSK	= 0x1f<<11,/* Bit 15..11:	PHY Device Address */
+	GM_SMI_CT_REG_A_MSK	= 0x1f<<6,/* Bit 10.. 6:	PHY Register Address */
+	GM_SMI_CT_OP_RD		= 1<<5,	/* Bit  5:	OpCode Read (0=Write)*/
+	GM_SMI_CT_RD_VAL	= 1<<4,	/* Bit  4:	Read Valid (Read completed) */
+	GM_SMI_CT_BUSY		= 1<<3,	/* Bit  3:	Busy (Operation in progress) */
+};
+	
+#define GM_SMI_CT_PHY_AD(x)	(((x)<<11) & GM_SMI_CT_PHY_A_MSK)
+#define GM_SMI_CT_REG_AD(x)	(((x)<<6) & GM_SMI_CT_REG_A_MSK)
+
+/*	GM_PHY_ADDR				16 bit r/w	GPHY Address Register */
+enum {
+	GM_PAR_MIB_CLR	= 1<<5,	/* Bit  5:	Set MIB Clear Counter Mode */
+	GM_PAR_MIB_TST	= 1<<4,	/* Bit  4:	MIB Load Counter (Test Mode) */
+};
+	
+/* Receive Frame Status Encoding */
+enum {
+	GMR_FS_LEN	= 0xffff<<16, /* Bit 31..16:	Rx Frame Length */
+	GMR_FS_VLAN	= 1<<13, /* Bit 13:	VLAN Packet */
+	GMR_FS_JABBER	= 1<<12, /* Bit 12:	Jabber Packet */
+	GMR_FS_UN_SIZE	= 1<<11, /* Bit 11:	Undersize Packet */
+	GMR_FS_MC	= 1<<10, /* Bit 10:	Multicast Packet */
+	GMR_FS_BC	= 1<<9, /* Bit  9:	Broadcast Packet */
+	GMR_FS_RX_OK	= 1<<8, /* Bit  8:	Receive OK (Good Packet) */
+	GMR_FS_GOOD_FC	= 1<<7, /* Bit  7:	Good Flow-Control Packet */
+	GMR_FS_BAD_FC	= 1<<6, /* Bit  6:	Bad  Flow-Control Packet */
+	GMR_FS_MII_ERR	= 1<<5, /* Bit  5:	MII Error */
+	GMR_FS_LONG_ERR	= 1<<4, /* Bit  4:	Too Long Packet */
+	GMR_FS_FRAGMENT	= 1<<3, /* Bit  3:	Fragment */
+
+	GMR_FS_CRC_ERR	= 1<<1, /* Bit  1:	CRC Error */
+	GMR_FS_RX_FF_OV	= 1<<0, /* Bit  0:	Rx FIFO Overflow */
+
+/*
+ * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
+ */
+	GMR_FS_ANY_ERR	= GMR_FS_CRC_ERR | GMR_FS_LONG_ERR | 
+		  	  GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC | 
+			  GMR_FS_JABBER,
+/* Rx GMAC FIFO Flush Mask (default) */
+	RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR |
+			   GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE | 
+			   GMR_FS_JABBER,
+};
+
+/*	RX_GMF_CTRL_T	32 bit	Rx GMAC FIFO Control/Test */
+enum {
+	GMF_WP_TST_ON	= 1<<14,	/* Write Pointer Test On */
+	GMF_WP_TST_OFF	= 1<<13,	/* Write Pointer Test Off */
+	GMF_WP_STEP	= 1<<12,	/* Write Pointer Step/Increment */
+
+	GMF_RP_TST_ON	= 1<<10,	/* Read Pointer Test On */
+	GMF_RP_TST_OFF	= 1<<9,		/* Read Pointer Test Off */
+	GMF_RP_STEP	= 1<<8,		/* Read Pointer Step/Increment */
+	GMF_RX_F_FL_ON	= 1<<7,		/* Rx FIFO Flush Mode On */
+	GMF_RX_F_FL_OFF	= 1<<6,		/* Rx FIFO Flush Mode Off */
+	GMF_CLI_RX_FO	= 1<<5,		/* Clear IRQ Rx FIFO Overrun */
+	GMF_CLI_RX_FC	= 1<<4,		/* Clear IRQ Rx Frame Complete */
+	GMF_OPER_ON	= 1<<3,		/* Operational Mode On */
+	GMF_OPER_OFF	= 1<<2,		/* Operational Mode Off */
+	GMF_RST_CLR	= 1<<1,		/* Clear GMAC FIFO Reset */
+	GMF_RST_SET	= 1<<0,		/* Set   GMAC FIFO Reset */
+
+	RX_GMF_FL_THR_DEF = 0xa,	/* flush threshold (default) */
+};
+
+
+/*	TX_GMF_CTRL_T	32 bit	Tx GMAC FIFO Control/Test */
+enum {
+	GMF_WSP_TST_ON	= 1<<18,/* Write Shadow Pointer Test On */
+	GMF_WSP_TST_OFF	= 1<<17,/* Write Shadow Pointer Test Off */
+	GMF_WSP_STEP	= 1<<16,/* Write Shadow Pointer Step/Increment */
+
+	GMF_CLI_TX_FU	= 1<<6,	/* Clear IRQ Tx FIFO Underrun */
+	GMF_CLI_TX_FC	= 1<<5,	/* Clear IRQ Tx Frame Complete */
+	GMF_CLI_TX_PE	= 1<<4,	/* Clear IRQ Tx Parity Error */
+};
+
+/*	GMAC_TI_ST_CTRL	 8 bit	Time Stamp Timer Ctrl Reg (YUKON only) */
+enum {
+	GMT_ST_START	= 1<<2,	/* Start Time Stamp Timer */
+	GMT_ST_STOP	= 1<<1,	/* Stop  Time Stamp Timer */
+	GMT_ST_CLR_IRQ	= 1<<0,	/* Clear Time Stamp Timer IRQ */
+};
+
+/*	GMAC_CTRL		32 bit	GMAC Control Reg (YUKON only) */
+enum {
+	GMC_H_BURST_ON	= 1<<7,	/* Half Duplex Burst Mode On */
+	GMC_H_BURST_OFF	= 1<<6,	/* Half Duplex Burst Mode Off */
+	GMC_F_LOOPB_ON	= 1<<5,	/* FIFO Loopback On */
+	GMC_F_LOOPB_OFF	= 1<<4,	/* FIFO Loopback Off */
+	GMC_PAUSE_ON	= 1<<3,	/* Pause On */
+	GMC_PAUSE_OFF	= 1<<2,	/* Pause Off */
+	GMC_RST_CLR	= 1<<1,	/* Clear GMAC Reset */
+	GMC_RST_SET	= 1<<0,	/* Set   GMAC Reset */
+};
+
+/*	GPHY_CTRL		32 bit	GPHY Control Reg (YUKON only) */
+enum {
+	GPC_SEL_BDT	= 1<<28, /* Select Bi-Dir. Transfer for MDC/MDIO */
+	GPC_INT_POL_HI	= 1<<27, /* IRQ Polarity is Active HIGH */
+	GPC_75_OHM	= 1<<26, /* Use 75 Ohm Termination instead of 50 */
+	GPC_DIS_FC	= 1<<25, /* Disable Automatic Fiber/Copper Detection */
+	GPC_DIS_SLEEP	= 1<<24, /* Disable Energy Detect */
+	GPC_HWCFG_M_3	= 1<<23, /* HWCFG_MODE[3] */
+	GPC_HWCFG_M_2	= 1<<22, /* HWCFG_MODE[2] */
+	GPC_HWCFG_M_1	= 1<<21, /* HWCFG_MODE[1] */
+	GPC_HWCFG_M_0	= 1<<20, /* HWCFG_MODE[0] */
+	GPC_ANEG_0	= 1<<19, /* ANEG[0] */
+	GPC_ENA_XC	= 1<<18, /* Enable MDI crossover */
+	GPC_DIS_125	= 1<<17, /* Disable 125 MHz clock */
+	GPC_ANEG_3	= 1<<16, /* ANEG[3] */
+	GPC_ANEG_2	= 1<<15, /* ANEG[2] */
+	GPC_ANEG_1	= 1<<14, /* ANEG[1] */
+	GPC_ENA_PAUSE	= 1<<13, /* Enable Pause (SYM_OR_REM) */
+	GPC_PHYADDR_4	= 1<<12, /* Bit 4 of Phy Addr */
+	GPC_PHYADDR_3	= 1<<11, /* Bit 3 of Phy Addr */
+	GPC_PHYADDR_2	= 1<<10, /* Bit 2 of Phy Addr */
+	GPC_PHYADDR_1	= 1<<9,	 /* Bit 1 of Phy Addr */
+	GPC_PHYADDR_0	= 1<<8,	 /* Bit 0 of Phy Addr */
+						/* Bits  7..2:	reserved */
+	GPC_RST_CLR	= 1<<1,	/* Clear GPHY Reset */
+	GPC_RST_SET	= 1<<0,	/* Set   GPHY Reset */
+};
+
+#define GPC_HWCFG_GMII_COP (GPC_HWCFG_M_3|GPC_HWCFG_M_2 | GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+#define GPC_HWCFG_GMII_FIB (GPC_HWCFG_M_2 | GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+#define GPC_ANEG_ADV_ALL_M  (GPC_ANEG_3 | GPC_ANEG_2 | GPC_ANEG_1 | GPC_ANEG_0)
+
+/* forced speed and duplex mode (don't mix with other ANEG bits) */
+#define GPC_FRC10MBIT_HALF	0
+#define GPC_FRC10MBIT_FULL	GPC_ANEG_0
+#define GPC_FRC100MBIT_HALF	GPC_ANEG_1
+#define GPC_FRC100MBIT_FULL	(GPC_ANEG_0 | GPC_ANEG_1)
+
+/* auto-negotiation with limited advertised speeds */
+/* mix only with master/slave settings (for copper) */
+#define GPC_ADV_1000_HALF	GPC_ANEG_2
+#define GPC_ADV_1000_FULL	GPC_ANEG_3
+#define GPC_ADV_ALL		(GPC_ANEG_2 | GPC_ANEG_3)
+
+/* master/slave settings */
+/* only for copper with 1000 Mbps */
+#define GPC_FORCE_MASTER	0
+#define GPC_FORCE_SLAVE		GPC_ANEG_0
+#define GPC_PREF_MASTER		GPC_ANEG_1
+#define GPC_PREF_SLAVE		(GPC_ANEG_1 | GPC_ANEG_0)
+
+/*	GMAC_IRQ_SRC	 8 bit	GMAC Interrupt Source Reg (YUKON only) */
+/*	GMAC_IRQ_MSK	 8 bit	GMAC Interrupt Mask   Reg (YUKON only) */
+enum {
+	GM_IS_TX_CO_OV	= 1<<5,	/* Transmit Counter Overflow IRQ */
+	GM_IS_RX_CO_OV	= 1<<4,	/* Receive Counter Overflow IRQ */
+	GM_IS_TX_FF_UR	= 1<<3,	/* Transmit FIFO Underrun */
+	GM_IS_TX_COMPL	= 1<<2,	/* Frame Transmission Complete */
+	GM_IS_RX_FF_OR	= 1<<1,	/* Receive FIFO Overrun */
+	GM_IS_RX_COMPL	= 1<<0,	/* Frame Reception Complete */
+
+#define GMAC_DEF_MSK	(GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | GM_IS_TX_FF_UR)
+
+/*	GMAC_LINK_CTRL	16 bit	GMAC Link Control Reg (YUKON only) */
+						/* Bits 15.. 2:	reserved */
+	GMLC_RST_CLR	= 1<<1,	/* Clear GMAC Link Reset */
+	GMLC_RST_SET	= 1<<0,	/* Set   GMAC Link Reset */
+
+
+/*	WOL_CTRL_STAT	16 bit	WOL Control/Status Reg */
+	WOL_CTL_LINK_CHG_OCC		= 1<<15,
+	WOL_CTL_MAGIC_PKT_OCC		= 1<<14,
+	WOL_CTL_PATTERN_OCC		= 1<<13,
+	WOL_CTL_CLEAR_RESULT		= 1<<12,
+	WOL_CTL_ENA_PME_ON_LINK_CHG	= 1<<11,
+	WOL_CTL_DIS_PME_ON_LINK_CHG	= 1<<10,
+	WOL_CTL_ENA_PME_ON_MAGIC_PKT	= 1<<9,
+	WOL_CTL_DIS_PME_ON_MAGIC_PKT	= 1<<8,
+	WOL_CTL_ENA_PME_ON_PATTERN	= 1<<7,
+	WOL_CTL_DIS_PME_ON_PATTERN	= 1<<6,
+	WOL_CTL_ENA_LINK_CHG_UNIT	= 1<<5,
+	WOL_CTL_DIS_LINK_CHG_UNIT	= 1<<4,
+	WOL_CTL_ENA_MAGIC_PKT_UNIT	= 1<<3,
+	WOL_CTL_DIS_MAGIC_PKT_UNIT	= 1<<2,
+	WOL_CTL_ENA_PATTERN_UNIT	= 1<<1,
+	WOL_CTL_DIS_PATTERN_UNIT	= 1<<0,
+};
+
+#define WOL_CTL_DEFAULT				\
+	(WOL_CTL_DIS_PME_ON_LINK_CHG |	\
+	WOL_CTL_DIS_PME_ON_PATTERN |	\
+	WOL_CTL_DIS_PME_ON_MAGIC_PKT |	\
+	WOL_CTL_DIS_LINK_CHG_UNIT |		\
+	WOL_CTL_DIS_PATTERN_UNIT |		\
+	WOL_CTL_DIS_MAGIC_PKT_UNIT)
+
+/*	WOL_MATCH_CTL	 8 bit	WOL Match Control Reg */
+#define WOL_CTL_PATT_ENA(x)	(1 << (x))
+
+
+/* XMAC II registers				      */
+enum {
+	XM_MMU_CMD	= 0x0000, /* 16 bit r/w	MMU Command Register */
+	XM_POFF		= 0x0008, /* 32 bit r/w	Packet Offset Register */
+	XM_BURST	= 0x000c, /* 32 bit r/w	Burst Register for half duplex*/
+	XM_1L_VLAN_TAG	= 0x0010, /* 16 bit r/w	One Level VLAN Tag ID */
+	XM_2L_VLAN_TAG	= 0x0014, /* 16 bit r/w	Two Level VLAN Tag ID */
+	XM_TX_CMD	= 0x0020, /* 16 bit r/w	Transmit Command Register */
+	XM_TX_RT_LIM	= 0x0024, /* 16 bit r/w	Transmit Retry Limit Register */
+	XM_TX_STIME	= 0x0028, /* 16 bit r/w	Transmit Slottime Register */
+	XM_TX_IPG	= 0x002c, /* 16 bit r/w	Transmit Inter Packet Gap */
+	XM_RX_CMD	= 0x0030, /* 16 bit r/w	Receive Command Register */
+	XM_PHY_ADDR	= 0x0034, /* 16 bit r/w	PHY Address Register */
+	XM_PHY_DATA	= 0x0038, /* 16 bit r/w	PHY Data Register */
+	XM_GP_PORT	= 0x0040, /* 32 bit r/w	General Purpose Port Register */
+	XM_IMSK		= 0x0044, /* 16 bit r/w	Interrupt Mask Register */
+	XM_ISRC		= 0x0048, /* 16 bit r/o	Interrupt Status Register */
+	XM_HW_CFG	= 0x004c, /* 16 bit r/w	Hardware Config Register */
+	XM_TX_LO_WM	= 0x0060, /* 16 bit r/w	Tx FIFO Low Water Mark */
+	XM_TX_HI_WM	= 0x0062, /* 16 bit r/w	Tx FIFO High Water Mark */
+	XM_TX_THR	= 0x0064, /* 16 bit r/w	Tx Request Threshold */
+	XM_HT_THR	= 0x0066, /* 16 bit r/w	Host Request Threshold */
+	XM_PAUSE_DA	= 0x0068, /* NA reg r/w	Pause Destination Address */
+	XM_CTL_PARA	= 0x0070, /* 32 bit r/w	Control Parameter Register */
+	XM_MAC_OPCODE	= 0x0074, /* 16 bit r/w	Opcode for MAC control frames */
+	XM_MAC_PTIME	= 0x0076, /* 16 bit r/w	Pause time for MAC ctrl frames*/
+	XM_TX_STAT	= 0x0078, /* 32 bit r/o	Tx Status LIFO Register */
+
+	XM_EXM_START	= 0x0080, /* r/w	Start Address of the EXM Regs */
+#define XM_EXM(reg)	(XM_EXM_START + ((reg) << 3))
+};
+
+enum {
+	XM_SRC_CHK	= 0x0100, /* NA reg r/w	Source Check Address Register */
+	XM_SA		= 0x0108, /* NA reg r/w	Station Address Register */
+	XM_HSM		= 0x0110, /* 64 bit r/w	Hash Match Address Registers */
+	XM_RX_LO_WM	= 0x0118, /* 16 bit r/w	Receive Low Water Mark */
+	XM_RX_HI_WM	= 0x011a, /* 16 bit r/w	Receive High Water Mark */
+	XM_RX_THR	= 0x011c, /* 32 bit r/w	Receive Request Threshold */
+	XM_DEV_ID	= 0x0120, /* 32 bit r/o	Device ID Register */
+	XM_MODE		= 0x0124, /* 32 bit r/w	Mode Register */
+	XM_LSA		= 0x0128, /* NA reg r/o	Last Source Register */
+	XM_TS_READ	= 0x0130, /* 32 bit r/o	Time Stamp Read Register */
+	XM_TS_LOAD	= 0x0134, /* 32 bit r/o	Time Stamp Load Value */
+	XM_STAT_CMD	= 0x0200, /* 16 bit r/w	Statistics Command Register */
+	XM_RX_CNT_EV	= 0x0204, /* 32 bit r/o	Rx Counter Event Register */
+	XM_TX_CNT_EV	= 0x0208, /* 32 bit r/o	Tx Counter Event Register */
+	XM_RX_EV_MSK	= 0x020c, /* 32 bit r/w	Rx Counter Event Mask */
+	XM_TX_EV_MSK	= 0x0210, /* 32 bit r/w	Tx Counter Event Mask */
+	XM_TXF_OK	= 0x0280, /* 32 bit r/o	Frames Transmitted OK Conuter */
+	XM_TXO_OK_HI	= 0x0284, /* 32 bit r/o	Octets Transmitted OK High Cnt*/
+	XM_TXO_OK_LO	= 0x0288, /* 32 bit r/o	Octets Transmitted OK Low Cnt */
+	XM_TXF_BC_OK	= 0x028c, /* 32 bit r/o	Broadcast Frames Xmitted OK */
+	XM_TXF_MC_OK	= 0x0290, /* 32 bit r/o	Multicast Frames Xmitted OK */
+	XM_TXF_UC_OK	= 0x0294, /* 32 bit r/o	Unicast Frames Xmitted OK */
+	XM_TXF_LONG	= 0x0298, /* 32 bit r/o	Tx Long Frame Counter */
+	XM_TXE_BURST	= 0x029c, /* 32 bit r/o	Tx Burst Event Counter */
+	XM_TXF_MPAUSE	= 0x02a0, /* 32 bit r/o	Tx Pause MAC Ctrl Frame Cnt */
+	XM_TXF_MCTRL	= 0x02a4, /* 32 bit r/o	Tx MAC Ctrl Frame Counter */
+	XM_TXF_SNG_COL	= 0x02a8, /* 32 bit r/o	Tx Single Collision Counter */
+	XM_TXF_MUL_COL	= 0x02ac, /* 32 bit r/o	Tx Multiple Collision Counter */
+	XM_TXF_ABO_COL	= 0x02b0, /* 32 bit r/o	Tx aborted due to Exces. Col. */
+	XM_TXF_LAT_COL	= 0x02b4, /* 32 bit r/o	Tx Late Collision Counter */
+	XM_TXF_DEF	= 0x02b8, /* 32 bit r/o	Tx Deferred Frame Counter */
+	XM_TXF_EX_DEF	= 0x02bc, /* 32 bit r/o	Tx Excessive Deferall Counter */
+	XM_TXE_FIFO_UR	= 0x02c0, /* 32 bit r/o	Tx FIFO Underrun Event Cnt */
+	XM_TXE_CS_ERR	= 0x02c4, /* 32 bit r/o	Tx Carrier Sense Error Cnt */
+	XM_TXP_UTIL	= 0x02c8, /* 32 bit r/o	Tx Utilization in % */
+	XM_TXF_64B	= 0x02d0, /* 32 bit r/o	64 Byte Tx Frame Counter */
+	XM_TXF_127B	= 0x02d4, /* 32 bit r/o	65-127 Byte Tx Frame Counter */
+	XM_TXF_255B	= 0x02d8, /* 32 bit r/o	128-255 Byte Tx Frame Counter */
+	XM_TXF_511B	= 0x02dc, /* 32 bit r/o	256-511 Byte Tx Frame Counter */
+	XM_TXF_1023B	= 0x02e0, /* 32 bit r/o	512-1023 Byte Tx Frame Counter*/
+	XM_TXF_MAX_SZ	= 0x02e4, /* 32 bit r/o	1024-MaxSize Byte Tx Frame Cnt*/
+	XM_RXF_OK	= 0x0300, /* 32 bit r/o	Frames Received OK */
+	XM_RXO_OK_HI	= 0x0304, /* 32 bit r/o	Octets Received OK High Cnt */
+	XM_RXO_OK_LO	= 0x0308, /* 32 bit r/o	Octets Received OK Low Counter*/
+	XM_RXF_BC_OK	= 0x030c, /* 32 bit r/o	Broadcast Frames Received OK */
+	XM_RXF_MC_OK	= 0x0310, /* 32 bit r/o	Multicast Frames Received OK */
+	XM_RXF_UC_OK	= 0x0314, /* 32 bit r/o	Unicast Frames Received OK */
+	XM_RXF_MPAUSE	= 0x0318, /* 32 bit r/o	Rx Pause MAC Ctrl Frame Cnt */
+	XM_RXF_MCTRL	= 0x031c, /* 32 bit r/o	Rx MAC Ctrl Frame Counter */
+	XM_RXF_INV_MP	= 0x0320, /* 32 bit r/o	Rx invalid Pause Frame Cnt */
+	XM_RXF_INV_MOC	= 0x0324, /* 32 bit r/o	Rx Frames with inv. MAC Opcode*/
+	XM_RXE_BURST	= 0x0328, /* 32 bit r/o	Rx Burst Event Counter */
+	XM_RXE_FMISS	= 0x032c, /* 32 bit r/o	Rx Missed Frames Event Cnt */
+	XM_RXF_FRA_ERR	= 0x0330, /* 32 bit r/o	Rx Framing Error Counter */
+	XM_RXE_FIFO_OV	= 0x0334, /* 32 bit r/o	Rx FIFO overflow Event Cnt */
+	XM_RXF_JAB_PKT	= 0x0338, /* 32 bit r/o	Rx Jabber Packet Frame Cnt */
+	XM_RXE_CAR_ERR	= 0x033c, /* 32 bit r/o	Rx Carrier Event Error Cnt */
+	XM_RXF_LEN_ERR	= 0x0340, /* 32 bit r/o	Rx in Range Length Error */
+	XM_RXE_SYM_ERR	= 0x0344, /* 32 bit r/o	Rx Symbol Error Counter */
+	XM_RXE_SHT_ERR	= 0x0348, /* 32 bit r/o	Rx Short Event Error Cnt */
+	XM_RXE_RUNT	= 0x034c, /* 32 bit r/o	Rx Runt Event Counter */
+	XM_RXF_LNG_ERR	= 0x0350, /* 32 bit r/o	Rx Frame too Long Error Cnt */
+	XM_RXF_FCS_ERR	= 0x0354, /* 32 bit r/o	Rx Frame Check Seq. Error Cnt */
+	XM_RXF_CEX_ERR	= 0x035c, /* 32 bit r/o	Rx Carrier Ext Error Frame Cnt*/
+	XM_RXP_UTIL	= 0x0360, /* 32 bit r/o	Rx Utilization in % */
+	XM_RXF_64B	= 0x0368, /* 32 bit r/o	64 Byte Rx Frame Counter */
+	XM_RXF_127B	= 0x036c, /* 32 bit r/o	65-127 Byte Rx Frame Counter */
+	XM_RXF_255B	= 0x0370, /* 32 bit r/o	128-255 Byte Rx Frame Counter */
+	XM_RXF_511B	= 0x0374, /* 32 bit r/o	256-511 Byte Rx Frame Counter */
+	XM_RXF_1023B	= 0x0378, /* 32 bit r/o	512-1023 Byte Rx Frame Counter*/
+	XM_RXF_MAX_SZ	= 0x037c, /* 32 bit r/o	1024-MaxSize Byte Rx Frame Cnt*/
+};
+
+/*	XM_MMU_CMD	16 bit r/w	MMU Command Register */
+enum {
+	XM_MMU_PHY_RDY	= 1<<12,/* Bit 12:	PHY Read Ready */
+	XM_MMU_PHY_BUSY	= 1<<11,/* Bit 11:	PHY Busy */
+	XM_MMU_IGN_PF	= 1<<10,/* Bit 10:	Ignore Pause Frame */
+	XM_MMU_MAC_LB	= 1<<9,	/* Bit  9:	Enable MAC Loopback */
+	XM_MMU_FRC_COL	= 1<<7,	/* Bit  7:	Force Collision */
+	XM_MMU_SIM_COL	= 1<<6,	/* Bit  6:	Simulate Collision */
+	XM_MMU_NO_PRE	= 1<<5,	/* Bit  5:	No MDIO Preamble */
+	XM_MMU_GMII_FD	= 1<<4,	/* Bit  4:	GMII uses Full Duplex */
+	XM_MMU_RAT_CTRL	= 1<<3,	/* Bit  3:	Enable Rate Control */
+	XM_MMU_GMII_LOOP= 1<<2,	/* Bit  2:	PHY is in Loopback Mode */
+	XM_MMU_ENA_RX	= 1<<1,	/* Bit  1:	Enable Receiver */
+	XM_MMU_ENA_TX	= 1<<0,	/* Bit  0:	Enable Transmitter */
+};
+
+
+/*	XM_TX_CMD	16 bit r/w	Transmit Command Register */
+enum {
+	XM_TX_BK2BK	= 1<<6,	/* Bit  6:	Ignor Carrier Sense (Tx Bk2Bk)*/
+	XM_TX_ENC_BYP	= 1<<5,	/* Bit  5:	Set Encoder in Bypass Mode */
+	XM_TX_SAM_LINE	= 1<<4,	/* Bit  4: (sc)	Start utilization calculation */
+	XM_TX_NO_GIG_MD	= 1<<3,	/* Bit  3:	Disable Carrier Extension */
+	XM_TX_NO_PRE	= 1<<2,	/* Bit  2:	Disable Preamble Generation */
+	XM_TX_NO_CRC	= 1<<1,	/* Bit  1:	Disable CRC Generation */
+	XM_TX_AUTO_PAD	= 1<<0,	/* Bit  0:	Enable Automatic Padding */
+};
+
+/*	XM_TX_RT_LIM	16 bit r/w	Transmit Retry Limit Register */
+#define XM_RT_LIM_MSK	0x1f	/* Bit  4..0:	Tx Retry Limit */
+
+
+/*	XM_TX_STIME	16 bit r/w	Transmit Slottime Register */
+#define XM_STIME_MSK	0x7f	/* Bit  6..0:	Tx Slottime bits */
+
+
+/*	XM_TX_IPG	16 bit r/w	Transmit Inter Packet Gap */
+#define XM_IPG_MSK		0xff	/* Bit  7..0:	IPG value bits */
+
+
+/*	XM_RX_CMD	16 bit r/w	Receive Command Register */
+enum {
+	XM_RX_LENERR_OK	= 1<<8,	/* Bit  8	don't set Rx Err bit for */
+				/*		inrange error packets */
+	XM_RX_BIG_PK_OK	= 1<<7,	/* Bit  7	don't set Rx Err bit for */
+				/*		jumbo packets */
+	XM_RX_IPG_CAP	= 1<<6,	/* Bit  6	repl. type field with IPG */
+	XM_RX_TP_MD	= 1<<5,	/* Bit  5:	Enable transparent Mode */
+	XM_RX_STRIP_FCS	= 1<<4,	/* Bit  4:	Enable FCS Stripping */
+	XM_RX_SELF_RX	= 1<<3,	/* Bit  3: 	Enable Rx of own packets */
+	XM_RX_SAM_LINE	= 1<<2,	/* Bit  2: (sc)	Start utilization calculation */
+	XM_RX_STRIP_PAD	= 1<<1,	/* Bit  1:	Strip pad bytes of Rx frames */
+	XM_RX_DIS_CEXT	= 1<<0,	/* Bit  0:	Disable carrier ext. check */
+};
+
+
+/*	XM_PHY_ADDR	16 bit r/w	PHY Address Register */
+#define XM_PHY_ADDR_SZ	0x1f	/* Bit  4..0:	PHY Address bits */
+
+
+/*	XM_GP_PORT	32 bit r/w	General Purpose Port Register */
+enum {
+	XM_GP_ANIP	= 1<<6,	/* Bit  6: (ro)	Auto-Neg. in progress */
+	XM_GP_FRC_INT	= 1<<5,	/* Bit  5: (sc)	Force Interrupt */
+	XM_GP_RES_MAC	= 1<<3,	/* Bit  3: (sc)	Reset MAC and FIFOs */
+	XM_GP_RES_STAT	= 1<<2,	/* Bit  2: (sc)	Reset the statistics module */
+	XM_GP_INP_ASS	= 1<<0,	/* Bit  0: (ro) GP Input Pin asserted */
+};
+
+
+/*	XM_IMSK		16 bit r/w	Interrupt Mask Register */
+/*	XM_ISRC		16 bit r/o	Interrupt Status Register */
+enum {
+	XM_IS_LNK_AE	= 1<<14, /* Bit 14:	Link Asynchronous Event */
+	XM_IS_TX_ABORT	= 1<<13, /* Bit 13:	Transmit Abort, late Col. etc */
+	XM_IS_FRC_INT	= 1<<12, /* Bit 12:	Force INT bit set in GP */
+	XM_IS_INP_ASS	= 1<<11,	/* Bit 11:	Input Asserted, GP bit 0 set */
+	XM_IS_LIPA_RC	= 1<<10,	/* Bit 10:	Link Partner requests config */
+	XM_IS_RX_PAGE	= 1<<9,	/* Bit  9:	Page Received */
+	XM_IS_TX_PAGE	= 1<<8,	/* Bit  8:	Next Page Loaded for Transmit */
+	XM_IS_AND	= 1<<7,	/* Bit  7:	Auto-Negotiation Done */
+	XM_IS_TSC_OV	= 1<<6,	/* Bit  6:	Time Stamp Counter Overflow */
+	XM_IS_RXC_OV	= 1<<5,	/* Bit  5:	Rx Counter Event Overflow */
+	XM_IS_TXC_OV	= 1<<4,	/* Bit  4:	Tx Counter Event Overflow */
+	XM_IS_RXF_OV	= 1<<3,	/* Bit  3:	Receive FIFO Overflow */
+	XM_IS_TXF_UR	= 1<<2,	/* Bit  2:	Transmit FIFO Underrun */
+	XM_IS_TX_COMP	= 1<<1,	/* Bit  1:	Frame Tx Complete */
+	XM_IS_RX_COMP	= 1<<0,	/* Bit  0:	Frame Rx Complete */
+};
+
+#define XM_DEF_MSK	(~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | \
+			   XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | \
+			   XM_IS_RXF_OV | XM_IS_TXF_UR))
+
+
+/*	XM_HW_CFG	16 bit r/w	Hardware Config Register */
+enum {
+	XM_HW_GEN_EOP	= 1<<3,	/* Bit  3:	generate End of Packet pulse */
+	XM_HW_COM4SIG	= 1<<2,	/* Bit  2:	use Comma Detect for Sig. Det.*/
+	XM_HW_GMII_MD	= 1<<0,	/* Bit  0:	GMII Interface selected */
+};
+
+
+/*	XM_TX_LO_WM	16 bit r/w	Tx FIFO Low Water Mark */
+/*	XM_TX_HI_WM	16 bit r/w	Tx FIFO High Water Mark */
+#define XM_TX_WM_MSK	0x01ff	/* Bit  9.. 0	Tx FIFO Watermark bits */
+
+/*	XM_TX_THR	16 bit r/w	Tx Request Threshold */
+/*	XM_HT_THR	16 bit r/w	Host Request Threshold */
+/*	XM_RX_THR	16 bit r/w	Rx Request Threshold */
+#define XM_THR_MSK		0x03ff	/* Bit 10.. 0	Rx/Tx Request Threshold bits */
+
+
+/*	XM_TX_STAT	32 bit r/o	Tx Status LIFO Register */
+enum {
+	XM_ST_VALID	= (1UL<<31),	/* Bit 31:	Status Valid */
+	XM_ST_BYTE_CNT	= (0x3fffL<<17),	/* Bit 30..17:	Tx frame Length */
+	XM_ST_RETRY_CNT	= (0x1fL<<12),	/* Bit 16..12:	Retry Count */
+	XM_ST_EX_COL	= 1<<11,	/* Bit 11:	Excessive Collisions */
+	XM_ST_EX_DEF	= 1<<10,	/* Bit 10:	Excessive Deferral */
+	XM_ST_BURST	= 1<<9,		/* Bit  9:	p. xmitted in burst md*/
+	XM_ST_DEFER	= 1<<8,		/* Bit  8:	packet was defered */
+	XM_ST_BC	= 1<<7,		/* Bit  7:	Broadcast packet */
+	XM_ST_MC	= 1<<6,		/* Bit  6:	Multicast packet */
+	XM_ST_UC	= 1<<5,		/* Bit  5:	Unicast packet */
+	XM_ST_TX_UR	= 1<<4,		/* Bit  4:	FIFO Underrun occured */
+	XM_ST_CS_ERR	= 1<<3,		/* Bit  3:	Carrier Sense Error */
+	XM_ST_LAT_COL	= 1<<2,		/* Bit  2:	Late Collision Error */
+	XM_ST_MUL_COL	= 1<<1,		/* Bit  1:	Multiple Collisions */
+	XM_ST_SGN_COL	= 1<<0,		/* Bit  0:	Single Collision */
+};
+
+/*	XM_RX_LO_WM	16 bit r/w	Receive Low Water Mark */
+/*	XM_RX_HI_WM	16 bit r/w	Receive High Water Mark */
+#define XM_RX_WM_MSK	0x03ff		/* Bit 11.. 0:	Rx FIFO Watermark bits */
+
+
+/*	XM_DEV_ID	32 bit r/o	Device ID Register */
+#define XM_DEV_OUI	(0x00ffffffUL<<8)	/* Bit 31..8:	Device OUI */
+#define XM_DEV_REV	(0x07L << 5)		/* Bit  7..5:	Chip Rev Num */
+
+
+/*	XM_MODE		32 bit r/w	Mode Register */
+enum {
+	XM_MD_ENA_REJ	= 1<<26, /* Bit 26:	Enable Frame Reject */
+	XM_MD_SPOE_E	= 1<<25, /* Bit 25:	Send Pause on Edge */
+									/* 		extern generated */
+	XM_MD_TX_REP	= 1<<24, /* Bit 24:	Transmit Repeater Mode */
+	XM_MD_SPOFF_I	= 1<<23, /* Bit 23:	Send Pause on FIFO full */
+									/*		intern generated */
+	XM_MD_LE_STW	= 1<<22, /* Bit 22:	Rx Stat Word in Little Endian */
+	XM_MD_TX_CONT	= 1<<21, /* Bit 21:	Send Continuous */
+	XM_MD_TX_PAUSE	= 1<<20, /* Bit 20: (sc)	Send Pause Frame */
+	XM_MD_ATS	= 1<<19, /* Bit 19:	Append Time Stamp */
+	XM_MD_SPOL_I	= 1<<18, /* Bit 18:	Send Pause on Low */
+									/*		intern generated */
+	XM_MD_SPOH_I	= 1<<17, /* Bit 17:	Send Pause on High */
+									/*		intern generated */
+	XM_MD_CAP	= 1<<16, /* Bit 16:	Check Address Pair */
+	XM_MD_ENA_HASH	= 1<<15, /* Bit 15:	Enable Hashing */
+	XM_MD_CSA	= 1<<14, /* Bit 14:	Check Station Address */
+	XM_MD_CAA	= 1<<13, /* Bit 13:	Check Address Array */
+	XM_MD_RX_MCTRL	= 1<<12, /* Bit 12:	Rx MAC Control Frame */
+	XM_MD_RX_RUNT	= 1<<11, /* Bit 11:	Rx Runt Frames */
+	XM_MD_RX_IRLE	= 1<<10, /* Bit 10:	Rx in Range Len Err Frame */
+	XM_MD_RX_LONG	= 1<<9,  /* Bit  9:	Rx Long Frame */
+	XM_MD_RX_CRCE	= 1<<8,  /* Bit  8:	Rx CRC Error Frame */
+	XM_MD_RX_ERR	= 1<<7,  /* Bit  7:	Rx Error Frame */
+	XM_MD_DIS_UC	= 1<<6,  /* Bit  6:	Disable Rx Unicast */
+	XM_MD_DIS_MC	= 1<<5,  /* Bit  5:	Disable Rx Multicast */
+	XM_MD_DIS_BC	= 1<<4,  /* Bit  4:	Disable Rx Broadcast */
+	XM_MD_ENA_PROM	= 1<<3,  /* Bit  3:	Enable Promiscuous */
+	XM_MD_ENA_BE	= 1<<2,  /* Bit  2:	Enable Big Endian */
+	XM_MD_FTF	= 1<<1,  /* Bit  1: (sc)	Flush Tx FIFO */
+	XM_MD_FRF	= 1<<0,  /* Bit  0: (sc)	Flush Rx FIFO */
+};
+
+#define XM_PAUSE_MODE	(XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
+#define XM_DEF_MODE		(XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+				XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA)
+
+/*	XM_STAT_CMD	16 bit r/w	Statistics Command Register */
+enum {
+	XM_SC_SNP_RXC	= 1<<5,	/* Bit  5: (sc)	Snap Rx Counters */
+	XM_SC_SNP_TXC	= 1<<4,	/* Bit  4: (sc)	Snap Tx Counters */
+	XM_SC_CP_RXC	= 1<<3,	/* Bit  3: 	Copy Rx Counters Continuously */
+	XM_SC_CP_TXC	= 1<<2,	/* Bit  2:	Copy Tx Counters Continuously */
+	XM_SC_CLR_RXC	= 1<<1,	/* Bit  1: (sc)	Clear Rx Counters */
+	XM_SC_CLR_TXC	= 1<<0,	/* Bit  0: (sc) Clear Tx Counters */
+};
+
+
+/*	XM_RX_CNT_EV	32 bit r/o	Rx Counter Event Register */
+/*	XM_RX_EV_MSK	32 bit r/w	Rx Counter Event Mask */
+enum {
+	XMR_MAX_SZ_OV	= 1<<31, /* Bit 31:	1024-MaxSize Rx Cnt Ov*/
+	XMR_1023B_OV	= 1<<30, /* Bit 30:	512-1023Byte Rx Cnt Ov*/
+	XMR_511B_OV	= 1<<29, /* Bit 29:	256-511 Byte Rx Cnt Ov*/
+	XMR_255B_OV	= 1<<28, /* Bit 28:	128-255 Byte Rx Cnt Ov*/
+	XMR_127B_OV	= 1<<27, /* Bit 27:	65-127 Byte Rx Cnt Ov */
+	XMR_64B_OV	= 1<<26, /* Bit 26:	64 Byte Rx Cnt Ov */
+	XMR_UTIL_OV	= 1<<25, /* Bit 25:	Rx Util Cnt Overflow */
+	XMR_UTIL_UR	= 1<<24, /* Bit 24:	Rx Util Cnt Underrun */
+	XMR_CEX_ERR_OV	= 1<<23, /* Bit 23:	CEXT Err Cnt Ov */
+	XMR_FCS_ERR_OV	= 1<<21, /* Bit 21:	Rx FCS Error Cnt Ov */
+	XMR_LNG_ERR_OV	= 1<<20, /* Bit 20:	Rx too Long Err Cnt Ov*/
+	XMR_RUNT_OV	= 1<<19, /* Bit 19:	Runt Event Cnt Ov */
+	XMR_SHT_ERR_OV	= 1<<18, /* Bit 18:	Rx Short Ev Err Cnt Ov*/
+	XMR_SYM_ERR_OV	= 1<<17, /* Bit 17:	Rx Sym Err Cnt Ov */
+	XMR_CAR_ERR_OV	= 1<<15, /* Bit 15:	Rx Carr Ev Err Cnt Ov */
+	XMR_JAB_PKT_OV	= 1<<14, /* Bit 14:	Rx Jabb Packet Cnt Ov */
+	XMR_FIFO_OV	= 1<<13, /* Bit 13:	Rx FIFO Ov Ev Cnt Ov */
+	XMR_FRA_ERR_OV	= 1<<12, /* Bit 12:	Rx Framing Err Cnt Ov */
+	XMR_FMISS_OV	= 1<<11, /* Bit 11:	Rx Missed Ev Cnt Ov */
+	XMR_BURST	= 1<<10, /* Bit 10:	Rx Burst Event Cnt Ov */
+	XMR_INV_MOC	= 1<<9,  /* Bit  9:	Rx with inv. MAC OC Ov*/
+	XMR_INV_MP	= 1<<8,  /* Bit  8:	Rx inv Pause Frame Ov */
+	XMR_MCTRL_OV	= 1<<7,  /* Bit  7:	Rx MAC Ctrl-F Cnt Ov */
+	XMR_MPAUSE_OV	= 1<<6,  /* Bit  6:	Rx Pause MAC Ctrl-F Ov*/
+	XMR_UC_OK_OV	= 1<<5,  /* Bit  5:	Rx Unicast Frame CntOv*/
+	XMR_MC_OK_OV	= 1<<4,  /* Bit  4:	Rx Multicast Cnt Ov */
+	XMR_BC_OK_OV	= 1<<3,  /* Bit  3:	Rx Broadcast Cnt Ov */
+	XMR_OK_LO_OV	= 1<<2,  /* Bit  2:	Octets Rx OK Low CntOv*/
+	XMR_OK_HI_OV	= 1<<1,  /* Bit  1:	Octets Rx OK Hi Cnt Ov*/
+	XMR_OK_OV	= 1<<0,  /* Bit  0:	Frames Received Ok Ov */
+};
+
+#define XMR_DEF_MSK		(XMR_OK_LO_OV | XMR_OK_HI_OV)
+
+/*	XM_TX_CNT_EV	32 bit r/o	Tx Counter Event Register */
+/*	XM_TX_EV_MSK	32 bit r/w	Tx Counter Event Mask */
+enum {
+	XMT_MAX_SZ_OV	= 1<<25,	/* Bit 25:	1024-MaxSize Tx Cnt Ov*/
+	XMT_1023B_OV	= 1<<24,	/* Bit 24:	512-1023Byte Tx Cnt Ov*/
+	XMT_511B_OV	= 1<<23,	/* Bit 23:	256-511 Byte Tx Cnt Ov*/
+	XMT_255B_OV	= 1<<22,	/* Bit 22:	128-255 Byte Tx Cnt Ov*/
+	XMT_127B_OV	= 1<<21,	/* Bit 21:	65-127 Byte Tx Cnt Ov */
+	XMT_64B_OV	= 1<<20,	/* Bit 20:	64 Byte Tx Cnt Ov */
+	XMT_UTIL_OV	= 1<<19,	/* Bit 19:	Tx Util Cnt Overflow */
+	XMT_UTIL_UR	= 1<<18,	/* Bit 18:	Tx Util Cnt Underrun */
+	XMT_CS_ERR_OV	= 1<<17,	/* Bit 17:	Tx Carr Sen Err Cnt Ov*/
+	XMT_FIFO_UR_OV	= 1<<16,	/* Bit 16:	Tx FIFO Ur Ev Cnt Ov */
+	XMT_EX_DEF_OV	= 1<<15,	/* Bit 15:	Tx Ex Deferall Cnt Ov */
+	XMT_DEF	= 1<<14,	/* Bit 14:	Tx Deferred Cnt Ov */
+	XMT_LAT_COL_OV	= 1<<13,	/* Bit 13:	Tx Late Col Cnt Ov */
+	XMT_ABO_COL_OV	= 1<<12,	/* Bit 12:	Tx abo dueto Ex Col Ov*/
+	XMT_MUL_COL_OV	= 1<<11,	/* Bit 11:	Tx Mult Col Cnt Ov */
+	XMT_SNG_COL	= 1<<10,	/* Bit 10:	Tx Single Col Cnt Ov */
+	XMT_MCTRL_OV	= 1<<9,		/* Bit  9:	Tx MAC Ctrl Counter Ov*/
+	XMT_MPAUSE	= 1<<8,		/* Bit  8:	Tx Pause MAC Ctrl-F Ov*/
+	XMT_BURST	= 1<<7,		/* Bit  7:	Tx Burst Event Cnt Ov */
+	XMT_LONG	= 1<<6,		/* Bit  6:	Tx Long Frame Cnt Ov */
+	XMT_UC_OK_OV	= 1<<5,		/* Bit  5:	Tx Unicast Cnt Ov */
+	XMT_MC_OK_OV	= 1<<4,		/* Bit  4:	Tx Multicast Cnt Ov */
+	XMT_BC_OK_OV	= 1<<3,		/* Bit  3:	Tx Broadcast Cnt Ov */
+	XMT_OK_LO_OV	= 1<<2,		/* Bit  2:	Octets Tx OK Low CntOv*/
+	XMT_OK_HI_OV	= 1<<1,		/* Bit  1:	Octets Tx OK Hi Cnt Ov*/
+	XMT_OK_OV	= 1<<0,		/* Bit  0:	Frames Tx Ok Ov */
+};
+
+#define XMT_DEF_MSK		(XMT_OK_LO_OV | XMT_OK_HI_OV)
+
+struct skge_rx_desc {
+	u32		control;
+	u32		next_offset;
+	u32		dma_lo;
+	u32		dma_hi;
+	u32		status;
+	u32		timestamp;
+	u16		csum2;
+	u16		csum1;
+	u16		csum2_start;
+	u16		csum1_start;
+};
+
+struct skge_tx_desc {
+	u32		control;
+	u32		next_offset;
+	u32		dma_lo;
+	u32		dma_hi;
+	u32		status;
+	u32		csum_offs;
+	u16		csum_write;
+	u16		csum_start;
+	u32		rsvd;
+};
+
+struct skge_element {
+	struct skge_element	*next;
+	void			*desc;
+	struct sk_buff  	*skb;
+	DECLARE_PCI_UNMAP_ADDR(mapaddr);
+	DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
+struct skge_ring {
+	struct skge_element *to_clean;
+	struct skge_element *to_use;
+	struct skge_element *start;
+	unsigned long	    count;
+};
+
+
+struct skge_hw {
+	void __iomem  	     *regs;
+	struct pci_dev	     *pdev;
+	u32		     intr_mask;
+	struct net_device    *dev[2];
+
+	u8		     mac_cfg;
+	u8	     	     chip_id;
+	u8		     phy_type;
+	u8		     pmd_type;
+	u16		     phy_addr;
+
+	u32	     	     ram_size;
+	u32	     	     ram_offset;
+	
+	struct tasklet_struct ext_tasklet;
+	spinlock_t	     phy_lock;
+};
+
+static inline int isdualport(const struct skge_hw *hw)
+{
+	return !(hw->mac_cfg & CFG_SNG_MAC);
+}
+
+static inline u8 chip_rev(const struct skge_hw *hw)
+{
+	return (hw->mac_cfg & CFG_CHIP_R_MSK) >> 4;
+}
+
+static inline int iscopper(const struct skge_hw *hw)
+{
+	return (hw->pmd_type == 'T');
+}
+
+enum {
+	FLOW_MODE_NONE 		= 0, /* No Flow-Control */
+	FLOW_MODE_LOC_SEND	= 1, /* Local station sends PAUSE */
+	FLOW_MODE_REM_SEND	= 2, /* Symmetric or just remote */
+	FLOW_MODE_SYMMETRIC	= 3, /* Both stations may send PAUSE */
+};
+	
+struct skge_port {
+	u32		     msg_enable;
+	struct skge_hw	     *hw;
+	struct net_device    *netdev;
+	int		     port;
+
+	spinlock_t	     tx_lock;
+	u32		     tx_avail;
+	struct skge_ring     tx_ring;
+	struct skge_ring     rx_ring;
+
+	struct net_device_stats net_stats;
+
+	u8		     rx_csum;
+	u8		     blink_on;
+	u8		     flow_control;
+	u8		     wol;
+	u8		     autoneg;	/* AUTONEG_ENABLE, AUTONEG_DISABLE */
+	u8		     duplex;	/* DUPLEX_HALF, DUPLEX_FULL */
+	u16		     speed;	/* SPEED_1000, SPEED_100, ... */
+	u32		     advertising;
+
+	void		     *mem;	/* PCI memory for rings */
+	dma_addr_t	     dma;
+	unsigned long	     mem_size;
+
+	struct timer_list    link_check;
+	struct timer_list    led_blink;
+};
+
+
+/* Register accessor for memory mapped device */
+static inline u32 skge_read32(const struct skge_hw *hw, int reg)
+{
+	return readl(hw->regs + reg);
+
+}
+
+static inline u16 skge_read16(const struct skge_hw *hw, int reg)
+{
+	return readw(hw->regs + reg);
+}
+
+static inline u8 skge_read8(const struct skge_hw *hw, int reg)
+{
+	return readb(hw->regs + reg);
+}
+
+static inline void skge_write32(const struct skge_hw *hw, int reg, u32 val)
+{
+	writel(val, hw->regs + reg);
+}
+
+static inline void skge_write16(const struct skge_hw *hw, int reg, u16 val)
+{
+	writew(val, hw->regs + reg);
+}
+
+static inline void skge_write8(const struct skge_hw *hw, int reg, u8 val)
+{
+	writeb(val, hw->regs + reg);
+}
+
+/* MAC Related Registers inside the device. */
+#define SKGEMAC_REG(port,reg)	(((port)<<7)+(reg))
+
+/* PCI config space can be accessed via memory mapped space */
+#define SKGEPCI_REG(reg) ((reg)+ 0x380)
+
+#define SKGEXM_REG(port, reg) \
+	((BASE_XMAC_1 + (port) * (BASE_XMAC_2 - BASE_XMAC_1)) | (reg) << 1)
+
+static inline u32 skge_xm_read32(const struct skge_hw *hw, int port, int reg)
+{
+	return skge_read32(hw, SKGEXM_REG(port,reg));
+}
+
+static inline u16 skge_xm_read16(const struct skge_hw *hw, int port, int reg)
+{
+	return skge_read16(hw, SKGEXM_REG(port,reg));
+}
+
+static inline u8 skge_xm_read8(const struct skge_hw *hw, int port, int reg)
+{
+	return skge_read8(hw, SKGEXM_REG(port,reg));
+}
+
+static inline void skge_xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
+{
+	skge_write32(hw, SKGEXM_REG(port,r), v);
+}
+
+static inline void skge_xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
+{
+	skge_write16(hw, SKGEXM_REG(port,r), v);
+}
+
+static inline void skge_xm_write8(const struct skge_hw *hw, int port, int r, u8 v)
+{
+	skge_write8(hw, SKGEXM_REG(port,r), v);
+}
+
+static inline void skge_xm_outhash(const struct skge_hw *hw, int port, int reg,
+				   const u8 *hash)
+{
+	skge_xm_write16(hw, port, reg, 
+			(u16)hash[0] | ((u16)hash[1] << 8));
+	skge_xm_write16(hw, port, reg+2, 
+			(u16)hash[2] | ((u16)hash[3] << 8));
+	skge_xm_write16(hw, port, reg+4, 
+			(u16)hash[4] | ((u16)hash[5] << 8));
+	skge_xm_write16(hw, port, reg+6, 
+			(u16)hash[6] | ((u16)hash[7] << 8));
+}
+
+static inline void skge_xm_outaddr(const struct skge_hw *hw, int port, int reg,
+				   const u8 *addr)
+{
+	skge_xm_write16(hw, port, reg, 
+			(u16)addr[0] | ((u16)addr[1] << 8));
+	skge_xm_write16(hw, port, reg, 
+			(u16)addr[2] | ((u16)addr[3] << 8));
+	skge_xm_write16(hw, port, reg, 
+			(u16)addr[4] | ((u16)addr[5] << 8));
+}
+
+
+#define SKGEGMA_REG(port,reg) \
+	((reg) + BASE_GMAC_1 + \
+	 (port) * (BASE_GMAC_2-BASE_GMAC_1))
+
+static inline u16 skge_gma_read16(const struct skge_hw *hw, int port, int reg)
+{
+	return skge_read16(hw, SKGEGMA_REG(port,reg));
+}
+
+static inline u32 skge_gma_read32(const struct skge_hw *hw, int port, int reg)
+{
+	return (u32) skge_read16(hw, SKGEGMA_REG(port,reg))
+		| ((u32)skge_read16(hw, SKGEGMA_REG(port,reg+4)) << 16);
+}
+
+static inline u8 skge_gma_read8(const struct skge_hw *hw, int port, int reg)
+{
+	return skge_read8(hw, SKGEGMA_REG(port,reg));
+}
+
+static inline void skge_gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
+{
+	skge_write16(hw, SKGEGMA_REG(port,r), v);
+}
+
+static inline void skge_gma_write32(const struct skge_hw *hw, int port, int r, u32 v)
+{
+	skge_write16(hw, SKGEGMA_REG(port, r), (u16) v);
+	skge_write32(hw, SKGEGMA_REG(port, r+4), (u16)(v >> 16));
+}
+
+static inline void skge_gma_write8(const struct skge_hw *hw, int port, int r, u8 v)
+{
+	skge_write8(hw, SKGEGMA_REG(port,r), v);
+}
+
+static inline void skge_gm_set_addr(struct skge_hw *hw, int port, int reg,
+				    const u8 *addr)
+{
+	skge_gma_write16(hw, port, reg,
+			 (u16) addr[0] | ((u16) addr[1] << 8));
+	skge_gma_write16(hw, port, reg+4,
+			 (u16) addr[2] | ((u16) addr[3] << 8));
+	skge_gma_write16(hw, port, reg+8,
+			 (u16) addr[4] | ((u16) addr[5] << 8));
+}
+		
+#endif

+ 33 - 25
drivers/net/smc91x.c

@@ -129,7 +129,7 @@ MODULE_PARM_DESC(nowait, "set to 1 for no wait state");
 /*
  * Transmit timeout, default 5 seconds.
  */
-static int watchdog = 5000;
+static int watchdog = 1000;
 module_param(watchdog, int, 0400);
 MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
 
@@ -660,15 +660,14 @@ static void smc_hardware_send_pkt(unsigned long data)
 	SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG);
 
 	/*
-	 * If THROTTLE_TX_PKTS is set, we look at the TX_EMPTY flag
-	 * before queueing this packet for TX, and if it's clear then
-	 * we stop the queue here.  This will have the effect of
-	 * having at most 2 packets queued for TX in the chip's memory
-	 * at all time. If THROTTLE_TX_PKTS is not set then the queue
-	 * is stopped only when memory allocation (MC_ALLOC) does not
-	 * succeed right away.
+	 * If THROTTLE_TX_PKTS is set, we stop the queue here. This will
+	 * have the effect of having at most one packet queued for TX
+	 * in the chip's memory at all time.
+	 *
+	 * If THROTTLE_TX_PKTS is not set then the queue is stopped only
+	 * when memory allocation (MC_ALLOC) does not succeed right away.
 	 */
-	if (THROTTLE_TX_PKTS && !(SMC_GET_INT() & IM_TX_EMPTY_INT))
+	if (THROTTLE_TX_PKTS)
 		netif_stop_queue(dev);
 
 	/* queue the packet for TX */
@@ -792,17 +791,20 @@ static void smc_tx(struct net_device *dev)
 	DBG(2, "%s: TX STATUS 0x%04x PNR 0x%02x\n",
 		dev->name, tx_status, packet_no);
 
-	if (!(tx_status & TS_SUCCESS))
+	if (!(tx_status & ES_TX_SUC))
 		lp->stats.tx_errors++;
-	if (tx_status & TS_LOSTCAR)
+
+	if (tx_status & ES_LOSTCARR)
 		lp->stats.tx_carrier_errors++;
 
-	if (tx_status & TS_LATCOL) {
-		PRINTK("%s: late collision occurred on last xmit\n", dev->name);
+	if (tx_status & (ES_LATCOL | ES_16COL)) {
+		PRINTK("%s: %s occurred on last xmit\n", dev->name,
+		       (tx_status & ES_LATCOL) ?
+			"late collision" : "too many collisions");
 		lp->stats.tx_window_errors++;
 		if (!(lp->stats.tx_window_errors & 63) && net_ratelimit()) {
-			printk(KERN_INFO "%s: unexpectedly large numbers of "
-			       "late collisions. Please check duplex "
+			printk(KERN_INFO "%s: unexpectedly large number of "
+			       "bad collisions. Please check duplex "
 			       "setting.\n", dev->name);
 		}
 	}
@@ -1236,7 +1238,7 @@ static void smc_10bt_check_media(struct net_device *dev, int init)
 	old_carrier = netif_carrier_ok(dev) ? 1 : 0;
 
 	SMC_SELECT_BANK(0);
-	new_carrier = SMC_inw(ioaddr, EPH_STATUS_REG) & ES_LINK_OK ? 1 : 0;
+	new_carrier = (SMC_GET_EPH_STATUS() & ES_LINK_OK) ? 1 : 0;
 	SMC_SELECT_BANK(2);
 
 	if (init || (old_carrier != new_carrier)) {
@@ -1308,15 +1310,16 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 		if (!status)
 			break;
 
-		if (status & IM_RCV_INT) {
-			DBG(3, "%s: RX irq\n", dev->name);
-			smc_rcv(dev);
-		} else if (status & IM_TX_INT) {
+		if (status & IM_TX_INT) {
+			/* do this before RX as it will free memory quickly */
 			DBG(3, "%s: TX int\n", dev->name);
 			smc_tx(dev);
 			SMC_ACK_INT(IM_TX_INT);
 			if (THROTTLE_TX_PKTS)
 				netif_wake_queue(dev);
+		} else if (status & IM_RCV_INT) {
+			DBG(3, "%s: RX irq\n", dev->name);
+			smc_rcv(dev);
 		} else if (status & IM_ALLOC_INT) {
 			DBG(3, "%s: Allocation irq\n", dev->name);
 			tasklet_hi_schedule(&lp->tx_task);
@@ -1337,7 +1340,10 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 			/* multiple collisions */
 			lp->stats.collisions += card_stats & 0xF;
 		} else if (status & IM_RX_OVRN_INT) {
-			DBG(1, "%s: RX overrun\n", dev->name);
+			DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name,
+			       ({ int eph_st; SMC_SELECT_BANK(0);
+				  eph_st = SMC_GET_EPH_STATUS();
+				  SMC_SELECT_BANK(2); eph_st; }) );
 			SMC_ACK_INT(IM_RX_OVRN_INT);
 			lp->stats.rx_errors++;
 			lp->stats.rx_fifo_errors++;
@@ -1389,7 +1395,7 @@ static void smc_timeout(struct net_device *dev)
 {
 	struct smc_local *lp = netdev_priv(dev);
 	void __iomem *ioaddr = lp->base;
-	int status, mask, meminfo, fifo;
+	int status, mask, eph_st, meminfo, fifo;
 
 	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
 
@@ -1398,11 +1404,13 @@ static void smc_timeout(struct net_device *dev)
 	mask = SMC_GET_INT_MASK();
 	fifo = SMC_GET_FIFO();
 	SMC_SELECT_BANK(0);
+	eph_st = SMC_GET_EPH_STATUS();
 	meminfo = SMC_GET_MIR();
 	SMC_SELECT_BANK(2);
 	spin_unlock_irq(&lp->lock);
-	PRINTK( "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",
-		dev->name, status, mask, meminfo, fifo );
+	PRINTK( "%s: TX timeout (INT 0x%02x INTMASK 0x%02x "
+		"MEM 0x%04x FIFO 0x%04x EPH_ST 0x%04x)\n",
+		dev->name, status, mask, meminfo, fifo, eph_st );
 
 	smc_reset(dev);
 	smc_enable(dev);
@@ -1863,7 +1871,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
 	SMC_SELECT_BANK(1);
 	val = SMC_GET_BASE();
 	val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;
-	if (((unsigned long)ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val) { /*XXX: WTF? */
+	if (((unsigned int)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) {
 		printk("%s: IOADDR %p doesn't match configuration (%x).\n",
 			CARDNAME, ioaddr, val);
 	}

+ 4 - 11
drivers/net/smc91x.h

@@ -151,7 +151,7 @@
 
 /* We actually can't write halfwords properly if not word aligned */
 static inline void
-SMC_outw(u16 val, unsigned long ioaddr, int reg)
+SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 {
 	if (reg & 2) {
 		unsigned int v = val << 16;
@@ -317,7 +317,7 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l)
 #define SMC_insl(a, r, p, l) \
 	smc_pxa_dma_insl(a, lp->physaddr, r, dev->dma, p, l)
 static inline void
-smc_pxa_dma_insl(u_long ioaddr, u_long physaddr, int reg, int dma,
+smc_pxa_dma_insl(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
 		 u_char *buf, int len)
 {
 	dma_addr_t dmabuf;
@@ -355,7 +355,7 @@ smc_pxa_dma_insl(u_long ioaddr, u_long physaddr, int reg, int dma,
 #define SMC_insw(a, r, p, l) \
 	smc_pxa_dma_insw(a, lp->physaddr, r, dev->dma, p, l)
 static inline void
-smc_pxa_dma_insw(u_long ioaddr, u_long physaddr, int reg, int dma,
+smc_pxa_dma_insw(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
 		 u_char *buf, int len)
 {
 	dma_addr_t dmabuf;
@@ -680,14 +680,6 @@ static const char * chip_ids[ 16 ] =  {
 	NULL, NULL, NULL};
 
 
-/*
- . Transmit status bits
-*/
-#define TS_SUCCESS 0x0001
-#define TS_LOSTCAR 0x0400
-#define TS_LATCOL  0x0200
-#define TS_16COL   0x0010
-
 /*
  . Receive status bits
 */
@@ -845,6 +837,7 @@ static const char * chip_ids[ 16 ] =  {
 #define SMC_GET_FIFO()		SMC_inw( ioaddr, FIFO_REG )
 #define SMC_GET_PTR()		SMC_inw( ioaddr, PTR_REG )
 #define SMC_SET_PTR(x)		SMC_outw( x, ioaddr, PTR_REG )
+#define SMC_GET_EPH_STATUS()	SMC_inw( ioaddr, EPH_STATUS_REG )
 #define SMC_GET_RCR()		SMC_inw( ioaddr, RCR_REG )
 #define SMC_SET_RCR(x)		SMC_outw( x, ioaddr, RCR_REG )
 #define SMC_GET_REV()		SMC_inw( ioaddr, REV_REG )

+ 40 - 102
drivers/net/starfire.c

@@ -2,7 +2,7 @@
 /*
 	Written 1998-2000 by Donald Becker.
 
-	Current maintainer is Ion Badulescu <ionut@cs.columbia.edu>. Please
+	Current maintainer is Ion Badulescu <ionut ta badula tod org>. Please
 	send all bug reports to me, and not to Donald Becker, as this code
 	has been heavily modified from Donald's original version.
 
@@ -129,12 +129,18 @@
 	- put the chip to a D3 slumber on driver unload
 	- added config option to enable/disable NAPI
 
-TODO:	bugfixes (no bugs known as of right now)
+	LK1.4.2 (Ion Badulescu)
+	- finally added firmware (GPL'ed by Adaptec)
+	- removed compatibility code for 2.2.x
+
+TODO:	- fix forced speed/duplexing code (broken a long time ago, when
+	somebody converted the driver to use the generic MII code)
+	- fix VLAN support
 */
 
 #define DRV_NAME	"starfire"
-#define DRV_VERSION	"1.03+LK1.4.1"
-#define DRV_RELDATE	"February 10, 2002"
+#define DRV_VERSION	"1.03+LK1.4.2"
+#define DRV_RELDATE	"January 19, 2005"
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -145,25 +151,15 @@ TODO:	bugfixes (no bugs known as of right now)
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-/*
- * Adaptec's license for their drivers (which is where I got the
- * firmware files) does not allow one to redistribute them. Thus, we can't
- * include the firmware with this driver.
- *
- * However, should a legal-to-distribute firmware become available,
- * the driver developer would need only to obtain the firmware in the
- * form of a C header file.
- * Once that's done, the #undef below must be changed into a #define
- * for this driver to really use the firmware. Note that Rx/Tx
- * hardware TCP checksumming is not possible without the firmware.
- *
- * WANTED: legal firmware to include with this GPL'd driver.
- */
-#undef HAS_FIRMWARE
+#include "starfire_firmware.h"
 /*
  * The current frame processor firmware fails to checksum a fragment
  * of length 1. If and when this is fixed, the #define below can be removed.
@@ -172,13 +168,7 @@ TODO:	bugfixes (no bugs known as of right now)
 /*
  * Define this if using the driver with the zero-copy patch
  */
-#if defined(HAS_FIRMWARE) && defined(MAX_SKB_FRAGS)
 #define ZEROCOPY
-#endif
-
-#ifdef HAS_FIRMWARE
-#include "starfire_firmware.h"
-#endif /* HAS_FIRMWARE */
 
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define VLAN_SUPPORT
@@ -202,11 +192,7 @@ static int mtu;
    The Starfire has a 512 element hash table based on the Ethernet CRC. */
 static int multicast_filter_limit = 512;
 /* Whether to do TCP/UDP checksums in hardware */
-#ifdef HAS_FIRMWARE
 static int enable_hw_cksum = 1;
-#else
-static int enable_hw_cksum = 0;
-#endif
 
 #define PKT_BUF_SZ	1536		/* Size of each temporary Rx buffer.*/
 /*
@@ -291,43 +277,15 @@ static int full_duplex[MAX_UNITS] = {0, };
 #define RX_DESC_ADDR_SIZE RxDescAddr32bit
 #endif
 
-#ifdef MAX_SKB_FRAGS
 #define skb_first_frag_len(skb)	skb_headlen(skb)
 #define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1)
-#else  /* not MAX_SKB_FRAGS */
-#define skb_first_frag_len(skb)	(skb->len)
-#define skb_num_frags(skb) 1
-#endif /* not MAX_SKB_FRAGS */
-
-/* 2.2.x compatibility code */
-#if LINUX_VERSION_CODE < 0x20300
-
-#include "starfire-kcomp22.h"
-
-#else  /* LINUX_VERSION_CODE > 0x20300 */
-
-#include <linux/crc32.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-
-#include <linux/if_vlan.h>
-
-#define init_tx_timer(dev, func, timeout) \
-	dev->tx_timeout = func; \
-	dev->watchdog_timeo = timeout;
-#define kick_tx_timer(dev, func, timeout)
-
-#define netif_start_if(dev)
-#define netif_stop_if(dev)
-
-#define PCI_SLOT_NAME(pci_dev)	pci_name(pci_dev)
-
-#endif /* LINUX_VERSION_CODE > 0x20300 */
 
 #ifdef HAVE_NETDEV_POLL
 #define init_poll(dev) \
+do { \
 	dev->poll = &netdev_poll; \
-	dev->weight = max_interrupt_work;
+	dev->weight = max_interrupt_work; \
+} while (0)
 #define netdev_rx(dev, ioaddr) \
 do { \
 	u32 intr_enable; \
@@ -341,7 +299,7 @@ do { \
 		/* Paranoia check */ \
 		intr_enable = readl(ioaddr + IntrEnable); \
 		if (intr_enable & (IntrRxDone | IntrRxEmpty)) { \
-			printk("%s: interrupt while in polling mode!\n", dev->name); \
+			printk(KERN_INFO "%s: interrupt while in polling mode!\n", dev->name); \
 			intr_enable &= ~(IntrRxDone | IntrRxEmpty); \
 			writel(intr_enable, ioaddr + IntrEnable); \
 		} \
@@ -371,6 +329,7 @@ KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELD
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
 
 module_param(max_interrupt_work, int, 0);
 module_param(mtu, int, 0);
@@ -425,7 +384,7 @@ on the 32/64 bitness of the architecture), and relies on automatic
 minimum-length padding.  It does not use the completion queue
 consumer index, but instead checks for non-zero status entries.
 
-For receive this driver uses type 0/1/2/3 receive descriptors.  The driver
+For receive this driver uses type 2/3 receive descriptors.  The driver
 allocates full frame size skbuffs for the Rx ring buffers, so all frames
 should fit in a single descriptor.  The driver does not use the completion
 queue consumer index, but instead checks for non-zero status entries.
@@ -476,7 +435,7 @@ IVc. Errata
 
 */
 
-
+
 
 enum chip_capability_flags {CanHaveMII=1, };
 
@@ -670,7 +629,6 @@ struct full_rx_done_desc {
 	u32 timestamp;
 };
 /* XXX: this is ugly and I'm not sure it's worth the trouble -Ion */
-#ifdef HAS_FIRMWARE
 #ifdef VLAN_SUPPORT
 typedef struct full_rx_done_desc rx_done_desc;
 #define RxComplType RxComplType3
@@ -678,15 +636,6 @@ typedef struct full_rx_done_desc rx_done_desc;
 typedef struct csum_rx_done_desc rx_done_desc;
 #define RxComplType RxComplType2
 #endif /* not VLAN_SUPPORT */
-#else  /* not HAS_FIRMWARE */
-#ifdef VLAN_SUPPORT
-typedef struct basic_rx_done_desc rx_done_desc;
-#define RxComplType RxComplType1
-#else  /* not VLAN_SUPPORT */
-typedef struct short_rx_done_desc rx_done_desc;
-#define RxComplType RxComplType0
-#endif /* not VLAN_SUPPORT */
-#endif /* not HAS_FIRMWARE */
 
 enum rx_done_bits {
 	RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,
@@ -898,13 +847,10 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
 	/* enable MWI -- it vastly improves Rx performance on sparc64 */
 	pci_set_mwi(pdev);
 
-#ifdef MAX_SKB_FRAGS
-	dev->features |= NETIF_F_SG;
-#endif /* MAX_SKB_FRAGS */
 #ifdef ZEROCOPY
 	/* Starfire can do TCP/UDP checksumming */
 	if (enable_hw_cksum)
-		dev->features |= NETIF_F_IP_CSUM;
+		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
 #endif /* ZEROCOPY */
 #ifdef VLAN_SUPPORT
 	dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
@@ -1008,7 +954,8 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
 	dev->hard_start_xmit = &start_tx;
-	init_tx_timer(dev, tx_timeout, TX_TIMEOUT);
+	dev->tx_timeout = tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
 	init_poll(dev);
 	dev->stop = &netdev_close;
 	dev->get_stats = &get_stats;
@@ -1039,7 +986,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
 				if ((mdio_read(dev, phy, MII_BMCR) & BMCR_RESET) == 0)
 					break;
 			if (boguscnt == 0) {
-				printk("%s: PHY reset never completed!\n", dev->name);
+				printk("%s: PHY#%d reset never completed!\n", dev->name, phy);
 				continue;
 			}
 			mii_status = mdio_read(dev, phy, MII_BMSR);
@@ -1110,6 +1057,7 @@ static int netdev_open(struct net_device *dev)
 	size_t tx_done_q_size, rx_done_q_size, tx_ring_size, rx_ring_size;
 
 	/* Do we ever need to reset the chip??? */
+
 	retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
 	if (retval)
 		return retval;
@@ -1211,7 +1159,6 @@ static int netdev_open(struct net_device *dev)
 
 	writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl);
 
-	netif_start_if(dev);
 	netif_start_queue(dev);
 
 	if (debug > 1)
@@ -1238,13 +1185,11 @@ static int netdev_open(struct net_device *dev)
 	writel(ETH_P_8021Q, ioaddr + VlanType);
 #endif /* VLAN_SUPPORT */
 
-#ifdef HAS_FIRMWARE
 	/* Load Rx/Tx firmware into the frame processors */
 	for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++)
 		writel(firmware_rx[i], ioaddr + RxGfpMem + i * 4);
 	for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++)
 		writel(firmware_tx[i], ioaddr + TxGfpMem + i * 4);
-#endif /* HAS_FIRMWARE */
 	if (enable_hw_cksum)
 		/* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
 		writel(TxEnable|TxGFPEnable|RxEnable|RxGFPEnable, ioaddr + GenCtrl);
@@ -1378,8 +1323,6 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 	u32 status;
 	int i;
 
-	kick_tx_timer(dev, tx_timeout, TX_TIMEOUT);
-
 	/*
 	 * be cautious here, wrapping the queue has weird semantics
 	 * and we may not have enough slots even when it seems we do.
@@ -1404,7 +1347,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 		}
 
 		if (has_bad_length)
-			skb_checksum_help(skb);
+			skb_checksum_help(skb, 0);
 	}
 #endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
 
@@ -1433,12 +1376,10 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 			np->tx_info[entry].mapping =
 				pci_map_single(np->pci_dev, skb->data, skb_first_frag_len(skb), PCI_DMA_TODEVICE);
 		} else {
-#ifdef MAX_SKB_FRAGS
 			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[i - 1];
 			status |= this_frag->size;
 			np->tx_info[entry].mapping =
 				pci_map_single(np->pci_dev, page_address(this_frag->page) + this_frag->page_offset, this_frag->size, PCI_DMA_TODEVICE);
-#endif /* MAX_SKB_FRAGS */
 		}
 
 		np->tx_ring[entry].addr = cpu_to_dma(np->tx_info[entry].mapping);
@@ -1531,7 +1472,6 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
 				np->tx_info[entry].mapping = 0;
 				np->dirty_tx += np->tx_info[entry].used_slots;
 				entry = (entry + np->tx_info[entry].used_slots) % TX_RING_SIZE;
-#ifdef MAX_SKB_FRAGS
 				{
 					int i;
 					for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
@@ -1543,7 +1483,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
 						entry++;
 					}
 				}
-#endif /* MAX_SKB_FRAGS */
+
 				dev_kfree_skb_irq(skb);
 			}
 			np->tx_done_q[np->tx_done].status = 0;
@@ -1603,7 +1543,7 @@ static int __netdev_rx(struct net_device *dev, int *quota)
 		if (debug > 4)
 			printk(KERN_DEBUG "  netdev_rx() status of %d was %#8.8x.\n", np->rx_done, desc_status);
 		if (!(desc_status & RxOK)) {
-			/* There was a error. */
+			/* There was an error. */
 			if (debug > 2)
 				printk(KERN_DEBUG "  netdev_rx() Rx error was %#8.8x.\n", desc_status);
 			np->stats.rx_errors++;
@@ -1656,11 +1596,10 @@ static int __netdev_rx(struct net_device *dev, int *quota)
 #endif
 
 		skb->protocol = eth_type_trans(skb, dev);
-#if defined(HAS_FIRMWARE) || defined(VLAN_SUPPORT)
+#ifdef VLAN_SUPPORT
 		if (debug > 4)
 			printk(KERN_DEBUG "  netdev_rx() status2 of %d was %#4.4x.\n", np->rx_done, le16_to_cpu(desc->status2));
 #endif
-#ifdef HAS_FIRMWARE
 		if (le16_to_cpu(desc->status2) & 0x0100) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			np->stats.rx_compressed++;
@@ -1679,7 +1618,6 @@ static int __netdev_rx(struct net_device *dev, int *quota)
 			skb->csum = le16_to_cpu(desc->csum);
 			printk(KERN_DEBUG "%s: checksum_hw, status2 = %#x\n", dev->name, le16_to_cpu(desc->status2));
 		}
-#endif /* HAS_FIRMWARE */
 #ifdef VLAN_SUPPORT
 		if (np->vlgrp && le16_to_cpu(desc->status2) & 0x0200) {
 			if (debug > 4)
@@ -1900,9 +1838,6 @@ static struct net_device_stats *get_stats(struct net_device *dev)
 }
 
 
-/* Chips may use the upper or lower CRC bits, and may reverse and/or invert
-   them.  Select the endian-ness that results in minimal calculations.
-*/
 static void set_rx_mode(struct net_device *dev)
 {
 	struct netdev_private *np = netdev_priv(dev);
@@ -1969,6 +1904,8 @@ static void set_rx_mode(struct net_device *dev)
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 		     i++, mclist = mclist->next) {
+			/* The chip uses the upper 9 CRC bits
+			   as index into the hash table */
 			int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
 			__u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1];
 
@@ -2001,7 +1938,7 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 	struct netdev_private *np = netdev_priv(dev);
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, PCI_SLOT_NAME(np->pci_dev));
+	strcpy(info->bus_info, pci_name(np->pci_dev));
 }
 
 static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -2083,7 +2020,6 @@ static int netdev_close(struct net_device *dev)
 	int i;
 
 	netif_stop_queue(dev);
-	netif_stop_if(dev);
 
 	if (debug > 1) {
 		printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n",
@@ -2184,7 +2120,13 @@ static int __init starfire_init (void)
 /* when a module, this is printed whether or not devices are found in probe */
 #ifdef MODULE
 	printk(version);
+#ifdef HAVE_NETDEV_POLL
+	printk(KERN_INFO DRV_NAME ": polling (NAPI) enabled\n");
+#else
+	printk(KERN_INFO DRV_NAME ": polling (NAPI) disabled\n");
 #endif
+#endif
+
 #ifndef ADDR_64BITS
 	/* we can do this test only at run-time... sigh */
 	if (sizeof(dma_addr_t) == sizeof(u64)) {
@@ -2192,10 +2134,6 @@ static int __init starfire_init (void)
 		return -ENODEV;
 	}
 #endif /* not ADDR_64BITS */
-#ifndef HAS_FIRMWARE
-	/* unconditionally disable hw cksums if firmware is not present */
-	enable_hw_cksum = 0;
-#endif /* not HAS_FIRMWARE */
 	return pci_module_init (&starfire_driver);
 }
 

+ 346 - 0
drivers/net/starfire_firmware.h

@@ -0,0 +1,346 @@
+/*
+ * Copyright 2003 Adaptec, Inc.
+ *
+ * Please read the following license before using the Adaptec Software
+ * ("Program"). If you do not agree to the license terms, do not use the
+ * Program:
+ *
+ * You agree to be bound by version 2 of the General Public License ("GPL")
+ * dated June 1991, which can be found at http://www.fsf.org/licenses/gpl.html.
+ * If the link is broken, write to Free Software Foundation, 59 Temple Place,
+ * Boston, Massachusetts 02111-1307.
+ *
+ * BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE IT IS LICENSED "AS IS" AND
+ * THERE IS NO WARRANTY FOR THE PROGRAM, INCLUDING BUT NOT LIMITED TO THE
+ * IMPLIED WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * (TO THE EXTENT PERMITTED BY APPLICABLE LAW). USE OF THE PROGRAM IS AT YOUR
+ * OWN RISK. IN NO EVENT WILL ADAPTEC OR ITS LICENSORS BE LIABLE TO YOU FOR
+ * DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM.
+ *
+ */
+
+static const u32 firmware_rx[] = {
+  0x010003dc, 0x00000000,
+  0x04000421, 0x00000086,
+  0x80000015, 0x0000180e,
+  0x81000015, 0x00006664,
+  0x1a0040ab, 0x00000b06,
+  0x14200011, 0x00000000,
+  0x14204022, 0x0000aaaa,
+  0x14204022, 0x00000300,
+  0x14204022, 0x00000000,
+  0x1a0040ab, 0x00000b14,
+  0x14200011, 0x00000000,
+  0x83000015, 0x00000002,
+  0x04000021, 0x00000000,
+  0x00000010, 0x00000000,
+  0x04000421, 0x00000087,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00008015, 0x00000000,
+  0x0000003e, 0x00000000,
+  0x00000010, 0x00000000,
+  0x82000015, 0x00004000,
+  0x009e8050, 0x00000000,
+  0x03008015, 0x00000000,
+  0x86008015, 0x00000000,
+  0x82000015, 0x00008000,
+  0x0100001c, 0x00000000,
+  0x000050a0, 0x0000010c,
+  0x4e20d011, 0x00006008,
+  0x1420d012, 0x00004008,
+  0x0000f090, 0x00007000,
+  0x0000c8b0, 0x00003000,
+  0x00004040, 0x00000000,
+  0x00108015, 0x00000000,
+  0x00a2c150, 0x00004000,
+  0x00a400b0, 0x00000014,
+  0x00000020, 0x00000000,
+  0x2500400d, 0x00002525,
+  0x00047220, 0x00003100,
+  0x00934070, 0x00000000,
+  0x00000020, 0x00000000,
+  0x00924460, 0x00000184,
+  0x2b20c011, 0x00000000,
+  0x0000c420, 0x00000540,
+  0x36014018, 0x0000422d,
+  0x14200011, 0x00000000,
+  0x00924460, 0x00000183,
+  0x3200001f, 0x00000034,
+  0x02ac0015, 0x00000002,
+  0x00a60110, 0x00000008,
+  0x42200011, 0x00000000,
+  0x00924060, 0x00000103,
+  0x0000001e, 0x00000000,
+  0x00000020, 0x00000100,
+  0x0000001e, 0x00000000,
+  0x00924460, 0x00000086,
+  0x00004080, 0x00000000,
+  0x0092c070, 0x00000000,
+  0x00924060, 0x00000100,
+  0x0000c890, 0x00005000,
+  0x00a6c110, 0x00000000,
+  0x00b0c090, 0x00000012,
+  0x021c0015, 0x00000000,
+  0x3200001f, 0x00000034,
+  0x00924460, 0x00000510,
+  0x44210011, 0x00000000,
+  0x42000011, 0x00000000,
+  0x83000015, 0x00000040,
+  0x00924460, 0x00000508,
+  0x45014018, 0x00004545,
+  0x00808050, 0x00000000,
+  0x62208012, 0x00000000,
+  0x82000015, 0x00000800,
+  0x15200011, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x80000015, 0x0000eea4,
+  0x81000015, 0x0000005f,
+  0x00000060, 0x00000000,
+  0x00004120, 0x00000000,
+  0x00004a00, 0x00004000,
+  0x00924460, 0x00000190,
+  0x5601401a, 0x00005956,
+  0x14000011, 0x00000000,
+  0x00934050, 0x00000018,
+  0x00930050, 0x00000018,
+  0x3601403a, 0x0000002d,
+  0x000643a9, 0x00000000,
+  0x0000c420, 0x00000140,
+  0x5601401a, 0x00005956,
+  0x14000011, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x000642a9, 0x00000000,
+  0x00024420, 0x00000183,
+  0x5601401a, 0x00005956,
+  0x82000015, 0x00002000,
+  0x15200011, 0x00000000,
+  0x82000015, 0x00000010,
+  0x15200011, 0x00000000,
+  0x82000015, 0x00000010,
+  0x15200011, 0x00000000,
+};	/* 104 Rx instructions */
+#define FIRMWARE_RX_SIZE 104
+
+static const u32 firmware_tx[] = {
+  0x010003dc, 0x00000000,
+  0x04000421, 0x00000086,
+  0x80000015, 0x0000180e,
+  0x81000015, 0x00006664,
+  0x1a0040ab, 0x00000b06,
+  0x14200011, 0x00000000,
+  0x14204022, 0x0000aaaa,
+  0x14204022, 0x00000300,
+  0x14204022, 0x00000000,
+  0x1a0040ab, 0x00000b14,
+  0x14200011, 0x00000000,
+  0x83000015, 0x00000002,
+  0x04000021, 0x00000000,
+  0x00000010, 0x00000000,
+  0x04000421, 0x00000087,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00008015, 0x00000000,
+  0x0000003e, 0x00000000,
+  0x00000010, 0x00000000,
+  0x82000015, 0x00004000,
+  0x009e8050, 0x00000000,
+  0x03008015, 0x00000000,
+  0x86008015, 0x00000000,
+  0x82000015, 0x00008000,
+  0x0100001c, 0x00000000,
+  0x000050a0, 0x0000010c,
+  0x4e20d011, 0x00006008,
+  0x1420d012, 0x00004008,
+  0x0000f090, 0x00007000,
+  0x0000c8b0, 0x00003000,
+  0x00004040, 0x00000000,
+  0x00108015, 0x00000000,
+  0x00a2c150, 0x00004000,
+  0x00a400b0, 0x00000014,
+  0x00000020, 0x00000000,
+  0x2500400d, 0x00002525,
+  0x00047220, 0x00003100,
+  0x00934070, 0x00000000,
+  0x00000020, 0x00000000,
+  0x00924460, 0x00000184,
+  0x2b20c011, 0x00000000,
+  0x0000c420, 0x00000540,
+  0x36014018, 0x0000422d,
+  0x14200011, 0x00000000,
+  0x00924460, 0x00000183,
+  0x3200001f, 0x00000034,
+  0x02ac0015, 0x00000002,
+  0x00a60110, 0x00000008,
+  0x42200011, 0x00000000,
+  0x00924060, 0x00000103,
+  0x0000001e, 0x00000000,
+  0x00000020, 0x00000100,
+  0x0000001e, 0x00000000,
+  0x00924460, 0x00000086,
+  0x00004080, 0x00000000,
+  0x0092c070, 0x00000000,
+  0x00924060, 0x00000100,
+  0x0000c890, 0x00005000,
+  0x00a6c110, 0x00000000,
+  0x00b0c090, 0x00000012,
+  0x021c0015, 0x00000000,
+  0x3200001f, 0x00000034,
+  0x00924460, 0x00000510,
+  0x44210011, 0x00000000,
+  0x42000011, 0x00000000,
+  0x83000015, 0x00000040,
+  0x00924460, 0x00000508,
+  0x45014018, 0x00004545,
+  0x00808050, 0x00000000,
+  0x62208012, 0x00000000,
+  0x82000015, 0x00000800,
+  0x15200011, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x80000015, 0x0000eea4,
+  0x81000015, 0x0000005f,
+  0x00000060, 0x00000000,
+  0x00004120, 0x00000000,
+  0x00004a00, 0x00004000,
+  0x00924460, 0x00000190,
+  0x5601401a, 0x00005956,
+  0x14000011, 0x00000000,
+  0x00934050, 0x00000018,
+  0x00930050, 0x00000018,
+  0x3601403a, 0x0000002d,
+  0x000643a9, 0x00000000,
+  0x0000c420, 0x00000140,
+  0x5601401a, 0x00005956,
+  0x14000011, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x000642a9, 0x00000000,
+  0x00024420, 0x00000183,
+  0x5601401a, 0x00005956,
+  0x82000015, 0x00002000,
+  0x15200011, 0x00000000,
+  0x82000015, 0x00000010,
+  0x15200011, 0x00000000,
+  0x82000015, 0x00000010,
+  0x15200011, 0x00000000,
+};	/* 104 Tx instructions */
+#define FIRMWARE_TX_SIZE 104
+#if 0
+static const u32 firmware_wol[] = {
+  0x010003dc, 0x00000000,
+  0x19000421, 0x00000087,
+  0x80000015, 0x00001a1a,
+  0x81000015, 0x00001a1a,
+  0x1a0040ab, 0x00000b06,
+  0x15200011, 0x00000000,
+  0x15204022, 0x0000aaaa,
+  0x15204022, 0x00000300,
+  0x15204022, 0x00000000,
+  0x1a0040ab, 0x00000b15,
+  0x15200011, 0x00000000,
+  0x83000015, 0x00000002,
+  0x04000021, 0x00000000,
+  0x00000010, 0x00000000,
+  0x04000421, 0x00000087,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00008015, 0x00000000,
+  0x0000003e, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x82000015, 0x00004000,
+  0x82000015, 0x00008000,
+  0x0000000c, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00004080, 0x00000100,
+  0x1f20c011, 0x00001122,
+  0x2720f011, 0x00003011,
+  0x19200071, 0x00000000,
+  0x1a200051, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x1d2040a4, 0x00003344,
+  0x1d2040a2, 0x00005566,
+  0x000040a0, 0x00000100,
+  0x00108050, 0x00000001,
+  0x1a208012, 0x00000006,
+  0x82000015, 0x00008080,
+  0x010003dc, 0x00000000,
+  0x1d2040a4, 0x00002233,
+  0x1d2040a4, 0x00004455,
+  0x2d208011, 0x00000005,
+  0x1d2040a4, 0x00006611,
+  0x00108050, 0x00000001,
+  0x27200011, 0x00000000,
+  0x1d2050a4, 0x00006600,
+  0x82000015, 0x00008080,
+  0x010003dc, 0x00000000,
+  0x00000050, 0x00000000,
+  0x1b200031, 0x00000000,
+  0x0000001e, 0x00000000,
+  0x0000001e, 0x00000000,
+  0x0000001e, 0x00000000,
+  0x0000001e, 0x00000000,
+  0x00924460, 0x00000086,
+  0x00004080, 0x00000000,
+  0x0092c070, 0x00000000,
+  0x00924060, 0x00000100,
+  0x0000c890, 0x00005000,
+  0x00a6c110, 0x00000000,
+  0x00b0c090, 0x00000012,
+  0x021c0015, 0x00000000,
+  0x3200001f, 0x00000034,
+  0x00924460, 0x00000510,
+  0x44210011, 0x00000000,
+  0x42000011, 0x00000000,
+  0x83000015, 0x00000040,
+  0x00924460, 0x00000508,
+  0x476a0012, 0x00000100,
+  0x83000015, 0x00000008,
+  0x16200011, 0x00000000,
+  0x001e8050, 0x00000000,
+  0x001e8050, 0x00000000,
+  0x00808050, 0x00000000,
+  0x03008015, 0x00000000,
+  0x62208012, 0x00000000,
+  0x82000015, 0x00000800,
+  0x16200011, 0x00000000,
+  0x80000015, 0x0000eea4,
+  0x81000015, 0x0000005f,
+  0x00000020, 0x00000000,
+  0x00004120, 0x00000000,
+  0x00004a00, 0x00004000,
+  0x00924460, 0x00000190,
+  0x5c01401a, 0x0000595c,
+  0x15000011, 0x00000000,
+  0x00934050, 0x00000018,
+  0x00930050, 0x00000018,
+  0x3601403a, 0x0000002d,
+  0x00064029, 0x00000000,
+  0x0000c420, 0x00000140,
+  0x5c01401a, 0x0000595c,
+  0x15000011, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00000010, 0x00000000,
+  0x00064029, 0x00000000,
+  0x00024420, 0x00000183,
+  0x5c01401a, 0x0000595c,
+  0x82000015, 0x00002000,
+  0x16200011, 0x00000000,
+  0x82000015, 0x00000010,
+  0x16200011, 0x00000000,
+  0x82000015, 0x00000010,
+  0x16200011, 0x00000000,
+};	/* 104 WoL instructions */
+#define FIRMWARE_WOL_SIZE 104
+#endif

+ 2 - 2
drivers/net/tlan.c

@@ -2819,7 +2819,7 @@ void TLan_PhyMonitor( struct net_device *dev )
  	       if (priv->link) {
 		      priv->link = 0;
 	              printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name);
-	              dev->flags &= ~IFF_RUNNING;
+		      netif_carrier_off(dev);
 		      TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT );
 		      return;
 		}
@@ -2829,7 +2829,7 @@ void TLan_PhyMonitor( struct net_device *dev )
         if ((phy_status & MII_GS_LINK) && !priv->link) {
  		priv->link = 1;
         	printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name);
-        	dev->flags |= IFF_RUNNING;
+		netif_carrier_on(dev);
         }
 
 	/* Setup a new monitor */

+ 3 - 8
drivers/net/tokenring/ibmtr.c

@@ -888,11 +888,6 @@ static int tok_open(struct net_device *dev)
 	ti->sap_status   = CLOSED; /* CLOSED or OPEN      */
 	ti->open_failure =     NO; /* NO     or YES       */
 	ti->open_mode    = MANUAL; /* MANUAL or AUTOMATIC */
-	/* 12/2000 not typical Linux, but we can use RUNNING to let us know when
-	the network has crapped out or cables are disconnected. Useful because
-	the IFF_UP flag stays up the whole time, until ifconfig tr0 down.
-	*/
-	dev->flags &= ~IFF_RUNNING;
 
 	ti->sram_phys &= ~1; /* to reverse what we do in tok_close */
 	/* init the spinlock */
@@ -1242,7 +1237,7 @@ irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 		ti->open_status = CLOSED;
 		ti->sap_status  = CLOSED;
 		ti->open_mode   = AUTOMATIC;
-		dev->flags &= ~IFF_RUNNING;
+		netif_carrier_off(dev);
 		netif_stop_queue(dev);
 		ti->open_action = RESTART;
 		outb(0, dev->base_addr + ADAPTRESET);
@@ -1323,7 +1318,7 @@ irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 				break;
 			}
 			netif_wake_queue(dev);
-			dev->flags |= IFF_RUNNING;/*BMS 12/2000*/
+			netif_carrier_on(dev);
 			break;
 		case DIR_INTERRUPT:
 		case DIR_MOD_OPEN_PARAMS:
@@ -1427,7 +1422,7 @@ irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 								ring_status);
 			if(ring_status& (REMOVE_RECV|AUTO_REMOVAL|LOBE_FAULT)){
 				netif_stop_queue(dev);
-				dev->flags &= ~IFF_RUNNING;/*not typical Linux*/
+				netif_carrier_off(dev);
 				DPRINTK("Remove received, or Auto-removal error"
 					", or Lobe fault\n");
 				DPRINTK("We'll try to reopen the closed adapter"

+ 176 - 144
drivers/net/wan/hdlc_fr.c

@@ -2,7 +2,7 @@
  * Generic HDLC support routines for Linux
  * Frame Relay support
  *
- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -27,6 +27,10 @@
  active = open and "link reliable"
  exist = new = not used
 
+ CCITT LMI: ITU-T Q.933 Annex A
+ ANSI LMI: ANSI T1.617 Annex D
+ CISCO LMI: the original, aka "Gang of Four" LMI
+
 */
 
 #include <linux/module.h>
@@ -49,45 +53,41 @@
 #undef DEBUG_ECN
 #undef DEBUG_LINK
 
-#define MAXLEN_LMISTAT  20	/* max size of status enquiry frame */
-
-#define PVC_STATE_NEW	 0x01
-#define PVC_STATE_ACTIVE 0x02
-#define PVC_STATE_FECN	 0x08 /* FECN condition */
-#define PVC_STATE_BECN	 0x10 /* BECN condition */
-
-
-#define FR_UI		 0x03
-#define FR_PAD		 0x00
-
-#define NLPID_IP	 0xCC
-#define NLPID_IPV6	 0x8E
-#define NLPID_SNAP	 0x80
-#define NLPID_PAD	 0x00
-#define NLPID_Q933	 0x08
-
-
-#define LMI_DLCI                   0 /* LMI DLCI */
-#define LMI_PROTO               0x08
-#define LMI_CALLREF             0x00 /* Call Reference */
-#define LMI_ANSI_LOCKSHIFT      0x95 /* ANSI lockshift */
-#define LMI_REPTYPE                1 /* report type */
-#define LMI_CCITT_REPTYPE       0x51
-#define LMI_ALIVE                  3 /* keep alive */
-#define LMI_CCITT_ALIVE         0x53
-#define LMI_PVCSTAT                7 /* pvc status */
-#define LMI_CCITT_PVCSTAT       0x57
-#define LMI_FULLREP                0 /* full report  */
-#define LMI_INTEGRITY              1 /* link integrity report */
-#define LMI_SINGLE                 2 /* single pvc report */
+#define FR_UI			0x03
+#define FR_PAD			0x00
+
+#define NLPID_IP		0xCC
+#define NLPID_IPV6		0x8E
+#define NLPID_SNAP		0x80
+#define NLPID_PAD		0x00
+#define NLPID_CCITT_ANSI_LMI	0x08
+#define NLPID_CISCO_LMI		0x09
+
+
+#define LMI_CCITT_ANSI_DLCI	   0 /* LMI DLCI */
+#define LMI_CISCO_DLCI		1023
+
+#define LMI_CALLREF		0x00 /* Call Reference */
+#define LMI_ANSI_LOCKSHIFT	0x95 /* ANSI locking shift */
+#define LMI_ANSI_CISCO_REPTYPE	0x01 /* report type */
+#define LMI_CCITT_REPTYPE	0x51
+#define LMI_ANSI_CISCO_ALIVE	0x03 /* keep alive */
+#define LMI_CCITT_ALIVE		0x53
+#define LMI_ANSI_CISCO_PVCSTAT	0x07 /* PVC status */
+#define LMI_CCITT_PVCSTAT	0x57
+
+#define LMI_FULLREP		0x00 /* full report  */
+#define LMI_INTEGRITY		0x01 /* link integrity report */
+#define LMI_SINGLE		0x02 /* single PVC report */
+
 #define LMI_STATUS_ENQUIRY      0x75
 #define LMI_STATUS              0x7D /* reply */
 
 #define LMI_REPT_LEN               1 /* report type element length */
 #define LMI_INTEG_LEN              2 /* link integrity element length */
 
-#define LMI_LENGTH                13 /* standard LMI frame length */
-#define LMI_ANSI_LENGTH           14
+#define LMI_CCITT_CISCO_LENGTH	  13 /* LMI frame lengths */
+#define LMI_ANSI_LENGTH		  14
 
 
 typedef struct {
@@ -223,51 +223,34 @@ static inline struct net_device** get_dev_p(pvc_device *pvc, int type)
 }
 
 
-static inline u16 status_to_dlci(u8 *status, int *active, int *new)
-{
-	*new = (status[2] & 0x08) ? 1 : 0;
-	*active = (status[2] & 0x02) ? 1 : 0;
-
-	return ((status[0] & 0x3F) << 4) | ((status[1] & 0x78) >> 3);
-}
-
-
-static inline void dlci_to_status(u16 dlci, u8 *status, int active, int new)
-{
-	status[0] = (dlci >> 4) & 0x3F;
-	status[1] = ((dlci << 3) & 0x78) | 0x80;
-	status[2] = 0x80;
-
-	if (new)
-		status[2] |= 0x08;
-	else if (active)
-		status[2] |= 0x02;
-}
-
-
-
 static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
 {
 	u16 head_len;
 	struct sk_buff *skb = *skb_p;
 
 	switch (skb->protocol) {
-	case __constant_ntohs(ETH_P_IP):
+	case __constant_ntohs(NLPID_CCITT_ANSI_LMI):
 		head_len = 4;
 		skb_push(skb, head_len);
-		skb->data[3] = NLPID_IP;
+		skb->data[3] = NLPID_CCITT_ANSI_LMI;
 		break;
 
-	case __constant_ntohs(ETH_P_IPV6):
+	case __constant_ntohs(NLPID_CISCO_LMI):
 		head_len = 4;
 		skb_push(skb, head_len);
-		skb->data[3] = NLPID_IPV6;
+		skb->data[3] = NLPID_CISCO_LMI;
 		break;
 
-	case __constant_ntohs(LMI_PROTO):
+	case __constant_ntohs(ETH_P_IP):
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = NLPID_IP;
+		break;
+
+	case __constant_ntohs(ETH_P_IPV6):
 		head_len = 4;
 		skb_push(skb, head_len);
-		skb->data[3] = LMI_PROTO;
+		skb->data[3] = NLPID_IPV6;
 		break;
 
 	case __constant_ntohs(ETH_P_802_3):
@@ -461,13 +444,14 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
 	hdlc_device *hdlc = dev_to_hdlc(dev);
 	struct sk_buff *skb;
 	pvc_device *pvc = hdlc->state.fr.first_pvc;
-	int len = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? LMI_ANSI_LENGTH
-		: LMI_LENGTH;
-	int stat_len = 3;
+	int lmi = hdlc->state.fr.settings.lmi;
+	int dce = hdlc->state.fr.settings.dce;
+	int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH;
+	int stat_len = (lmi == LMI_CISCO) ? 6 : 3;
 	u8 *data;
 	int i = 0;
 
-	if (hdlc->state.fr.settings.dce && fullrep) {
+	if (dce && fullrep) {
 		len += hdlc->state.fr.dce_pvc_count * (2 + stat_len);
 		if (len > HDLC_MAX_MRU) {
 			printk(KERN_WARNING "%s: Too many PVCs while sending "
@@ -484,29 +468,31 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
 	}
 	memset(skb->data, 0, len);
 	skb_reserve(skb, 4);
-	skb->protocol = __constant_htons(LMI_PROTO);
-	fr_hard_header(&skb, LMI_DLCI);
+	if (lmi == LMI_CISCO) {
+		skb->protocol = __constant_htons(NLPID_CISCO_LMI);
+		fr_hard_header(&skb, LMI_CISCO_DLCI);
+	} else {
+		skb->protocol = __constant_htons(NLPID_CCITT_ANSI_LMI);
+		fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI);
+	}
 	data = skb->tail;
 	data[i++] = LMI_CALLREF;
-	data[i++] = hdlc->state.fr.settings.dce
-		? LMI_STATUS : LMI_STATUS_ENQUIRY;
-	if (hdlc->state.fr.settings.lmi == LMI_ANSI)
+	data[i++] = dce ? LMI_STATUS : LMI_STATUS_ENQUIRY;
+	if (lmi == LMI_ANSI)
 		data[i++] = LMI_ANSI_LOCKSHIFT;
-	data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
-		? LMI_CCITT_REPTYPE : LMI_REPTYPE;
+	data[i++] = lmi == LMI_CCITT ? LMI_CCITT_REPTYPE :
+		LMI_ANSI_CISCO_REPTYPE;
 	data[i++] = LMI_REPT_LEN;
 	data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
-
-	data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
-		? LMI_CCITT_ALIVE : LMI_ALIVE;
+	data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE;
 	data[i++] = LMI_INTEG_LEN;
 	data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
 	data[i++] = hdlc->state.fr.rxseq;
 
-	if (hdlc->state.fr.settings.dce && fullrep) {
+	if (dce && fullrep) {
 		while (pvc) {
-			data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
-				? LMI_CCITT_PVCSTAT : LMI_PVCSTAT;
+			data[i++] = lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT :
+				LMI_ANSI_CISCO_PVCSTAT;
 			data[i++] = stat_len;
 
 			/* LMI start/restart */
@@ -523,8 +509,20 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
 				fr_log_dlci_active(pvc);
 			}
 
-			dlci_to_status(pvc->dlci, data + i,
-				       pvc->state.active, pvc->state.new);
+			if (lmi == LMI_CISCO) {
+				data[i] = pvc->dlci >> 8;
+				data[i + 1] = pvc->dlci & 0xFF;
+			} else {
+				data[i] = (pvc->dlci >> 4) & 0x3F;
+				data[i + 1] = ((pvc->dlci << 3) & 0x78) | 0x80;
+				data[i + 2] = 0x80;
+			}
+
+			if (pvc->state.new)
+				data[i + 2] |= 0x08;
+			else if (pvc->state.active)
+				data[i + 2] |= 0x02;
+
 			i += stat_len;
 			pvc = pvc->next;
 		}
@@ -569,6 +567,8 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
 			pvc_carrier(0, pvc);
 			pvc->state.exist = pvc->state.active = 0;
 			pvc->state.new = 0;
+			if (!hdlc->state.fr.settings.dce)
+				pvc->state.bandwidth = 0;
 			pvc = pvc->next;
 		}
 	}
@@ -583,11 +583,12 @@ static void fr_timer(unsigned long arg)
 	int i, cnt = 0, reliable;
 	u32 list;
 
-	if (hdlc->state.fr.settings.dce)
+	if (hdlc->state.fr.settings.dce) {
 		reliable = hdlc->state.fr.request &&
 			time_before(jiffies, hdlc->state.fr.last_poll +
 				    hdlc->state.fr.settings.t392 * HZ);
-	else {
+		hdlc->state.fr.request = 0;
+	} else {
 		hdlc->state.fr.last_errors <<= 1; /* Shift the list */
 		if (hdlc->state.fr.request) {
 			if (hdlc->state.fr.reliable)
@@ -634,65 +635,88 @@ static void fr_timer(unsigned long arg)
 static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
 {
 	hdlc_device *hdlc = dev_to_hdlc(dev);
-	int stat_len;
 	pvc_device *pvc;
-	int reptype = -1, error, no_ram;
 	u8 rxseq, txseq;
-	int i;
+	int lmi = hdlc->state.fr.settings.lmi;
+	int dce = hdlc->state.fr.settings.dce;
+	int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i;
 
-	if (skb->len < ((hdlc->state.fr.settings.lmi == LMI_ANSI)
-			? LMI_ANSI_LENGTH : LMI_LENGTH)) {
+	if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH :
+			LMI_CCITT_CISCO_LENGTH)) {
 		printk(KERN_INFO "%s: Short LMI frame\n", dev->name);
 		return 1;
 	}
 
-	if (skb->data[5] != (!hdlc->state.fr.settings.dce ?
-			     LMI_STATUS : LMI_STATUS_ENQUIRY)) {
-		printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
-		       dev->name, skb->data[2],
-		       hdlc->state.fr.settings.dce ? "enquiry" : "reply");
+	if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI :
+			     NLPID_CCITT_ANSI_LMI)) {
+		printk(KERN_INFO "%s: Received non-LMI frame with LMI"
+		       " DLCI\n", dev->name);
+		return 1;
+	}
+
+	if (skb->data[4] != LMI_CALLREF) {
+		printk(KERN_INFO "%s: Invalid LMI Call reference (0x%02X)\n",
+		       dev->name, skb->data[4]);
+		return 1;
+	}
+
+	if (skb->data[5] != (dce ? LMI_STATUS_ENQUIRY : LMI_STATUS)) {
+		printk(KERN_INFO "%s: Invalid LMI Message type (0x%02X)\n",
+		       dev->name, skb->data[5]);
 		return 1;
 	}
 
-	i = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? 7 : 6;
+	if (lmi == LMI_ANSI) {
+		if (skb->data[6] != LMI_ANSI_LOCKSHIFT) {
+			printk(KERN_INFO "%s: Not ANSI locking shift in LMI"
+			       " message (0x%02X)\n", dev->name, skb->data[6]);
+			return 1;
+		}
+		i = 7;
+	} else
+		i = 6;
 
-	if (skb->data[i] !=
-	    ((hdlc->state.fr.settings.lmi == LMI_CCITT)
-	     ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
-		printk(KERN_INFO "%s: Not a report type=%x\n",
+	if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_REPTYPE :
+			     LMI_ANSI_CISCO_REPTYPE)) {
+		printk(KERN_INFO "%s: Not an LMI Report type IE (0x%02X)\n",
 		       dev->name, skb->data[i]);
 		return 1;
 	}
-	i++;
 
-	i++;				/* Skip length field */
+	if (skb->data[++i] != LMI_REPT_LEN) {
+		printk(KERN_INFO "%s: Invalid LMI Report type IE length"
+		       " (%u)\n", dev->name, skb->data[i]);
+		return 1;
+	}
 
-	reptype = skb->data[i++];
+	reptype = skb->data[++i];
+	if (reptype != LMI_INTEGRITY && reptype != LMI_FULLREP) {
+		printk(KERN_INFO "%s: Unsupported LMI Report type (0x%02X)\n",
+		       dev->name, reptype);
+		return 1;
+	}
 
-	if (skb->data[i]!=
-	    ((hdlc->state.fr.settings.lmi == LMI_CCITT)
-	     ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
-		printk(KERN_INFO "%s: Unsupported status element=%x\n",
-		       dev->name, skb->data[i]);
+	if (skb->data[++i] != (lmi == LMI_CCITT ? LMI_CCITT_ALIVE :
+			       LMI_ANSI_CISCO_ALIVE)) {
+		printk(KERN_INFO "%s: Not an LMI Link integrity verification"
+		       " IE (0x%02X)\n", dev->name, skb->data[i]);
 		return 1;
 	}
-	i++;
 
-	i++;			/* Skip length field */
+	if (skb->data[++i] != LMI_INTEG_LEN) {
+		printk(KERN_INFO "%s: Invalid LMI Link integrity verification"
+		       " IE length (%u)\n", dev->name, skb->data[i]);
+		return 1;
+	}
+	i++;
 
 	hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
 	rxseq = skb->data[i++];	/* Should confirm our sequence */
 
 	txseq = hdlc->state.fr.txseq;
 
-	if (hdlc->state.fr.settings.dce) {
-		if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
-			printk(KERN_INFO "%s: Unsupported report type=%x\n",
-			       dev->name, reptype);
-			return 1;
-		}
+	if (dce)
 		hdlc->state.fr.last_poll = jiffies;
-	}
 
 	error = 0;
 	if (!hdlc->state.fr.reliable)
@@ -703,7 +727,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
 		error = 1;
 	}
 
-	if (hdlc->state.fr.settings.dce) {
+	if (dce) {
 		if (hdlc->state.fr.fullrep_sent && !error) {
 /* Stop sending full report - the last one has been confirmed by DTE */
 			hdlc->state.fr.fullrep_sent = 0;
@@ -725,6 +749,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
 			hdlc->state.fr.dce_changed = 0;
 		}
 
+		hdlc->state.fr.request = 1; /* got request */
 		fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0);
 		return 0;
 	}
@@ -739,7 +764,6 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
 	if (reptype != LMI_FULLREP)
 		return 0;
 
-	stat_len = 3;
 	pvc = hdlc->state.fr.first_pvc;
 
 	while (pvc) {
@@ -750,24 +774,35 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
 	no_ram = 0;
 	while (skb->len >= i + 2 + stat_len) {
 		u16 dlci;
+		u32 bw;
 		unsigned int active, new;
 
-		if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_CCITT)
-				     ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
-			printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
-			       dev->name, skb->data[i]);
+		if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT :
+				       LMI_ANSI_CISCO_PVCSTAT)) {
+			printk(KERN_INFO "%s: Not an LMI PVC status IE"
+			       " (0x%02X)\n", dev->name, skb->data[i]);
 			return 1;
 		}
-		i++;
 
-		if (skb->data[i] != stat_len) {
-			printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
-			       dev->name, skb->data[i]);
+		if (skb->data[++i] != stat_len) {
+			printk(KERN_INFO "%s: Invalid LMI PVC status IE length"
+			       " (%u)\n", dev->name, skb->data[i]);
 			return 1;
 		}
 		i++;
 
-		dlci = status_to_dlci(skb->data + i, &active, &new);
+		new = !! (skb->data[i + 2] & 0x08);
+		active = !! (skb->data[i + 2] & 0x02);
+		if (lmi == LMI_CISCO) {
+			dlci = (skb->data[i] << 8) | skb->data[i + 1];
+			bw = (skb->data[i + 3] << 16) |
+				(skb->data[i + 4] << 8) |
+				(skb->data[i + 5]);
+		} else {
+			dlci = ((skb->data[i] & 0x3F) << 4) |
+				((skb->data[i + 1] & 0x78) >> 3);
+			bw = 0;
+		}
 
 		pvc = add_pvc(dev, dlci);
 
@@ -783,9 +818,11 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
 			pvc->state.deleted = 0;
 			if (active != pvc->state.active ||
 			    new != pvc->state.new ||
+			    bw != pvc->state.bandwidth ||
 			    !pvc->state.exist) {
 				pvc->state.new = new;
 				pvc->state.active = active;
+				pvc->state.bandwidth = bw;
 				pvc_carrier(active, pvc);
 				fr_log_dlci_active(pvc);
 			}
@@ -801,6 +838,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
 			pvc_carrier(0, pvc);
 			pvc->state.active = pvc->state.new = 0;
 			pvc->state.exist = 0;
+			pvc->state.bandwidth = 0;
 			fr_log_dlci_active(pvc);
 		}
 		pvc = pvc->next;
@@ -829,22 +867,15 @@ static int fr_rx(struct sk_buff *skb)
 
 	dlci = q922_to_dlci(skb->data);
 
-	if (dlci == LMI_DLCI) {
-		if (hdlc->state.fr.settings.lmi == LMI_NONE)
-			goto rx_error; /* LMI packet with no LMI? */
-
-		if (data[3] == LMI_PROTO) {
-			if (fr_lmi_recv(ndev, skb))
-				goto rx_error;
-			else {
-				dev_kfree_skb_any(skb);
-				return NET_RX_SUCCESS;
-			}
-		}
-
-		printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
-		       ndev->name);
-		goto rx_error;
+	if ((dlci == LMI_CCITT_ANSI_DLCI &&
+	     (hdlc->state.fr.settings.lmi == LMI_ANSI ||
+	      hdlc->state.fr.settings.lmi == LMI_CCITT)) ||
+	    (dlci == LMI_CISCO_DLCI &&
+	     hdlc->state.fr.settings.lmi == LMI_CISCO)) {
+		if (fr_lmi_recv(ndev, skb))
+			goto rx_error;
+		dev_kfree_skb_any(skb);
+		return NET_RX_SUCCESS;
 	}
 
 	pvc = find_pvc(hdlc, dlci);
@@ -1170,7 +1201,8 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
 
 		if ((new_settings.lmi != LMI_NONE &&
 		     new_settings.lmi != LMI_ANSI &&
-		     new_settings.lmi != LMI_CCITT) ||
+		     new_settings.lmi != LMI_CCITT &&
+		     new_settings.lmi != LMI_CISCO) ||
 		    new_settings.t391 < 1 ||
 		    new_settings.t392 < 2 ||
 		    new_settings.n391 < 1 ||

+ 11 - 5
drivers/net/wan/hdlc_generic.c

@@ -1,7 +1,7 @@
 /*
  * Generic HDLC support routines for Linux
  *
- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -38,7 +38,7 @@
 #include <linux/hdlc.h>
 
 
-static const char* version = "HDLC support module revision 1.17";
+static const char* version = "HDLC support module revision 1.18";
 
 #undef DEBUG_LINK
 
@@ -126,10 +126,13 @@ void hdlc_set_carrier(int on, struct net_device *dev)
 	if (!hdlc->open)
 		goto carrier_exit;
 
-	if (hdlc->carrier)
+	if (hdlc->carrier) {
+		printk(KERN_INFO "%s: Carrier detected\n", dev->name);
 		__hdlc_set_carrier_on(dev);
-	else
+	} else {
+		printk(KERN_INFO "%s: Carrier lost\n", dev->name);
 		__hdlc_set_carrier_off(dev);
+	}
 
 carrier_exit:
 	spin_unlock_irqrestore(&hdlc->state_lock, flags);
@@ -157,8 +160,11 @@ int hdlc_open(struct net_device *dev)
 
 	spin_lock_irq(&hdlc->state_lock);
 
-	if (hdlc->carrier)
+	if (hdlc->carrier) {
+		printk(KERN_INFO "%s: Carrier detected\n", dev->name);
 		__hdlc_set_carrier_on(dev);
+	} else
+		printk(KERN_INFO "%s: No carrier\n", dev->name);
 
 	hdlc->open = 1;
 

+ 2 - 6
drivers/net/wan/lmc/lmc_main.c

@@ -723,7 +723,7 @@ static void lmc_watchdog (unsigned long data) /*fold00*/
         /* lmc_reset (sc); Why reset??? The link can go down ok */
 
         /* Inform the world that link has been lost */
-        dev->flags &= ~IFF_RUNNING;
+	netif_carrier_off(dev);
     }
 
     /*
@@ -736,7 +736,7 @@ static void lmc_watchdog (unsigned long data) /*fold00*/
          /* lmc_reset (sc); Again why reset??? */
 
          /* Inform the world that link protocol is back up. */
-         dev->flags |= IFF_RUNNING;
+	 netif_carrier_on(dev);
 
          /* Now we have to tell the syncppp that we had an outage
           * and that it should deal.  Calling sppp_reopen here
@@ -1168,8 +1168,6 @@ static void lmc_running_reset (struct net_device *dev) /*fold00*/
     sc->lmc_media->set_link_status (sc, 1);
     sc->lmc_media->set_status (sc, NULL);
 
-    //dev->flags |= IFF_RUNNING;
-    
     netif_wake_queue(dev);
 
     sc->lmc_txfull = 0;
@@ -1233,8 +1231,6 @@ static int lmc_ifdown (struct net_device *dev) /*fold00*/
     csr6 &= ~LMC_DEC_SR;		/* Turn off the Receive bit */
     LMC_CSR_WRITE (sc, csr_command, csr6);
 
-    dev->flags &= ~IFF_RUNNING;
-
     sc->stats.rx_missed_errors +=
         LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
 

+ 69 - 263
drivers/net/wireless/orinoco.c

@@ -492,6 +492,9 @@ EXPORT_SYMBOL(orinoco_debug);
 static int suppress_linkstatus; /* = 0 */
 module_param(suppress_linkstatus, bool, 0644);
 MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
+static int ignore_disconnect; /* = 0 */
+module_param(ignore_disconnect, int, 0644);
+MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
 
 /********************************************************************/
 /* Compile time configuration and compatibility stuff               */
@@ -604,7 +607,6 @@ struct hermes_rx_descriptor {
 static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int __orinoco_program_rids(struct net_device *dev);
 static void __orinoco_set_multicast_list(struct net_device *dev);
-static int orinoco_debug_dump_recs(struct net_device *dev);
 
 /********************************************************************/
 /* Internal helper functions                                        */
@@ -655,7 +657,7 @@ static int orinoco_open(struct net_device *dev)
 	return err;
 }
 
-int orinoco_stop(struct net_device *dev)
+static int orinoco_stop(struct net_device *dev)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	int err = 0;
@@ -686,7 +688,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
 	struct orinoco_private *priv = netdev_priv(dev);
 	hermes_t *hw = &priv->hw;
 	struct iw_statistics *wstats = &priv->wstats;
-	int err = 0;
+	int err;
 	unsigned long flags;
 
 	if (! netif_device_present(dev)) {
@@ -695,9 +697,21 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
 		return NULL; /* FIXME: Can we do better than this? */
 	}
 
+	/* If busy, return the old stats.  Returning NULL may cause
+	 * the interface to disappear from /proc/net/wireless */
 	if (orinoco_lock(priv, &flags) != 0)
-		return NULL;  /* FIXME: Erg, we've been signalled, how
-			       * do we propagate this back up? */
+		return wstats;
+
+	/* We can't really wait for the tallies inquiry command to
+	 * complete, so we just use the previous results and trigger
+	 * a new tallies inquiry command for next time - Jean II */
+	/* FIXME: Really we should wait for the inquiry to come back -
+	 * as it is the stats we give don't make a whole lot of sense.
+	 * Unfortunately, it's not clear how to do that within the
+	 * wireless extensions framework: I think we're in user
+	 * context, but a lock seems to be held by the time we get in
+	 * here so we're not safe to sleep here. */
+	hermes_inquire(hw, HERMES_INQ_TALLIES);
 
 	if (priv->iw_mode == IW_MODE_ADHOC) {
 		memset(&wstats->qual, 0, sizeof(wstats->qual));
@@ -716,25 +730,16 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
 
 		err = HERMES_READ_RECORD(hw, USER_BAP,
 					 HERMES_RID_COMMSQUALITY, &cq);
-		
-		wstats->qual.qual = (int)le16_to_cpu(cq.qual);
-		wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
-		wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
-		wstats->qual.updated = 7;
+
+		if (!err) {
+			wstats->qual.qual = (int)le16_to_cpu(cq.qual);
+			wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
+			wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
+			wstats->qual.updated = 7;
+		}
 	}
 
-	/* We can't really wait for the tallies inquiry command to
-	 * complete, so we just use the previous results and trigger
-	 * a new tallies inquiry command for next time - Jean II */
-	/* FIXME: We're in user context (I think?), so we should just
-           wait for the tallies to come through */
-	err = hermes_inquire(hw, HERMES_INQ_TALLIES);
-               
 	orinoco_unlock(priv, &flags);
-
-	if (err)
-		return NULL;
-		
 	return wstats;
 }
 
@@ -1275,9 +1280,10 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 			len = sizeof(tallies);
 		}
 		
-		/* Read directly the data (no seek) */
-		hermes_read_words(hw, HERMES_DATA1, (void *) &tallies,
-				  len / 2); /* FIXME: blech! */
+		err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
+				       infofid, sizeof(info));
+		if (err)
+			break;
 		
 		/* Increment our various counters */
 		/* wstats->discard.nwid - no wrong BSSID stuff */
@@ -1307,8 +1313,10 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 			break;
 		}
 
-		hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus,
-				  len / 2);
+		err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
+				       infofid, sizeof(info));
+		if (err)
+			break;
 		newstatus = le16_to_cpu(linkstatus.linkstatus);
 
 		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
@@ -1317,7 +1325,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 
 		if (connected)
 			netif_carrier_on(dev);
-		else
+		else if (!ignore_disconnect)
 			netif_carrier_off(dev);
 
 		if (newstatus != priv->last_linkstatus)
@@ -1350,6 +1358,8 @@ int __orinoco_up(struct net_device *dev)
 	struct hermes *hw = &priv->hw;
 	int err;
 
+	netif_carrier_off(dev); /* just to make sure */
+
 	err = __orinoco_program_rids(dev);
 	if (err) {
 		printk(KERN_ERR "%s: Error %d configuring card\n",
@@ -1413,7 +1423,7 @@ int orinoco_reinit_firmware(struct net_device *dev)
 		return err;
 
 	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-	if (err == -EIO) {
+	if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
 		/* Try workaround for old Symbol firmware bug */
 		printk(KERN_WARNING "%s: firmware ALLOC bug detected "
 		       "(old Symbol firmware?). Trying to work around... ",
@@ -1610,17 +1620,15 @@ static int __orinoco_program_rids(struct net_device *dev)
 		return err;
 	}
 	/* Set the channel/frequency */
-	if (priv->channel == 0) {
-		printk(KERN_DEBUG "%s: Channel is 0 in __orinoco_program_rids()\n", dev->name);
-		if (priv->createibss)
-			priv->channel = 10;
-	}
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL,
-				   priv->channel);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d setting channel\n",
-		       dev->name, err);
-		return err;
+	if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFOWNCHANNEL,
+					   priv->channel);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting channel %d\n",
+			       dev->name, err, priv->channel);
+			return err;
+		}
 	}
 
 	if (priv->has_ibss) {
@@ -1916,7 +1924,7 @@ static void orinoco_reset(struct net_device *dev)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct hermes *hw = &priv->hw;
-	int err = 0;
+	int err;
 	unsigned long flags;
 
 	if (orinoco_lock(priv, &flags) != 0)
@@ -1938,20 +1946,20 @@ static void orinoco_reset(struct net_device *dev)
 
 	orinoco_unlock(priv, &flags);
 
-	if (priv->hard_reset)
+	if (priv->hard_reset) {
 		err = (*priv->hard_reset)(priv);
-	if (err) {
-		printk(KERN_ERR "%s: orinoco_reset: Error %d "
-		       "performing  hard reset\n", dev->name, err);
-		/* FIXME: shutdown of some sort */
-		return;
+		if (err) {
+			printk(KERN_ERR "%s: orinoco_reset: Error %d "
+			       "performing hard reset\n", dev->name, err);
+			goto disable;
+		}
 	}
 
 	err = orinoco_reinit_firmware(dev);
 	if (err) {
 		printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
 		       dev->name, err);
-		return;
+		goto disable;
 	}
 
 	spin_lock_irq(&priv->lock); /* This has to be called from user context */
@@ -1972,6 +1980,10 @@ static void orinoco_reset(struct net_device *dev)
 	spin_unlock_irq(&priv->lock);
 
 	return;
+ disable:
+	hermes_set_irqmask(hw, 0);
+	netif_device_detach(dev);
+	printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
 }
 
 /********************************************************************/
@@ -2056,7 +2068,7 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 		if (events & HERMES_EV_ALLOC)
 			__orinoco_ev_alloc(dev, hw);
 		
-		hermes_write_regn(hw, EVACK, events);
+		hermes_write_regn(hw, EVACK, evstat);
 
 		evstat = hermes_read_regn(hw, EVSTAT);
 		events = evstat & hw->inten;
@@ -2215,6 +2227,8 @@ static int determine_firmware(struct net_device *dev)
 			       firmver >= 0x31000;
 		priv->has_preamble = (firmver >= 0x20000);
 		priv->ibss_port = 4;
+ 		priv->broken_disableport = (firmver == 0x25013) ||
+ 					   (firmver >= 0x30000 && firmver <= 0x31000);
 		/* Tested with Intel firmware : 0x20015 => Jean II */
 		/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
 		break;
@@ -2267,7 +2281,7 @@ static int orinoco_init(struct net_device *dev)
 	priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
 
 	/* Initialize the firmware */
-	err = hermes_init(hw);
+	err = orinoco_reinit_firmware(dev);
 	if (err != 0) {
 		printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
 		       dev->name, err);
@@ -2400,31 +2414,12 @@ static int orinoco_init(struct net_device *dev)
 	/* By default use IEEE/IBSS ad-hoc mode if we have it */
 	priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss);
 	set_port_type(priv);
-	priv->channel = 10; /* default channel, more-or-less arbitrary */
+	priv->channel = 0; /* use firmware default */
 
 	priv->promiscuous = 0;
 	priv->wep_on = 0;
 	priv->tx_key = 0;
 
-	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-	if (err == -EIO) {
-		/* Try workaround for old Symbol firmware bug */
-		printk(KERN_WARNING "%s: firmware ALLOC bug detected "
-		       "(old Symbol firmware?). Trying to work around... ",
-		       dev->name);
-		
-		priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
-		err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-		if (err)
-			printk("failed!\n");
-		else
-			printk("ok.\n");
-	}
-	if (err) {
-		printk("%s: Error %d allocating Tx buffer\n", dev->name, err);
-		goto out;
-	}
-
 	/* Make the hardware available, as long as it hasn't been
 	 * removed elsewhere (e.g. by PCMCIA hot unplug) */
 	spin_lock_irq(&priv->lock);
@@ -2450,7 +2445,7 @@ struct net_device *alloc_orinocodev(int sizeof_card,
 	priv = netdev_priv(dev);
 	priv->ndev = dev;
 	if (sizeof_card)
-		priv->card = (void *)((unsigned long)netdev_priv(dev)
+		priv->card = (void *)((unsigned long)priv
 				      + sizeof(struct orinoco_private));
 	else
 		priv->card = NULL;
@@ -2555,6 +2550,7 @@ static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
 	}
 
 	len = le16_to_cpu(essidbuf.len);
+	BUG_ON(len > IW_ESSID_MAX_SIZE);
 
 	memset(buf, 0, IW_ESSID_MAX_SIZE+1);
 	memcpy(buf, p, len);
@@ -2923,13 +2919,14 @@ static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
 	memset(&essidbuf, 0, sizeof(essidbuf));
 
 	if (erq->flags) {
-		if (erq->length > IW_ESSID_MAX_SIZE)
+		/* iwconfig includes the NUL in the specified length */
+		if (erq->length > IW_ESSID_MAX_SIZE+1)
 			return -E2BIG;
 		
 		if (copy_from_user(&essidbuf, erq->pointer, erq->length))
 			return -EFAULT;
 
-		essidbuf[erq->length] = '\0';
+		essidbuf[IW_ESSID_MAX_SIZE] = '\0';
 	}
 
 	if (orinoco_lock(priv, &flags) != 0)
@@ -3855,7 +3852,6 @@ orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 				{ SIOCIWFIRSTPRIV + 0x7, 0,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 				  "get_ibssport" },
-				{ SIOCIWLASTPRIV, 0, 0, "dump_recs" },
 			};
 
 			wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
@@ -3943,14 +3939,6 @@ orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 		err = orinoco_ioctl_getibssport(dev, wrq);
 		break;
 
-	case SIOCIWLASTPRIV:
-		err = orinoco_debug_dump_recs(dev);
-		if (err)
-			printk(KERN_ERR "%s: Unable to dump records (%d)\n",
-			       dev->name, err);
-		break;
-
-
 	default:
 		err = -EOPNOTSUPP;
 	}
@@ -3964,187 +3952,6 @@ orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 	return err;
 }
 
-struct {
-	u16 rid;
-	char *name;
-	int displaytype;
-#define DISPLAY_WORDS	0
-#define DISPLAY_BYTES	1
-#define DISPLAY_STRING	2
-#define DISPLAY_XSTRING	3
-} record_table[] = {
-#define DEBUG_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type }
-	DEBUG_REC(CNFPORTTYPE,WORDS),
-	DEBUG_REC(CNFOWNMACADDR,BYTES),
-	DEBUG_REC(CNFDESIREDSSID,STRING),
-	DEBUG_REC(CNFOWNCHANNEL,WORDS),
-	DEBUG_REC(CNFOWNSSID,STRING),
-	DEBUG_REC(CNFOWNATIMWINDOW,WORDS),
-	DEBUG_REC(CNFSYSTEMSCALE,WORDS),
-	DEBUG_REC(CNFMAXDATALEN,WORDS),
-	DEBUG_REC(CNFPMENABLED,WORDS),
-	DEBUG_REC(CNFPMEPS,WORDS),
-	DEBUG_REC(CNFMULTICASTRECEIVE,WORDS),
-	DEBUG_REC(CNFMAXSLEEPDURATION,WORDS),
-	DEBUG_REC(CNFPMHOLDOVERDURATION,WORDS),
-	DEBUG_REC(CNFOWNNAME,STRING),
-	DEBUG_REC(CNFOWNDTIMPERIOD,WORDS),
-	DEBUG_REC(CNFMULTICASTPMBUFFERING,WORDS),
-	DEBUG_REC(CNFWEPENABLED_AGERE,WORDS),
-	DEBUG_REC(CNFMANDATORYBSSID_SYMBOL,WORDS),
-	DEBUG_REC(CNFWEPDEFAULTKEYID,WORDS),
-	DEBUG_REC(CNFDEFAULTKEY0,BYTES),
-	DEBUG_REC(CNFDEFAULTKEY1,BYTES),
-	DEBUG_REC(CNFMWOROBUST_AGERE,WORDS),
-	DEBUG_REC(CNFDEFAULTKEY2,BYTES),
-	DEBUG_REC(CNFDEFAULTKEY3,BYTES),
-	DEBUG_REC(CNFWEPFLAGS_INTERSIL,WORDS),
-	DEBUG_REC(CNFWEPKEYMAPPINGTABLE,WORDS),
-	DEBUG_REC(CNFAUTHENTICATION,WORDS),
-	DEBUG_REC(CNFMAXASSOCSTA,WORDS),
-	DEBUG_REC(CNFKEYLENGTH_SYMBOL,WORDS),
-	DEBUG_REC(CNFTXCONTROL,WORDS),
-	DEBUG_REC(CNFROAMINGMODE,WORDS),
-	DEBUG_REC(CNFHOSTAUTHENTICATION,WORDS),
-	DEBUG_REC(CNFRCVCRCERROR,WORDS),
-	DEBUG_REC(CNFMMLIFE,WORDS),
-	DEBUG_REC(CNFALTRETRYCOUNT,WORDS),
-	DEBUG_REC(CNFBEACONINT,WORDS),
-	DEBUG_REC(CNFAPPCFINFO,WORDS),
-	DEBUG_REC(CNFSTAPCFINFO,WORDS),
-	DEBUG_REC(CNFPRIORITYQUSAGE,WORDS),
-	DEBUG_REC(CNFTIMCTRL,WORDS),
-	DEBUG_REC(CNFTHIRTY2TALLY,WORDS),
-	DEBUG_REC(CNFENHSECURITY,WORDS),
-	DEBUG_REC(CNFGROUPADDRESSES,BYTES),
-	DEBUG_REC(CNFCREATEIBSS,WORDS),
-	DEBUG_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS),
-	DEBUG_REC(CNFRTSTHRESHOLD,WORDS),
-	DEBUG_REC(CNFTXRATECONTROL,WORDS),
-	DEBUG_REC(CNFPROMISCUOUSMODE,WORDS),
-	DEBUG_REC(CNFBASICRATES_SYMBOL,WORDS),
-	DEBUG_REC(CNFPREAMBLE_SYMBOL,WORDS),
-	DEBUG_REC(CNFSHORTPREAMBLE,WORDS),
-	DEBUG_REC(CNFWEPKEYS_AGERE,BYTES),
-	DEBUG_REC(CNFEXCLUDELONGPREAMBLE,WORDS),
-	DEBUG_REC(CNFTXKEY_AGERE,WORDS),
-	DEBUG_REC(CNFAUTHENTICATIONRSPTO,WORDS),
-	DEBUG_REC(CNFBASICRATES,WORDS),
-	DEBUG_REC(CNFSUPPORTEDRATES,WORDS),
-	DEBUG_REC(CNFTICKTIME,WORDS),
-	DEBUG_REC(CNFSCANREQUEST,WORDS),
-	DEBUG_REC(CNFJOINREQUEST,WORDS),
-	DEBUG_REC(CNFAUTHENTICATESTATION,WORDS),
-	DEBUG_REC(CNFCHANNELINFOREQUEST,WORDS),
-	DEBUG_REC(MAXLOADTIME,WORDS),
-	DEBUG_REC(DOWNLOADBUFFER,WORDS),
-	DEBUG_REC(PRIID,WORDS),
-	DEBUG_REC(PRISUPRANGE,WORDS),
-	DEBUG_REC(CFIACTRANGES,WORDS),
-	DEBUG_REC(NICSERNUM,XSTRING),
-	DEBUG_REC(NICID,WORDS),
-	DEBUG_REC(MFISUPRANGE,WORDS),
-	DEBUG_REC(CFISUPRANGE,WORDS),
-	DEBUG_REC(CHANNELLIST,WORDS),
-	DEBUG_REC(REGULATORYDOMAINS,WORDS),
-	DEBUG_REC(TEMPTYPE,WORDS),
-/*  	DEBUG_REC(CIS,BYTES), */
-	DEBUG_REC(STAID,WORDS),
-	DEBUG_REC(CURRENTSSID,STRING),
-	DEBUG_REC(CURRENTBSSID,BYTES),
-	DEBUG_REC(COMMSQUALITY,WORDS),
-	DEBUG_REC(CURRENTTXRATE,WORDS),
-	DEBUG_REC(CURRENTBEACONINTERVAL,WORDS),
-	DEBUG_REC(CURRENTSCALETHRESHOLDS,WORDS),
-	DEBUG_REC(PROTOCOLRSPTIME,WORDS),
-	DEBUG_REC(SHORTRETRYLIMIT,WORDS),
-	DEBUG_REC(LONGRETRYLIMIT,WORDS),
-	DEBUG_REC(MAXTRANSMITLIFETIME,WORDS),
-	DEBUG_REC(MAXRECEIVELIFETIME,WORDS),
-	DEBUG_REC(CFPOLLABLE,WORDS),
-	DEBUG_REC(AUTHENTICATIONALGORITHMS,WORDS),
-	DEBUG_REC(PRIVACYOPTIONIMPLEMENTED,WORDS),
-	DEBUG_REC(OWNMACADDR,BYTES),
-	DEBUG_REC(SCANRESULTSTABLE,WORDS),
-	DEBUG_REC(PHYTYPE,WORDS),
-	DEBUG_REC(CURRENTCHANNEL,WORDS),
-	DEBUG_REC(CURRENTPOWERSTATE,WORDS),
-	DEBUG_REC(CCAMODE,WORDS),
-	DEBUG_REC(SUPPORTEDDATARATES,WORDS),
-	DEBUG_REC(BUILDSEQ,BYTES),
-	DEBUG_REC(FWID,XSTRING)
-#undef DEBUG_REC
-};
-
-#define DEBUG_LTV_SIZE		128
-
-static int orinoco_debug_dump_recs(struct net_device *dev)
-{
-	struct orinoco_private *priv = netdev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	u8 *val8;
-	u16 *val16;
-	int i,j;
-	u16 length;
-	int err;
-
-	/* I'm not sure: we might have a lock here, so we'd better go
-           atomic, just in case. */
-	val8 = kmalloc(DEBUG_LTV_SIZE + 2, GFP_ATOMIC);
-	if (! val8)
-		return -ENOMEM;
-	val16 = (u16 *)val8;
-
-	for (i = 0; i < ARRAY_SIZE(record_table); i++) {
-		u16 rid = record_table[i].rid;
-		int len;
-
-		memset(val8, 0, DEBUG_LTV_SIZE + 2);
-
-		err = hermes_read_ltv(hw, USER_BAP, rid, DEBUG_LTV_SIZE,
-				      &length, val8);
-		if (err) {
-			DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid);
-			continue;
-		}
-		val16 = (u16 *)val8;
-		if (length == 0)
-			continue;
-
-		printk(KERN_DEBUG "%-15s (0x%04x): length=%d (%d bytes)\tvalue=",
-		       record_table[i].name,
-		       rid, length, (length-1)*2);
-		len = min(((int)length-1)*2, DEBUG_LTV_SIZE);
-
-		switch (record_table[i].displaytype) {
-		case DISPLAY_WORDS:
-			for (j = 0; j < len / 2; j++)
-				printk("%04X-", le16_to_cpu(val16[j]));
-			break;
-
-		case DISPLAY_BYTES:
-		default:
-			for (j = 0; j < len; j++)
-				printk("%02X:", val8[j]);
-			break;
-
-		case DISPLAY_STRING:
-			len = min(len, le16_to_cpu(val16[0])+2);
-			val8[len] = '\0';
-			printk("\"%s\"", (char *)&val16[1]);
-			break;
-
-		case DISPLAY_XSTRING:
-			printk("'%s'", (char *)val8);
-		}
-
-		printk("\n");
-	}
-
-	kfree(val8);
-
-	return 0;
-}
 
 /********************************************************************/
 /* Debugging                                                        */
@@ -4218,7 +4025,6 @@ EXPORT_SYMBOL(free_orinocodev);
 
 EXPORT_SYMBOL(__orinoco_up);
 EXPORT_SYMBOL(__orinoco_down);
-EXPORT_SYMBOL(orinoco_stop);
 EXPORT_SYMBOL(orinoco_reinit_firmware);
 
 EXPORT_SYMBOL(orinoco_interrupt);

+ 0 - 1
drivers/net/wireless/orinoco.h

@@ -119,7 +119,6 @@ extern struct net_device *alloc_orinocodev(int sizeof_card,
 extern void free_orinocodev(struct net_device *dev);
 extern int __orinoco_up(struct net_device *dev);
 extern int __orinoco_down(struct net_device *dev);
-extern int orinoco_stop(struct net_device *dev);
 extern int orinoco_reinit_firmware(struct net_device *dev);
 extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
 

+ 1 - 1
drivers/pci/pci-driver.c

@@ -396,7 +396,7 @@ int pci_register_driver(struct pci_driver *drv)
 	/* FIXME, once all of the existing PCI drivers have been fixed to set
 	 * the pci shutdown function, this test can go away. */
 	if (!drv->driver.shutdown)
-		drv->driver.shutdown = pci_device_shutdown,
+		drv->driver.shutdown = pci_device_shutdown;
 	drv->driver.owner = drv->owner;
 	drv->driver.kobj.ktype = &pci_driver_kobj_type;
 	pci_init_dynids(&drv->dynids);

+ 20 - 17
drivers/s390/scsi/zfcp_aux.c

@@ -97,11 +97,6 @@ MODULE_PARM_DESC(loglevel,
 		 "FC ERP QDIO CIO Config FSF SCSI Other, "
 		 "levels: 0=none 1=normal 2=devel 3=trace");
 
-#ifdef ZFCP_PRINT_FLAGS
-u32 flags_dump = 0;
-module_param(flags_dump, uint, 0);
-#endif
-
 /****************************************************************/
 /************** Functions without logging ***********************/
 /****************************************************************/
@@ -223,13 +218,20 @@ zfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text,
  * Parse "device=..." parameter string.
  */
 static int __init
-zfcp_device_setup(char *str)
+zfcp_device_setup(char *devstr)
 {
-	char *tmp;
+	char *tmp, *str;
+	size_t len;
 
-	if (!str)
+	if (!devstr)
 		return 0;
 
+	len = strlen(devstr) + 1;
+	str = (char *) kmalloc(len, GFP_KERNEL);
+	if (!str)
+		goto err_out;
+	memcpy(str, devstr, len);
+
 	tmp = strchr(str, ',');
 	if (!tmp)
 		goto err_out;
@@ -246,10 +248,12 @@ zfcp_device_setup(char *str)
 	zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0);
 	if (*tmp != '\0')
 		goto err_out;
+	kfree(str);
 	return 1;
 
  err_out:
 	ZFCP_LOG_NORMAL("Parse error for device parameter string %s\n", str);
+	kfree(str);
 	return 0;
 }
 
@@ -525,7 +529,7 @@ zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
 
  out:
 	if (fsf_req != NULL)
-		zfcp_fsf_req_cleanup(fsf_req);
+		zfcp_fsf_req_free(fsf_req);
 
 	if ((adapter != NULL) && (retval != -ENXIO))
 		zfcp_adapter_put(adapter);
@@ -1154,7 +1158,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
 	INIT_LIST_HEAD(&adapter->port_remove_lh);
 
 	/* initialize list of fsf requests */
-	rwlock_init(&adapter->fsf_req_list_lock);
+	spin_lock_init(&adapter->fsf_req_list_lock);
 	INIT_LIST_HEAD(&adapter->fsf_req_list_head);
 
 	/* initialize abort lock */
@@ -1239,9 +1243,9 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
 	zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
 	dev_set_drvdata(&adapter->ccw_device->dev, NULL);
 	/* sanity check: no pending FSF requests */
-	read_lock_irqsave(&adapter->fsf_req_list_lock, flags);
+	spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
 	retval = !list_empty(&adapter->fsf_req_list_head);
-	read_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
+	spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
 	if (retval) {
 		ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, "
 				"%i requests outstanding\n",
@@ -1483,19 +1487,15 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
 		fcp_rscn_element++;
 		switch (fcp_rscn_element->addr_format) {
 		case ZFCP_PORT_ADDRESS:
-			ZFCP_LOG_FLAGS(1, "ZFCP_PORT_ADDRESS\n");
 			range_mask = ZFCP_PORTS_RANGE_PORT;
 			break;
 		case ZFCP_AREA_ADDRESS:
-			ZFCP_LOG_FLAGS(1, "ZFCP_AREA_ADDRESS\n");
 			range_mask = ZFCP_PORTS_RANGE_AREA;
 			break;
 		case ZFCP_DOMAIN_ADDRESS:
-			ZFCP_LOG_FLAGS(1, "ZFCP_DOMAIN_ADDRESS\n");
 			range_mask = ZFCP_PORTS_RANGE_DOMAIN;
 			break;
 		case ZFCP_FABRIC_ADDRESS:
-			ZFCP_LOG_FLAGS(1, "ZFCP_FABRIC_ADDRESS\n");
 			range_mask = ZFCP_PORTS_RANGE_FABRIC;
 			break;
 		default:
@@ -1762,7 +1762,10 @@ static void zfcp_ns_gid_pn_handler(unsigned long data)
 	ct_iu_req = zfcp_sg_to_address(ct->req);
 	ct_iu_resp = zfcp_sg_to_address(ct->resp);
 
-	if ((ct->status != 0) || zfcp_check_ct_response(&ct_iu_resp->header)) {
+	if (ct->status != 0)
+		goto failed;
+
+	if (zfcp_check_ct_response(&ct_iu_resp->header)) {
 		/* FIXME: do we need some specific erp entry points */
 		atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
 		goto failed;

+ 8 - 17
drivers/s390/scsi/zfcp_def.h

@@ -62,9 +62,6 @@
 #include <linux/syscalls.h>
 #include <linux/ioctl.h>
 
-/************************ DEBUG FLAGS *****************************************/
-
-#define	ZFCP_PRINT_FLAGS
 
 /********************* GENERAL DEFINES *********************************/
 
@@ -152,8 +149,10 @@ typedef u32 scsi_lun_t;
 #define FSF_QTCB_UNSOLICITED_STATUS		0x6305
 #define ZFCP_STATUS_READ_FAILED_THRESHOLD	3
 #define ZFCP_STATUS_READS_RECOM		        FSF_STATUS_READS_RECOM
-#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES	6
-#define ZFCP_EXCHANGE_CONFIG_DATA_SLEEP		50
+
+/* Do 1st retry in 1 second, then double the timeout for each following retry */
+#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP	100
+#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES	7
 
 /* timeout value for "default timer" for fsf requests */
 #define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ);
@@ -472,17 +471,6 @@ do { \
 	ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args)
 #endif
 
-#ifndef ZFCP_PRINT_FLAGS
-# define ZFCP_LOG_FLAGS(level, fmt, args...)
-#else
-extern u32 flags_dump;
-# define ZFCP_LOG_FLAGS(level, fmt, args...) \
-do { \
-	if (level <= flags_dump) \
-		_ZFCP_LOG(fmt, ##args); \
-} while (0)
-#endif
-
 /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
 
 /* 
@@ -502,6 +490,7 @@ do { \
 #define ZFCP_STATUS_COMMON_CLOSING              0x02000000
 #define ZFCP_STATUS_COMMON_ERP_INUSE		0x01000000
 #define ZFCP_STATUS_COMMON_ACCESS_DENIED	0x00800000
+#define ZFCP_STATUS_COMMON_ACCESS_BOXED		0x00400000
 
 /* adapter status */
 #define ZFCP_STATUS_ADAPTER_QDIOUP		0x00000002
@@ -763,6 +752,7 @@ typedef void (*zfcp_send_els_handler_t)(unsigned long);
 /**
  * struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els
  * @adapter: adapter where request is sent from
+ * @port: port where ELS is destinated (port reference count has to be increased)
  * @d_id: destiniation id of port where request is sent to
  * @req: scatter-gather list for request
  * @resp: scatter-gather list for response
@@ -777,6 +767,7 @@ typedef void (*zfcp_send_els_handler_t)(unsigned long);
  */
 struct zfcp_send_els {
 	struct zfcp_adapter *adapter;
+	struct zfcp_port *port;
 	fc_id_t d_id;
 	struct scatterlist *req;
 	struct scatterlist *resp;
@@ -871,7 +862,7 @@ struct zfcp_adapter {
 	u32			ports;	           /* number of remote ports */
         struct timer_list       scsi_er_timer;     /* SCSI err recovery watch */
 	struct list_head	fsf_req_list_head; /* head of FSF req list */
-	rwlock_t		fsf_req_list_lock; /* lock for ops on list of
+	spinlock_t		fsf_req_list_lock; /* lock for ops on list of
 						      FSF requests */
         atomic_t       		fsf_reqs_active;   /* # active FSF reqs */
 	struct zfcp_qdio_queue	request_queue;	   /* request queue */

+ 83 - 38
drivers/s390/scsi/zfcp_erp.c

@@ -35,7 +35,7 @@
 
 #include "zfcp_ext.h"
 
-static int zfcp_erp_adisc(struct zfcp_adapter *, fc_id_t);
+static int zfcp_erp_adisc(struct zfcp_port *);
 static void zfcp_erp_adisc_handler(unsigned long);
 
 static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int);
@@ -295,12 +295,12 @@ zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask)
 
 /**
  * zfcp_erp_adisc - send ADISC ELS command
- * @adapter: adapter structure
- * @d_id: d_id of port where ADISC is sent to
+ * @port: port structure
  */
 int
-zfcp_erp_adisc(struct zfcp_adapter *adapter, fc_id_t d_id)
+zfcp_erp_adisc(struct zfcp_port *port)
 {
+	struct zfcp_adapter *adapter = port->adapter;
 	struct zfcp_send_els *send_els;
 	struct zfcp_ls_adisc *adisc;
 	void *address = NULL;
@@ -332,7 +332,8 @@ zfcp_erp_adisc(struct zfcp_adapter *adapter, fc_id_t d_id)
 	send_els->req_count = send_els->resp_count = 1;
 
 	send_els->adapter = adapter;
-	send_els->d_id = d_id;
+	send_els->port = port;
+	send_els->d_id = port->d_id;
 	send_els->handler = zfcp_erp_adisc_handler;
 	send_els->handler_data = (unsigned long) send_els;
 
@@ -350,7 +351,7 @@ zfcp_erp_adisc(struct zfcp_adapter *adapter, fc_id_t d_id)
 	ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x "
 		      "(wwpn=0x%016Lx, wwnn=0x%016Lx, "
 		      "hard_nport_id=0x%08x, nport_id=0x%08x)\n",
-		      adapter->s_id, d_id, (wwn_t) adisc->wwpn,
+		      adapter->s_id, send_els->d_id, (wwn_t) adisc->wwpn,
 		      (wwn_t) adisc->wwnn, adisc->hard_nport_id,
 		      adisc->nport_id);
 
@@ -367,7 +368,7 @@ zfcp_erp_adisc(struct zfcp_adapter *adapter, fc_id_t d_id)
 	retval = zfcp_fsf_send_els(send_els);
 	if (retval != 0) {
 		ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port "
-				"0x%08x on adapter %s\n", d_id,
+				"0x%08x on adapter %s\n", send_els->d_id,
 				zfcp_get_busid_by_adapter(adapter));
 		del_timer(send_els->timer);
 		goto freemem;
@@ -411,14 +412,9 @@ zfcp_erp_adisc_handler(unsigned long data)
 	del_timer(send_els->timer);
 
 	adapter = send_els->adapter;
+	port = send_els->port;
 	d_id = send_els->d_id;
 
-	read_lock(&zfcp_data.config_lock);
-	port = zfcp_get_port_by_did(send_els->adapter, send_els->d_id);
-	read_unlock(&zfcp_data.config_lock);
-
-	BUG_ON(port == NULL);
-
 	/* request rejected or timed out */
 	if (send_els->status != 0) {
 		ZFCP_LOG_NORMAL("ELS request rejected/timed out, "
@@ -482,7 +478,7 @@ zfcp_test_link(struct zfcp_port *port)
 	int retval;
 
 	zfcp_port_get(port);
-	retval = zfcp_erp_adisc(port->adapter, port->d_id);
+	retval = zfcp_erp_adisc(port);
 	if (retval != 0) {
 		zfcp_port_put(port);
 		ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx "
@@ -895,7 +891,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
 
 	if (erp_action->fsf_req) {
 		/* take lock to ensure that request is not being deleted meanwhile */
-		write_lock(&adapter->fsf_req_list_lock);
+		spin_lock(&adapter->fsf_req_list_lock);
 		/* check whether fsf req does still exist */
 		list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list)
 		    if (fsf_req == erp_action->fsf_req)
@@ -938,7 +934,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
 			 */
 			erp_action->fsf_req = NULL;
 		}
-		write_unlock(&adapter->fsf_req_list_lock);
+		spin_unlock(&adapter->fsf_req_list_lock);
 	} else
 		debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq");
 
@@ -2286,12 +2282,12 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
 {
 	int retval = ZFCP_ERP_SUCCEEDED;
 	int retries;
+	int sleep = ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 
 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
-	retries = ZFCP_EXCHANGE_CONFIG_DATA_RETRIES;
 
-	do {
+	for (retries = ZFCP_EXCHANGE_CONFIG_DATA_RETRIES; retries; retries--) {
 		atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
 				  &adapter->status);
 		ZFCP_LOG_DEBUG("Doing exchange config data\n");
@@ -2329,16 +2325,17 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
 				      zfcp_get_busid_by_adapter(adapter));
 			break;
 		}
-		if (atomic_test_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
-				     &adapter->status)) {
-			ZFCP_LOG_DEBUG("host connection still initialising... "
-				       "waiting and retrying...\n");
-			/* sleep a little bit before retry */
-			msleep(jiffies_to_msecs(ZFCP_EXCHANGE_CONFIG_DATA_SLEEP));
-		}
-	} while ((retries--) &&
-		 atomic_test_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
-				  &adapter->status));
+
+		if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
+				     &adapter->status))
+			break;
+
+		ZFCP_LOG_DEBUG("host connection still initialising... "
+			       "waiting and retrying...\n");
+		/* sleep a little bit before retry */
+		msleep(jiffies_to_msecs(sleep));
+		sleep *= 2;
+	}
 
 	if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
 			      &adapter->status)) {
@@ -3484,6 +3481,45 @@ zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
 	list_move(&erp_action->list, &erp_action->adapter->erp_ready_head);
 }
 
+/*
+ * function:	zfcp_erp_port_boxed
+ *
+ * purpose:
+ */
+void
+zfcp_erp_port_boxed(struct zfcp_port *port)
+{
+	struct zfcp_adapter *adapter = port->adapter;
+	unsigned long flags;
+
+	debug_text_event(adapter->erp_dbf, 3, "p_access_boxed");
+	debug_event(adapter->erp_dbf, 3, &port->wwpn, sizeof(wwn_t));
+	read_lock_irqsave(&zfcp_data.config_lock, flags);
+	zfcp_erp_modify_port_status(port,
+			ZFCP_STATUS_COMMON_ACCESS_BOXED,
+			ZFCP_SET);
+	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED);
+}
+
+/*
+ * function:	zfcp_erp_unit_boxed
+ *
+ * purpose:
+ */
+void
+zfcp_erp_unit_boxed(struct zfcp_unit *unit)
+{
+	struct zfcp_adapter *adapter = unit->port->adapter;
+
+	debug_text_event(adapter->erp_dbf, 3, "u_access_boxed");
+	debug_event(adapter->erp_dbf, 3, &unit->fcp_lun, sizeof(fcp_lun_t));
+	zfcp_erp_modify_unit_status(unit,
+			ZFCP_STATUS_COMMON_ACCESS_BOXED,
+			ZFCP_SET);
+	zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED);
+}
+
 /*
  * function:	zfcp_erp_port_access_denied
  *
@@ -3495,11 +3531,13 @@ zfcp_erp_port_access_denied(struct zfcp_port *port)
 	struct zfcp_adapter *adapter = port->adapter;
 	unsigned long flags;
 
-	debug_text_event(adapter->erp_dbf, 3, "p_access_block");
+	debug_text_event(adapter->erp_dbf, 3, "p_access_denied");
 	debug_event(adapter->erp_dbf, 3, &port->wwpn, sizeof(wwn_t));
 	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED |
-				    ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
+	zfcp_erp_modify_port_status(port,
+			ZFCP_STATUS_COMMON_ERP_FAILED |
+			ZFCP_STATUS_COMMON_ACCESS_DENIED,
+			ZFCP_SET);
 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
@@ -3513,10 +3551,12 @@ zfcp_erp_unit_access_denied(struct zfcp_unit *unit)
 {
 	struct zfcp_adapter *adapter = unit->port->adapter;
 
-	debug_text_event(adapter->erp_dbf, 3, "u_access_block");
+	debug_text_event(adapter->erp_dbf, 3, "u_access_denied");
 	debug_event(adapter->erp_dbf, 3, &unit->fcp_lun, sizeof(fcp_lun_t));
-	zfcp_erp_modify_unit_status(unit, ZFCP_STATUS_COMMON_ERP_FAILED |
-				    ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
+	zfcp_erp_modify_unit_status(unit,
+			ZFCP_STATUS_COMMON_ERP_FAILED |
+			ZFCP_STATUS_COMMON_ACCESS_DENIED,
+			ZFCP_SET);
 }
 
 /*
@@ -3530,7 +3570,7 @@ zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter)
 	struct zfcp_port *port;
 	unsigned long flags;
 
-	debug_text_event(adapter->erp_dbf, 3, "a_access_unblock");
+	debug_text_event(adapter->erp_dbf, 3, "a_access_recover");
 	debug_event(adapter->erp_dbf, 3, &adapter->name, 8);
 
 	read_lock_irqsave(&zfcp_data.config_lock, flags);
@@ -3553,10 +3593,12 @@ zfcp_erp_port_access_changed(struct zfcp_port *port)
 	struct zfcp_adapter *adapter = port->adapter;
 	struct zfcp_unit *unit;
 
-	debug_text_event(adapter->erp_dbf, 3, "p_access_unblock");
+	debug_text_event(adapter->erp_dbf, 3, "p_access_recover");
 	debug_event(adapter->erp_dbf, 3, &port->wwpn, sizeof(wwn_t));
 
 	if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED,
+			      &port->status) &&
+	    !atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED,
 			      &port->status)) {
 		if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status))
 			list_for_each_entry(unit, &port->unit_list_head, list)
@@ -3583,10 +3625,13 @@ zfcp_erp_unit_access_changed(struct zfcp_unit *unit)
 {
 	struct zfcp_adapter *adapter = unit->port->adapter;
 
-	debug_text_event(adapter->erp_dbf, 3, "u_access_unblock");
+	debug_text_event(adapter->erp_dbf, 3, "u_access_recover");
 	debug_event(adapter->erp_dbf, 3, &unit->fcp_lun, sizeof(fcp_lun_t));
 
-	if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &unit->status))
+	if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED,
+			      &unit->status) &&
+	    !atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED,
+			      &unit->status))
 		return;
 
 	ZFCP_LOG_NORMAL("reopen of unit 0x%016Lx on port 0x%016Lx "

+ 3 - 1
drivers/s390/scsi/zfcp_ext.h

@@ -116,7 +116,7 @@ extern int  zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
 					   struct timer_list*, int);
 extern int  zfcp_fsf_req_complete(struct zfcp_fsf_req *);
 extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *);
-extern void zfcp_fsf_req_cleanup(struct zfcp_fsf_req *);
+extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
 extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_command_task_management(
 	struct zfcp_adapter *, struct zfcp_unit *, u8, int);
 extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(
@@ -171,6 +171,8 @@ extern int  zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long);
 
 extern int  zfcp_test_link(struct zfcp_port *);
 
+extern void zfcp_erp_port_boxed(struct zfcp_port *);
+extern void zfcp_erp_unit_boxed(struct zfcp_unit *);
 extern void zfcp_erp_port_access_denied(struct zfcp_port *);
 extern void zfcp_erp_unit_access_denied(struct zfcp_unit *);
 extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *);

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 31 - 179
drivers/s390/scsi/zfcp_fsf.c


+ 15 - 53
drivers/s390/scsi/zfcp_qdio.c

@@ -229,52 +229,14 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter,
 			ZFCP_LOG_TRACE("status is"
 				       " QDIO_STATUS_OUTBOUND_INT \n");
 		}
-	}			// if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE))
+	}
 	if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) {
 		retval = -EIO;
 
-		ZFCP_LOG_FLAGS(1, "QDIO_STATUS_LOOK_FOR_ERROR \n");
-
 		ZFCP_LOG_INFO("QDIO problem occurred (status=0x%x, "
 			      "qdio_error=0x%x, siga_error=0x%x)\n",
 			      status, qdio_error, siga_error);
 
-		if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION) {
-			ZFCP_LOG_FLAGS(2,
-				       "QDIO_STATUS_ACTIVATE_CHECK_CONDITION\n");
-		}
-		if (status & QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR) {
-			ZFCP_LOG_FLAGS(2,
-				       "QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR\n");
-		}
-		if (status & QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR) {
-			ZFCP_LOG_FLAGS(2,
-				       "QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR\n");
-		}
-
-		if (siga_error & QDIO_SIGA_ERROR_ACCESS_EXCEPTION) {
-			ZFCP_LOG_FLAGS(2, "QDIO_SIGA_ERROR_ACCESS_EXCEPTION\n");
-		}
-
-		if (siga_error & QDIO_SIGA_ERROR_B_BIT_SET) {
-			ZFCP_LOG_FLAGS(2, "QDIO_SIGA_ERROR_B_BIT_SET\n");
-		}
-
-		switch (qdio_error) {
-		case 0:
-			ZFCP_LOG_FLAGS(3, "QDIO_OK");
-			break;
-		case SLSB_P_INPUT_ERROR:
-			ZFCP_LOG_FLAGS(1, "SLSB_P_INPUT_ERROR\n");
-			break;
-		case SLSB_P_OUTPUT_ERROR:
-			ZFCP_LOG_FLAGS(1, "SLSB_P_OUTPUT_ERROR\n");
-			break;
-		default:
-			ZFCP_LOG_NORMAL("bug: unknown QDIO error 0x%x\n",
-					qdio_error);
-			break;
-		}
 		/* Restarting IO on the failed adapter from scratch */
 		debug_text_event(adapter->erp_dbf, 1, "qdio_err");
                /*
@@ -484,37 +446,37 @@ int
 zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
 {
 	struct zfcp_fsf_req *fsf_req;
-	int retval = 0;
 
 	/* invalid (per convention used in this driver) */
 	if (unlikely(!sbale_addr)) {
 		ZFCP_LOG_NORMAL("bug: invalid reqid\n");
-		retval = -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	/* valid request id and thus (hopefully :) valid fsf_req address */
 	fsf_req = (struct zfcp_fsf_req *) sbale_addr;
 
+	/* serialize with zfcp_fsf_req_dismiss_all */
+	spin_lock(&adapter->fsf_req_list_lock);
+	if (list_empty(&adapter->fsf_req_list_head)) {
+		spin_unlock(&adapter->fsf_req_list_lock);
+		return 0;
+	}
+	list_del(&fsf_req->list);
+	atomic_dec(&adapter->fsf_reqs_active);
+	spin_unlock(&adapter->fsf_req_list_lock);
+	
 	if (unlikely(adapter != fsf_req->adapter)) {
 		ZFCP_LOG_NORMAL("bug: invalid reqid (fsf_req=%p, "
 				"fsf_req->adapter=%p, adapter=%p)\n",
 				fsf_req, fsf_req->adapter, adapter);
-		retval = -EINVAL;
-		goto out;
-	}
-
-	ZFCP_LOG_TRACE("fsf_req at %p, QTCB at %p\n", fsf_req, fsf_req->qtcb);
-	if (likely(fsf_req->qtcb)) {
-		ZFCP_LOG_TRACE("hex dump of QTCB:\n");
-		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) fsf_req->qtcb,
-			      sizeof(struct fsf_qtcb));
+		return -EINVAL;
 	}
 
 	/* finish the FSF request */
 	zfcp_fsf_req_complete(fsf_req);
- out:
-	return retval;
+
+	return 0;
 }
 
 /**

+ 13 - 11
drivers/s390/scsi/zfcp_scsi.c

@@ -433,7 +433,7 @@ zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id)
  *		FAILED	- otherwise
  */
 int
-zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+__zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 {
 	int retval = SUCCESS;
 	struct zfcp_fsf_req *new_fsf_req, *old_fsf_req;
@@ -575,7 +575,7 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 	    *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[0];
 	dbf_fsf_qual[1] =
 	    *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[2];
-	zfcp_fsf_req_cleanup(new_fsf_req);
+	zfcp_fsf_req_free(new_fsf_req);
 #else
 	retval = zfcp_fsf_req_wait_and_cleanup(new_fsf_req,
 					       ZFCP_UNINTERRUPTIBLE, &status);
@@ -611,6 +611,17 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 	return retval;
 }
 
+int
+zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+{
+	int rc;
+	struct Scsi_Host *scsi_host = scpnt->device->host;
+	spin_lock_irq(scsi_host->host_lock);
+	rc = __zfcp_scsi_eh_abort_handler(scpnt);
+	spin_unlock_irq(scsi_host->host_lock);
+	return rc;
+}
+
 /*
  * function:	zfcp_scsi_eh_device_reset_handler
  *
@@ -625,8 +636,6 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
 	struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
 	struct Scsi_Host *scsi_host = scpnt->device->host;
 
-	spin_unlock_irq(scsi_host->host_lock);
-
 	if (!unit) {
 		ZFCP_LOG_NORMAL("bug: Tried reset for nonexistent unit\n");
 		retval = SUCCESS;
@@ -669,7 +678,6 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
 		retval = SUCCESS;
 	}
  out:
-	spin_lock_irq(scsi_host->host_lock);
 	return retval;
 }
 
@@ -723,8 +731,6 @@ zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
 	struct zfcp_unit *unit;
 	struct Scsi_Host *scsi_host = scpnt->device->host;
 
-	spin_unlock_irq(scsi_host->host_lock);
-
 	unit = (struct zfcp_unit *) scpnt->device->hostdata;
 	ZFCP_LOG_NORMAL("bus reset because of problems with "
 			"unit 0x%016Lx\n", unit->fcp_lun);
@@ -732,7 +738,6 @@ zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
 	zfcp_erp_wait(unit->port->adapter);
 	retval = SUCCESS;
 
-	spin_lock_irq(scsi_host->host_lock);
 	return retval;
 }
 
@@ -750,8 +755,6 @@ zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 	struct zfcp_unit *unit;
 	struct Scsi_Host *scsi_host = scpnt->device->host;
 
-	spin_unlock_irq(scsi_host->host_lock);
-
 	unit = (struct zfcp_unit *) scpnt->device->hostdata;
 	ZFCP_LOG_NORMAL("host reset because of problems with "
 			"unit 0x%016Lx\n", unit->fcp_lun);
@@ -759,7 +762,6 @@ zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 	zfcp_erp_wait(unit->port->adapter);
 	retval = SUCCESS;
 
-	spin_lock_irq(scsi_host->host_lock);
 	return retval;
 }
 

+ 0 - 3
drivers/scsi/3w-9xxx.c

@@ -1695,8 +1695,6 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
 
 	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
 
-	spin_unlock_irq(tw_dev->host->host_lock);
-
 	tw_dev->num_resets++;
 
 	printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0x2c, SCpnt->device->id, SCpnt->cmnd[0]);
@@ -1709,7 +1707,6 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
 
 	retval = SUCCESS;
 out:
-	spin_lock_irq(tw_dev->host->host_lock);
 	return retval;
 } /* End twa_scsi_eh_reset() */
 

+ 0 - 3
drivers/scsi/3w-xxxx.c

@@ -1430,8 +1430,6 @@ static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt)
 
 	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
 
-	spin_unlock_irq(tw_dev->host->host_lock);
-
 	tw_dev->num_resets++;
 
 	printk(KERN_WARNING "3w-xxxx: scsi%d: WARNING: Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, SCpnt->device->id, SCpnt->cmnd[0]);
@@ -1444,7 +1442,6 @@ static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt)
 
 	retval = SUCCESS;
 out:
-	spin_lock_irq(tw_dev->host->host_lock);
 	return retval;
 } /* End tw_scsi_eh_reset() */
 

+ 13 - 13
drivers/scsi/53c700.c

@@ -170,7 +170,6 @@ MODULE_LICENSE("GPL");
 STATIC int NCR_700_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
 STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt);
 STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt);
-STATIC int NCR_700_dev_reset(struct scsi_cmnd * SCpnt);
 STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);
 STATIC void NCR_700_chip_setup(struct Scsi_Host *host);
 STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
@@ -330,7 +329,6 @@ NCR_700_detect(struct scsi_host_template *tpnt,
 	/* Fill in the missing routines from the host template */
 	tpnt->queuecommand = NCR_700_queuecommand;
 	tpnt->eh_abort_handler = NCR_700_abort;
-	tpnt->eh_device_reset_handler = NCR_700_dev_reset;
 	tpnt->eh_bus_reset_handler = NCR_700_bus_reset;
 	tpnt->eh_host_reset_handler = NCR_700_host_reset;
 	tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST;
@@ -1959,34 +1957,31 @@ NCR_700_bus_reset(struct scsi_cmnd * SCp)
 	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants BUS reset, cmd %p\n\t",
 	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun, SCp);
 	scsi_print_command(SCp);
+
 	/* In theory, eh_complete should always be null because the
 	 * eh is single threaded, but just in case we're handling a
 	 * reset via sg or something */
-	while(hostdata->eh_complete != NULL) {
+	spin_lock_irq(SCp->device->host->host_lock);
+	while (hostdata->eh_complete != NULL) {
 		spin_unlock_irq(SCp->device->host->host_lock);
 		msleep_interruptible(100);
 		spin_lock_irq(SCp->device->host->host_lock);
 	}
+
 	hostdata->eh_complete = &complete;
 	NCR_700_internal_bus_reset(SCp->device->host);
+
 	spin_unlock_irq(SCp->device->host->host_lock);
 	wait_for_completion(&complete);
 	spin_lock_irq(SCp->device->host->host_lock);
+
 	hostdata->eh_complete = NULL;
 	/* Revalidate the transport parameters of the failing device */
 	if(hostdata->fast)
 		spi_schedule_dv_device(SCp->device);
-	return SUCCESS;
-}
 
-STATIC int
-NCR_700_dev_reset(struct scsi_cmnd * SCp)
-{
-	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants device reset\n\t",
-	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
-	scsi_print_command(SCp);
-	
-	return FAILED;
+	spin_unlock_irq(SCp->device->host->host_lock);
+	return SUCCESS;
 }
 
 STATIC int
@@ -1996,8 +1991,13 @@ NCR_700_host_reset(struct scsi_cmnd * SCp)
 	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
 	scsi_print_command(SCp);
 
+	spin_lock_irq(SCp->device->host->host_lock);
+
 	NCR_700_internal_bus_reset(SCp->device->host);
 	NCR_700_chip_reset(SCp->device->host);
+
+	spin_unlock_irq(SCp->device->host->host_lock);
+
 	return SUCCESS;
 }
 

+ 7 - 1
drivers/scsi/BusLogic.c

@@ -2746,9 +2746,15 @@ static int BusLogic_host_reset(struct scsi_cmnd * SCpnt)
 
 	unsigned int id = SCpnt->device->id;
 	struct BusLogic_TargetStatistics *stats = &HostAdapter->TargetStatistics[id];
+	int rc;
+
+	spin_lock_irq(SCpnt->device->host->host_lock);
+
 	BusLogic_IncrementErrorCounter(&stats->HostAdapterResetsRequested);
 
-	return BusLogic_ResetHostAdapter(HostAdapter, false);
+	rc = BusLogic_ResetHostAdapter(HostAdapter, false);
+	spin_unlock_irq(SCpnt->device->host->host_lock);
+	return rc;
 }
 
 /*

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 119 - 1046
drivers/scsi/FlashPoint.c


Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно