summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2012-03-15 11:08:55 -0400
committerAnthony G. Basile <blueness@gentoo.org>2012-03-15 11:08:55 -0400
commitb7a6f90d3700011af95712bbd6f8ec4aa89a63e9 (patch)
tree33af07c0c60829e04e0eebb61a380bfc9a5c74fd
parentGrsec/PaX: 2.9-2.6.32.58-201203062047 + 2.9-3.2.9-201203062051 (diff)
downloadhardened-patchset-20120314.tar.gz
hardened-patchset-20120314.tar.bz2
hardened-patchset-20120314.zip
Grsec/PaX: 2.9-2.6.32.58-201203131839 + 2.9-3.2.11-20120314195620120314
-rw-r--r--2.6.32/0000_README2
-rw-r--r--2.6.32/4420_grsecurity-2.9-2.6.32.58-201203131839.patch (renamed from 2.6.32/4420_grsecurity-2.9-2.6.32.58-201203062047.patch)18315
-rw-r--r--2.6.32/4445_grsec-pax-without-grsec.patch11
-rw-r--r--2.6.32/4450_grsec-kconfig-default-gids.patch14
-rw-r--r--2.6.32/4460-grsec-kconfig-proc-user.patch4
-rw-r--r--2.6.32/4465_selinux-avc_audit-log-curr_ip.patch2
-rw-r--r--3.2.11/0000_README (renamed from 3.2.9/0000_README)2
-rw-r--r--3.2.11/4420_grsecurity-2.9-3.2.11-201203141956.patch (renamed from 3.2.9/4420_grsecurity-2.9-3.2.9-201203062051.patch)2007
-rw-r--r--3.2.11/4425_grsec_enable_xtpax.patch (renamed from 3.2.9/4425_grsec_enable_xtpax.patch)0
-rw-r--r--3.2.11/4430_grsec-remove-localversion-grsec.patch (renamed from 3.2.9/4430_grsec-remove-localversion-grsec.patch)0
-rw-r--r--3.2.11/4435_grsec-mute-warnings.patch (renamed from 3.2.9/4435_grsec-mute-warnings.patch)0
-rw-r--r--3.2.11/4440_grsec-remove-protected-paths.patch (renamed from 3.2.9/4440_grsec-remove-protected-paths.patch)2
-rw-r--r--3.2.11/4445_grsec-pax-without-grsec.patch (renamed from 3.2.9/4445_grsec-pax-without-grsec.patch)11
-rw-r--r--3.2.11/4450_grsec-kconfig-default-gids.patch (renamed from 3.2.9/4450_grsec-kconfig-default-gids.patch)14
-rw-r--r--3.2.11/4455_grsec-kconfig-gentoo.patch (renamed from 3.2.9/4455_grsec-kconfig-gentoo.patch)0
-rw-r--r--3.2.11/4460-grsec-kconfig-proc-user.patch (renamed from 3.2.9/4460-grsec-kconfig-proc-user.patch)4
-rw-r--r--3.2.11/4465_selinux-avc_audit-log-curr_ip.patch (renamed from 3.2.9/4465_selinux-avc_audit-log-curr_ip.patch)2
-rw-r--r--3.2.11/4470_disable-compat_vdso.patch (renamed from 3.2.9/4470_disable-compat_vdso.patch)0
18 files changed, 20018 insertions, 372 deletions
diff --git a/2.6.32/0000_README b/2.6.32/0000_README
index c4a9001..1858adf 100644
--- a/2.6.32/0000_README
+++ b/2.6.32/0000_README
@@ -22,7 +22,7 @@ Patch: 1056_linux-2.6.32.57.patch
From: http://www.kernel.org
Desc: Linux 2.6.32.57
-Patch: 4420_grsecurity-2.9-2.6.32.58-201203062047.patch
+Patch: 4420_grsecurity-2.9-2.6.32.58-201203131839.patch
From: http://www.grsecurity.net
Desc: hardened-sources base patch from upstream grsecurity
diff --git a/2.6.32/4420_grsecurity-2.9-2.6.32.58-201203062047.patch b/2.6.32/4420_grsecurity-2.9-2.6.32.58-201203131839.patch
index bbdf047..325d13c 100644
--- a/2.6.32/4420_grsecurity-2.9-2.6.32.58-201203062047.patch
+++ b/2.6.32/4420_grsecurity-2.9-2.6.32.58-201203131839.patch
@@ -1,5 +1,5 @@
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
-index e1efc40..47f0daf 100644
+index e1efc40..76e689e 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -1,15 +1,19 @@
@@ -96,7 +96,15 @@ index e1efc40..47f0daf 100644
keywords.c
ksym.c*
ksym.h*
-@@ -127,13 +148,16 @@ machtypes.h
+@@ -117,6 +138,7 @@ kxgettext
+ lkc_defs.h
+ lex.c
+ lex.*.c
++lib1funcs.S
+ logo_*.c
+ logo_*_clut224.c
+ logo_*_mono.c
+@@ -127,13 +149,16 @@ machtypes.h
map
maui_boot.h
mconf
@@ -113,7 +121,7 @@ index e1efc40..47f0daf 100644
mktables
mktree
modpost
-@@ -149,6 +173,7 @@ patches*
+@@ -149,6 +174,7 @@ patches*
pca200e.bin
pca200e_ecd.bin2
piggy.gz
@@ -121,7 +129,7 @@ index e1efc40..47f0daf 100644
piggyback
pnmtologo
ppc_defs.h*
-@@ -157,12 +182,15 @@ qconf
+@@ -157,12 +183,15 @@ qconf
raid6altivec*.c
raid6int*.c
raid6tables.c
@@ -137,7 +145,7 @@ index e1efc40..47f0daf 100644
sm_tbl*
split-include
syscalltab.h
-@@ -171,6 +199,7 @@ tftpboot.img
+@@ -171,6 +200,7 @@ tftpboot.img
timeconst.h
times.h*
trix_boot.h
@@ -145,7 +153,7 @@ index e1efc40..47f0daf 100644
utsrelease.h*
vdso-syms.lds
vdso.lds
-@@ -186,14 +215,20 @@ version.h*
+@@ -186,14 +216,20 @@ version.h*
vmlinux
vmlinux-*
vmlinux.aout
@@ -184,8 +192,27 @@ index c840e7d..f4c451c 100644
pcbit= [HW,ISDN]
pcd. [PARIDE]
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 613da5d..4fe3eda 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -5725,6 +5725,14 @@ L: netdev@vger.kernel.org
+ S: Maintained
+ F: drivers/net/vmxnet3/
+
++VMware PVSCSI driver
++M: Alok Kataria <akataria@vmware.com>
++M: VMware PV-Drivers <pv-drivers@vmware.com>
++L: linux-scsi@vger.kernel.org
++S: Maintained
++F: drivers/scsi/vmw_pvscsi.c
++F: drivers/scsi/vmw_pvscsi.h
++
+ VOLTAGE AND CURRENT REGULATOR FRAMEWORK
+ M: Liam Girdwood <lrg@slimlogic.co.uk>
+ M: Mark Brown <broonie@opensource.wolfsonmicro.com>
diff --git a/Makefile b/Makefile
-index ed78982..bcc432e 100644
+index ed78982..cb8fa66 100644
--- a/Makefile
+++ b/Makefile
@@ -221,8 +221,9 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
@@ -220,7 +247,7 @@ index ed78982..bcc432e 100644
include/linux/version.h headers_% \
kernelrelease kernelversion
-@@ -526,6 +527,48 @@ else
+@@ -526,6 +527,50 @@ else
KBUILD_CFLAGS += -O2
endif
@@ -246,7 +273,9 @@ index ed78982..bcc432e 100644
+CHECKER_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/checker_plugin.so -DCHECKER_PLUGIN
+endif
+endif
-+GCC_PLUGINS_CFLAGS := $(CONSTIFY_PLUGIN_CFLAGS) $(STACKLEAK_PLUGIN_CFLAGS) $(KALLOCSTAT_PLUGIN_CFLAGS) $(KERNEXEC_PLUGIN_CFLAGS) $(CHECKER_PLUGIN_CFLAGS)
++COLORIZE_PLUGIN_CFLAGS := -fplugin=$(objtree)/tools/gcc/colorize_plugin.so
++GCC_PLUGINS_CFLAGS := $(CONSTIFY_PLUGIN_CFLAGS) $(STACKLEAK_PLUGIN_CFLAGS) $(KALLOCSTAT_PLUGIN_CFLAGS)
++GCC_PLUGINS_CFLAGS += $(KERNEXEC_PLUGIN_CFLAGS) $(CHECKER_PLUGIN_CFLAGS) $(COLORIZE_PLUGIN_CFLAGS)
+GCC_PLUGINS_AFLAGS := $(KERNEXEC_PLUGIN_AFLAGS)
+export CONSTIFY_PLUGIN STACKLEAK_PLUGIN KERNEXEC_PLUGIN CHECKER_PLUGIN
+ifeq ($(KBUILD_EXTMOD),)
@@ -269,7 +298,7 @@ index ed78982..bcc432e 100644
include $(srctree)/arch/$(SRCARCH)/Makefile
ifneq ($(CONFIG_FRAME_WARN),0)
-@@ -647,7 +690,7 @@ export mod_strip_cmd
+@@ -647,7 +692,7 @@ export mod_strip_cmd
ifeq ($(KBUILD_EXTMOD),)
@@ -278,7 +307,7 @@ index ed78982..bcc432e 100644
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
-@@ -868,6 +911,8 @@ vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE
+@@ -868,6 +913,8 @@ vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE
# The actual objects are generated when descending,
# make sure no implicit rule kicks in
@@ -287,7 +316,7 @@ index ed78982..bcc432e 100644
$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
# Handle descending into subdirectories listed in $(vmlinux-dirs)
-@@ -877,7 +922,7 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
+@@ -877,7 +924,7 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
# Error messages still appears in the original language
PHONY += $(vmlinux-dirs)
@@ -296,7 +325,7 @@ index ed78982..bcc432e 100644
$(Q)$(MAKE) $(build)=$@
# Build the kernel release string
-@@ -986,6 +1031,7 @@ prepare0: archprepare FORCE
+@@ -986,6 +1033,7 @@ prepare0: archprepare FORCE
$(Q)$(MAKE) $(build)=. missing-syscalls
# All the preparing..
@@ -304,7 +333,7 @@ index ed78982..bcc432e 100644
prepare: prepare0
# The asm symlink changes when $(ARCH) changes.
-@@ -1127,6 +1173,8 @@ all: modules
+@@ -1127,6 +1175,8 @@ all: modules
# using awk while concatenating to the final file.
PHONY += modules
@@ -313,7 +342,7 @@ index ed78982..bcc432e 100644
modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
@$(kecho) ' Building modules, stage 2.';
-@@ -1136,7 +1184,7 @@ modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
+@@ -1136,7 +1186,7 @@ modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
# Target to prepare building external modules
PHONY += modules_prepare
@@ -322,7 +351,7 @@ index ed78982..bcc432e 100644
# Target to install modules
PHONY += modules_install
-@@ -1201,7 +1249,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \
+@@ -1201,7 +1251,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \
include/linux/autoconf.h include/linux/version.h \
include/linux/utsrelease.h \
include/linux/bounds.h include/asm*/asm-offsets.h \
@@ -331,7 +360,7 @@ index ed78982..bcc432e 100644
# clean - Delete most, but leave enough to build external modules
#
-@@ -1245,7 +1293,7 @@ distclean: mrproper
+@@ -1245,7 +1295,7 @@ distclean: mrproper
@find $(srctree) $(RCS_FIND_IGNORE) \
\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
@@ -340,7 +369,7 @@ index ed78982..bcc432e 100644
-o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
-type f -print | xargs rm -f
-@@ -1292,6 +1340,7 @@ help:
+@@ -1292,6 +1342,7 @@ help:
@echo ' modules_prepare - Set up for building external modules'
@echo ' tags/TAGS - Generate tags file for editors'
@echo ' cscope - Generate cscope index'
@@ -348,7 +377,7 @@ index ed78982..bcc432e 100644
@echo ' kernelrelease - Output the release version string'
@echo ' kernelversion - Output the version stored in Makefile'
@echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
-@@ -1393,6 +1442,8 @@ PHONY += $(module-dirs) modules
+@@ -1393,6 +1444,8 @@ PHONY += $(module-dirs) modules
$(module-dirs): crmodverdir $(objtree)/Module.symvers
$(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
@@ -357,7 +386,7 @@ index ed78982..bcc432e 100644
modules: $(module-dirs)
@$(kecho) ' Building modules, stage 2.';
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
-@@ -1448,7 +1499,7 @@ endif # KBUILD_EXTMOD
+@@ -1448,7 +1501,7 @@ endif # KBUILD_EXTMOD
quiet_cmd_tags = GEN $@
cmd_tags = $(CONFIG_SHELL) $(srctree)/scripts/tags.sh $@
@@ -366,7 +395,7 @@ index ed78982..bcc432e 100644
$(call cmd,tags)
# Scripts to check various things for consistency
-@@ -1513,17 +1564,21 @@ else
+@@ -1513,17 +1566,21 @@ else
target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@))
endif
@@ -392,7 +421,7 @@ index ed78982..bcc432e 100644
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
%.symtypes: %.c prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
-@@ -1533,11 +1588,15 @@ endif
+@@ -1533,11 +1590,15 @@ endif
$(cmd_crmodverdir)
$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
$(build)=$(build-dir)
@@ -431,6 +460,33 @@ index 610dff4..f396854 100644
#define smp_mb__before_atomic_dec() smp_mb()
#define smp_mb__after_atomic_dec() smp_mb()
#define smp_mb__before_atomic_inc() smp_mb()
+diff --git a/arch/alpha/include/asm/cache.h b/arch/alpha/include/asm/cache.h
+index f199e69..af005f5 100644
+--- a/arch/alpha/include/asm/cache.h
++++ b/arch/alpha/include/asm/cache.h
+@@ -4,19 +4,20 @@
+ #ifndef __ARCH_ALPHA_CACHE_H
+ #define __ARCH_ALPHA_CACHE_H
+
++#include <linux/const.h>
+
+ /* Bytes per L1 (data) cache line. */
+ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV6)
+-# define L1_CACHE_BYTES 64
+ # define L1_CACHE_SHIFT 6
+ #else
+ /* Both EV4 and EV5 are write-through, read-allocate,
+ direct-mapped, physical.
+ */
+-# define L1_CACHE_BYTES 32
+ # define L1_CACHE_SHIFT 5
+ #endif
+
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
++
+ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+ #define SMP_CACHE_BYTES L1_CACHE_BYTES
+
diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h
index 5c75c1b..c82f878 100644
--- a/arch/alpha/include/asm/elf.h
@@ -692,7 +748,7 @@ index b68faef..6dd1496 100644
select HAVE_KRETPROBES if (HAVE_KPROBES)
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
-index d0daeab..ff286a8 100644
+index d0daeab..ca7e10e 100644
--- a/arch/arm/include/asm/atomic.h
+++ b/arch/arm/include/asm/atomic.h
@@ -15,6 +15,10 @@
@@ -706,6 +762,271 @@ index d0daeab..ff286a8 100644
#define ATOMIC_INIT(i) { (i) }
#ifdef __KERNEL__
+@@ -24,8 +28,16 @@
+ * strex/ldrex monitor on some implementations. The reason we can use it for
+ * atomic_set() is the clrex or dummy strex done on every exception return.
+ */
+-#define atomic_read(v) ((v)->counter)
++#define atomic_read(v) (*(volatile int *)&(v)->counter)
++static inline int atomic_read_unchecked(const atomic_unchecked_t *v)
++{
++ return v->counter;
++}
+ #define atomic_set(v,i) (((v)->counter) = (i))
++static inline void atomic_set_unchecked(atomic_unchecked_t *v, int i)
++{
++ v->counter = i;
++}
+
+ #if __LINUX_ARM_ARCH__ >= 6
+
+@@ -40,6 +52,35 @@ static inline void atomic_add(int i, atomic_t *v)
+ int result;
+
+ __asm__ __volatile__("@ atomic_add\n"
++"1: ldrex %1, [%2]\n"
++" add %0, %1, %3\n"
++
++#ifdef CONFIG_PAX_REFCOUNT
++" bvc 3f\n"
++"2: bkpt 0xf103\n"
++"3:\n"
++#endif
++
++" strex %1, %0, [%2]\n"
++" teq %1, #0\n"
++" bne 1b"
++
++#ifdef CONFIG_PAX_REFCOUNT
++"\n4:\n"
++ _ASM_EXTABLE(2b, 4b)
++#endif
++
++ : "=&r" (result), "=&r" (tmp)
++ : "r" (&v->counter), "Ir" (i)
++ : "cc");
++}
++
++static inline void atomic_add_unchecked(int i, atomic_unchecked_t *v)
++{
++ unsigned long tmp;
++ int result;
++
++ __asm__ __volatile__("@ atomic_add_unchecked\n"
+ "1: ldrex %0, [%2]\n"
+ " add %0, %0, %3\n"
+ " strex %1, %0, [%2]\n"
+@@ -58,6 +99,42 @@ static inline int atomic_add_return(int i, atomic_t *v)
+ smp_mb();
+
+ __asm__ __volatile__("@ atomic_add_return\n"
++"1: ldrex %1, [%2]\n"
++" add %0, %1, %3\n"
++
++#ifdef CONFIG_PAX_REFCOUNT
++" bvc 3f\n"
++" mov %0, %1\n"
++"2: bkpt 0xf103\n"
++"3:\n"
++#endif
++
++" strex %1, %0, [%2]\n"
++" teq %1, #0\n"
++" bne 1b"
++
++#ifdef CONFIG_PAX_REFCOUNT
++"\n4:\n"
++ _ASM_EXTABLE(2b, 4b)
++#endif
++
++ : "=&r" (result), "=&r" (tmp)
++ : "r" (&v->counter), "Ir" (i)
++ : "cc");
++
++ smp_mb();
++
++ return result;
++}
++
++static inline int atomic_add_return_unchecked(int i, atomic_unchecked_t *v)
++{
++ unsigned long tmp;
++ int result;
++
++ smp_mb();
++
++ __asm__ __volatile__("@ atomic_add_return_unchecked\n"
+ "1: ldrex %0, [%2]\n"
+ " add %0, %0, %3\n"
+ " strex %1, %0, [%2]\n"
+@@ -78,6 +155,35 @@ static inline void atomic_sub(int i, atomic_t *v)
+ int result;
+
+ __asm__ __volatile__("@ atomic_sub\n"
++"1: ldrex %1, [%2]\n"
++" sub %0, %1, %3\n"
++
++#ifdef CONFIG_PAX_REFCOUNT
++" bvc 3f\n"
++"2: bkpt 0xf103\n"
++"3:\n"
++#endif
++
++" strex %1, %0, [%2]\n"
++" teq %1, #0\n"
++" bne 1b"
++
++#ifdef CONFIG_PAX_REFCOUNT
++"\n4:\n"
++ _ASM_EXTABLE(2b, 4b)
++#endif
++
++ : "=&r" (result), "=&r" (tmp)
++ : "r" (&v->counter), "Ir" (i)
++ : "cc");
++}
++
++static inline void atomic_sub_unchecked(int i, atomic_unchecked_t *v)
++{
++ unsigned long tmp;
++ int result;
++
++ __asm__ __volatile__("@ atomic_sub_unchecked\n"
+ "1: ldrex %0, [%2]\n"
+ " sub %0, %0, %3\n"
+ " strex %1, %0, [%2]\n"
+@@ -96,11 +202,25 @@ static inline int atomic_sub_return(int i, atomic_t *v)
+ smp_mb();
+
+ __asm__ __volatile__("@ atomic_sub_return\n"
+-"1: ldrex %0, [%2]\n"
+-" sub %0, %0, %3\n"
++"1: ldrex %1, [%2]\n"
++" sub %0, %1, %3\n"
++
++#ifdef CONFIG_PAX_REFCOUNT
++" bvc 3f\n"
++" mov %0, %1\n"
++"2: bkpt 0xf103\n"
++"3:\n"
++#endif
++
+ " strex %1, %0, [%2]\n"
+ " teq %1, #0\n"
+ " bne 1b"
++
++#ifdef CONFIG_PAX_REFCOUNT
++"\n4:\n"
++ _ASM_EXTABLE(2b, 4b)
++#endif
++
+ : "=&r" (result), "=&r" (tmp)
+ : "r" (&v->counter), "Ir" (i)
+ : "cc");
+@@ -132,6 +252,28 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
+ return oldval;
+ }
+
++static inline int atomic_cmpxchg_unchecked(atomic_unchecked_t *ptr, int old, int new)
++{
++ unsigned long oldval, res;
++
++ smp_mb();
++
++ do {
++ __asm__ __volatile__("@ atomic_cmpxchg_unchecked\n"
++ "ldrex %1, [%2]\n"
++ "mov %0, #0\n"
++ "teq %1, %3\n"
++ "strexeq %0, %4, [%2]\n"
++ : "=&r" (res), "=&r" (oldval)
++ : "r" (&ptr->counter), "Ir" (old), "r" (new)
++ : "cc");
++ } while (res);
++
++ smp_mb();
++
++ return oldval;
++}
++
+ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+ {
+ unsigned long tmp, tmp2;
+@@ -207,6 +349,10 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+ #endif /* __LINUX_ARM_ARCH__ */
+
+ #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
++static inline int atomic_xchg_unchecked(atomic_unchecked_t *v, int new)
++{
++ return xchg(&v->counter, new);
++}
+
+ static inline int atomic_add_unless(atomic_t *v, int a, int u)
+ {
+@@ -220,11 +366,27 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
+ #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+ #define atomic_inc(v) atomic_add(1, v)
++static inline void atomic_inc_unchecked(atomic_unchecked_t *v)
++{
++ atomic_add_unchecked(1, v);
++}
+ #define atomic_dec(v) atomic_sub(1, v)
++static inline void atomic_dec_unchecked(atomic_unchecked_t *v)
++{
++ atomic_sub_unchecked(1, v);
++}
+
+ #define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0)
++static inline int atomic_inc_and_test_unchecked(atomic_unchecked_t *v)
++{
++ return atomic_add_return_unchecked(1, v) == 0;
++}
+ #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
+ #define atomic_inc_return(v) (atomic_add_return(1, v))
++static inline int atomic_inc_return_unchecked(atomic_unchecked_t *v)
++{
++ return atomic_add_return_unchecked(1, v);
++}
+ #define atomic_dec_return(v) (atomic_sub_return(1, v))
+ #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
+
+diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
+index 66c160b..bca1449 100644
+--- a/arch/arm/include/asm/cache.h
++++ b/arch/arm/include/asm/cache.h
+@@ -4,8 +4,10 @@
+ #ifndef __ASMARM_CACHE_H
+ #define __ASMARM_CACHE_H
+
++#include <linux/const.h>
++
+ #define L1_CACHE_SHIFT CONFIG_ARM_L1_CACHE_SHIFT
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ /*
+ * Memory returned by kmalloc() may be used for DMA, so we must make
+diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
+index 3d0cdd2..19957c5 100644
+--- a/arch/arm/include/asm/cacheflush.h
++++ b/arch/arm/include/asm/cacheflush.h
+@@ -216,13 +216,13 @@ struct cpu_cache_fns {
+ void (*dma_inv_range)(const void *, const void *);
+ void (*dma_clean_range)(const void *, const void *);
+ void (*dma_flush_range)(const void *, const void *);
+-};
++} __no_const;
+
+ struct outer_cache_fns {
+ void (*inv_range)(unsigned long, unsigned long);
+ void (*clean_range)(unsigned long, unsigned long);
+ void (*flush_range)(unsigned long, unsigned long);
+-};
++} __no_const;
+
+ /*
+ * Select the calling method
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 6aac3f5..265536b 100644
--- a/arch/arm/include/asm/elf.h
@@ -738,6 +1059,55 @@ index c019949..388fdd1 100644
KM_TYPE_NR
};
+diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
+index 3a32af4..c8def8a 100644
+--- a/arch/arm/include/asm/page.h
++++ b/arch/arm/include/asm/page.h
+@@ -122,7 +122,7 @@ struct cpu_user_fns {
+ void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr);
+ void (*cpu_copy_user_highpage)(struct page *to, struct page *from,
+ unsigned long vaddr);
+-};
++} __no_const;
+
+ #ifdef MULTI_USER
+ extern struct cpu_user_fns cpu_user;
+diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
+index d65b2f5..9d87555 100644
+--- a/arch/arm/include/asm/system.h
++++ b/arch/arm/include/asm/system.h
+@@ -86,6 +86,8 @@ void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
+
+ #define xchg(ptr,x) \
+ ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
++#define xchg_unchecked(ptr,x) \
++ ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+ extern asmlinkage void __backtrace(void);
+ extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
+@@ -98,7 +100,7 @@ extern int cpu_architecture(void);
+ extern void cpu_init(void);
+
+ void arm_machine_restart(char mode, const char *cmd);
+-extern void (*arm_pm_restart)(char str, const char *cmd);
++extern void (*arm_pm_restart)(char str, const char *cmd) __noreturn;
+
+ #define UDBG_UNDEFINED (1 << 0)
+ #define UDBG_SYSCALL (1 << 1)
+@@ -505,6 +507,13 @@ static inline unsigned long long __cmpxchg64_mb(volatile void *ptr,
+
+ #endif /* __LINUX_ARM_ARCH__ >= 6 */
+
++#define _ASM_EXTABLE(from, to) \
++" .pushsection __ex_table,\"a\"\n"\
++" .align 3\n" \
++" .long " #from ", " #to"\n" \
++" .popsection"
++
++
+ #endif /* __ASSEMBLY__ */
+
+ #define arch_align_stack(x) (x)
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 1d6bd40..fba0cb9 100644
--- a/arch/arm/include/asm/uaccess.h
@@ -825,6 +1195,69 @@ index ba8ccfe..2dc34dc 100644
#ifndef __ARMEB__
.gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7}
#else /* ! __ARMEB__ */
+diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
+index 61f90d3..771ab27 100644
+--- a/arch/arm/kernel/process.c
++++ b/arch/arm/kernel/process.c
+@@ -83,7 +83,7 @@ static int __init hlt_setup(char *__unused)
+ __setup("nohlt", nohlt_setup);
+ __setup("hlt", hlt_setup);
+
+-void arm_machine_restart(char mode, const char *cmd)
++__noreturn void arm_machine_restart(char mode, const char *cmd)
+ {
+ /*
+ * Clean and disable cache, and turn off interrupts
+@@ -117,7 +117,7 @@ void arm_machine_restart(char mode, const char *cmd)
+ void (*pm_power_off)(void);
+ EXPORT_SYMBOL(pm_power_off);
+
+-void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;
++void (*arm_pm_restart)(char str, const char *cmd) __noreturn = arm_machine_restart;
+ EXPORT_SYMBOL_GPL(arm_pm_restart);
+
+
+@@ -195,6 +195,7 @@ __setup("reboot=", reboot_setup);
+
+ void machine_halt(void)
+ {
++ BUG();
+ }
+
+
+@@ -202,6 +203,7 @@ void machine_power_off(void)
+ {
+ if (pm_power_off)
+ pm_power_off();
++ BUG();
+ }
+
+ void machine_restart(char *cmd)
+diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
+index c6c57b6..0c3b29e 100644
+--- a/arch/arm/kernel/setup.c
++++ b/arch/arm/kernel/setup.c
+@@ -92,16 +92,16 @@ EXPORT_SYMBOL(elf_hwcap);
+ struct processor processor;
+ #endif
+ #ifdef MULTI_TLB
+-struct cpu_tlb_fns cpu_tlb;
++struct cpu_tlb_fns cpu_tlb __read_only;
+ #endif
+ #ifdef MULTI_USER
+-struct cpu_user_fns cpu_user;
++struct cpu_user_fns cpu_user __read_only;
+ #endif
+ #ifdef MULTI_CACHE
+-struct cpu_cache_fns cpu_cache;
++struct cpu_cache_fns cpu_cache __read_only;
+ #endif
+ #ifdef CONFIG_OUTER_CACHE
+-struct outer_cache_fns outer_cache;
++struct outer_cache_fns outer_cache __read_only;
+ #endif
+
+ struct stack {
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 3f361a7..6e806e1 100644
--- a/arch/arm/kernel/traps.c
@@ -847,6 +1280,29 @@ index 3f361a7..6e806e1 100644
do_exit(SIGSEGV);
}
+diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
+index aecf87df..bed731b 100644
+--- a/arch/arm/kernel/vmlinux.lds.S
++++ b/arch/arm/kernel/vmlinux.lds.S
+@@ -74,14 +74,18 @@ SECTIONS
+ #ifndef CONFIG_XIP_KERNEL
+ __init_begin = _stext;
+ INIT_DATA
++ EXIT_TEXT
++ EXIT_DATA
+ . = ALIGN(PAGE_SIZE);
+ __init_end = .;
+ #endif
+ }
+
+ /DISCARD/ : { /* Exit code and data */
++#ifdef CONFIG_XIP_KERNEL
+ EXIT_TEXT
+ EXIT_DATA
++#endif
+ *(.exitcall.exit)
+ *(.discard)
+ *(.ARM.exidx.exit.text)
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S
index e4fe124..0fc246b 100644
--- a/arch/arm/lib/copy_from_user.S
@@ -874,6 +1330,18 @@ index e4fe124..0fc246b 100644
.section .fixup,"ax"
.align 0
+diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S
+index 6ee2f67..d1cce76 100644
+--- a/arch/arm/lib/copy_page.S
++++ b/arch/arm/lib/copy_page.S
+@@ -10,6 +10,7 @@
+ * ASM optimised string functions
+ */
+ #include <linux/linkage.h>
++#include <linux/const.h>
+ #include <asm/assembler.h>
+ #include <asm/asm-offsets.h>
+ #include <asm/cache.h>
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
index 1a71e15..ac7b258 100644
--- a/arch/arm/lib/copy_to_user.S
@@ -1076,7 +1544,7 @@ index c83fdc8..ab9fc44 100644
.valid = suspend_valid_only_mem,
};
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
-index 3191cd6..c0739db 100644
+index 3191cd6..c322981 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -166,6 +166,13 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
@@ -1127,6 +1595,27 @@ index 3191cd6..c0739db 100644
/*
* First Level Translation Fault Handler
*
+@@ -569,6 +603,20 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
+ const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
+ struct siginfo info;
+
++#ifdef CONFIG_PAX_REFCOUNT
++ if (fsr_fs(ifsr) == 2) {
++ unsigned int bkpt;
++
++ if (!probe_kernel_address((unsigned int *)addr, bkpt) && bkpt == 0xe12f1073) {
++ current->thread.error_code = ifsr;
++ current->thread.trap_no = 0;
++ pax_report_refcount_overflow(regs);
++ fixup_exception(regs);
++ return;
++ }
++ }
++#endif
++
+ if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
+ return;
+
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index f5abc51..7ec524c 100644
--- a/arch/arm/mm/mmap.c
@@ -1193,6 +1682,22 @@ index 8d97db2..b66cfa5 100644
.enter = s3c_pm_enter,
.prepare = s3c_pm_prepare,
.finish = s3c_pm_finish,
+diff --git a/arch/avr32/include/asm/cache.h b/arch/avr32/include/asm/cache.h
+index d3cf35a..0ba6053 100644
+--- a/arch/avr32/include/asm/cache.h
++++ b/arch/avr32/include/asm/cache.h
+@@ -1,8 +1,10 @@
+ #ifndef __ASM_AVR32_CACHE_H
+ #define __ASM_AVR32_CACHE_H
+
++#include <linux/const.h>
++
+ #define L1_CACHE_SHIFT 5
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ /*
+ * Memory returned by kmalloc() may be used for DMA, so we must make
diff --git a/arch/avr32/include/asm/elf.h b/arch/avr32/include/asm/elf.h
index d5d1d41..856e2ed 100644
--- a/arch/avr32/include/asm/elf.h
@@ -1285,6 +1790,26 @@ index b61d86d..e292c7f 100644
if (exception_trace && printk_ratelimit())
printk("%s%s[%d]: segfault at %08lx pc %08lx "
"sp %08lx ecr %lu\n",
+diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h
+index 93f6c63..d144953 100644
+--- a/arch/blackfin/include/asm/cache.h
++++ b/arch/blackfin/include/asm/cache.h
+@@ -7,12 +7,14 @@
+ #ifndef __ARCH_BLACKFIN_CACHE_H
+ #define __ARCH_BLACKFIN_CACHE_H
+
++#include <linux/const.h>
++
+ /*
+ * Bytes per L1 cache line
+ * Blackfin loads 32 bytes for cache
+ */
+ #define L1_CACHE_SHIFT 5
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+ #define SMP_CACHE_BYTES L1_CACHE_BYTES
+
+ #define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c
index cce79d0..c406c85 100644
--- a/arch/blackfin/kernel/kgdb.c
@@ -1311,6 +1836,39 @@ index 8837be4..b2fb413 100644
.enter = bfin_pm_enter,
.valid = bfin_pm_valid,
};
+diff --git a/arch/cris/include/arch-v10/arch/cache.h b/arch/cris/include/arch-v10/arch/cache.h
+index aea2718..3639a60 100644
+--- a/arch/cris/include/arch-v10/arch/cache.h
++++ b/arch/cris/include/arch-v10/arch/cache.h
+@@ -1,8 +1,9 @@
+ #ifndef _ASM_ARCH_CACHE_H
+ #define _ASM_ARCH_CACHE_H
+
++#include <linux/const.h>
+ /* Etrax 100LX have 32-byte cache-lines. */
+-#define L1_CACHE_BYTES 32
+ #define L1_CACHE_SHIFT 5
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #endif /* _ASM_ARCH_CACHE_H */
+diff --git a/arch/cris/include/arch-v32/arch/cache.h b/arch/cris/include/arch-v32/arch/cache.h
+index dfc7305..417f5b3 100644
+--- a/arch/cris/include/arch-v32/arch/cache.h
++++ b/arch/cris/include/arch-v32/arch/cache.h
+@@ -1,11 +1,12 @@
+ #ifndef _ASM_CRIS_ARCH_CACHE_H
+ #define _ASM_CRIS_ARCH_CACHE_H
+
++#include <linux/const.h>
+ #include <arch/hwregs/dma.h>
+
+ /* A cache-line is 32 bytes. */
+-#define L1_CACHE_BYTES 32
+ #define L1_CACHE_SHIFT 5
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ void flush_dma_list(dma_descr_data *descr);
+ void flush_dma_descr(dma_descr_data *descr, int flush_buf);
diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h
index 00a57af..c3ef0cd 100644
--- a/arch/frv/include/asm/atomic.h
@@ -1332,6 +1890,23 @@ index 00a57af..c3ef0cd 100644
static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
{
int c, old;
+diff --git a/arch/frv/include/asm/cache.h b/arch/frv/include/asm/cache.h
+index 7dc0f0f..1e6a620 100644
+--- a/arch/frv/include/asm/cache.h
++++ b/arch/frv/include/asm/cache.h
+@@ -12,10 +12,11 @@
+ #ifndef __ASM_CACHE_H
+ #define __ASM_CACHE_H
+
++#include <linux/const.h>
+
+ /* bytes per L1 cache line */
+ #define L1_CACHE_SHIFT (CONFIG_FRV_L1_CACHE_SHIFT)
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES
+
diff --git a/arch/frv/include/asm/kmap_types.h b/arch/frv/include/asm/kmap_types.h
index f8e16b2..c73ff79 100644
--- a/arch/frv/include/asm/kmap_types.h
@@ -1376,6 +1951,22 @@ index 385fd30..6c3d97e 100644
goto success;
addr = vma->vm_end;
}
+diff --git a/arch/h8300/include/asm/cache.h b/arch/h8300/include/asm/cache.h
+index c635028..6d9445a 100644
+--- a/arch/h8300/include/asm/cache.h
++++ b/arch/h8300/include/asm/cache.h
+@@ -1,8 +1,10 @@
+ #ifndef __ARCH_H8300_CACHE_H
+ #define __ARCH_H8300_CACHE_H
+
++#include <linux/const.h>
++
+ /* bytes per L1 cache line */
+-#define L1_CACHE_BYTES 4
++#define L1_CACHE_BYTES _AC(4,UL)
+
+ /* m68k-elf-gcc 2.95.2 doesn't like these */
+
diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c
index e4a80d8..11a7ea1 100644
--- a/arch/ia64/hp/common/hwsw_iommu.c
@@ -1479,6 +2070,27 @@ index 88405cb..de5ca5d 100644
/* Atomic operations are already serializing */
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
+diff --git a/arch/ia64/include/asm/cache.h b/arch/ia64/include/asm/cache.h
+index e7482bd..d1c9b8e 100644
+--- a/arch/ia64/include/asm/cache.h
++++ b/arch/ia64/include/asm/cache.h
+@@ -1,6 +1,7 @@
+ #ifndef _ASM_IA64_CACHE_H
+ #define _ASM_IA64_CACHE_H
+
++#include <linux/const.h>
+
+ /*
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+@@ -9,7 +10,7 @@
+
+ /* Bytes per L1 (data) cache line. */
+ #define L1_CACHE_SHIFT CONFIG_IA64_L1_CACHE_SHIFT
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #ifdef CONFIG_SMP
+ # define SMP_CACHE_SHIFT L1_CACHE_SHIFT
diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h
index 8d3c79c..71b3af6 100644
--- a/arch/ia64/include/asm/dma-mapping.h
@@ -1979,6 +2591,22 @@ index 98b6849..8046766 100644
.alloc_coherent = sn_dma_alloc_coherent,
.free_coherent = sn_dma_free_coherent,
.map_page = sn_dma_map_page,
+diff --git a/arch/m32r/include/asm/cache.h b/arch/m32r/include/asm/cache.h
+index 40b3ee9..8c2c112 100644
+--- a/arch/m32r/include/asm/cache.h
++++ b/arch/m32r/include/asm/cache.h
+@@ -1,8 +1,10 @@
+ #ifndef _ASM_M32R_CACHE_H
+ #define _ASM_M32R_CACHE_H
+
++#include <linux/const.h>
++
+ /* L1 cache line size */
+ #define L1_CACHE_SHIFT 4
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #endif /* _ASM_M32R_CACHE_H */
diff --git a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c
index 82abd15..d95ae5d 100644
--- a/arch/m32r/lib/usercopy.c
@@ -2003,6 +2631,41 @@ index 82abd15..d95ae5d 100644
prefetchw(to);
if (access_ok(VERIFY_READ, from, n))
__copy_user_zeroing(to,from,n);
+diff --git a/arch/m68k/include/asm/cache.h b/arch/m68k/include/asm/cache.h
+index ecafbe1..432c3e4 100644
+--- a/arch/m68k/include/asm/cache.h
++++ b/arch/m68k/include/asm/cache.h
+@@ -4,9 +4,11 @@
+ #ifndef __ARCH_M68K_CACHE_H
+ #define __ARCH_M68K_CACHE_H
+
++#include <linux/const.h>
++
+ /* bytes per L1 cache line */
+ #define L1_CACHE_SHIFT 4
+-#define L1_CACHE_BYTES (1<< L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES
+
+diff --git a/arch/microblaze/include/asm/cache.h b/arch/microblaze/include/asm/cache.h
+index c209c47..2ba96e2 100644
+--- a/arch/microblaze/include/asm/cache.h
++++ b/arch/microblaze/include/asm/cache.h
+@@ -13,11 +13,12 @@
+ #ifndef _ASM_MICROBLAZE_CACHE_H
+ #define _ASM_MICROBLAZE_CACHE_H
+
++#include <linux/const.h>
+ #include <asm/registers.h>
+
+ #define L1_CACHE_SHIFT 2
+ /* word-granular cache in microblaze */
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #define SMP_CACHE_BYTES L1_CACHE_BYTES
+
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index fd7620f..63d73a6 100644
--- a/arch/mips/Kconfig
@@ -2073,6 +2736,23 @@ index 09e7128..111035b 100644
#endif /* CONFIG_64BIT */
/*
+diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h
+index 37f175c..c7a3065 100644
+--- a/arch/mips/include/asm/cache.h
++++ b/arch/mips/include/asm/cache.h
+@@ -9,10 +9,11 @@
+ #ifndef _ASM_CACHE_H
+ #define _ASM_CACHE_H
+
++#include <linux/const.h>
+ #include <kmalloc.h>
+
+ #define L1_CACHE_SHIFT CONFIG_MIPS_L1_CACHE_SHIFT
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #define SMP_CACHE_SHIFT L1_CACHE_SHIFT
+ #define SMP_CACHE_BYTES L1_CACHE_BYTES
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index 7990694..4e93acf 100644
--- a/arch/mips/include/asm/elf.h
@@ -2297,6 +2977,26 @@ index e97a7a2..f18f5b0 100644
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
+diff --git a/arch/mn10300/proc-mn103e010/include/proc/cache.h b/arch/mn10300/proc-mn103e010/include/proc/cache.h
+index bdc1f9a..e8de5c5 100644
+--- a/arch/mn10300/proc-mn103e010/include/proc/cache.h
++++ b/arch/mn10300/proc-mn103e010/include/proc/cache.h
+@@ -11,12 +11,14 @@
+ #ifndef _ASM_PROC_CACHE_H
+ #define _ASM_PROC_CACHE_H
+
++#include <linux/const.h>
++
+ /* L1 cache */
+
+ #define L1_CACHE_NWAYS 4 /* number of ways in caches */
+ #define L1_CACHE_NENTRIES 256 /* number of entries in each way */
+-#define L1_CACHE_BYTES 16 /* bytes per entry */
+ #define L1_CACHE_SHIFT 4 /* shift for bytes per entry */
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT) /* bytes per entry */
+ #define L1_CACHE_WAYDISP 0x1000 /* displacement of one way from the next */
+
+ #define L1_CACHE_TAG_VALID 0x00000001 /* cache tag valid bit */
diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h
index 8bc9e96..26554f8 100644
--- a/arch/parisc/include/asm/atomic.h
@@ -2318,6 +3018,34 @@ index 8bc9e96..26554f8 100644
#else /* CONFIG_64BIT */
#include <asm-generic/atomic64.h>
+diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h
+index 32c2cca..a7b3a64 100644
+--- a/arch/parisc/include/asm/cache.h
++++ b/arch/parisc/include/asm/cache.h
+@@ -5,6 +5,7 @@
+ #ifndef __ARCH_PARISC_CACHE_H
+ #define __ARCH_PARISC_CACHE_H
+
++#include <linux/const.h>
+
+ /*
+ * PA 2.0 processors have 64-byte cachelines; PA 1.1 processors have
+@@ -15,13 +16,13 @@
+ * just ruin performance.
+ */
+ #ifdef CONFIG_PA20
+-#define L1_CACHE_BYTES 64
+ #define L1_CACHE_SHIFT 6
+ #else
+-#define L1_CACHE_BYTES 32
+ #define L1_CACHE_SHIFT 5
+ #endif
+
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
++
+ #ifndef __ASSEMBLY__
+
+ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h
index 9c802eb..0592e41 100644
--- a/arch/parisc/include/asm/elf.h
@@ -2693,6 +3421,27 @@ index c107b74..409dc0f 100644
CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
ifeq ($(CONFIG_PPC64),y)
+diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
+index 81de6eb..d5d0e24 100644
+--- a/arch/powerpc/include/asm/cache.h
++++ b/arch/powerpc/include/asm/cache.h
+@@ -3,6 +3,7 @@
+
+ #ifdef __KERNEL__
+
++#include <linux/const.h>
+
+ /* bytes per L1 cache line */
+ #if defined(CONFIG_8xx) || defined(CONFIG_403GCX)
+@@ -18,7 +19,7 @@
+ #define L1_CACHE_SHIFT 7
+ #endif
+
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #define SMP_CACHE_BYTES L1_CACHE_BYTES
+
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index 6d94d27..50d4cad 100644
--- a/arch/powerpc/include/asm/device.h
@@ -3263,6 +4012,34 @@ index a4c8b38..1b09ad9 100644
.alloc_coherent = ibmebus_alloc_coherent,
.free_coherent = ibmebus_free_coherent,
.map_sg = ibmebus_map_sg,
+diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
+index 8564a41..67f3471 100644
+--- a/arch/powerpc/kernel/irq.c
++++ b/arch/powerpc/kernel/irq.c
+@@ -490,9 +490,6 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
+ host->ops = ops;
+ host->of_node = of_node_get(of_node);
+
+- if (host->ops->match == NULL)
+- host->ops->match = default_irq_host_match;
+-
+ spin_lock_irqsave(&irq_big_lock, flags);
+
+ /* If it's a legacy controller, check for duplicates and
+@@ -567,7 +564,12 @@ struct irq_host *irq_find_host(struct device_node *node)
+ */
+ spin_lock_irqsave(&irq_big_lock, flags);
+ list_for_each_entry(h, &irq_hosts, link)
+- if (h->ops->match(h, node)) {
++ if (h->ops->match) {
++ if (h->ops->match(h, node)) {
++ found = h;
++ break;
++ }
++ } else if (default_irq_host_match(h, node)) {
+ found = h;
+ break;
+ }
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index 641c74b..8339ad7 100644
--- a/arch/powerpc/kernel/kgdb.c
@@ -4024,6 +4801,22 @@ index ae7c8f9..3f01a0c 100644
#define smp_mb__before_atomic_dec() smp_mb()
#define smp_mb__after_atomic_dec() smp_mb()
#define smp_mb__before_atomic_inc() smp_mb()
+diff --git a/arch/s390/include/asm/cache.h b/arch/s390/include/asm/cache.h
+index 9b86681..c5140db 100644
+--- a/arch/s390/include/asm/cache.h
++++ b/arch/s390/include/asm/cache.h
+@@ -11,8 +11,10 @@
+ #ifndef __ARCH_S390_CACHE_H
+ #define __ARCH_S390_CACHE_H
+
+-#define L1_CACHE_BYTES 256
++#include <linux/const.h>
++
+ #define L1_CACHE_SHIFT 8
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #define __read_mostly __attribute__((__section__(".data.read_mostly")))
+
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index e885442..e3a2817 100644
--- a/arch/s390/include/asm/elf.h
@@ -4280,6 +5073,21 @@ index 0ab74ae..c8b68f9 100644
mm->get_unmapped_area = s390_get_unmapped_area_topdown;
mm->unmap_area = arch_unmap_area_topdown;
}
+diff --git a/arch/score/include/asm/cache.h b/arch/score/include/asm/cache.h
+index ae3d59f..f65f075 100644
+--- a/arch/score/include/asm/cache.h
++++ b/arch/score/include/asm/cache.h
+@@ -1,7 +1,9 @@
+ #ifndef _ASM_SCORE_CACHE_H
+ #define _ASM_SCORE_CACHE_H
+
++#include <linux/const.h>
++
+ #define L1_CACHE_SHIFT 4
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #endif /* _ASM_SCORE_CACHE_H */
diff --git a/arch/score/include/asm/system.h b/arch/score/include/asm/system.h
index 589d5c7..669e274 100644
--- a/arch/score/include/asm/system.h
@@ -4319,6 +5127,23 @@ index d936c1a..304a252 100644
.enter = hp6x0_pm_enter,
.valid = suspend_valid_only_mem,
};
+diff --git a/arch/sh/include/asm/cache.h b/arch/sh/include/asm/cache.h
+index 02df18e..ae3a793 100644
+--- a/arch/sh/include/asm/cache.h
++++ b/arch/sh/include/asm/cache.h
+@@ -9,10 +9,11 @@
+ #define __ASM_SH_CACHE_H
+ #ifdef __KERNEL__
+
++#include <linux/const.h>
+ #include <linux/init.h>
+ #include <cpu/cache.h>
+
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #define __read_mostly __attribute__((__section__(".data.read_mostly")))
+
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index 8a8a993..7b3079b 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
@@ -4461,17 +5286,19 @@ index 113225b..7fd04e7 100644
VMLINUX_MAIN += $(patsubst %/, %/lib.a, $(libs-y)) $(libs-y)
VMLINUX_MAIN += $(drivers-y) $(net-y)
-diff --git a/arch/sparc/include/asm/atomic.h b/arch/sparc/include/asm/atomic.h
-index 8ff83d8..4a459c2 100644
---- a/arch/sparc/include/asm/atomic.h
-+++ b/arch/sparc/include/asm/atomic.h
-@@ -4,5 +4,6 @@
- #include <asm/atomic_64.h>
- #else
- #include <asm/atomic_32.h>
+diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h
+index f0d343c..cf36e68 100644
+--- a/arch/sparc/include/asm/atomic_32.h
++++ b/arch/sparc/include/asm/atomic_32.h
+@@ -13,6 +13,8 @@
+
+ #include <linux/types.h>
+
+#include <asm-generic/atomic64.h>
- #endif
- #endif
++
+ #ifdef __KERNEL__
+
+ #include <asm/system.h>
diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h
index f5cc06f..f858d47 100644
--- a/arch/sparc/include/asm/atomic_64.h
@@ -4669,15 +5496,18 @@ index f5cc06f..f858d47 100644
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
diff --git a/arch/sparc/include/asm/cache.h b/arch/sparc/include/asm/cache.h
-index 41f85ae..fb54d5e 100644
+index 41f85ae..73b80b5 100644
--- a/arch/sparc/include/asm/cache.h
+++ b/arch/sparc/include/asm/cache.h
-@@ -8,7 +8,7 @@
+@@ -7,8 +7,10 @@
+ #ifndef _SPARC_CACHE_H
#define _SPARC_CACHE_H
++#include <linux/const.h>
++
#define L1_CACHE_SHIFT 5
-#define L1_CACHE_BYTES 32
-+#define L1_CACHE_BYTES 32UL
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
#define L1_CACHE_ALIGN(x) ((((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)))
#ifdef CONFIG_SPARC32
@@ -6965,6 +7795,26 @@ index fc633db..5e1a1c2 100644
include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
#This will adjust *FLAGS accordingly to the platform.
+diff --git a/arch/um/include/asm/cache.h b/arch/um/include/asm/cache.h
+index 19e1bdd..3665b77 100644
+--- a/arch/um/include/asm/cache.h
++++ b/arch/um/include/asm/cache.h
+@@ -1,6 +1,7 @@
+ #ifndef __UM_CACHE_H
+ #define __UM_CACHE_H
+
++#include <linux/const.h>
+
+ #if defined(CONFIG_UML_X86) && !defined(CONFIG_64BIT)
+ # define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT)
+@@ -12,6 +13,6 @@
+ # define L1_CACHE_SHIFT 5
+ #endif
+
+-#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
++#define L1_CACHE_BYTES (_AC(1,UL) << L1_CACHE_SHIFT)
+
+ #endif
diff --git a/arch/um/include/asm/kmap_types.h b/arch/um/include/asm/kmap_types.h
index 6c03acd..a5e0215 100644
--- a/arch/um/include/asm/kmap_types.h
@@ -15884,7 +16734,7 @@ index c097e7d..c689cf4 100644
/*
* End of kprobes section
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
-index 34a56a9..87790b4 100644
+index 34a56a9..74613c5 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -53,6 +53,8 @@
@@ -16267,7 +17117,7 @@ index 34a56a9..87790b4 100644
* We entered an interrupt context - irqs are off:
*/
2: TRACE_IRQS_OFF
-+ pax_force_retaddr
++ pax_force_retaddr_bts
ret
CFI_ENDPROC
-END(save_args)
@@ -27403,6 +28253,67 @@ index f9153a3..51eab3d 100644
struct trap_info;
void xen_copy_trap_info(struct trap_info *traps);
+diff --git a/arch/xtensa/variants/dc232b/include/variant/core.h b/arch/xtensa/variants/dc232b/include/variant/core.h
+index 525bd3d..ef888b1 100644
+--- a/arch/xtensa/variants/dc232b/include/variant/core.h
++++ b/arch/xtensa/variants/dc232b/include/variant/core.h
+@@ -119,9 +119,9 @@
+ ----------------------------------------------------------------------*/
+
+ #define XCHAL_ICACHE_LINESIZE 32 /* I-cache line size in bytes */
+-#define XCHAL_DCACHE_LINESIZE 32 /* D-cache line size in bytes */
+ #define XCHAL_ICACHE_LINEWIDTH 5 /* log2(I line size in bytes) */
+ #define XCHAL_DCACHE_LINEWIDTH 5 /* log2(D line size in bytes) */
++#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */
+
+ #define XCHAL_ICACHE_SIZE 16384 /* I-cache size in bytes or 0 */
+ #define XCHAL_DCACHE_SIZE 16384 /* D-cache size in bytes or 0 */
+diff --git a/arch/xtensa/variants/fsf/include/variant/core.h b/arch/xtensa/variants/fsf/include/variant/core.h
+index 2f33760..835e50a 100644
+--- a/arch/xtensa/variants/fsf/include/variant/core.h
++++ b/arch/xtensa/variants/fsf/include/variant/core.h
+@@ -11,6 +11,7 @@
+ #ifndef _XTENSA_CORE_H
+ #define _XTENSA_CORE_H
+
++#include <linux/const.h>
+
+ /****************************************************************************
+ Parameters Useful for Any Code, USER or PRIVILEGED
+@@ -112,9 +113,9 @@
+ ----------------------------------------------------------------------*/
+
+ #define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */
+-#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */
+ #define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */
+ #define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */
++#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */
+
+ #define XCHAL_ICACHE_SIZE 8192 /* I-cache size in bytes or 0 */
+ #define XCHAL_DCACHE_SIZE 8192 /* D-cache size in bytes or 0 */
+diff --git a/arch/xtensa/variants/s6000/include/variant/core.h b/arch/xtensa/variants/s6000/include/variant/core.h
+index af00795..2bb8105 100644
+--- a/arch/xtensa/variants/s6000/include/variant/core.h
++++ b/arch/xtensa/variants/s6000/include/variant/core.h
+@@ -11,6 +11,7 @@
+ #ifndef _XTENSA_CORE_CONFIGURATION_H
+ #define _XTENSA_CORE_CONFIGURATION_H
+
++#include <linux/const.h>
+
+ /****************************************************************************
+ Parameters Useful for Any Code, USER or PRIVILEGED
+@@ -118,9 +119,9 @@
+ ----------------------------------------------------------------------*/
+
+ #define XCHAL_ICACHE_LINESIZE 16 /* I-cache line size in bytes */
+-#define XCHAL_DCACHE_LINESIZE 16 /* D-cache line size in bytes */
+ #define XCHAL_ICACHE_LINEWIDTH 4 /* log2(I line size in bytes) */
+ #define XCHAL_DCACHE_LINEWIDTH 4 /* log2(D line size in bytes) */
++#define XCHAL_DCACHE_LINESIZE (_AC(1,UL) << XCHAL_DCACHE_LINEWIDTH) /* D-cache line size in bytes */
+
+ #define XCHAL_ICACHE_SIZE 32768 /* I-cache size in bytes or 0 */
+ #define XCHAL_DCACHE_SIZE 32768 /* D-cache size in bytes or 0 */
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 15c6308..96e83c2 100644
--- a/block/blk-integrity.c
@@ -36715,7 +37626,7 @@ index 968cb14..f0ad2e4 100644
"raid1:%s: read error corrected "
"(%d sectors at %llu on %s)\n",
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
-index 1b4e232..cf0f534 100644
+index 1b4e232..cf0f534b 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1255,7 +1255,7 @@ static void end_sync_read(struct bio *bio, int error)
@@ -38118,6 +39029,12628 @@ index ab68886..ca405e8 100644
MODULE_PARM(X, "1-" __MODULE_STRING(ATL2_MAX_NIC) "i"); \
MODULE_PARM_DESC(X, desc);
#else
+diff --git a/drivers/net/benet/Makefile b/drivers/net/benet/Makefile
+index a60cd80..0ed11ef 100644
+--- a/drivers/net/benet/Makefile
++++ b/drivers/net/benet/Makefile
+@@ -1,7 +1,9 @@
+ #
+-# Makefile to build the network driver for ServerEngine's BladeEngine.
++# Makefile to build the be2net network driver
+ #
+
++EXTRA_CFLAGS += -DCONFIG_PALAU
++
+ obj-$(CONFIG_BE2NET) += be2net.o
+
+-be2net-y := be_main.o be_cmds.o be_ethtool.o
++be2net-y := be_main.o be_cmds.o be_ethtool.o be_compat.o be_misc.o
+diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
+index 5c74ff0..7382603 100644
+--- a/drivers/net/benet/be.h
++++ b/drivers/net/benet/be.h
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (C) 2005 - 2009 ServerEngines
++ * Copyright (C) 2005 - 2011 Emulex
+ * 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. The full GNU General
++ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+- * linux-drivers@serverengines.com
++ * linux-drivers@emulex.com
+ *
+- * ServerEngines
+- * 209 N. Fair Oaks Ave
+- * Sunnyvale, CA 94085
++ * Emulex
++ * 3333 Susan Street
++ * Costa Mesa, CA 92626
+ */
+
+ #ifndef BE_H
+@@ -29,32 +29,53 @@
+ #include <linux/workqueue.h>
+ #include <linux/interrupt.h>
+ #include <linux/firmware.h>
++#include <linux/jhash.h>
++#ifndef CONFIG_PALAU
++#include <linux/inet_lro.h>
++#endif
+
++#ifdef CONFIG_PALAU
++#include "be_compat.h"
++#endif
+ #include "be_hw.h"
+
+-#define DRV_VER "2.101.205"
++#ifdef CONFIG_PALAU
++#include "version.h"
++#define DRV_VER STR_BE_MAJOR "." STR_BE_MINOR "."\
++ STR_BE_BUILD "." STR_BE_BRANCH
++#else
++#define DRV_VER "2.0.348"
++#endif
+ #define DRV_NAME "be2net"
+-#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
+-#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC"
+-#define OC_NAME "Emulex OneConnect 10Gbps NIC"
+-#define OC_NAME1 "Emulex OneConnect 10Gbps NIC (be3)"
+-#define DRV_DESC BE_NAME "Driver"
++#define BE_NAME "Emulex BladeEngine2"
++#define BE3_NAME "Emulex BladeEngine3"
++#define OC_NAME "Emulex OneConnect"
++#define OC_NAME_BE OC_NAME "(be3)"
++#define OC_NAME_LANCER OC_NAME "(Lancer)"
++#define DRV_DESC "Emulex OneConnect 10Gbps NIC Driver"
+
+-#define BE_VENDOR_ID 0x19a2
++#define BE_VENDOR_ID 0x19a2
++#define EMULEX_VENDOR_ID 0x10df
+ #define BE_DEVICE_ID1 0x211
+ #define BE_DEVICE_ID2 0x221
+-#define OC_DEVICE_ID1 0x700
+-#define OC_DEVICE_ID2 0x701
+-#define OC_DEVICE_ID3 0x710
++#define OC_DEVICE_ID1 0x700 /* Device Id for BE2 cards */
++#define OC_DEVICE_ID2 0x710 /* Device Id for BE3 cards */
++#define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */
++
++#define OC_SUBSYS_DEVICE_ID1 0xE602
++#define OC_SUBSYS_DEVICE_ID2 0xE642
++#define OC_SUBSYS_DEVICE_ID3 0xE612
++#define OC_SUBSYS_DEVICE_ID4 0xE652
+
+ static inline char *nic_name(struct pci_dev *pdev)
+ {
+ switch (pdev->device) {
+ case OC_DEVICE_ID1:
+- case OC_DEVICE_ID2:
+ return OC_NAME;
++ case OC_DEVICE_ID2:
++ return OC_NAME_BE;
+ case OC_DEVICE_ID3:
+- return OC_NAME1;
++ return OC_NAME_LANCER;
+ case BE_DEVICE_ID2:
+ return BE3_NAME;
+ default:
+@@ -63,7 +84,7 @@ static inline char *nic_name(struct pci_dev *pdev)
+ }
+
+ /* Number of bytes of an RX frame that are copied to skb->data */
+-#define BE_HDR_LEN 64
++#define BE_HDR_LEN ((u16) 64)
+ #define BE_MAX_JUMBO_FRAME_SIZE 9018
+ #define BE_MIN_MTU 256
+
+@@ -79,10 +100,24 @@ static inline char *nic_name(struct pci_dev *pdev)
+ #define MCC_Q_LEN 128 /* total size not to exceed 8 pages */
+ #define MCC_CQ_LEN 256
+
++#define MAX_RSS_QS 4 /* BE limit is 4 queues/port */
++
++#define MAX_RX_QS (MAX_RSS_QS + 1)
++
++#ifdef MQ_TX
++#define MAX_TX_QS 8
++#else
++#define MAX_TX_QS 1
++#endif
++
++#define BE_MAX_MSIX_VECTORS (MAX_RX_QS + 1)/* RSS qs + 1 def Rx + Tx */
+ #define BE_NAPI_WEIGHT 64
+-#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
++#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
+ #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST)
+
++#define BE_MAX_LRO_DESCRIPTORS 16
++#define BE_MAX_FRAGS_PER_FRAME (min((u32) 16, (u32) MAX_SKB_FRAGS))
++
+ #define FW_VER_LEN 32
+
+ struct be_dma_mem {
+@@ -127,6 +162,11 @@ static inline void *queue_tail_node(struct be_queue_info *q)
+ return q->dma_mem.va + q->tail * q->entry_size;
+ }
+
++static inline void *queue_index_node(struct be_queue_info *q, u16 index)
++{
++ return q->dma_mem.va + index * q->entry_size;
++}
++
+ static inline void queue_head_inc(struct be_queue_info *q)
+ {
+ index_inc(&q->head, q->len);
+@@ -137,6 +177,7 @@ static inline void queue_tail_inc(struct be_queue_info *q)
+ index_inc(&q->tail, q->len);
+ }
+
++
+ struct be_eq_obj {
+ struct be_queue_info q;
+ char desc[32];
+@@ -146,6 +187,7 @@ struct be_eq_obj {
+ u16 min_eqd; /* in usecs */
+ u16 max_eqd; /* in usecs */
+ u16 cur_eqd; /* in usecs */
++ u8 eq_idx;
+
+ struct napi_struct napi;
+ };
+@@ -153,49 +195,20 @@ struct be_eq_obj {
+ struct be_mcc_obj {
+ struct be_queue_info q;
+ struct be_queue_info cq;
++ bool rearm_cq;
+ };
+
+-struct be_drvr_stats {
++struct be_tx_stats {
+ u32 be_tx_reqs; /* number of TX requests initiated */
+ u32 be_tx_stops; /* number of times TX Q was stopped */
+- u32 be_fwd_reqs; /* number of send reqs through forwarding i/f */
+ u32 be_tx_wrbs; /* number of tx WRBs used */
+- u32 be_tx_events; /* number of tx completion events */
+ u32 be_tx_compl; /* number of tx completion entries processed */
+ ulong be_tx_jiffies;
+ u64 be_tx_bytes;
+ u64 be_tx_bytes_prev;
+ u64 be_tx_pkts;
+ u32 be_tx_rate;
+-
+- u32 cache_barrier[16];
+-
+- u32 be_ethrx_post_fail;/* number of ethrx buffer alloc failures */
+- u32 be_polls; /* number of times NAPI called poll function */
+- u32 be_rx_events; /* number of ucast rx completion events */
+- u32 be_rx_compl; /* number of rx completion entries processed */
+- ulong be_rx_jiffies;
+- u64 be_rx_bytes;
+- u64 be_rx_bytes_prev;
+- u64 be_rx_pkts;
+- u32 be_rx_rate;
+- /* number of non ether type II frames dropped where
+- * frame len > length field of Mac Hdr */
+- u32 be_802_3_dropped_frames;
+- /* number of non ether type II frames malformed where
+- * in frame len < length field of Mac Hdr */
+- u32 be_802_3_malformed_frames;
+- u32 be_rxcp_err; /* Num rx completion entries w/ err set. */
+- ulong rx_fps_jiffies; /* jiffies at last FPS calc */
+- u32 be_rx_frags;
+- u32 be_prev_rx_frags;
+- u32 be_rx_fps; /* Rx frags per second */
+-};
+-
+-struct be_stats_obj {
+- struct be_drvr_stats drvr_stats;
+- struct net_device_stats net_stats;
+- struct be_dma_mem cmd;
++ u32 be_ipv6_ext_hdr_tx_drop;
+ };
+
+ struct be_tx_obj {
+@@ -203,23 +216,124 @@ struct be_tx_obj {
+ struct be_queue_info cq;
+ /* Remember the skbs that were transmitted */
+ struct sk_buff *sent_skb_list[TX_Q_LEN];
++ struct be_tx_stats stats;
+ };
+
+ /* Struct to remember the pages posted for rx frags */
+ struct be_rx_page_info {
+ struct page *page;
+- dma_addr_t bus;
++ DEFINE_DMA_UNMAP_ADDR(bus);
+ u16 page_offset;
+ bool last_page_user;
+ };
+
++struct be_rx_stats {
++ u32 rx_post_fail;/* number of ethrx buffer alloc failures */
++ u32 rx_polls; /* number of times NAPI called poll function */
++ u32 rx_events; /* number of ucast rx completion events */
++ u32 rx_compl; /* number of rx completion entries processed */
++ ulong rx_jiffies;
++ u64 rx_bytes;
++ u64 rx_bytes_prev;
++ u64 rx_pkts;
++ u32 rx_rate;
++ u32 rx_mcast_pkts;
++ u32 rxcp_err; /* Num rx completion entries w/ err set. */
++ ulong rx_fps_jiffies; /* jiffies at last FPS calc */
++ u32 rx_frags;
++ u32 prev_rx_frags;
++ u32 rx_fps; /* Rx frags per second */
++ u32 rx_drops_no_frags;
++};
++
++struct be_rx_compl_info {
++ u32 rss_hash;
++ u16 vlan_tag;
++ u16 pkt_size;
++ u16 rxq_idx;
++ u16 port;
++ u8 vlanf;
++ u8 num_rcvd;
++ u8 err;
++ u8 ipf;
++ u8 tcpf;
++ u8 udpf;
++ u8 ip_csum;
++ u8 l4_csum;
++ u8 ipv6;
++ u8 vtm;
++ u8 pkt_type;
++};
++
+ struct be_rx_obj {
++ struct be_adapter *adapter;
+ struct be_queue_info q;
+ struct be_queue_info cq;
+- struct be_rx_page_info page_info_tbl[RX_Q_LEN];
++ struct be_rx_compl_info rxcp;
++ struct be_rx_page_info *page_info_tbl;
++ struct net_lro_mgr lro_mgr;
++ struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS];
++ struct be_eq_obj rx_eq;
++ struct be_rx_stats stats;
++ u8 rss_id;
++ bool rx_post_starved; /* Zero rx frags have been posted to BE */
++ u16 prev_frag_idx;
++ u32 cache_line_barrier[16];
+ };
+
+-#define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */
++struct be_drv_stats {
++ u32 be_on_die_temperature;
++ u32 be_tx_events;
++ u32 eth_red_drops;
++ u32 rx_drops_no_pbuf;
++ u32 rx_drops_no_txpb;
++ u32 rx_drops_no_erx_descr;
++ u32 rx_drops_no_tpre_descr;
++ u32 rx_drops_too_many_frags;
++ u32 rx_drops_invalid_ring;
++ u32 forwarded_packets;
++ u32 rx_drops_mtu;
++ u32 rx_crc_errors;
++ u32 rx_alignment_symbol_errors;
++ u32 rx_pause_frames;
++ u32 rx_priority_pause_frames;
++ u32 rx_control_frames;
++ u32 rx_in_range_errors;
++ u32 rx_out_range_errors;
++ u32 rx_frame_too_long;
++ u32 rx_address_match_errors;
++ u32 rx_dropped_too_small;
++ u32 rx_dropped_too_short;
++ u32 rx_dropped_header_too_small;
++ u32 rx_dropped_tcp_length;
++ u32 rx_dropped_runt;
++ u32 rx_ip_checksum_errs;
++ u32 rx_tcp_checksum_errs;
++ u32 rx_udp_checksum_errs;
++ u32 rx_switched_unicast_packets;
++ u32 rx_switched_multicast_packets;
++ u32 rx_switched_broadcast_packets;
++ u32 tx_pauseframes;
++ u32 tx_priority_pauseframes;
++ u32 tx_controlframes;
++ u32 rxpp_fifo_overflow_drop;
++ u32 rx_input_fifo_overflow_drop;
++ u32 pmem_fifo_overflow_drop;
++ u32 jabber_events;
++};
++
++struct be_vf_cfg {
++ unsigned char vf_mac_addr[ETH_ALEN];
++ u32 vf_if_handle;
++ u32 vf_pmac_id;
++ u16 vf_def_vid;
++ u16 vf_vlan_tag;
++ u32 vf_tx_rate;
++};
++
++#define BE_INVALID_PMAC_ID 0xffffffff
++#define BE_FLAGS_DCBX (1 << 16)
++
+ struct be_adapter {
+ struct pci_dev *pdev;
+ struct net_device *netdev;
+@@ -228,7 +342,7 @@ struct be_adapter {
+ u8 __iomem *db; /* Door Bell */
+ u8 __iomem *pcicfg; /* PCI config space */
+
+- spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */
++ struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
+ struct be_dma_mem mbox_mem;
+ /* Mbox mem is adjusted to align to 16 bytes. The allocated addr
+ * is stored for freeing purpose */
+@@ -238,66 +352,121 @@ struct be_adapter {
+ spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */
+ spinlock_t mcc_cq_lock;
+
+- struct msix_entry msix_entries[BE_NUM_MSIX_VECTORS];
+- bool msix_enabled;
++ struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS];
++ u32 num_msix_vec;
+ bool isr_registered;
+
+ /* TX Rings */
+ struct be_eq_obj tx_eq;
+- struct be_tx_obj tx_obj;
++ struct be_tx_obj tx_obj[MAX_TX_QS];
++ u8 num_tx_qs;
++ u8 prio_tc_map[MAX_TX_QS]; /* prio_tc_map[prio] => tc-id */
++ u8 tc_txq_map[MAX_TX_QS]; /* tc_txq_map[tc-id] => txq index */
+
+ u32 cache_line_break[8];
+
+ /* Rx rings */
+- struct be_eq_obj rx_eq;
+- struct be_rx_obj rx_obj;
++ struct be_rx_obj rx_obj[MAX_RX_QS]; /* one default non-rss Q */
++ u32 num_rx_qs;
++
++ struct be_dma_mem stats_cmd;
++ struct net_device_stats net_stats;
++ struct be_drv_stats drv_stats;
+ u32 big_page_size; /* Compounded page size shared by rx wrbs */
+- bool rx_post_starved; /* Zero rx frags have been posted to BE */
+
+ struct vlan_group *vlan_grp;
+- u16 num_vlans;
++ u16 vlans_added;
++ u16 max_vlans; /* Number of vlans supported */
+ u8 vlan_tag[VLAN_GROUP_ARRAY_LEN];
++ u8 vlan_prio_bmap; /* Available priority BitMap */
++ u16 recommended_prio; /* Recommended Priority */
++ struct be_dma_mem rx_filter;
+
+- struct be_stats_obj stats;
+ /* Work queue used to perform periodic tasks like getting statistics */
+ struct delayed_work work;
++ u16 work_counter;
+
+- /* Ethtool knobs and info */
+- bool rx_csum; /* BE card must perform rx-checksumming */
++ u32 flags;
++ bool rx_csum; /* BE card must perform rx-checksumming */
++ u32 max_rx_coal;
+ char fw_ver[FW_VER_LEN];
+ u32 if_handle; /* Used to configure filtering */
+ u32 pmac_id; /* MAC addr handle used by BE card */
++ u32 beacon_state; /* for set_phys_id */
+
+- bool link_up;
++ bool eeh_err;
++ int link_status;
+ u32 port_num;
++ u32 hba_port_num;
+ bool promiscuous;
+- u32 cap;
++ bool wol;
++ u32 function_mode;
++ u32 function_caps;
+ u32 rx_fc; /* Rx flow control */
+ u32 tx_fc; /* Tx flow control */
++ bool ue_detected;
++ bool stats_cmd_sent;
++ bool gro_supported;
++ int link_speed;
++ u8 port_type;
++ u8 transceiver;
++ u8 autoneg;
+ u8 generation; /* BladeEngine ASIC generation */
++ u32 flash_status;
++ struct completion flash_compl;
++
++ u8 eq_next_idx;
++ bool be3_native;
++ u16 num_vfs;
++ struct be_vf_cfg *vf_cfg;
++ u8 is_virtfn;
++ u16 pvid;
++ u32 sli_family;
++ u8 port_name[4];
++ char model_number[32];
+ };
+
+ /* BladeEngine Generation numbers */
+ #define BE_GEN2 2
+ #define BE_GEN3 3
+
+-extern const struct ethtool_ops be_ethtool_ops;
++#define ON 1
++#define OFF 0
++#define lancer_chip(adapter) (adapter->pdev->device == OC_DEVICE_ID3)
++#define lancer_A0_chip(adapter) \
++ (adapter->sli_family == LANCER_A0_SLI_FAMILY)
+
+-#define drvr_stats(adapter) (&adapter->stats.drvr_stats)
++extern struct ethtool_ops be_ethtool_ops;
+
+-static inline unsigned int be_pci_func(struct be_adapter *adapter)
+-{
+- return PCI_FUNC(adapter->pdev->devfn);
+-}
++#define msix_enabled(adapter) (adapter->num_msix_vec > 0)
++#define tx_stats(txo) (&txo->stats)
++#define rx_stats(rxo) (&rxo->stats)
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
++#define BE_SET_NETDEV_OPS(netdev, ops) be_netdev_ops_init(netdev, ops)
++#else
+ #define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops)
++#endif
++
++#define for_all_rx_queues(adapter, rxo, i) \
++ for (i = 0, rxo = &adapter->rx_obj[i]; i < adapter->num_rx_qs; \
++ i++, rxo++)
++
++/* Just skip the first default non-rss queue */
++#define for_all_rss_queues(adapter, rxo, i) \
++ for (i = 0, rxo = &adapter->rx_obj[i+1]; i < (adapter->num_rx_qs - 1);\
++ i++, rxo++)
++
++#define for_all_tx_queues(adapter, txo, i) \
++ for (i = 0, txo = &adapter->tx_obj[i]; i < adapter->num_tx_qs; \
++ i++, txo++)
+
+ #define PAGE_SHIFT_4K 12
+ #define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
+
+ /* Returns number of pages spanned by the data starting at the given addr */
+-#define PAGES_4K_SPANNED(_address, size) \
+- ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
++#define PAGES_4K_SPANNED(_address, size) \
++ ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
+ (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
+
+ /* Byte offset into the page corresponding to given address */
+@@ -305,7 +474,7 @@ static inline unsigned int be_pci_func(struct be_adapter *adapter)
+ ((size_t)(addr) & (PAGE_SIZE_4K-1))
+
+ /* Returns bit offset within a DWORD of a bitfield */
+-#define AMAP_BIT_OFFSET(_struct, field) \
++#define AMAP_BIT_OFFSET(_struct, field) \
+ (((size_t)&(((_struct *)0)->field))%32)
+
+ /* Returns the bit mask of the field that is NOT shifted into location. */
+@@ -356,6 +525,11 @@ static inline void swap_dws(void *wrb, int len)
+ #endif /* __BIG_ENDIAN */
+ }
+
++static inline bool vlan_configured(struct be_adapter *adapter)
++{
++ return adapter->vlan_grp && adapter->vlans_added;
++}
++
+ static inline u8 is_tcp_pkt(struct sk_buff *skb)
+ {
+ u8 val = 0;
+@@ -380,9 +554,65 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
+ return val;
+ }
+
++static inline u8 is_ipv6_ext_hdr(struct sk_buff *skb)
++{
++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
++ if (ip_hdr(skb)->version == 6)
++ return ipv6_ext_hdr(ipv6_hdr(skb)->nexthdr);
++ else
++#endif
++ return 0;
++}
++
++static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
++{
++ u32 sli_intf;
++
++ pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf);
++ adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
++}
++
++static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
++{
++ u32 addr;
++
++ addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0);
++
++ mac[5] = (u8)(addr & 0xFF);
++ mac[4] = (u8)((addr >> 8) & 0xFF);
++ mac[3] = (u8)((addr >> 16) & 0xFF);
++ /* Use the OUI programmed in hardware */
++ memcpy(mac, adapter->netdev->dev_addr, 3);
++}
++
++static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
++ struct sk_buff *skb)
++{
++ u8 vlan_prio = 0;
++ u16 vlan_tag = 0;
++
++ vlan_tag = vlan_tx_tag_get(skb);
++ vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
++ /* If vlan priority provided by OS is NOT in available bmap */
++ if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
++ vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) |
++ adapter->recommended_prio;
++
++ return vlan_tag;
++}
++
++#define be_physfn(adapter) (!adapter->is_virtfn)
++
+ extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
+ u16 num_popped);
+-extern void be_link_status_update(struct be_adapter *adapter, bool link_up);
++extern void be_link_status_update(struct be_adapter *adapter, int link_status);
+ extern void netdev_stats_update(struct be_adapter *adapter);
++extern void be_parse_stats(struct be_adapter *adapter);
+ extern int be_load_fw(struct be_adapter *adapter, u8 *func);
++
++#ifdef CONFIG_PALAU
++extern void be_sysfs_create_group(struct be_adapter *adapter);
++extern void be_sysfs_remove_group(struct be_adapter *adapter);
++#endif
++
+ #endif /* BE_H */
+diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
+index 28a0eda..b4ca89c 100644
+--- a/drivers/net/benet/be_cmds.c
++++ b/drivers/net/benet/be_cmds.c
+@@ -1,30 +1,45 @@
+ /*
+- * Copyright (C) 2005 - 2009 ServerEngines
++ * Copyright (C) 2005 - 2011 Emulex
+ * 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. The full GNU General
++ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+- * linux-drivers@serverengines.com
++ * linux-drivers@emulex.com
+ *
+- * ServerEngines
+- * 209 N. Fair Oaks Ave
+- * Sunnyvale, CA 94085
++ * Emulex
++ * 3333 Susan Street
++ * Costa Mesa, CA 92626
+ */
+
+ #include "be.h"
+ #include "be_cmds.h"
+
++/* Must be a power of 2 or else MODULO will BUG_ON */
++static int be_get_temp_freq = 64;
++
++static inline void *embedded_payload(struct be_mcc_wrb *wrb)
++{
++ return wrb->payload.embedded_payload;
++}
++
+ static void be_mcc_notify(struct be_adapter *adapter)
+ {
+ struct be_queue_info *mccq = &adapter->mcc_obj.q;
+ u32 val = 0;
+
++ if (adapter->eeh_err) {
++ dev_info(&adapter->pdev->dev, "Error in Card Detected! Cannot issue commands\n");
++ return;
++ }
++
+ val |= mccq->id & DB_MCCQ_RING_ID_MASK;
+ val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
++
++ wmb();
+ iowrite32(val, adapter->db + DB_MCCQ_OFFSET);
+ }
+
+@@ -59,21 +74,67 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
+
+ compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
+ CQE_STATUS_COMPL_MASK;
++
++ if ((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) &&
++ (compl->tag1 == CMD_SUBSYSTEM_COMMON)) {
++ adapter->flash_status = compl_status;
++ complete(&adapter->flash_compl);
++ }
++
+ if (compl_status == MCC_STATUS_SUCCESS) {
+- if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) {
+- struct be_cmd_resp_get_stats *resp =
+- adapter->stats.cmd.va;
+- be_dws_le_to_cpu(&resp->hw_stats,
+- sizeof(resp->hw_stats));
++ if ((compl->tag0 == OPCODE_ETH_GET_STATISTICS) &&
++ (compl->tag1 == CMD_SUBSYSTEM_ETH)) {
++ if (adapter->generation == BE_GEN3) {
++ struct be_cmd_resp_get_stats_v1 *resp =
++ adapter->stats_cmd.va;
++
++ be_dws_le_to_cpu(&resp->hw_stats,
++ sizeof(resp->hw_stats));
++ } else {
++ struct be_cmd_resp_get_stats_v0 *resp =
++ adapter->stats_cmd.va;
++
++ be_dws_le_to_cpu(&resp->hw_stats,
++ sizeof(resp->hw_stats));
++ }
++ be_parse_stats(adapter);
+ netdev_stats_update(adapter);
++ adapter->stats_cmd_sent = false;
++ }
++ if (compl->tag0 ==
++ OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) {
++ struct be_mcc_wrb *mcc_wrb =
++ queue_index_node(&adapter->mcc_obj.q,
++ compl->tag1);
++ struct be_cmd_resp_get_cntl_addnl_attribs *resp =
++ embedded_payload(mcc_wrb);
++ adapter->drv_stats.be_on_die_temperature =
++ resp->on_die_temperature;
++ }
++ } else {
++ if (compl->tag0 == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES)
++ be_get_temp_freq = 0;
++
++ if (compl->tag1 == MCC_WRB_PASS_THRU)
++ goto done;
++
++ if (compl_status == MCC_STATUS_NOT_SUPPORTED ||
++ compl_status == MCC_STATUS_ILLEGAL_REQUEST)
++ goto done;
++
++ if (compl_status == MCC_STATUS_UNAUTHORIZED_REQUEST) {
++ dev_warn(&adapter->pdev->dev, "This domain(VM) is not "
++ "permitted to execute this cmd (opcode %d)\n",
++ compl->tag0);
++ } else {
++ extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
++ CQE_STATUS_EXTD_MASK;
++ dev_err(&adapter->pdev->dev, "Cmd (opcode %d) failed:"
++ "status %d, extd-status %d\n",
++ compl->tag0, compl_status, extd_status);
+ }
+- } else if (compl_status != MCC_STATUS_NOT_SUPPORTED) {
+- extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
+- CQE_STATUS_EXTD_MASK;
+- dev_warn(&adapter->pdev->dev,
+- "Error in cmd completion: status(compl/extd)=%d/%d\n",
+- compl_status, extd_status);
+ }
++done:
+ return compl_status;
+ }
+
+@@ -82,7 +143,70 @@ static void be_async_link_state_process(struct be_adapter *adapter,
+ struct be_async_event_link_state *evt)
+ {
+ be_link_status_update(adapter,
+- evt->port_link_status == ASYNC_EVENT_LINK_UP);
++ ((evt->port_link_status & ~ASYNC_EVENT_LOGICAL) ==
++ ASYNC_EVENT_LINK_UP ? LINK_UP : LINK_DOWN));
++}
++
++/* Grp5 CoS Priority evt */
++static void be_async_grp5_cos_priority_process(struct be_adapter *adapter,
++ struct be_async_event_grp5_cos_priority *evt)
++{
++ if (evt->valid) {
++ adapter->vlan_prio_bmap = evt->available_priority_bmap;
++ adapter->recommended_prio &= ~VLAN_PRIO_MASK;
++ adapter->recommended_prio =
++ evt->reco_default_priority << VLAN_PRIO_SHIFT;
++ }
++}
++
++/* Grp5 QOS Speed evt */
++static void be_async_grp5_qos_speed_process(struct be_adapter *adapter,
++ struct be_async_event_grp5_qos_link_speed *evt)
++{
++ if (evt->physical_port == adapter->hba_port_num) {
++ /* qos_link_speed is in units of 10 Mbps */
++ adapter->link_speed = evt->qos_link_speed * 10;
++ }
++}
++
++/*Grp5 PVID evt*/
++static void be_async_grp5_pvid_state_process(struct be_adapter *adapter,
++ struct be_async_event_grp5_pvid_state *evt)
++{
++ if (evt->enabled)
++ adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK ;
++ else
++ adapter->pvid = 0;
++}
++
++static void be_async_grp5_evt_process(struct be_adapter *adapter,
++ u32 trailer, struct be_mcc_compl *evt)
++{
++ u8 event_type = 0;
++
++ event_type = (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) &
++ ASYNC_TRAILER_EVENT_TYPE_MASK;
++
++ switch (event_type) {
++ case ASYNC_EVENT_COS_PRIORITY:
++ be_async_grp5_cos_priority_process(adapter,
++ (struct be_async_event_grp5_cos_priority *)evt);
++ break;
++ case ASYNC_EVENT_QOS_SPEED:
++ be_async_grp5_qos_speed_process(adapter,
++ (struct be_async_event_grp5_qos_link_speed *)evt);
++ break;
++ case ASYNC_EVENT_PVID_STATE:
++ be_async_grp5_pvid_state_process(adapter,
++ (struct be_async_event_grp5_pvid_state *)evt);
++ break;
++ case GRP5_TYPE_PRIO_TC_MAP:
++ memcpy(adapter->prio_tc_map, evt, MAX_TX_QS);
++ break;
++ default:
++ printk(KERN_WARNING "Unknown grp5 event!\n");
++ break;
++ }
+ }
+
+ static inline bool is_link_state_evt(u32 trailer)
+@@ -92,6 +216,13 @@ static inline bool is_link_state_evt(u32 trailer)
+ ASYNC_EVENT_CODE_LINK_STATE);
+ }
+
++static inline bool is_grp5_evt(u32 trailer)
++{
++ return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
++ ASYNC_TRAILER_EVENT_CODE_MASK) ==
++ ASYNC_EVENT_CODE_GRP_5);
++}
++
+ static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
+ {
+ struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq;
+@@ -104,46 +235,67 @@ static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
+ return NULL;
+ }
+
+-int be_process_mcc(struct be_adapter *adapter)
++void be_async_mcc_enable(struct be_adapter *adapter)
++{
++ spin_lock_bh(&adapter->mcc_cq_lock);
++
++ be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, 0);
++ adapter->mcc_obj.rearm_cq = true;
++
++ spin_unlock_bh(&adapter->mcc_cq_lock);
++}
++
++void be_async_mcc_disable(struct be_adapter *adapter)
++{
++ adapter->mcc_obj.rearm_cq = false;
++}
++
++int be_process_mcc(struct be_adapter *adapter, int *status)
+ {
+ struct be_mcc_compl *compl;
+- int num = 0, status = 0;
++ int num = 0;
++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
+
+ spin_lock_bh(&adapter->mcc_cq_lock);
+ while ((compl = be_mcc_compl_get(adapter))) {
+ if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
+ /* Interpret flags as an async trailer */
+- BUG_ON(!is_link_state_evt(compl->flags));
+-
+- /* Interpret compl as a async link evt */
+- be_async_link_state_process(adapter,
++ if (is_link_state_evt(compl->flags))
++ be_async_link_state_process(adapter,
+ (struct be_async_event_link_state *) compl);
++ else if (is_grp5_evt(compl->flags))
++ be_async_grp5_evt_process(adapter,
++ compl->flags, compl);
++
+ } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
+- status = be_mcc_compl_process(adapter, compl);
+- atomic_dec(&adapter->mcc_obj.q.used);
++ *status = be_mcc_compl_process(adapter, compl);
++ atomic_dec(&mcc_obj->q.used);
+ }
+ be_mcc_compl_use(compl);
+ num++;
+ }
+
+- if (num)
+- be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, num);
+-
+ spin_unlock_bh(&adapter->mcc_cq_lock);
+- return status;
++ return num;
+ }
+
+ /* Wait till no more pending mcc requests are present */
+ static int be_mcc_wait_compl(struct be_adapter *adapter)
+ {
+ #define mcc_timeout 120000 /* 12s timeout */
+- int i, status;
++ int i, num, status = 0;
++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
++
++ if (adapter->eeh_err)
++ return -EIO;
++
+ for (i = 0; i < mcc_timeout; i++) {
+- status = be_process_mcc(adapter);
+- if (status)
+- return status;
++ num = be_process_mcc(adapter, &status);
++ if (num)
++ be_cq_notify(adapter, mcc_obj->cq.id,
++ mcc_obj->rearm_cq, num);
+
+- if (atomic_read(&adapter->mcc_obj.q.used) == 0)
++ if (atomic_read(&mcc_obj->q.used) == 0)
+ break;
+ udelay(100);
+ }
+@@ -151,7 +303,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
+ dev_err(&adapter->pdev->dev, "mccq poll timed out\n");
+ return -1;
+ }
+- return 0;
++ return status;
+ }
+
+ /* Notify MCC requests and wait for completion */
+@@ -163,23 +315,34 @@ static int be_mcc_notify_wait(struct be_adapter *adapter)
+
+ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
+ {
+- int cnt = 0, wait = 5;
++ int msecs = 0;
+ u32 ready;
+
++ if (adapter->eeh_err) {
++ dev_err(&adapter->pdev->dev, "Error detected in card.Cannot issue commands\n");
++ return -EIO;
++ }
+ do {
+- ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
++ ready = ioread32(db);
++ if (ready == 0xffffffff) {
++ dev_err(&adapter->pdev->dev,
++ "pci slot disconnected\n");
++ return -1;
++ }
++
++ ready &= MPU_MAILBOX_DB_RDY_MASK;
+ if (ready)
+ break;
+
+- if (cnt > 4000000) {
++ if (msecs > 4000) {
+ dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
++ be_detect_dump_ue(adapter);
+ return -1;
+ }
+
+- if (cnt > 50)
+- wait = 200;
+- cnt += wait;
+- udelay(wait);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout(msecs_to_jiffies(1));
++ msecs++;
+ } while (true);
+
+ return 0;
+@@ -198,6 +361,11 @@ static int be_mbox_notify_wait(struct be_adapter *adapter)
+ struct be_mcc_mailbox *mbox = mbox_mem->va;
+ struct be_mcc_compl *compl = &mbox->compl;
+
++ /* wait for ready to be set */
++ status = be_mbox_db_ready_wait(adapter, db);
++ if (status != 0)
++ return status;
++
+ val |= MPU_MAILBOX_DB_HI_MASK;
+ /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
+ val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
+@@ -232,7 +400,12 @@ static int be_mbox_notify_wait(struct be_adapter *adapter)
+
+ static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage)
+ {
+- u32 sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET);
++ u32 sem;
++
++ if (lancer_chip(adapter))
++ sem = ioread32(adapter->db + MPU_EP_SEMAPHORE_IF_TYPE2_OFFSET);
++ else
++ sem = ioread32(adapter->csr + MPU_EP_SEMAPHORE_OFFSET);
+
+ *stage = sem & EP_SEMAPHORE_POST_STAGE_MASK;
+ if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK)
+@@ -245,30 +418,29 @@ int be_cmd_POST(struct be_adapter *adapter)
+ {
+ u16 stage;
+ int status, timeout = 0;
++ struct device *dev = &adapter->pdev->dev;
+
+ do {
+ status = be_POST_stage_get(adapter, &stage);
+ if (status) {
+- dev_err(&adapter->pdev->dev, "POST error; stage=0x%x\n",
+- stage);
++ dev_err(dev, "POST error; stage=0x%x\n", stage);
+ return -1;
+ } else if (stage != POST_STAGE_ARMFW_RDY) {
+ set_current_state(TASK_INTERRUPTIBLE);
+- schedule_timeout(2 * HZ);
++ if (schedule_timeout(2 * HZ)) {
++ dev_err(dev, "POST cmd aborted\n");
++ return -EINTR;
++ }
+ timeout += 2;
+ } else {
+ return 0;
+ }
+- } while (timeout < 20);
++ } while (timeout < 40);
+
+- dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage);
++ dev_err(dev, "POST timeout; stage=0x%x\n", stage);
+ return -1;
+ }
+
+-static inline void *embedded_payload(struct be_mcc_wrb *wrb)
+-{
+- return wrb->payload.embedded_payload;
+-}
+
+ static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
+ {
+@@ -277,7 +449,7 @@ static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
+
+ /* Don't touch the hdr after it's prepared */
+ static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
+- bool embedded, u8 sge_cnt)
++ bool embedded, u8 sge_cnt, u32 opcode)
+ {
+ if (embedded)
+ wrb->embedded |= MCC_WRB_EMBEDDED_MASK;
+@@ -285,7 +457,8 @@ static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
+ wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) <<
+ MCC_WRB_SGE_CNT_SHIFT;
+ wrb->payload_length = payload_len;
+- be_dws_cpu_to_le(wrb, 20);
++ wrb->tag0 = opcode;
++ be_dws_cpu_to_le(wrb, 8);
+ }
+
+ /* Don't touch the hdr after it's prepared */
+@@ -295,6 +468,7 @@ static void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
+ req_hdr->opcode = opcode;
+ req_hdr->subsystem = subsystem;
+ req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
++ req_hdr->version = 0;
+ }
+
+ static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
+@@ -349,7 +523,11 @@ static struct be_mcc_wrb *wrb_from_mccq(struct be_adapter *adapter)
+ struct be_queue_info *mccq = &adapter->mcc_obj.q;
+ struct be_mcc_wrb *wrb;
+
+- BUG_ON(atomic_read(&mccq->used) >= mccq->len);
++ if (atomic_read(&mccq->used) >= mccq->len) {
++ dev_err(&adapter->pdev->dev, "Out of MCCQ wrbs\n");
++ return NULL;
++ }
++
+ wrb = queue_head_node(mccq);
+ queue_head_inc(mccq);
+ atomic_inc(&mccq->used);
+@@ -357,6 +535,59 @@ static struct be_mcc_wrb *wrb_from_mccq(struct be_adapter *adapter)
+ return wrb;
+ }
+
++/* Tell fw we're about to start firing cmds by writing a
++ * special pattern across the wrb hdr; uses mbox
++ */
++int be_cmd_fw_init(struct be_adapter *adapter)
++{
++ u8 *wrb;
++ int status;
++
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
++
++ wrb = (u8 *)wrb_from_mbox(adapter);
++ *wrb++ = 0xFF;
++ *wrb++ = 0x12;
++ *wrb++ = 0x34;
++ *wrb++ = 0xFF;
++ *wrb++ = 0xFF;
++ *wrb++ = 0x56;
++ *wrb++ = 0x78;
++ *wrb = 0xFF;
++
++ status = be_mbox_notify_wait(adapter);
++
++ mutex_unlock(&adapter->mbox_lock);
++ return status;
++}
++
++/* Tell fw we're done with firing cmds by writing a
++ * special pattern across the wrb hdr; uses mbox
++ */
++int be_cmd_fw_clean(struct be_adapter *adapter)
++{
++ u8 *wrb;
++ int status;
++
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
++
++ wrb = (u8 *)wrb_from_mbox(adapter);
++ *wrb++ = 0xFF;
++ *wrb++ = 0xAA;
++ *wrb++ = 0xBB;
++ *wrb++ = 0xFF;
++ *wrb++ = 0xFF;
++ *wrb++ = 0xCC;
++ *wrb++ = 0xDD;
++ *wrb = 0xFF;
++
++ status = be_mbox_notify_wait(adapter);
++
++ mutex_unlock(&adapter->mbox_lock);
++ return status;
++}
+ int be_cmd_eq_create(struct be_adapter *adapter,
+ struct be_queue_info *eq, int eq_delay)
+ {
+@@ -365,20 +596,19 @@ int be_cmd_eq_create(struct be_adapter *adapter,
+ struct be_dma_mem *q_mem = &eq->dma_mem;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_COMMON_EQ_CREATE);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_EQ_CREATE, sizeof(*req));
+
+ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+- AMAP_SET_BITS(struct amap_eq_context, func, req->context,
+- be_pci_func(adapter));
+ AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1);
+ /* 4byte eqe*/
+ AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0);
+@@ -397,7 +627,7 @@ int be_cmd_eq_create(struct be_adapter *adapter,
+ eq->created = true;
+ }
+
+- spin_unlock(&adapter->mbox_lock);
++ mutex_unlock(&adapter->mbox_lock);
+ return status;
+ }
+
+@@ -409,12 +639,14 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
+ struct be_cmd_req_mac_query *req;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_NTWK_MAC_QUERY);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req));
+@@ -433,13 +665,13 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
+ memcpy(mac_addr, resp->mac.addr, ETH_ALEN);
+ }
+
+- spin_unlock(&adapter->mbox_lock);
++ mutex_unlock(&adapter->mbox_lock);
+ return status;
+ }
+
+ /* Uses synchronous MCCQ */
+ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
+- u32 if_id, u32 *pmac_id)
++ u32 if_id, u32 *pmac_id, u32 domain)
+ {
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_pmac_add *req;
+@@ -448,13 +680,19 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_NTWK_PMAC_ADD);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req));
+
++ req->hdr.domain = domain;
+ req->if_id = cpu_to_le32(if_id);
+ memcpy(req->mac_address, mac_addr, ETH_ALEN);
+
+@@ -464,12 +702,13 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
+ *pmac_id = le32_to_cpu(resp->pmac_id);
+ }
+
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
+
+ /* Uses synchronous MCCQ */
+-int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id)
++int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 dom)
+ {
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_pmac_del *req;
+@@ -478,20 +717,26 @@ int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id)
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_NTWK_PMAC_DEL);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req));
+
++ req->hdr.domain = dom;
+ req->if_id = cpu_to_le32(if_id);
+ req->pmac_id = cpu_to_le32(pmac_id);
+
+ status = be_mcc_notify_wait(adapter);
+
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+-
+ return status;
+ }
+
+@@ -506,29 +751,51 @@ int be_cmd_cq_create(struct be_adapter *adapter,
+ void *ctxt;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+ ctxt = &req->context;
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_CQ_CREATE);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_CQ_CREATE, sizeof(*req));
+
+ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+- AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm);
+- AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay);
+- AMAP_SET_BITS(struct amap_cq_context, count, ctxt,
+- __ilog2_u32(cq->len/256));
+- AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1);
+- AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts);
+- AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1);
+- AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id);
+- AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1);
+- AMAP_SET_BITS(struct amap_cq_context, func, ctxt, be_pci_func(adapter));
++ if (lancer_chip(adapter)) {
++ req->hdr.version = 2;
++ req->page_size = 1; /* 1 for 4K */
++ AMAP_SET_BITS(struct amap_cq_context_lancer, coalescwm, ctxt,
++ coalesce_wm);
++ AMAP_SET_BITS(struct amap_cq_context_lancer, nodelay, ctxt,
++ no_delay);
++ AMAP_SET_BITS(struct amap_cq_context_lancer, count, ctxt,
++ __ilog2_u32(cq->len/256));
++ AMAP_SET_BITS(struct amap_cq_context_lancer, valid, ctxt, 1);
++ AMAP_SET_BITS(struct amap_cq_context_lancer, eventable,
++ ctxt, 1);
++ AMAP_SET_BITS(struct amap_cq_context_lancer, eqid,
++ ctxt, eq->id);
++ AMAP_SET_BITS(struct amap_cq_context_lancer, armed, ctxt, 1);
++ } else {
++ AMAP_SET_BITS(struct amap_cq_context_be, coalescwm, ctxt,
++ coalesce_wm);
++ AMAP_SET_BITS(struct amap_cq_context_be, nodelay,
++ ctxt, no_delay);
++ AMAP_SET_BITS(struct amap_cq_context_be, count, ctxt,
++ __ilog2_u32(cq->len/256));
++ AMAP_SET_BITS(struct amap_cq_context_be, valid, ctxt, 1);
++ AMAP_SET_BITS(struct amap_cq_context_be, solevent,
++ ctxt, sol_evts);
++ AMAP_SET_BITS(struct amap_cq_context_be, eventable, ctxt, 1);
++ AMAP_SET_BITS(struct amap_cq_context_be, eqid, ctxt, eq->id);
++ AMAP_SET_BITS(struct amap_cq_context_be, armed, ctxt, 1);
++ }
++
+ be_dws_cpu_to_le(ctxt, sizeof(req->context));
+
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+@@ -540,8 +807,7 @@ int be_cmd_cq_create(struct be_adapter *adapter,
+ cq->created = true;
+ }
+
+- spin_unlock(&adapter->mbox_lock);
+-
++ mutex_unlock(&adapter->mbox_lock);
+ return status;
+ }
+
+@@ -553,7 +819,68 @@ static u32 be_encoded_q_len(int q_len)
+ return len_encoded;
+ }
+
+-int be_cmd_mccq_create(struct be_adapter *adapter,
++int be_cmd_mccq_ext_create(struct be_adapter *adapter,
++ struct be_queue_info *mccq,
++ struct be_queue_info *cq)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_mcc_ext_create *req;
++ struct be_dma_mem *q_mem = &mccq->dma_mem;
++ void *ctxt;
++ int status;
++
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
++
++ wrb = wrb_from_mbox(adapter);
++ req = embedded_payload(wrb);
++ ctxt = &req->context;
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_MCC_CREATE_EXT);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req));
++
++ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
++ if (lancer_chip(adapter)) {
++ req->hdr.version = 1;
++ req->cq_id = cpu_to_le16(cq->id);
++
++ AMAP_SET_BITS(struct amap_mcc_context_lancer, ring_size, ctxt,
++ be_encoded_q_len(mccq->len));
++ AMAP_SET_BITS(struct amap_mcc_context_lancer, valid, ctxt, 1);
++ AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_id,
++ ctxt, cq->id);
++ AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_valid,
++ ctxt, 1);
++
++ } else {
++ AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1);
++ AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt,
++ be_encoded_q_len(mccq->len));
++ AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id);
++ }
++
++ /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */
++ req->async_event_bitmap[0] |= cpu_to_le32(0x00000022);
++
++ be_dws_cpu_to_le(ctxt, sizeof(req->context));
++
++ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
++
++ status = be_mbox_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb);
++ mccq->id = le16_to_cpu(resp->id);
++ mccq->created = true;
++ }
++
++ mutex_unlock(&adapter->mbox_lock);
++ return status;
++}
++
++int be_cmd_mccq_org_create(struct be_adapter *adapter,
+ struct be_queue_info *mccq,
+ struct be_queue_info *cq)
+ {
+@@ -563,24 +890,25 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
+ void *ctxt;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+ ctxt = &req->context;
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_MCC_CREATE);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_MCC_CREATE, sizeof(*req));
+
+- req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
++ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+- AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, be_pci_func(adapter));
+- AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1);
+- AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt,
+- be_encoded_q_len(mccq->len));
+- AMAP_SET_BITS(struct amap_mcc_context, cq_id, ctxt, cq->id);
++ AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1);
++ AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt,
++ be_encoded_q_len(mccq->len));
++ AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id);
+
+ be_dws_cpu_to_le(ctxt, sizeof(req->context));
+
+@@ -592,75 +920,93 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
+ mccq->id = le16_to_cpu(resp->id);
+ mccq->created = true;
+ }
+- spin_unlock(&adapter->mbox_lock);
+
++ mutex_unlock(&adapter->mbox_lock);
+ return status;
+ }
+
+-int be_cmd_txq_create(struct be_adapter *adapter,
+- struct be_queue_info *txq,
++int be_cmd_mccq_create(struct be_adapter *adapter,
++ struct be_queue_info *mccq,
+ struct be_queue_info *cq)
+ {
++ int status;
++
++ status = be_cmd_mccq_ext_create(adapter, mccq, cq);
++ if (status && !lancer_chip(adapter)) {
++ dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 "
++ "or newer to avoid conflicting priorities between NIC "
++ "and FCoE traffic");
++ status = be_cmd_mccq_org_create(adapter, mccq, cq);
++ }
++ return status;
++}
++
++int be_cmd_txq_create(struct be_adapter *adapter, struct be_queue_info *txq,
++ struct be_queue_info *cq, u8 *tc_id)
++{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_eth_tx_create *req;
+ struct be_dma_mem *q_mem = &txq->dma_mem;
+- void *ctxt;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+- ctxt = &req->context;
+-
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_TX_CREATE);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_TX_CREATE,
+ sizeof(*req));
+
+- req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
++ if (adapter->flags & BE_FLAGS_DCBX || lancer_chip(adapter)) {
++ req->hdr.version = 1;
++ req->if_id = cpu_to_le16(adapter->if_handle);
++ }
++ if (adapter->flags & BE_FLAGS_DCBX)
++ req->type = cpu_to_le16(ETX_QUEUE_TYPE_PRIORITY);
++ else
++ req->type = cpu_to_le16(ETX_QUEUE_TYPE_STANDARD);
+ req->ulp_num = BE_ULP1_NUM;
+- req->type = BE_ETH_TX_RING_TYPE_STANDARD;
+-
+- AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt,
+- be_encoded_q_len(txq->len));
+- AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt,
+- be_pci_func(adapter));
+- AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1);
+- AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id);
+-
+- be_dws_cpu_to_le(ctxt, sizeof(req->context));
+-
++ req->cq_id = cpu_to_le16(cq->id);
++ req->queue_size = be_encoded_q_len(txq->len);
++ req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify_wait(adapter);
+ if (!status) {
+ struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb);
+ txq->id = le16_to_cpu(resp->cid);
++ if (adapter->flags & BE_FLAGS_DCBX)
++ *tc_id = resp->tc_id;
+ txq->created = true;
+ }
+
+- spin_unlock(&adapter->mbox_lock);
+-
++ mutex_unlock(&adapter->mbox_lock);
+ return status;
+ }
+
+-/* Uses mbox */
++/* Uses MCC */
+ int be_cmd_rxq_create(struct be_adapter *adapter,
+ struct be_queue_info *rxq, u16 cq_id, u16 frag_size,
+- u16 max_frame_size, u32 if_id, u32 rss)
++ u16 max_frame_size, u32 if_id, u32 rss, u8 *rss_id)
+ {
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_eth_rx_create *req;
+ struct be_dma_mem *q_mem = &rxq->dma_mem;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ spin_lock_bh(&adapter->mcc_lock);
+
+- wrb = wrb_from_mbox(adapter);
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_ETH_RX_CREATE);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_CREATE,
+ sizeof(*req));
+@@ -673,15 +1019,16 @@ int be_cmd_rxq_create(struct be_adapter *adapter,
+ req->max_frame_size = cpu_to_le16(max_frame_size);
+ req->rss_queue = cpu_to_le32(rss);
+
+- status = be_mbox_notify_wait(adapter);
++ status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb);
+ rxq->id = le16_to_cpu(resp->id);
+ rxq->created = true;
++ *rss_id = resp->rss_id;
+ }
+
+- spin_unlock(&adapter->mbox_lock);
+-
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
+
+@@ -696,13 +1043,12 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
+ u8 subsys = 0, opcode = 0;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+-
+ switch (queue_type) {
+ case QTYPE_EQ:
+ subsys = CMD_SUBSYSTEM_COMMON;
+@@ -727,13 +1073,47 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
+ default:
+ BUG();
+ }
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, opcode);
++
+ be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req));
+ req->id = cpu_to_le16(q->id);
+
+ status = be_mbox_notify_wait(adapter);
++ if (!status)
++ q->created = false;
+
+- spin_unlock(&adapter->mbox_lock);
++ mutex_unlock(&adapter->mbox_lock);
++ return status;
++}
+
++/* Uses MCC */
++int be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_q_destroy *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_RX_DESTROY);
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_DESTROY,
++ sizeof(*req));
++ req->id = cpu_to_le16(q->id);
++
++ status = be_mcc_notify_wait(adapter);
++ if (!status)
++ q->created = false;
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
+
+@@ -741,22 +1121,26 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
+ * Uses mbox
+ */
+ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
+- u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id)
++ u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id,
++ u32 domain)
+ {
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_if_create *req;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_NTWK_INTERFACE_CREATE);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req));
+
++ req->hdr.domain = domain;
+ req->capability_flags = cpu_to_le32(cap_flags);
+ req->enable_flags = cpu_to_le32(en_flags);
+ req->pmac_invalid = pmac_invalid;
+@@ -771,33 +1155,35 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
+ *pmac_id = le32_to_cpu(resp->pmac_id);
+ }
+
+- spin_unlock(&adapter->mbox_lock);
++ mutex_unlock(&adapter->mbox_lock);
+ return status;
+ }
+
+ /* Uses mbox */
+-int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id)
++int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain)
+ {
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_if_destroy *req;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_NTWK_INTERFACE_DESTROY);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req));
+
++ req->hdr.domain = domain;
+ req->interface_id = cpu_to_le32(interface_id);
+
+ status = be_mbox_notify_wait(adapter);
+
+- spin_unlock(&adapter->mbox_lock);
+-
++ mutex_unlock(&adapter->mbox_lock);
+ return status;
+ }
+
+@@ -808,33 +1194,48 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id)
+ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
+ {
+ struct be_mcc_wrb *wrb;
+- struct be_cmd_req_get_stats *req;
++ struct be_cmd_req_hdr *hdr;
+ struct be_sge *sge;
++ int status = 0;
++
++ if (MODULO(adapter->work_counter, be_get_temp_freq) == 0)
++ be_cmd_get_die_temperature(adapter);
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+- req = nonemb_cmd->va;
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ hdr = nonemb_cmd->va;
+ sge = nonembedded_sgl(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
+- wrb->tag0 = OPCODE_ETH_GET_STATISTICS;
++ be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1,
++ OPCODE_ETH_GET_STATISTICS);
+
+- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+- OPCODE_ETH_GET_STATISTICS, sizeof(*req));
++ be_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH,
++ OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size);
++
++ if (adapter->generation == BE_GEN3)
++ hdr->version = 1;
++
++ wrb->tag1 = CMD_SUBSYSTEM_ETH;
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd->size);
+
+ be_mcc_notify(adapter);
++ adapter->stats_cmd_sent = true;
+
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+- return 0;
++ return status;
+ }
+
+ /* Uses synchronous mcc */
+ int be_cmd_link_status_query(struct be_adapter *adapter,
+- bool *link_up)
++ int *link_status, u8 *mac_speed, u16 *link_speed, u32 dom)
+ {
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_link_status *req;
+@@ -843,50 +1244,216 @@ int be_cmd_link_status_query(struct be_adapter *adapter,
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
+ req = embedded_payload(wrb);
+
+- *link_up = false;
++ *link_status = LINK_DOWN;
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_NTWK_LINK_STATUS_QUERY);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req));
+
++ req->hdr.domain = dom;
++
+ status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ struct be_cmd_resp_link_status *resp = embedded_payload(wrb);
+- if (resp->mac_speed != PHY_LINK_SPEED_ZERO)
+- *link_up = true;
++ if (resp->mac_speed != PHY_LINK_SPEED_ZERO) {
++ *link_status = LINK_UP;
++ *link_speed = le16_to_cpu(resp->link_speed);
++ *mac_speed = resp->mac_speed;
++ }
+ }
+
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
+
+-/* Uses Mbox */
+-int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver)
++/* Uses synchronous mcc */
++int be_cmd_get_die_temperature(struct be_adapter *adapter)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_cntl_addnl_attribs *req;
++ u16 mccq_index;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ mccq_index = adapter->mcc_obj.q.head;
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req));
++
++ wrb->tag1 = mccq_index;
++
++ be_mcc_notify(adapter);
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++
++/* Uses synchronous mcc */
++int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_fat *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_MANAGE_FAT);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_MANAGE_FAT, sizeof(*req));
++ req->fat_operation = cpu_to_le32(QUERY_FAT);
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_get_fat *resp = embedded_payload(wrb);
++ if (log_size && resp->log_size)
++ *log_size = le32_to_cpu(resp->log_size) -
++ sizeof(u32);
++ }
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
++{
++ struct be_dma_mem get_fat_cmd;
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_fat *req;
++ struct be_sge *sge;
++ u32 offset = 0, total_size, buf_size,
++ log_offset = sizeof(u32), payload_len;
++ int status;
++
++ if (buf_len == 0)
++ return;
++
++ total_size = buf_len;
++
++ get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024;
++ get_fat_cmd.va = pci_alloc_consistent(adapter->pdev,
++ get_fat_cmd.size,
++ &get_fat_cmd.dma);
++ if (!get_fat_cmd.va) {
++ status = -ENOMEM;
++ dev_err(&adapter->pdev->dev,
++ "Memory allocation failure while retrieving FAT data\n");
++ return;
++ }
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ while (total_size) {
++ buf_size = min(total_size, (u32)60*1024);
++ total_size -= buf_size;
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = get_fat_cmd.va;
++ sge = nonembedded_sgl(wrb);
++
++ payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size;
++ be_wrb_hdr_prepare(wrb, payload_len, false, 1,
++ OPCODE_COMMON_MANAGE_FAT);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_MANAGE_FAT, payload_len);
++
++ sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.dma));
++ sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF);
++ sge->len = cpu_to_le32(get_fat_cmd.size);
++
++ req->fat_operation = cpu_to_le32(RETRIEVE_FAT);
++ req->read_log_offset = cpu_to_le32(log_offset);
++ req->read_log_length = cpu_to_le32(buf_size);
++ req->data_buffer_size = cpu_to_le32(buf_size);
++
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_get_fat *resp = get_fat_cmd.va;
++ memcpy(buf + offset,
++ resp->data_buffer,
++ le32_to_cpu(resp->read_log_length));
++ } else {
++ dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n");
++ goto err;
++ }
++ offset += buf_size;
++ log_offset += buf_size;
++ }
++err:
++ pci_free_consistent(adapter->pdev, get_fat_cmd.size,
++ get_fat_cmd.va,
++ get_fat_cmd.dma);
++ spin_unlock_bh(&adapter->mcc_lock);
++}
++
++/* Uses synchronous mcc */
++int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver,
++ char *fw_on_flash)
+ {
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_fw_version *req;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
+
+- wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_GET_FW_VERSION);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_FW_VERSION, sizeof(*req));
+
+- status = be_mbox_notify_wait(adapter);
++ status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb);
+- strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN);
++ strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN-1);
++ if (fw_on_flash)
++ strncpy(fw_on_flash, resp->fw_on_flash_version_string,
++ FW_VER_LEN-1);
+ }
+-
+- spin_unlock(&adapter->mbox_lock);
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
+
+@@ -897,13 +1464,19 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd)
+ {
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_modify_eq_delay *req;
++ int status = 0;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_MODIFY_EQ_DELAY);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req));
+@@ -915,8 +1488,9 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd)
+
+ be_mcc_notify(adapter);
+
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+- return 0;
++ return status;
+ }
+
+ /* Uses sycnhronous mcc */
+@@ -930,9 +1504,14 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_NTWK_VLAN_CONFIG);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req));
+@@ -948,79 +1527,63 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
+
+ status = be_mcc_notify_wait(adapter);
+
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
+
+-/* Uses MCC for this command as it may be called in BH context
+- * Uses synchronous mcc
+- */
+-int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en)
++int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
+ {
+ struct be_mcc_wrb *wrb;
+- struct be_cmd_req_promiscuous_config *req;
++ struct be_dma_mem *mem = &adapter->rx_filter;
++ struct be_cmd_req_rx_filter *req = mem->va;
++ struct be_sge *sge;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+- req = embedded_payload(wrb);
+-
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+-
+- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+- OPCODE_ETH_PROMISCUOUS, sizeof(*req));
+-
+- if (port_num)
+- req->port1_promiscuous = en;
+- else
+- req->port0_promiscuous = en;
+-
+- status = be_mcc_notify_wait(adapter);
+-
+- spin_unlock_bh(&adapter->mcc_lock);
+- return status;
+-}
+-
+-/*
+- * Uses MCC for this command as it may be called in BH context
+- * (mc == NULL) => multicast promiscous
+- */
+-int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
+- struct dev_mc_list *mc_list, u32 mc_count)
+-{
+-#define BE_MAX_MC 32 /* set mcast promisc if > 32 */
+- struct be_mcc_wrb *wrb;
+- struct be_cmd_req_mcast_mac_config *req;
+-
+- spin_lock_bh(&adapter->mcc_lock);
+-
+- wrb = wrb_from_mccq(adapter);
+- req = embedded_payload(wrb);
+-
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+-
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ sge = nonembedded_sgl(wrb);
++ sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma));
++ sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF);
++ sge->len = cpu_to_le32(mem->size);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
++ OPCODE_COMMON_NTWK_RX_FILTER);
++
++ memset(req, 0, sizeof(*req));
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+- OPCODE_COMMON_NTWK_MULTICAST_SET, sizeof(*req));
++ OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req));
+
+- req->interface_id = if_id;
+- if (mc_list && mc_count <= BE_MAX_MC) {
+- int i;
+- struct dev_mc_list *mc;
+-
+- req->num_mac = cpu_to_le16(mc_count);
+-
+- for (mc = mc_list, i = 0; mc; mc = mc->next, i++)
+- memcpy(req->mac[i].byte, mc->dmi_addr, ETH_ALEN);
++ req->if_id = cpu_to_le32(adapter->if_handle);
++ if (flags & IFF_PROMISC) {
++ req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS |
++ BE_IF_FLAGS_VLAN_PROMISCUOUS);
++ if (value == ON)
++ req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS |
++ BE_IF_FLAGS_VLAN_PROMISCUOUS);
++ } else if (flags & IFF_ALLMULTI) {
++ req->if_flags_mask = req->if_flags =
++ cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
+ } else {
+- req->promiscuous = 1;
+- }
++ struct netdev_hw_addr *ha;
++ int i = 0;
+
+- be_mcc_notify_wait(adapter);
++ req->if_flags_mask = req->if_flags =
++ cpu_to_le32(BE_IF_FLAGS_MULTICAST);
++ req->mcast_num = cpu_to_le16(netdev_mc_count(adapter->netdev));
++ netdev_for_each_mc_addr(ha, adapter->netdev)
++ memcpy(req->mcast_mac[i++].byte, ha->DMI_ADDR,
++ ETH_ALEN);
++ }
++ status = be_mcc_notify_wait(adapter);
+
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+-
+- return 0;
++ return status;
+ }
+
+ /* Uses synchrounous mcc */
+@@ -1033,9 +1596,14 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc)
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_SET_FLOW_CONTROL);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req));
+@@ -1045,6 +1613,7 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc)
+
+ status = be_mcc_notify_wait(adapter);
+
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
+@@ -1059,9 +1628,14 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc)
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_GET_FLOW_CONTROL);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req));
+@@ -1074,23 +1648,27 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc)
+ *rx_fc = le16_to_cpu(resp->rx_flow_control);
+ }
+
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
+
+ /* Uses mbox */
+-int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap)
++int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
++ u32 *mode, u32 *function_caps)
+ {
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_query_fw_cfg *req;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_QUERY_FIRMWARE_CONFIG);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req));
+@@ -1099,10 +1677,11 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap)
+ if (!status) {
+ struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb);
+ *port_num = le32_to_cpu(resp->phys_port);
+- *cap = le32_to_cpu(resp->function_cap);
++ *mode = le32_to_cpu(resp->function_mode);
++ *function_caps = le32_to_cpu(resp->function_caps);
+ }
+
+- spin_unlock(&adapter->mbox_lock);
++ mutex_unlock(&adapter->mbox_lock);
+ return status;
+ }
+
+@@ -1113,19 +1692,161 @@ int be_cmd_reset_function(struct be_adapter *adapter)
+ struct be_cmd_req_hdr *req;
+ int status;
+
+- spin_lock(&adapter->mbox_lock);
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+ req = embedded_payload(wrb);
+
+- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_FUNCTION_RESET);
+
+ be_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_FUNCTION_RESET, sizeof(*req));
+
+ status = be_mbox_notify_wait(adapter);
+
+- spin_unlock(&adapter->mbox_lock);
++ mutex_unlock(&adapter->mbox_lock);
++ return status;
++}
++
++int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_rss_config *req;
++ u32 myhash[10] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF,
++ 0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF};
++ int status;
++
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
++
++ wrb = wrb_from_mbox(adapter);
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_ETH_RSS_CONFIG);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
++ OPCODE_ETH_RSS_CONFIG, sizeof(*req));
++
++ req->if_id = cpu_to_le32(adapter->if_handle);
++ req->enable_rss = cpu_to_le16(RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4);
++ req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1);
++ memcpy(req->cpu_table, rsstable, table_size);
++ memcpy(req->hash, myhash, sizeof(myhash));
++ be_dws_cpu_to_le(req->hash, sizeof(req->hash));
++
++ status = be_mbox_notify_wait(adapter);
++
++ mutex_unlock(&adapter->mbox_lock);
++ return status;
++}
++
++/* Uses sync mcc */
++int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num,
++ u8 bcn, u8 sts, u8 state)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_enable_disable_beacon *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_ENABLE_DISABLE_BEACON);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_ENABLE_DISABLE_BEACON, sizeof(*req));
++
++ req->port_num = port_num;
++ req->beacon_state = state;
++ req->beacon_duration = bcn;
++ req->status_duration = sts;
++
++ status = be_mcc_notify_wait(adapter);
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++/* Uses sync mcc */
++int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_beacon_state *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_GET_BEACON_STATE);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_GET_BEACON_STATE, sizeof(*req));
++
++ req->port_num = port_num;
++
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_get_beacon_state *resp =
++ embedded_payload(wrb);
++ *state = resp->beacon_state;
++ }
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++/* Uses sync mcc */
++int be_cmd_read_port_type(struct be_adapter *adapter, u32 port,
++ u8 *connector)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_port_type *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(struct be_cmd_resp_port_type), true, 0,
++ OPCODE_COMMON_READ_TRANSRECV_DATA);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_READ_TRANSRECV_DATA, sizeof(*req));
++
++ req->port = cpu_to_le32(port);
++ req->page_num = cpu_to_le32(TR_PAGE_A0);
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_port_type *resp = embedded_payload(wrb);
++ *connector = resp->data.connector;
++ }
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
+
+@@ -1133,16 +1854,24 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
+ u32 flash_type, u32 flash_opcode, u32 buf_size)
+ {
+ struct be_mcc_wrb *wrb;
+- struct be_cmd_write_flashrom *req = cmd->va;
++ struct be_cmd_write_flashrom *req;
+ struct be_sge *sge;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
++ adapter->flash_status = 0;
+
+ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err_unlock;
++ }
++ req = cmd->va;
+ sge = nonembedded_sgl(wrb);
+
+- be_wrb_hdr_prepare(wrb, cmd->size, false, 1);
++ be_wrb_hdr_prepare(wrb, cmd->size, false, 1,
++ OPCODE_COMMON_WRITE_FLASHROM);
++ wrb->tag1 = CMD_SUBSYSTEM_COMMON;
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_WRITE_FLASHROM, cmd->size);
+@@ -1154,8 +1883,852 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
+ req->params.op_code = cpu_to_le32(flash_opcode);
+ req->params.data_buf_size = cpu_to_le32(buf_size);
+
++ be_mcc_notify(adapter);
++ spin_unlock_bh(&adapter->mcc_lock);
++
++ if (!wait_for_completion_timeout(&adapter->flash_compl,
++ msecs_to_jiffies(40000)))
++ status = -1;
++ else
++ status = adapter->flash_status;
++
++ return status;
++
++err_unlock:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
++ int offset)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_write_flashrom *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req)+4, true, 0,
++ OPCODE_COMMON_READ_FLASHROM);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4);
++
++ req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT);
++ req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT);
++ req->params.offset = cpu_to_le32(offset);
++ req->params.data_buf_size = cpu_to_le32(0x4);
++
++ status = be_mcc_notify_wait(adapter);
++ if (!status)
++ memcpy(flashed_crc, req->params.data_buf, 4);
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
++ struct be_dma_mem *nonemb_cmd)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_acpi_wol_magic_config *req;
++ struct be_sge *sge;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = nonemb_cmd->va;
++ sge = nonembedded_sgl(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
++ OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
++ OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, sizeof(*req));
++ memcpy(req->magic_mac, mac, ETH_ALEN);
++
++ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
++ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
++ sge->len = cpu_to_le32(nonemb_cmd->size);
++
++ status = be_mcc_notify_wait(adapter);
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
++ u8 loopback_type, u8 enable)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_set_lmode *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_LOWLEVEL_SET_LOOPBACK_MODE);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
++ OPCODE_LOWLEVEL_SET_LOOPBACK_MODE,
++ sizeof(*req));
++
++ req->src_port = port_num;
++ req->dest_port = port_num;
++ req->loopback_type = loopback_type;
++ req->loopback_state = enable;
++
++ status = be_mcc_notify_wait(adapter);
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
++ u32 loopback_type, u32 pkt_size, u32 num_pkts, u64 pattern)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_loopback_test *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_LOWLEVEL_LOOPBACK_TEST);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
++ OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req));
++ req->hdr.timeout = cpu_to_le32(4);
++
++ req->pattern = cpu_to_le64(pattern);
++ req->src_port = cpu_to_le32(port_num);
++ req->dest_port = cpu_to_le32(port_num);
++ req->pkt_size = cpu_to_le32(pkt_size);
++ req->num_pkts = cpu_to_le32(num_pkts);
++ req->loopback_type = cpu_to_le32(loopback_type);
++
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_loopback_test *resp = embedded_payload(wrb);
++ status = le32_to_cpu(resp->status);
++ }
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern,
++ u32 byte_cnt, struct be_dma_mem *cmd)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_ddrdma_test *req;
++ struct be_sge *sge;
++ int status;
++ int i, j = 0;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = cmd->va;
++ sge = nonembedded_sgl(wrb);
++ be_wrb_hdr_prepare(wrb, cmd->size, false, 1,
++ OPCODE_LOWLEVEL_HOST_DDR_DMA);
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
++ OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd->size);
++
++ sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma));
++ sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF);
++ sge->len = cpu_to_le32(cmd->size);
++
++ req->pattern = cpu_to_le64(pattern);
++ req->byte_count = cpu_to_le32(byte_cnt);
++ for (i = 0; i < byte_cnt; i++) {
++ req->snd_buff[i] = (u8)(pattern >> (j*8));
++ j++;
++ if (j > 7)
++ j = 0;
++ }
++
++ status = be_mcc_notify_wait(adapter);
++
++ if (!status) {
++ struct be_cmd_resp_ddrdma_test *resp;
++ resp = cmd->va;
++ if ((memcmp(resp->rcv_buff, req->snd_buff, byte_cnt) != 0) ||
++ resp->snd_err) {
++ status = -1;
++ }
++ }
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_get_seeprom_data(struct be_adapter *adapter,
++ struct be_dma_mem *nonemb_cmd)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_seeprom_read *req;
++ struct be_sge *sge;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ req = nonemb_cmd->va;
++ sge = nonembedded_sgl(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
++ OPCODE_COMMON_SEEPROM_READ);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_SEEPROM_READ, sizeof(*req));
++
++ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
++ sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
++ sge->len = cpu_to_le32(nonemb_cmd->size);
++
++ status = be_mcc_notify_wait(adapter);
++
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_get_phy_info(struct be_adapter *adapter,
++ struct be_phy_info *phy_info)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_phy_info *req;
++ struct be_sge *sge;
++ struct be_dma_mem cmd;
++ struct be_phy_info *resp_phy_info;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ cmd.size = sizeof(struct be_cmd_req_get_phy_info);
++ cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size,
++ &cmd.dma);
++ if (!cmd.va) {
++ dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
++ status = -ENOMEM;
++ goto err;
++ }
++
++ req = cmd.va;
++ sge = nonembedded_sgl(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
++ OPCODE_COMMON_GET_PHY_DETAILS);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_GET_PHY_DETAILS,
++ sizeof(*req));
++
++ sge->pa_hi = cpu_to_le32(upper_32_bits(cmd.dma));
++ sge->pa_lo = cpu_to_le32(cmd.dma & 0xFFFFFFFF);
++ sge->len = cpu_to_le32(cmd.size);
++
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ resp_phy_info = cmd.va + sizeof(struct be_cmd_req_hdr);
++ phy_info->phy_type = le16_to_cpu(resp_phy_info->phy_type);
++ phy_info->interface_type =
++ le16_to_cpu(resp_phy_info->interface_type);
++ phy_info->auto_speeds_supported =
++ le16_to_cpu(resp_phy_info->auto_speeds_supported);
++ phy_info->fixed_speeds_supported =
++ le16_to_cpu(resp_phy_info->fixed_speeds_supported);
++ phy_info->misc_params =
++ le32_to_cpu(resp_phy_info->misc_params);
++ }
++ pci_free_consistent(adapter->pdev, cmd.size,
++ cmd.va, cmd.dma);
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_set_qos *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_SET_QOS);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_SET_QOS, sizeof(*req));
++
++ req->hdr.domain = domain;
++ req->valid_bits = cpu_to_le32(BE_QOS_BITS_NIC);
++ req->max_bps_nic = cpu_to_le32(bps);
++
++ status = be_mcc_notify_wait(adapter);
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_get_cntl_attributes(struct be_adapter *adapter)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_cntl_attribs *req;
++ struct be_cmd_resp_cntl_attribs *resp;
++ struct be_sge *sge;
++ int status;
++ int payload_len = max(sizeof(*req), sizeof(*resp));
++ struct mgmt_controller_attrib *attribs;
++ struct be_dma_mem attribs_cmd;
++
++ memset(&attribs_cmd, 0, sizeof(struct be_dma_mem));
++ attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs);
++ attribs_cmd.va = pci_alloc_consistent(adapter->pdev, attribs_cmd.size,
++ &attribs_cmd.dma);
++ if (!attribs_cmd.va) {
++ dev_err(&adapter->pdev->dev,
++ "Memory allocation failure\n");
++ return -ENOMEM;
++ }
++
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
++
++ wrb = wrb_from_mbox(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = attribs_cmd.va;
++ sge = nonembedded_sgl(wrb);
++
++ be_wrb_hdr_prepare(wrb, payload_len, false, 1,
++ OPCODE_COMMON_GET_CNTL_ATTRIBUTES);
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_GET_CNTL_ATTRIBUTES, payload_len);
++ sge->pa_hi = cpu_to_le32(upper_32_bits(attribs_cmd.dma));
++ sge->pa_lo = cpu_to_le32(attribs_cmd.dma & 0xFFFFFFFF);
++ sge->len = cpu_to_le32(attribs_cmd.size);
++
++ status = be_mbox_notify_wait(adapter);
++ if (!status) {
++ attribs = (struct mgmt_controller_attrib *)(attribs_cmd.va +
++ sizeof(struct be_cmd_resp_hdr));
++ adapter->hba_port_num = attribs->hba_attribs.phy_port;
++ strncpy(adapter->model_number,
++ attribs->hba_attribs.controller_model_number, 31);
++ }
++
++err:
++ mutex_unlock(&adapter->mbox_lock);
++ pci_free_consistent(adapter->pdev, attribs_cmd.size, attribs_cmd.va,
++ attribs_cmd.dma);
++ return status;
++}
++
++/* Uses mbox */
++int be_cmd_req_native_mode(struct be_adapter *adapter)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_set_func_cap *req;
++ int status;
++
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
++
++ wrb = wrb_from_mbox(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP, sizeof(*req));
++
++ req->valid_cap_flags = cpu_to_le32(CAPABILITY_SW_TIMESTAMPS |
++ CAPABILITY_BE3_NATIVE_ERX_API);
++ req->cap_flags = cpu_to_le32(CAPABILITY_BE3_NATIVE_ERX_API);
++
++ status = be_mbox_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_set_func_cap *resp = embedded_payload(wrb);
++ adapter->be3_native = le32_to_cpu(resp->cap_flags) &
++ CAPABILITY_BE3_NATIVE_ERX_API;
++ }
++err:
++ mutex_unlock(&adapter->mbox_lock);
++ return status;
++}
++
++static void encode_port_names(struct be_adapter *adapter)
++{
++ switch (adapter->port_name[adapter->hba_port_num]) {
++ case '0':
++ adapter->port_name[adapter->hba_port_num] = 0;
++ break;
++ case '1':
++ adapter->port_name[adapter->hba_port_num] = 1;
++ break;
++ case '2':
++ adapter->port_name[adapter->hba_port_num] = 2;
++ break;
++ case '3':
++ adapter->port_name[adapter->hba_port_num] = 3;
++ break;
++ case '4':
++ adapter->port_name[adapter->hba_port_num] = 4;
++ break;
++ case 'A':
++ adapter->port_name[adapter->hba_port_num] = 5;
++ break;
++ case 'B':
++ adapter->port_name[adapter->hba_port_num] = 6;
++ break;
++ case 'C':
++ adapter->port_name[adapter->hba_port_num] = 7;
++ break;
++ case 'D':
++ adapter->port_name[adapter->hba_port_num] = 8;
++ break;
++ }
++}
++
++int be_cmd_query_port_names_v0(struct be_adapter *adapter, u8 *port_name)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_port_name *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_GET_PORT_NAME);
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_GET_PORT_NAME, sizeof(*req));
++
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_get_port_name *resp = embedded_payload(wrb);
++ port_name[0] = resp->port0_name;
++ port_name[1] = resp->port1_name;
++ }
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++
++ if(!status)
++ encode_port_names(adapter);
++ return status;
++}
++
++int be_cmd_query_port_names_v1(struct be_adapter *adapter, u8 *port_name)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_port_name *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_GET_PORT_NAME);
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_GET_PORT_NAME, sizeof(*req));
++ req->hdr.version = 1;
++
+ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_get_port_name_v1 *resp = embedded_payload(wrb);
++ port_name[0] = resp->port0_name;
++ port_name[1] = resp->port1_name;
++ port_name[2] = resp->port2_name;
++ port_name[3] = resp->port3_name;
++ }
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++
++ if (!status)
++ encode_port_names(adapter);
++ return status;
++}
++
++int be_cmd_req_pg_pfc(struct be_adapter *adapter, int *fw_num_txqs)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_pg *req;
++ int status, num = 0;
++ bool query = true;
++
++ *fw_num_txqs = MAX_TX_QS;
++
++ if (mutex_lock_interruptible(&adapter->mbox_lock))
++ return -1;
++
++enable_pfc:
++ wrb = wrb_from_mbox(adapter);
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_ETH_PG_FEATURE_QUERY_REQUEST);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
++ OPCODE_ETH_PG_FEATURE_QUERY_REQUEST, sizeof(*req));
++
++ if (query)
++ req->query |= cpu_to_le32(REQ_PG_QUERY);
++ req->pfc_pg |= cpu_to_le32(REQ_PG_FEAT);
++
++ status = be_mbox_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_pg *resp = embedded_payload(wrb);
++ if (query) {
++ if (le32_to_cpu(resp->pfc_pg) & REQ_PG_FEAT) {
++ num = le32_to_cpu(resp->num_tx_rings);
++ query = false;
++ goto enable_pfc;
++ }
++ } else {
++ adapter->flags |= BE_FLAGS_DCBX;
++ *fw_num_txqs = num;
++ }
++ }
++
++ mutex_unlock(&adapter->mbox_lock);
++ return status;
++}
++
++/* Set privilege(s) for a function */
++int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 mask, u32 *prev,
++ u32 domain)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_set_fn_privileges *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_SET_FN_PRIVILEGES);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_SET_FN_PRIVILEGES, sizeof(*req));
++
++ req->hdr.domain = domain;
++ req->privilege_mask = cpu_to_le32(mask);
++
++ status = be_mcc_notify_wait(adapter);
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++/* Get privilege(s) for a function */
++int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege,
++ u32 domain)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_fn_privileges *req;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_GET_FN_PRIVILEGES);
+
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_GET_FN_PRIVILEGES, sizeof(*req));
++
++ req->hdr.domain = domain;
++
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_get_fn_privileges *resp =
++ embedded_payload(wrb);
++ *privilege = le32_to_cpu(resp->privilege_mask);
++ } else
++ *privilege = 0;
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++/* Set Hyper switch config */
++int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
++ u32 domain, u16 intf_id)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_set_hsw_config *req;
++ void *ctxt;
++ int status;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++ ctxt = &req->context;
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_SET_HSW_CONFIG);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_SET_HSW_CONFIG, sizeof(*req));
++
++ req->hdr.domain = domain;
++ AMAP_SET_BITS(struct amap_set_hsw_context, interface_id, ctxt, intf_id);
++ if (pvid) {
++ AMAP_SET_BITS(struct amap_set_hsw_context, pvid_valid, ctxt, 1);
++ AMAP_SET_BITS(struct amap_set_hsw_context, pvid, ctxt, pvid);
++ }
++
++ be_dws_cpu_to_le(req->context, sizeof(req->context));
++ status = be_mcc_notify_wait(adapter);
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++/* Get Hyper switch config */
++int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid,
++ u32 domain, u16 intf_id)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_hsw_config *req;
++ void *ctxt;
++ int status;
++ u16 vid;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++ ctxt = &req->context;
++
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_GET_HSW_CONFIG);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_GET_HSW_CONFIG, sizeof(*req));
++
++ req->hdr.domain = domain;
++ AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, ctxt,
++ intf_id);
++ AMAP_SET_BITS(struct amap_get_hsw_req_context, pvid_valid, ctxt, 1);
++ be_dws_cpu_to_le(req->context, sizeof(req->context));
++
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_get_hsw_config *resp =
++ embedded_payload(wrb);
++ be_dws_le_to_cpu(&resp->context,
++ sizeof(resp->context));
++ vid = AMAP_GET_BITS(struct amap_get_hsw_resp_context,
++ pvid, &resp->context);
++ *pvid = le16_to_cpu(vid);
++ }
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_get_port_speed(struct be_adapter *adapter,
++ u8 port_num, u16 *dac_cable_len, u16 *port_speed)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_get_port_speed *req;
++ int status = 0;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++
++ req = embedded_payload(wrb);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_NTWK_GET_LINK_SPEED);
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_NTWK_GET_LINK_SPEED,
++ sizeof(*req));
++ req->port_num = port_num;
++ status = be_mcc_notify_wait(adapter);
++ if (!status) {
++ struct be_cmd_resp_get_port_speed *resp =
++ embedded_payload(wrb);
++ *dac_cable_len = resp->dac_cable_length;
++ *port_speed = resp->mac_speed;
++ }
++
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++int be_cmd_set_port_speed_v1(struct be_adapter *adapter,
++ u8 port_num, u16 mac_speed,
++ u16 dac_cable_len)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_cmd_req_set_port_speed_v1 *req;
++ int status = 0;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ req = embedded_payload(wrb);
++ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
++ OPCODE_COMMON_NTWK_SET_LINK_SPEED);
++
++ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
++ OPCODE_COMMON_NTWK_SET_LINK_SPEED,
++ sizeof(*req));
++ req->hdr.version=1;
++
++ req->port_num = port_num;
++ req->virt_port = port_num;
++ req->mac_speed = mac_speed;
++ req->dac_cable_length = dac_cable_len;
++ status = be_mcc_notify_wait(adapter);
++err:
++ spin_unlock_bh(&adapter->mcc_lock);
++ return status;
++}
++
++
++/* Uses sync mcc */
++#ifdef CONFIG_PALAU
++int be_cmd_pass_ext_ioctl(struct be_adapter *adapter, dma_addr_t dma,
++ int req_size, void *va)
++{
++ struct be_mcc_wrb *wrb;
++ struct be_sge *sge;
++ int status;
++ struct be_cmd_req_hdr *hdr = (struct be_cmd_req_hdr *) va;
++
++ spin_lock_bh(&adapter->mcc_lock);
++
++ wrb = wrb_from_mccq(adapter);
++ if (!wrb) {
++ status = -EBUSY;
++ goto err;
++ }
++ sge = nonembedded_sgl(wrb);
++
++ be_wrb_hdr_prepare(wrb, req_size, false, 1, hdr->opcode);
++ wrb->tag1 = MCC_WRB_PASS_THRU;
++ sge->pa_hi = cpu_to_le32(upper_32_bits(dma));
++ sge->pa_lo = cpu_to_le32(dma & 0xFFFFFFFF);
++ sge->len = cpu_to_le32(req_size);
++
++ status = be_mcc_notify_wait(adapter);
++err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+ }
++#endif
+diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
+index ad33d55..35aa5c7 100644
+--- a/drivers/net/benet/be_cmds.h
++++ b/drivers/net/benet/be_cmds.h
+@@ -1,20 +1,23 @@
+ /*
+- * Copyright (C) 2005 - 2009 ServerEngines
++ * Copyright (C) 2005 - 2011 Emulex
+ * 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. The full GNU General
++ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+- * linux-drivers@serverengines.com
++ * linux-drivers@emulex.com
+ *
+- * ServerEngines
+- * 209 N. Fair Oaks Ave
+- * Sunnyvale, CA 94085
++ * Emulex
++ * 3333 Susan Street
++ * Costa Mesa, CA 92626
+ */
+
++#ifndef BE_CMDS_H
++#define BE_CMDS_H
++
+ /*
+ * The driver sends configuration and managements command requests to the
+ * firmware in the BE. These requests are communicated to the processor
+@@ -29,9 +32,10 @@ struct be_sge {
+ u32 len;
+ };
+
+-#define MCC_WRB_EMBEDDED_MASK 1 /* bit 0 of dword 0*/
++#define MCC_WRB_EMBEDDED_MASK 1 /* bit 0 of dword 0*/
+ #define MCC_WRB_SGE_CNT_SHIFT 3 /* bits 3 - 7 of dword 0 */
+ #define MCC_WRB_SGE_CNT_MASK 0x1F /* bits 3 - 7 of dword 0 */
++#define MCC_WRB_PASS_THRU 0xFF /* this wrb is used for pass thru cmd */
+ struct be_mcc_wrb {
+ u32 embedded; /* dword 0 */
+ u32 payload_length; /* dword 1 */
+@@ -44,24 +48,19 @@ struct be_mcc_wrb {
+ } payload;
+ };
+
+-#define CQE_FLAGS_VALID_MASK (1 << 31)
+-#define CQE_FLAGS_ASYNC_MASK (1 << 30)
+-#define CQE_FLAGS_COMPLETED_MASK (1 << 28)
+-#define CQE_FLAGS_CONSUMED_MASK (1 << 27)
++#define CQE_FLAGS_VALID_MASK (1 << 31)
++#define CQE_FLAGS_ASYNC_MASK (1 << 30)
++#define CQE_FLAGS_COMPLETED_MASK (1 << 28)
++#define CQE_FLAGS_CONSUMED_MASK (1 << 27)
+
+ /* Completion Status */
+ enum {
+- MCC_STATUS_SUCCESS = 0x0,
+-/* The client does not have sufficient privileges to execute the command */
+- MCC_STATUS_INSUFFICIENT_PRIVILEGES = 0x1,
+-/* A parameter in the command was invalid. */
+- MCC_STATUS_INVALID_PARAMETER = 0x2,
+-/* There are insufficient chip resources to execute the command */
+- MCC_STATUS_INSUFFICIENT_RESOURCES = 0x3,
+-/* The command is completing because the queue was getting flushed */
+- MCC_STATUS_QUEUE_FLUSHING = 0x4,
+-/* The command is completing with a DMA error */
+- MCC_STATUS_DMA_FAILED = 0x5,
++ MCC_STATUS_SUCCESS = 0,
++ MCC_STATUS_FAILED = 1,
++ MCC_STATUS_ILLEGAL_REQUEST = 2,
++ MCC_STATUS_ILLEGAL_FIELD = 3,
++ MCC_STATUS_INSUFFICIENT_BUFFER = 4,
++ MCC_STATUS_UNAUTHORIZED_REQUEST = 5,
+ MCC_STATUS_NOT_SUPPORTED = 66
+ };
+
+@@ -81,15 +80,24 @@ struct be_mcc_compl {
+ * mcc_compl is interpreted as follows:
+ */
+ #define ASYNC_TRAILER_EVENT_CODE_SHIFT 8 /* bits 8 - 15 */
++#define ASYNC_TRAILER_EVENT_TYPE_SHIFT 16 /* bits 16 - 23 */
+ #define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF
++#define ASYNC_TRAILER_EVENT_TYPE_MASK 0xFF
+ #define ASYNC_EVENT_CODE_LINK_STATE 0x1
++#define ASYNC_EVENT_CODE_GRP_5 0x5
++#define ASYNC_EVENT_QOS_SPEED 0x1
++#define ASYNC_EVENT_COS_PRIORITY 0x2
++#define ASYNC_EVENT_PVID_STATE 0x3
++#define GRP5_TYPE_PRIO_TC_MAP 4
++
+ struct be_async_event_trailer {
+ u32 code;
+ };
+
+ enum {
+- ASYNC_EVENT_LINK_DOWN = 0x0,
+- ASYNC_EVENT_LINK_UP = 0x1
++ ASYNC_EVENT_LINK_DOWN = 0x0,
++ ASYNC_EVENT_LINK_UP = 0x1,
++ ASYNC_EVENT_LOGICAL = 0x2
+ };
+
+ /* When the event code of an async trailer is link-state, the mcc_compl
+@@ -101,7 +109,51 @@ struct be_async_event_link_state {
+ u8 port_duplex;
+ u8 port_speed;
+ u8 port_fault;
+- u8 rsvd0[7];
++ u8 rsvd0;
++ u16 qos_link_speed;
++ u32 event_tag;
++ struct be_async_event_trailer trailer;
++} __packed;
++
++/* When the event code of an async trailer is GRP-5 and event_type is QOS_SPEED
++ * the mcc_compl must be interpreted as follows
++ */
++struct be_async_event_grp5_qos_link_speed {
++ u8 physical_port;
++ u8 rsvd[5];
++ u16 qos_link_speed;
++ u32 event_tag;
++ struct be_async_event_trailer trailer;
++} __packed;
++
++/* When the event code of an async trailer is GRP5 and event type is
++ * CoS-Priority, the mcc_compl must be interpreted as follows
++ */
++struct be_async_event_grp5_cos_priority {
++ u8 physical_port;
++ u8 available_priority_bmap;
++ u8 reco_default_priority;
++ u8 valid;
++ u8 rsvd0;
++ u8 event_tag;
++ struct be_async_event_trailer trailer;
++} __packed;
++
++/* When the event code of an async trailer is GRP5 and event type is
++ * PVID state, the mcc_compl must be interpreted as follows
++ */
++struct be_async_event_grp5_pvid_state {
++ u8 enabled;
++ u8 rsvd0;
++ u16 tag;
++ u32 event_tag;
++ u32 rsvd1;
++ struct be_async_event_trailer trailer;
++} __packed;
++
++/* GRP5 prio-tc-map event */
++struct be_async_event_grp5_prio_tc_map {
++ u8 prio_tc_map[8]; /* map[prio] -> tc_id */
+ struct be_async_event_trailer trailer;
+ } __packed;
+
+@@ -111,41 +163,68 @@ struct be_mcc_mailbox {
+ };
+
+ #define CMD_SUBSYSTEM_COMMON 0x1
+-#define CMD_SUBSYSTEM_ETH 0x3
++#define CMD_SUBSYSTEM_ETH 0x3
++#define CMD_SUBSYSTEM_LOWLEVEL 0xb
+
+ #define OPCODE_COMMON_NTWK_MAC_QUERY 1
+ #define OPCODE_COMMON_NTWK_MAC_SET 2
+ #define OPCODE_COMMON_NTWK_MULTICAST_SET 3
+-#define OPCODE_COMMON_NTWK_VLAN_CONFIG 4
++#define OPCODE_COMMON_NTWK_VLAN_CONFIG 4
+ #define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5
++#define OPCODE_COMMON_READ_FLASHROM 6
+ #define OPCODE_COMMON_WRITE_FLASHROM 7
+ #define OPCODE_COMMON_CQ_CREATE 12
+ #define OPCODE_COMMON_EQ_CREATE 13
+-#define OPCODE_COMMON_MCC_CREATE 21
+-#define OPCODE_COMMON_NTWK_RX_FILTER 34
++#define OPCODE_COMMON_MCC_CREATE 21
++#define OPCODE_COMMON_SET_QOS 28
++#define OPCODE_COMMON_MCC_CREATE_EXT 90
++#define OPCODE_COMMON_SEEPROM_READ 30
++#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32
++#define OPCODE_COMMON_NTWK_RX_FILTER 34
+ #define OPCODE_COMMON_GET_FW_VERSION 35
+ #define OPCODE_COMMON_SET_FLOW_CONTROL 36
+ #define OPCODE_COMMON_GET_FLOW_CONTROL 37
+ #define OPCODE_COMMON_SET_FRAME_SIZE 39
+ #define OPCODE_COMMON_MODIFY_EQ_DELAY 41
+ #define OPCODE_COMMON_FIRMWARE_CONFIG 42
+-#define OPCODE_COMMON_NTWK_INTERFACE_CREATE 50
+-#define OPCODE_COMMON_NTWK_INTERFACE_DESTROY 51
+-#define OPCODE_COMMON_MCC_DESTROY 53
+-#define OPCODE_COMMON_CQ_DESTROY 54
+-#define OPCODE_COMMON_EQ_DESTROY 55
++#define OPCODE_COMMON_NTWK_INTERFACE_CREATE 50
++#define OPCODE_COMMON_NTWK_INTERFACE_DESTROY 51
++#define OPCODE_COMMON_MCC_DESTROY 53
++#define OPCODE_COMMON_CQ_DESTROY 54
++#define OPCODE_COMMON_EQ_DESTROY 55
++#define OPCODE_COMMON_NTWK_SET_LINK_SPEED 57
+ #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58
+ #define OPCODE_COMMON_NTWK_PMAC_ADD 59
+ #define OPCODE_COMMON_NTWK_PMAC_DEL 60
+ #define OPCODE_COMMON_FUNCTION_RESET 61
++#define OPCODE_COMMON_MANAGE_FAT 68
++#define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69
++#define OPCODE_COMMON_GET_BEACON_STATE 70
++#define OPCODE_COMMON_READ_TRANSRECV_DATA 73
++#define OPCODE_COMMON_GET_PORT_NAME 77
++#define OPCODE_COMMON_SET_FN_PRIVILEGES 100
++#define OPCODE_COMMON_GET_PHY_DETAILS 102
++#define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103
++#define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121
++#define OPCODE_COMMON_NTWK_GET_LINK_SPEED 134
++#define OPCODE_COMMON_GET_HSW_CONFIG 152
++#define OPCODE_COMMON_SET_HSW_CONFIG 153
++#define OPCODE_COMMON_GET_FN_PRIVILEGES 170
+
++#define OPCODE_ETH_RSS_CONFIG 1
+ #define OPCODE_ETH_ACPI_CONFIG 2
+ #define OPCODE_ETH_PROMISCUOUS 3
+ #define OPCODE_ETH_GET_STATISTICS 4
+ #define OPCODE_ETH_TX_CREATE 7
+-#define OPCODE_ETH_RX_CREATE 8
+-#define OPCODE_ETH_TX_DESTROY 9
+-#define OPCODE_ETH_RX_DESTROY 10
++#define OPCODE_ETH_RX_CREATE 8
++#define OPCODE_ETH_TX_DESTROY 9
++#define OPCODE_ETH_RX_DESTROY 10
++#define OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG 12
++#define OPCODE_ETH_PG_FEATURE_QUERY_REQUEST 23
++
++#define OPCODE_LOWLEVEL_HOST_DDR_DMA 17
++#define OPCODE_LOWLEVEL_LOOPBACK_TEST 18
++#define OPCODE_LOWLEVEL_SET_LOOPBACK_MODE 19
+
+ struct be_cmd_req_hdr {
+ u8 opcode; /* dword 0 */
+@@ -159,7 +238,7 @@ struct be_cmd_req_hdr {
+ };
+
+ #define RESP_HDR_INFO_OPCODE_SHIFT 0 /* bits 0 - 7 */
+-#define RESP_HDR_INFO_SUBSYS_SHIFT 8 /* bits 8 - 15 */
++#define RESP_HDR_INFO_SUBSYS_SHIFT 8 /* bits 8 - 15 */
+ struct be_cmd_resp_hdr {
+ u32 info; /* dword 0 */
+ u32 status; /* dword 1 */
+@@ -265,7 +344,7 @@ struct be_cmd_req_pmac_del {
+ /******************** Create CQ ***************************/
+ /* Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field */
+-struct amap_cq_context {
++struct amap_cq_context_be {
+ u8 cidx[11]; /* dword 0*/
+ u8 rsvd0; /* dword 0*/
+ u8 coalescwm[2]; /* dword 0*/
+@@ -288,11 +367,28 @@ struct amap_cq_context {
+ u8 rsvd5[32]; /* dword 3*/
+ } __packed;
+
++struct amap_cq_context_lancer {
++ u8 rsvd0[12]; /* dword 0*/
++ u8 coalescwm[2]; /* dword 0*/
++ u8 nodelay; /* dword 0*/
++ u8 rsvd1[12]; /* dword 0*/
++ u8 count[2]; /* dword 0*/
++ u8 valid; /* dword 0*/
++ u8 rsvd2; /* dword 0*/
++ u8 eventable; /* dword 0*/
++ u8 eqid[16]; /* dword 1*/
++ u8 rsvd3[15]; /* dword 1*/
++ u8 armed; /* dword 1*/
++ u8 rsvd4[32]; /* dword 2*/
++ u8 rsvd5[32]; /* dword 3*/
++} __packed;
++
+ struct be_cmd_req_cq_create {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+- u16 rsvd0;
+- u8 context[sizeof(struct amap_cq_context) / 8];
++ u8 page_size;
++ u8 rsvd0;
++ u8 context[sizeof(struct amap_cq_context_be) / 8];
+ struct phys_addr pages[8];
+ } __packed;
+
+@@ -302,10 +398,28 @@ struct be_cmd_resp_cq_create {
+ u16 rsvd0;
+ } __packed;
+
++struct be_cmd_req_get_fat {
++ struct be_cmd_req_hdr hdr;
++ u32 fat_operation;
++ u32 read_log_offset;
++ u32 read_log_length;
++ u32 data_buffer_size;
++ u32 data_buffer[1];
++} __packed;
++
++struct be_cmd_resp_get_fat {
++ struct be_cmd_resp_hdr hdr;
++ u32 log_size;
++ u32 read_log_length;
++ u32 rsvd[2];
++ u32 data_buffer[1];
++} __packed;
++
++
+ /******************** Create MCCQ ***************************/
+ /* Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field */
+-struct amap_mcc_context {
++struct amap_mcc_context_be {
+ u8 con_index[14];
+ u8 rsvd0[2];
+ u8 ring_size[4];
+@@ -320,11 +434,31 @@ struct amap_mcc_context {
+ u8 rsvd2[32];
+ } __packed;
+
++struct amap_mcc_context_lancer {
++ u8 async_cq_id[16];
++ u8 ring_size[4];
++ u8 rsvd0[12];
++ u8 rsvd1[31];
++ u8 valid;
++ u8 async_cq_valid[1];
++ u8 rsvd2[31];
++ u8 rsvd3[32];
++} __packed;
++
+ struct be_cmd_req_mcc_create {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+- u16 rsvd0;
+- u8 context[sizeof(struct amap_mcc_context) / 8];
++ u16 cq_id;
++ u8 context[sizeof(struct amap_mcc_context_be) / 8];
++ struct phys_addr pages[8];
++} __packed;
++
++struct be_cmd_req_mcc_ext_create {
++ struct be_cmd_req_hdr hdr;
++ u16 num_pages;
++ u16 cq_id;
++ u32 async_event_bitmap[1];
++ u8 context[sizeof(struct amap_mcc_context_be) / 8];
+ struct phys_addr pages[8];
+ } __packed;
+
+@@ -335,49 +469,32 @@ struct be_cmd_resp_mcc_create {
+ } __packed;
+
+ /******************** Create TxQ ***************************/
+-#define BE_ETH_TX_RING_TYPE_STANDARD 2
++#define ETX_QUEUE_TYPE_STANDARD 0x2
++#define ETX_QUEUE_TYPE_PRIORITY 0x10
+ #define BE_ULP1_NUM 1
+
+-/* Pseudo amap definition in which each bit of the actual structure is defined
+- * as a byte: used to calculate offset/shift/mask of each field */
+-struct amap_tx_context {
+- u8 rsvd0[16]; /* dword 0 */
+- u8 tx_ring_size[4]; /* dword 0 */
+- u8 rsvd1[26]; /* dword 0 */
+- u8 pci_func_id[8]; /* dword 1 */
+- u8 rsvd2[9]; /* dword 1 */
+- u8 ctx_valid; /* dword 1 */
+- u8 cq_id_send[16]; /* dword 2 */
+- u8 rsvd3[16]; /* dword 2 */
+- u8 rsvd4[32]; /* dword 3 */
+- u8 rsvd5[32]; /* dword 4 */
+- u8 rsvd6[32]; /* dword 5 */
+- u8 rsvd7[32]; /* dword 6 */
+- u8 rsvd8[32]; /* dword 7 */
+- u8 rsvd9[32]; /* dword 8 */
+- u8 rsvd10[32]; /* dword 9 */
+- u8 rsvd11[32]; /* dword 10 */
+- u8 rsvd12[32]; /* dword 11 */
+- u8 rsvd13[32]; /* dword 12 */
+- u8 rsvd14[32]; /* dword 13 */
+- u8 rsvd15[32]; /* dword 14 */
+- u8 rsvd16[32]; /* dword 15 */
+-} __packed;
+-
+ struct be_cmd_req_eth_tx_create {
+ struct be_cmd_req_hdr hdr;
+ u8 num_pages;
+ u8 ulp_num;
+- u8 type;
+- u8 bound_port;
+- u8 context[sizeof(struct amap_tx_context) / 8];
++ u16 type;
++ u16 if_id;
++ u8 queue_size;
++ u8 rsvd1;
++ u32 rsvd2;
++ u16 cq_id;
++ u16 rsvd3;
++ u32 rsvd4[13];
+ struct phys_addr pages[8];
+ } __packed;
+
+ struct be_cmd_resp_eth_tx_create {
+ struct be_cmd_resp_hdr hdr;
+ u16 cid;
+- u16 rsvd0;
++ u16 rid;
++ u32 db_offset;
++ u8 tc_id;
++ u8 rsvd0[3];
+ } __packed;
+
+ /******************** Create RxQ ***************************/
+@@ -396,7 +513,7 @@ struct be_cmd_req_eth_rx_create {
+ struct be_cmd_resp_eth_rx_create {
+ struct be_cmd_resp_hdr hdr;
+ u16 id;
+- u8 cpu_id;
++ u8 rss_id;
+ u8 rsvd0;
+ } __packed;
+
+@@ -429,14 +546,15 @@ enum be_if_flags {
+ BE_IF_FLAGS_VLAN = 0x100,
+ BE_IF_FLAGS_MCAST_PROMISCUOUS = 0x200,
+ BE_IF_FLAGS_PASS_L2_ERRORS = 0x400,
+- BE_IF_FLAGS_PASS_L3L4_ERRORS = 0x800
++ BE_IF_FLAGS_PASS_L3L4_ERRORS = 0x800,
++ BE_IF_FLAGS_MULTICAST = 0x1000
+ };
+
+ /* An RX interface is an object with one or more MAC addresses and
+ * filtering capabilities. */
+ struct be_cmd_req_if_create {
+ struct be_cmd_req_hdr hdr;
+- u32 version; /* ignore currntly */
++ u32 version; /* ignore currently */
+ u32 capability_flags;
+ u32 enable_flags;
+ u8 mac_addr[ETH_ALEN];
+@@ -458,7 +576,7 @@ struct be_cmd_req_if_destroy {
+ };
+
+ /*************** HW Stats Get **********************************/
+-struct be_port_rxf_stats {
++struct be_port_rxf_stats_v0 {
+ u32 rx_bytes_lsd; /* dword 0*/
+ u32 rx_bytes_msd; /* dword 1*/
+ u32 rx_total_frames; /* dword 2*/
+@@ -527,8 +645,8 @@ struct be_port_rxf_stats {
+ u32 rx_input_fifo_overflow; /* dword 65*/
+ };
+
+-struct be_rxf_stats {
+- struct be_port_rxf_stats port[2];
++struct be_rxf_stats_v0 {
++ struct be_port_rxf_stats_v0 port[2];
+ u32 rx_drops_no_pbuf; /* dword 132*/
+ u32 rx_drops_no_txpb; /* dword 133*/
+ u32 rx_drops_no_erx_descr; /* dword 134*/
+@@ -545,31 +663,51 @@ struct be_rxf_stats {
+ u32 rx_drops_invalid_ring; /* dword 145*/
+ u32 forwarded_packets; /* dword 146*/
+ u32 rx_drops_mtu; /* dword 147*/
+- u32 rsvd0[15];
++ u32 rsvd0[7];
++ u32 port0_jabber_events;
++ u32 port1_jabber_events;
++ u32 rsvd1[6];
+ };
+
+-struct be_erx_stats {
++struct be_erx_stats_v0 {
+ u32 rx_drops_no_fragments[44]; /* dwordS 0 to 43*/
+- u32 debug_wdma_sent_hold; /* dword 44*/
+- u32 debug_wdma_pbfree_sent_hold; /* dword 45*/
+- u32 debug_wdma_zerobyte_pbfree_sent_hold; /* dword 46*/
+- u32 debug_pmem_pbuf_dealloc; /* dword 47*/
++ u32 rsvd[4];
+ };
+
+-struct be_hw_stats {
+- struct be_rxf_stats rxf;
++struct be_pmem_stats {
++ u32 eth_red_drops;
++ u32 rsvd[5];
++};
++
++struct be_hw_stats_v0 {
++ struct be_rxf_stats_v0 rxf;
+ u32 rsvd[48];
+- struct be_erx_stats erx;
++ struct be_erx_stats_v0 erx;
++ struct be_pmem_stats pmem;
+ };
+
+-struct be_cmd_req_get_stats {
++struct be_cmd_req_get_stats_v0 {
+ struct be_cmd_req_hdr hdr;
+- u8 rsvd[sizeof(struct be_hw_stats)];
++ u8 rsvd[sizeof(struct be_hw_stats_v0)];
+ };
+
+-struct be_cmd_resp_get_stats {
++struct be_cmd_resp_get_stats_v0 {
+ struct be_cmd_resp_hdr hdr;
+- struct be_hw_stats hw_stats;
++ struct be_hw_stats_v0 hw_stats;
++};
++
++struct be_cmd_req_get_cntl_addnl_attribs {
++ struct be_cmd_req_hdr hdr;
++ u8 rsvd[8];
++};
++
++struct be_cmd_resp_get_cntl_addnl_attribs {
++ struct be_cmd_resp_hdr hdr;
++ u16 ipl_file_number;
++ u8 ipl_file_version;
++ u8 rsvd0;
++ u8 on_die_temperature; /* in degrees centigrade*/
++ u8 rsvd1[3];
+ };
+
+ struct be_cmd_req_vlan_config {
+@@ -581,30 +719,22 @@ struct be_cmd_req_vlan_config {
+ u16 normal_vlan[64];
+ } __packed;
+
+-struct be_cmd_req_promiscuous_config {
+- struct be_cmd_req_hdr hdr;
+- u8 port0_promiscuous;
+- u8 port1_promiscuous;
+- u16 rsvd0;
+-} __packed;
+-
++/******************** RX FILTER ******************************/
++#define BE_MAX_MC 64 /* set mcast promisc if > 64 */
+ struct macaddr {
+ u8 byte[ETH_ALEN];
+ };
+
+-struct be_cmd_req_mcast_mac_config {
++struct be_cmd_req_rx_filter {
+ struct be_cmd_req_hdr hdr;
+- u16 num_mac;
+- u8 promiscuous;
+- u8 interface_id;
+- struct macaddr mac[32];
+-} __packed;
+-
+-static inline struct be_hw_stats *
+-hw_stats_from_cmd(struct be_cmd_resp_get_stats *cmd)
+-{
+- return &cmd->hw_stats;
+-}
++ u32 global_flags_mask;
++ u32 global_flags;
++ u32 if_flags_mask;
++ u32 if_flags;
++ u32 if_id;
++ u32 mcast_num;
++ struct macaddr mcast_mac[BE_MAX_MC];
++};
+
+ /******************** Link Status Query *******************/
+ struct be_cmd_req_link_status {
+@@ -619,13 +749,18 @@ enum {
+ };
+
+ enum {
+- PHY_LINK_SPEED_ZERO = 0x0, /* => No link */
++ PHY_LINK_SPEED_ZERO = 0x0, /* => No link */
+ PHY_LINK_SPEED_10MBPS = 0x1,
+ PHY_LINK_SPEED_100MBPS = 0x2,
+ PHY_LINK_SPEED_1GBPS = 0x3,
+ PHY_LINK_SPEED_10GBPS = 0x4
+ };
+
++enum {
++ LINK_DOWN = 0x0,
++ LINK_UP = 0X1
++};
++
+ struct be_cmd_resp_link_status {
+ struct be_cmd_resp_hdr hdr;
+ u8 physical_port;
+@@ -634,9 +769,47 @@ struct be_cmd_resp_link_status {
+ u8 mac_fault;
+ u8 mgmt_mac_duplex;
+ u8 mgmt_mac_speed;
+- u16 rsvd0;
++ u16 link_speed;
++ u32 logical_link_status;
+ } __packed;
+
++/******************** Port Identification ***************************/
++/* Identifies the type of port attached to NIC */
++struct be_cmd_req_port_type {
++ struct be_cmd_req_hdr hdr;
++ u32 page_num;
++ u32 port;
++};
++
++enum {
++ TR_PAGE_A0 = 0xa0,
++ TR_PAGE_A2 = 0xa2
++};
++
++struct be_cmd_resp_port_type {
++ struct be_cmd_resp_hdr hdr;
++ u32 page_num;
++ u32 port;
++ struct data {
++ u8 identifier;
++ u8 identifier_ext;
++ u8 connector;
++ u8 transceiver[8];
++ u8 rsvd0[3];
++ u8 length_km;
++ u8 length_hm;
++ u8 length_om1;
++ u8 length_om2;
++ u8 length_cu;
++ u8 length_cu_m;
++ u8 vendor_name[16];
++ u8 rsvd;
++ u8 vendor_oui[3];
++ u8 vendor_pn[16];
++ u8 vendor_rev[4];
++ } data;
++};
++
+ /******************** Get FW Version *******************/
+ struct be_cmd_req_get_fw_version {
+ struct be_cmd_req_hdr hdr;
+@@ -686,9 +859,13 @@ struct be_cmd_resp_modify_eq_delay {
+ } __packed;
+
+ /******************** Get FW Config *******************/
++#define FLEX10_MODE 0x400
++#define VNIC_MODE 0x20000
++#define UMC_ENABLED 0x1000000
++
+ struct be_cmd_req_query_fw_cfg {
+ struct be_cmd_req_hdr hdr;
+- u32 rsvd[30];
++ u32 rsvd[31];
+ };
+
+ struct be_cmd_resp_query_fw_cfg {
+@@ -696,10 +873,61 @@ struct be_cmd_resp_query_fw_cfg {
+ u32 be_config_number;
+ u32 asic_revision;
+ u32 phys_port;
+- u32 function_cap;
++ u32 function_mode;
+ u32 rsvd[26];
++ u32 function_caps;
+ };
+
++/******************** RSS Config *******************/
++/* RSS types */
++#define RSS_ENABLE_NONE 0x0
++#define RSS_ENABLE_IPV4 0x1
++#define RSS_ENABLE_TCP_IPV4 0x2
++#define RSS_ENABLE_IPV6 0x4
++#define RSS_ENABLE_TCP_IPV6 0x8
++
++struct be_cmd_req_rss_config {
++ struct be_cmd_req_hdr hdr;
++ u32 if_id;
++ u16 enable_rss;
++ u16 cpu_table_size_log2;
++ u32 hash[10];
++ u8 cpu_table[128];
++ u8 flush;
++ u8 rsvd0[3];
++};
++
++/******************** Port Beacon ***************************/
++
++#define BEACON_STATE_ENABLED 0x1
++#define BEACON_STATE_DISABLED 0x0
++
++struct be_cmd_req_enable_disable_beacon {
++ struct be_cmd_req_hdr hdr;
++ u8 port_num;
++ u8 beacon_state;
++ u8 beacon_duration;
++ u8 status_duration;
++} __packed;
++
++struct be_cmd_resp_enable_disable_beacon {
++ struct be_cmd_resp_hdr resp_hdr;
++ u32 rsvd0;
++} __packed;
++
++struct be_cmd_req_get_beacon_state {
++ struct be_cmd_req_hdr hdr;
++ u8 port_num;
++ u8 rsvd0;
++ u16 rsvd1;
++} __packed;
++
++struct be_cmd_resp_get_beacon_state {
++ struct be_cmd_resp_hdr resp_hdr;
++ u8 beacon_state;
++ u8 rsvd0[3];
++} __packed;
++
+ /****************** Firmware Flash ******************/
+ struct flashrom_params {
+ u32 op_code;
+@@ -714,17 +942,468 @@ struct be_cmd_write_flashrom {
+ struct flashrom_params params;
+ };
+
++/************************ WOL *******************************/
++struct be_cmd_req_acpi_wol_magic_config {
++ struct be_cmd_req_hdr hdr;
++ u32 rsvd0[145];
++ u8 magic_mac[6];
++ u8 rsvd2[2];
++} __packed;
++
++/********************** LoopBack test *********************/
++struct be_cmd_req_loopback_test {
++ struct be_cmd_req_hdr hdr;
++ u32 loopback_type;
++ u32 num_pkts;
++ u64 pattern;
++ u32 src_port;
++ u32 dest_port;
++ u32 pkt_size;
++};
++
++struct be_cmd_resp_loopback_test {
++ struct be_cmd_resp_hdr resp_hdr;
++ u32 status;
++ u32 num_txfer;
++ u32 num_rx;
++ u32 miscomp_off;
++ u32 ticks_compl;
++};
++
++struct be_cmd_req_set_lmode {
++ struct be_cmd_req_hdr hdr;
++ u8 src_port;
++ u8 dest_port;
++ u8 loopback_type;
++ u8 loopback_state;
++};
++
++struct be_cmd_resp_set_lmode {
++ struct be_cmd_resp_hdr resp_hdr;
++ u8 rsvd0[4];
++};
++
++/********************** DDR DMA test *********************/
++struct be_cmd_req_ddrdma_test {
++ struct be_cmd_req_hdr hdr;
++ u64 pattern;
++ u32 byte_count;
++ u32 rsvd0;
++ u8 snd_buff[4096];
++ u8 rsvd1[4096];
++};
++
++struct be_cmd_resp_ddrdma_test {
++ struct be_cmd_resp_hdr hdr;
++ u64 pattern;
++ u32 byte_cnt;
++ u32 snd_err;
++ u8 rsvd0[4096];
++ u8 rcv_buff[4096];
++};
++
++/*********************** SEEPROM Read ***********************/
++
++#define BE_READ_SEEPROM_LEN 1024
++struct be_cmd_req_seeprom_read {
++ struct be_cmd_req_hdr hdr;
++ u8 rsvd0[BE_READ_SEEPROM_LEN];
++};
++
++struct be_cmd_resp_seeprom_read {
++ struct be_cmd_req_hdr hdr;
++ u8 seeprom_data[BE_READ_SEEPROM_LEN];
++};
++
++enum {
++ PHY_TYPE_CX4_10GB = 0,
++ PHY_TYPE_XFP_10GB,
++ PHY_TYPE_SFP_1GB,
++ PHY_TYPE_SFP_PLUS_10GB,
++ PHY_TYPE_KR_10GB,
++ PHY_TYPE_KX4_10GB,
++ PHY_TYPE_BASET_10GB,
++ PHY_TYPE_BASET_1GB,
++ PHY_TYPE_BASEX_1GB,
++ PHY_TYPE_SGMII,
++ PHY_TYPE_DISABLED = 255
++};
++
++#define BE_AN_EN 0x2
++#define BE_PAUSE_SYM_EN 0x80
++
++struct be_cmd_req_get_phy_info {
++ struct be_cmd_req_hdr hdr;
++ u8 rsvd0[24];
++};
++
++struct be_phy_info {
++ u16 phy_type;
++ u16 interface_type;
++ u32 misc_params;
++ u16 ext_phy_details;
++ u16 rsvd;
++ u16 auto_speeds_supported;
++ u16 fixed_speeds_supported;
++ u32 future_use[2];
++};
++
++struct be_cmd_resp_get_phy_info {
++ struct be_cmd_req_hdr hdr;
++ struct be_phy_info phy_info;
++};
++
++/*********************** Set QOS ***********************/
++
++#define BE_QOS_BITS_NIC 1
++
++struct be_cmd_req_set_qos {
++ struct be_cmd_req_hdr hdr;
++ u32 valid_bits;
++ u32 max_bps_nic;
++ u32 rsvd[7];
++};
++
++struct be_cmd_resp_set_qos {
++ struct be_cmd_resp_hdr hdr;
++ u32 rsvd;
++};
++
++/*********************** Controller Attributes ***********************/
++struct be_cmd_req_cntl_attribs {
++ struct be_cmd_req_hdr hdr;
++};
++
++struct be_cmd_resp_cntl_attribs {
++ struct be_cmd_resp_hdr hdr;
++ struct mgmt_controller_attrib attribs;
++};
++
++/******************* get port names ***************/
++struct be_cmd_req_get_port_name {
++ struct be_cmd_req_hdr hdr;
++ u32 rsvd0;
++};
++
++struct be_cmd_resp_get_port_name {
++ struct be_cmd_req_hdr hdr;
++ u8 port0_name;
++ u8 port1_name;
++ u8 rsvd0[2];
++};
++
++struct be_cmd_resp_get_port_name_v1 {
++ struct be_cmd_req_hdr hdr;
++ u32 pt : 2;
++ u32 rsvd0 : 30;
++ u8 port0_name;
++ u8 port1_name;
++ u8 port2_name;
++ u8 port3_name;
++};
++
++/*********************** Set driver function ***********************/
++#define CAPABILITY_SW_TIMESTAMPS 2
++#define CAPABILITY_BE3_NATIVE_ERX_API 4
++
++struct be_cmd_req_set_func_cap {
++ struct be_cmd_req_hdr hdr;
++ u32 valid_cap_flags;
++ u32 cap_flags;
++ u8 rsvd[212];
++};
++
++struct be_cmd_resp_set_func_cap {
++ struct be_cmd_resp_hdr hdr;
++ u32 valid_cap_flags;
++ u32 cap_flags;
++ u8 rsvd[212];
++};
++
++/*********************** PG Query Request ****************************/
++#define REQ_PG_QUERY 0x1
++#define REQ_PG_FEAT 0x1
++struct be_cmd_req_pg {
++ struct be_cmd_req_hdr hdr;
++ u32 query;
++ u32 pfc_pg;
++};
++
++struct be_cmd_resp_pg {
++ struct be_cmd_resp_hdr hdr;
++ u32 pfc_pg;
++ u32 num_tx_rings;
++};
++
++/*********************** Function Privileges ***********************/
++enum {
++ BE_PRIV_DEFAULT = 0x1,
++ BE_PRIV_LNKQUERY = 0x2,
++ BE_PRIV_LNKSTATS = 0x4,
++ BE_PRIV_LNKMGMT = 0x8,
++ BE_PRIV_LNKDIAG = 0x10,
++ BE_PRIV_UTILQUERY = 0x20,
++ BE_PRIV_FILTMGMT = 0x40,
++ BE_PRIV_IFACEMGMT = 0x80,
++ BE_PRIV_VHADM = 0x100,
++ BE_PRIV_DEVCFG = 0x200,
++ BE_PRIV_DEVSEC = 0x400
++};
++
++struct be_cmd_req_get_fn_privileges {
++ struct be_cmd_req_hdr hdr;
++ u32 rsvd;
++};
++
++struct be_cmd_resp_get_fn_privileges {
++ struct be_cmd_resp_hdr hdr;
++ u32 privilege_mask;
++};
++
++struct be_cmd_req_set_fn_privileges {
++ struct be_cmd_req_hdr hdr;
++ u32 privilege_mask;
++};
++
++struct be_cmd_resp_set_fn_privileges {
++ struct be_cmd_resp_hdr hdr;
++ u32 prev_privilege_mask;
++};
++
++/*********************** HSW Config ***********************/
++struct amap_set_hsw_context {
++ u8 interface_id[16];
++ u8 rsvd0[14];
++ u8 pvid_valid;
++ u8 rsvd1;
++ u8 rsvd2[16];
++ u8 pvid[16];
++ u8 rsvd3[32];
++ u8 rsvd4[32];
++ u8 rsvd5[32];
++} __packed;
++
++struct be_cmd_req_set_hsw_config {
++ struct be_cmd_req_hdr hdr;
++ u8 context[sizeof(struct amap_set_hsw_context) / 8];
++} __packed;
++
++struct be_cmd_resp_set_hsw_config {
++ struct be_cmd_resp_hdr hdr;
++ u32 rsvd;
++};
++
++struct amap_get_hsw_req_context {
++ u8 interface_id[16];
++ u8 rsvd0[14];
++ u8 pvid_valid;
++ u8 pport;
++} __packed;
++
++struct amap_get_hsw_resp_context {
++ u8 rsvd1[16];
++ u8 pvid[16];
++ u8 rsvd2[32];
++ u8 rsvd3[32];
++ u8 rsvd4[32];
++} __packed;
++
++struct be_cmd_req_get_hsw_config {
++ struct be_cmd_req_hdr hdr;
++ u8 context[sizeof(struct amap_get_hsw_req_context) / 8];
++} __packed;
++
++struct be_cmd_resp_get_hsw_config {
++ struct be_cmd_resp_hdr hdr;
++ u8 context[sizeof(struct amap_get_hsw_resp_context) / 8];
++ u32 rsvd;
++};
++
++/*************** Set speed ********************/
++struct be_cmd_req_set_port_speed_v1 {
++ struct be_cmd_req_hdr hdr;
++ u8 port_num;
++ u8 virt_port;
++ u16 mac_speed;
++ u16 dac_cable_length;
++ u16 rsvd0;
++};
++
++struct be_cmd_resp_set_port_speed_v1 {
++ struct be_cmd_resp_hdr hdr;
++ u32 rsvd0;
++};
++
++/************** get port speed *******************/
++struct be_cmd_req_get_port_speed {
++ struct be_cmd_req_hdr hdr;
++ u8 port_num;
++};
++
++struct be_cmd_resp_get_port_speed {
++ struct be_cmd_req_hdr hdr;
++ u16 mac_speed;
++ u16 dac_cable_length;
++};
++
++/*************** HW Stats Get v1 **********************************/
++#define BE_TXP_SW_SZ 48
++struct be_port_rxf_stats_v1 {
++ u32 rsvd0[12];
++ u32 rx_crc_errors;
++ u32 rx_alignment_symbol_errors;
++ u32 rx_pause_frames;
++ u32 rx_priority_pause_frames;
++ u32 rx_control_frames;
++ u32 rx_in_range_errors;
++ u32 rx_out_range_errors;
++ u32 rx_frame_too_long;
++ u32 rx_address_match_errors;
++ u32 rx_dropped_too_small;
++ u32 rx_dropped_too_short;
++ u32 rx_dropped_header_too_small;
++ u32 rx_dropped_tcp_length;
++ u32 rx_dropped_runt;
++ u32 rsvd1[10];
++ u32 rx_ip_checksum_errs;
++ u32 rx_tcp_checksum_errs;
++ u32 rx_udp_checksum_errs;
++ u32 rsvd2[7];
++ u32 rx_switched_unicast_packets;
++ u32 rx_switched_multicast_packets;
++ u32 rx_switched_broadcast_packets;
++ u32 rsvd3[3];
++ u32 tx_pauseframes;
++ u32 tx_priority_pauseframes;
++ u32 tx_controlframes;
++ u32 rsvd4[10];
++ u32 rxpp_fifo_overflow_drop;
++ u32 rx_input_fifo_overflow_drop;
++ u32 pmem_fifo_overflow_drop;
++ u32 jabber_events;
++ u32 rsvd5[3];
++};
++
++
++struct be_rxf_stats_v1 {
++ struct be_port_rxf_stats_v1 port[4];
++ u32 rsvd0[2];
++ u32 rx_drops_no_pbuf;
++ u32 rx_drops_no_txpb;
++ u32 rx_drops_no_erx_descr;
++ u32 rx_drops_no_tpre_descr;
++ u32 rsvd1[6];
++ u32 rx_drops_too_many_frags;
++ u32 rx_drops_invalid_ring;
++ u32 forwarded_packets;
++ u32 rx_drops_mtu;
++ u32 rsvd2[14];
++};
++
++struct be_erx_stats_v1 {
++ u32 rx_drops_no_fragments[68]; /* dwordS 0 to 67*/
++ u32 rsvd[4];
++};
++
++struct be_hw_stats_v1 {
++ struct be_rxf_stats_v1 rxf;
++ u32 rsvd0[BE_TXP_SW_SZ];
++ struct be_erx_stats_v1 erx;
++ struct be_pmem_stats pmem;
++ u32 rsvd1[3];
++};
++
++struct be_cmd_req_get_stats_v1 {
++ struct be_cmd_req_hdr hdr;
++ u8 rsvd[sizeof(struct be_hw_stats_v1)];
++};
++
++struct be_cmd_resp_get_stats_v1 {
++ struct be_cmd_resp_hdr hdr;
++ struct be_hw_stats_v1 hw_stats;
++};
++
++static inline void *
++hw_stats_from_cmd(struct be_adapter *adapter)
++{
++ if (adapter->generation == BE_GEN3) {
++ struct be_cmd_resp_get_stats_v1 *cmd = adapter->stats_cmd.va;
++
++ return &cmd->hw_stats;
++ } else {
++ struct be_cmd_resp_get_stats_v0 *cmd = adapter->stats_cmd.va;
++
++ return &cmd->hw_stats;
++ }
++}
++
++static inline void *be_port_rxf_stats_from_cmd(struct be_adapter *adapter)
++{
++ if (adapter->generation == BE_GEN3) {
++ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
++ struct be_rxf_stats_v1 *rxf_stats = &hw_stats->rxf;
++
++ return &rxf_stats->port[adapter->port_num];
++ } else {
++ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
++ struct be_rxf_stats_v0 *rxf_stats = &hw_stats->rxf;
++
++ return &rxf_stats->port[adapter->port_num];
++ }
++}
++
++static inline void *be_rxf_stats_from_cmd(struct be_adapter *adapter)
++{
++ if (adapter->generation == BE_GEN3) {
++ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
++
++ return &hw_stats->rxf;
++ } else {
++ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
++
++ return &hw_stats->rxf;
++ }
++}
++
++static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter)
++{
++ if (adapter->generation == BE_GEN3) {
++ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
++
++ return &hw_stats->erx;
++ } else {
++ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
++
++ return &hw_stats->erx;
++ }
++}
++
++static inline void *be_pmem_stats_from_cmd(struct be_adapter *adapter)
++{
++ if (adapter->generation == BE_GEN3) {
++ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
++
++ return &hw_stats->pmem;
++ } else {
++ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
++
++ return &hw_stats->pmem;
++ }
++}
++
+ extern int be_pci_fnum_get(struct be_adapter *adapter);
+ extern int be_cmd_POST(struct be_adapter *adapter);
+ extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
+ u8 type, bool permanent, u32 if_handle);
+ extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
+- u32 if_id, u32 *pmac_id);
+-extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id);
++ u32 if_id, u32 *pmac_id, u32 domain);
++extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id,
++ u32 domain);
+ extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags,
+ u32 en_flags, u8 *mac, bool pmac_invalid,
+- u32 *if_handle, u32 *pmac_id);
+-extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle);
++ u32 *if_handle, u32 *pmac_id, u32 domain);
++extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle,
++ u32 domain);
+ extern int be_cmd_eq_create(struct be_adapter *adapter,
+ struct be_queue_info *eq, int eq_delay);
+ extern int be_cmd_cq_create(struct be_adapter *adapter,
+@@ -736,36 +1415,92 @@ extern int be_cmd_mccq_create(struct be_adapter *adapter,
+ struct be_queue_info *cq);
+ extern int be_cmd_txq_create(struct be_adapter *adapter,
+ struct be_queue_info *txq,
+- struct be_queue_info *cq);
++ struct be_queue_info *cq, u8 *tc_id);
+ extern int be_cmd_rxq_create(struct be_adapter *adapter,
+ struct be_queue_info *rxq, u16 cq_id,
+ u16 frag_size, u16 max_frame_size, u32 if_id,
+- u32 rss);
++ u32 rss, u8 *rss_id);
+ extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
+ int type);
++extern int be_cmd_rxq_destroy(struct be_adapter *adapter,
++ struct be_queue_info *q);
+ extern int be_cmd_link_status_query(struct be_adapter *adapter,
+- bool *link_up);
++ int *link_status, u8 *mac_speed, u16 *link_speed, u32 dom);
+ extern int be_cmd_reset(struct be_adapter *adapter);
+ extern int be_cmd_get_stats(struct be_adapter *adapter,
+ struct be_dma_mem *nonemb_cmd);
+-extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver);
++extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver,
++ char *fw_on_flash);
+
+ extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd);
+ extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id,
+ u16 *vtag_array, u32 num, bool untagged,
+ bool promiscuous);
+-extern int be_cmd_promiscuous_config(struct be_adapter *adapter,
+- u8 port_num, bool en);
+-extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
+- struct dev_mc_list *mc_list, u32 mc_count);
++extern int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
+ extern int be_cmd_set_flow_control(struct be_adapter *adapter,
+ u32 tx_fc, u32 rx_fc);
+ extern int be_cmd_get_flow_control(struct be_adapter *adapter,
+ u32 *tx_fc, u32 *rx_fc);
+-extern int be_cmd_query_fw_cfg(struct be_adapter *adapter,
+- u32 *port_num, u32 *cap);
++extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
++ u32 *function_mode, u32 *functions_caps);
+ extern int be_cmd_reset_function(struct be_adapter *adapter);
+-extern int be_process_mcc(struct be_adapter *adapter);
++extern int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
++ u16 table_size);
++extern int be_process_mcc(struct be_adapter *adapter, int *status);
++extern int be_cmd_set_beacon_state(struct be_adapter *adapter,
++ u8 port_num, u8 beacon, u8 status, u8 state);
++extern int be_cmd_get_beacon_state(struct be_adapter *adapter,
++ u8 port_num, u32 *state);
++extern int be_cmd_read_port_type(struct be_adapter *adapter, u32 port,
++ u8 *connector);
+ extern int be_cmd_write_flashrom(struct be_adapter *adapter,
+ struct be_dma_mem *cmd, u32 flash_oper,
+ u32 flash_opcode, u32 buf_size);
++int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
++ int offset);
++extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
++ struct be_dma_mem *nonemb_cmd);
++extern int be_cmd_fw_init(struct be_adapter *adapter);
++extern int be_cmd_fw_clean(struct be_adapter *adapter);
++extern void be_async_mcc_enable(struct be_adapter *adapter);
++extern void be_async_mcc_disable(struct be_adapter *adapter);
++extern int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
++ u32 loopback_type, u32 pkt_size,
++ u32 num_pkts, u64 pattern);
++extern int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern,
++ u32 byte_cnt, struct be_dma_mem *cmd);
++extern int be_cmd_get_seeprom_data(struct be_adapter *adapter,
++ struct be_dma_mem *nonemb_cmd);
++extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
++ u8 loopback_type, u8 enable);
++extern int be_cmd_get_phy_info(struct be_adapter *adapter,
++ struct be_phy_info *phy_info);
++extern int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain);
++extern void be_detect_dump_ue(struct be_adapter *adapter);
++extern int be_cmd_get_die_temperature(struct be_adapter *adapter);
++extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter);
++extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size);
++extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf);
++extern int be_cmd_req_native_mode(struct be_adapter *adapter);
++extern int be_cmd_query_port_names_v0(struct be_adapter *adapter, u8 *port_name);
++extern int be_cmd_query_port_names_v1(struct be_adapter *adapter, u8 *port_name);
++extern int be_cmd_req_pg_pfc(struct be_adapter *adapter, int *fw_num_txqs);
++
++extern int be_cmd_get_fn_privileges(struct be_adapter *adapter,
++ u32 *privilege, u32 domain);
++extern int be_cmd_set_fn_privileges(struct be_adapter *adapter,
++ u32 mask, u32 *prev, u32 domain);
++extern int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
++ u32 domain, u16 intf_id);
++extern int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid,
++ u32 domain, u16 intf_id);
++extern int be_cmd_set_port_speed_v1(struct be_adapter *adapter, u8 port_num,
++ u16 mac_speed, u16 dac_cable_len);
++extern int be_cmd_get_port_speed(struct be_adapter *adapter, u8 port_num,
++ u16 *dac_cable_len, u16 *port_speed);
++#ifdef CONFIG_PALAU
++int be_cmd_pass_ext_ioctl(struct be_adapter *adapter, dma_addr_t dma,
++ int req_size, void *va);
++#endif
++
++#endif /* !BE_CMDS_H */
+diff --git a/drivers/net/benet/be_compat.c b/drivers/net/benet/be_compat.c
+new file mode 100644
+index 0000000..bdd1dba
+--- /dev/null
++++ b/drivers/net/benet/be_compat.c
+@@ -0,0 +1,630 @@
++/*
++ * Copyright (C) 2005 - 2011 Emulex
++ * 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. The full GNU General
++ * Public License is included in this distribution in the file called COPYING.
++ *
++ * Contact Information:
++ * linux-drivers@emulex.com
++ *
++ * Emulex
++ * 3333 Susan Street
++ * Costa Mesa, CA 92626
++ */
++
++#include "be.h"
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
++void be_netdev_ops_init(struct net_device *netdev, struct net_device_ops *ops)
++{
++ netdev->open = ops->ndo_open;
++ netdev->stop = ops->ndo_stop;
++ netdev->hard_start_xmit = ops->ndo_start_xmit;
++ netdev->set_mac_address = ops->ndo_set_mac_address;
++ netdev->get_stats = ops->ndo_get_stats;
++ netdev->set_multicast_list = ops->ndo_set_rx_mode;
++ netdev->change_mtu = ops->ndo_change_mtu;
++ netdev->vlan_rx_register = ops->ndo_vlan_rx_register;
++ netdev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
++ netdev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
++ netdev->do_ioctl = ops->ndo_do_ioctl;
++#ifdef CONFIG_NET_POLL_CONTROLLER
++ netdev->poll_controller = ops->ndo_poll_controller;
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
++ netdev->select_queue = ops->ndo_select_queue;
++#endif
++}
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
++int eth_validate_addr(struct net_device *netdev)
++{
++ return 0;
++}
++#endif
++
++/* New NAPI backport */
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
++
++int be_poll_compat(struct net_device *netdev, int *budget)
++{
++ struct napi_struct *napi = netdev->priv;
++ u32 work_done, can_do;
++
++ can_do = min(*budget, netdev->quota);
++ work_done = napi->poll(napi, can_do);
++
++ *budget -= work_done;
++ netdev->quota -= work_done;
++ if (napi->rx)
++ return (work_done >= can_do);
++ return 0;
++}
++
++
++#endif /* New NAPI backport */
++
++int be_netif_napi_add(struct net_device *netdev,
++ struct napi_struct *napi,
++ int (*poll) (struct napi_struct *, int), int weight)
++{
++#ifdef HAVE_SIMULATED_MULTI_NAPI
++ struct be_adapter *adapter = netdev_priv(netdev);
++ struct net_device *nd;
++
++ nd = alloc_netdev(0, "", ether_setup);
++ if (!nd)
++ return -ENOMEM;
++ nd->priv = napi;
++ nd->weight = BE_NAPI_WEIGHT;
++ nd->poll = be_poll_compat;
++ set_bit(__LINK_STATE_START, &nd->state);
++
++ if (napi == &adapter->rx_obj[0].rx_eq.napi)
++ napi->rx = true;
++ napi->poll = poll;
++ napi->dev = nd;
++#ifdef RHEL_NEW_NAPI
++ napi->napi.dev = netdev;
++#endif
++ return 0;
++#else
++ netif_napi_add(netdev, napi, poll, weight);
++ return 0;
++#endif
++}
++void be_netif_napi_del(struct net_device *netdev)
++{
++#ifdef HAVE_SIMULATED_MULTI_NAPI
++ struct be_adapter *adapter = netdev_priv(netdev);
++ struct napi_struct *napi;
++ struct be_rx_obj *rxo;
++ int i;
++
++ for_all_rx_queues(adapter, rxo, i) {
++ napi = &rxo->rx_eq.napi;
++ if (napi->dev) {
++ free_netdev(napi->dev);
++ napi->dev = NULL;
++ }
++ }
++
++ napi = &adapter->tx_eq.napi;
++ if (napi->dev) {
++ free_netdev(napi->dev);
++ napi->dev = NULL;
++ }
++#endif
++}
++/* INET_LRO backport */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
++
++#define TCP_HDR_LEN(tcph) (tcph->doff << 2)
++#define IP_HDR_LEN(iph) (iph->ihl << 2)
++#define TCP_PAYLOAD_LENGTH(iph, tcph) (ntohs(iph->tot_len) - IP_HDR_LEN(iph) \
++ - TCP_HDR_LEN(tcph))
++
++#define IPH_LEN_WO_OPTIONS 5
++#define TCPH_LEN_WO_OPTIONS 5
++#define TCPH_LEN_W_TIMESTAMP 8
++
++#define LRO_MAX_PG_HLEN 64
++#define LRO_INC_STATS(lro_mgr, attr) { lro_mgr->stats.attr++; }
++/*
++ * Basic tcp checks whether packet is suitable for LRO
++ */
++static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph,
++ int len, struct net_lro_desc *lro_desc)
++{
++ /* check ip header: don't aggregate padded frames */
++ if (ntohs(iph->tot_len) != len)
++ return -1;
++
++ if (iph->ihl != IPH_LEN_WO_OPTIONS)
++ return -1;
++
++ if (tcph->cwr || tcph->ece || tcph->urg || !tcph->ack
++ || tcph->rst || tcph->syn || tcph->fin)
++ return -1;
++
++ if (INET_ECN_is_ce(ipv4_get_dsfield(iph)))
++ return -1;
++
++ if (tcph->doff != TCPH_LEN_WO_OPTIONS
++ && tcph->doff != TCPH_LEN_W_TIMESTAMP)
++ return -1;
++
++ /* check tcp options (only timestamp allowed) */
++ if (tcph->doff == TCPH_LEN_W_TIMESTAMP) {
++ u32 *topt = (u32 *)(tcph + 1);
++
++ if (*topt != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
++ | (TCPOPT_TIMESTAMP << 8)
++ | TCPOLEN_TIMESTAMP))
++ return -1;
++
++ /* timestamp should be in right order */
++ topt++;
++ if (lro_desc && after(ntohl(lro_desc->tcp_rcv_tsval),
++ ntohl(*topt)))
++ return -1;
++
++ /* timestamp reply should not be zero */
++ topt++;
++ if (*topt == 0)
++ return -1;
++ }
++
++ return 0;
++}
++
++static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc)
++{
++ struct iphdr *iph = lro_desc->iph;
++ struct tcphdr *tcph = lro_desc->tcph;
++ u32 *p;
++ __wsum tcp_hdr_csum;
++
++ tcph->ack_seq = lro_desc->tcp_ack;
++ tcph->window = lro_desc->tcp_window;
++
++ if (lro_desc->tcp_saw_tstamp) {
++ p = (u32 *)(tcph + 1);
++ *(p+2) = lro_desc->tcp_rcv_tsecr;
++ }
++
++ iph->tot_len = htons(lro_desc->ip_tot_len);
++
++ iph->check = 0;
++ iph->check = ip_fast_csum((u8 *)lro_desc->iph, iph->ihl);
++
++ tcph->check = 0;
++ tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), 0);
++ lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum);
++ tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
++ lro_desc->ip_tot_len -
++ IP_HDR_LEN(iph), IPPROTO_TCP,
++ lro_desc->data_csum);
++}
++
++static __wsum lro_tcp_data_csum(struct iphdr *iph, struct tcphdr *tcph, int len)
++{
++ __wsum tcp_csum;
++ __wsum tcp_hdr_csum;
++ __wsum tcp_ps_hdr_csum;
++
++ tcp_csum = ~csum_unfold(tcph->check);
++ tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), tcp_csum);
++
++ tcp_ps_hdr_csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
++ len + TCP_HDR_LEN(tcph),
++ IPPROTO_TCP, 0);
++
++ return csum_sub(csum_sub(tcp_csum, tcp_hdr_csum),
++ tcp_ps_hdr_csum);
++}
++
++static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb,
++ struct iphdr *iph, struct tcphdr *tcph,
++ u16 vlan_tag, struct vlan_group *vgrp)
++{
++ int nr_frags;
++ u32 *ptr;
++ u32 tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
++
++ nr_frags = skb_shinfo(skb)->nr_frags;
++ lro_desc->parent = skb;
++ lro_desc->next_frag = &(skb_shinfo(skb)->frags[nr_frags]);
++ lro_desc->iph = iph;
++ lro_desc->tcph = tcph;
++ lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len;
++ lro_desc->tcp_ack = ntohl(tcph->ack_seq);
++ lro_desc->tcp_window = tcph->window;
++
++ lro_desc->pkt_aggr_cnt = 1;
++ lro_desc->ip_tot_len = ntohs(iph->tot_len);
++
++ if (tcph->doff == 8) {
++ ptr = (u32 *)(tcph+1);
++ lro_desc->tcp_saw_tstamp = 1;
++ lro_desc->tcp_rcv_tsval = *(ptr+1);
++ lro_desc->tcp_rcv_tsecr = *(ptr+2);
++ }
++
++ lro_desc->mss = tcp_data_len;
++ lro_desc->vgrp = vgrp;
++ lro_desc->vlan_tag = vlan_tag;
++ lro_desc->active = 1;
++
++ if (tcp_data_len)
++ lro_desc->data_csum = lro_tcp_data_csum(iph, tcph,
++ tcp_data_len);
++
++ if (!tcp_data_len)
++ lro_desc->ack_cnt++;
++}
++
++static inline void lro_clear_desc(struct net_lro_desc *lro_desc)
++{
++ memset(lro_desc, 0, sizeof(struct net_lro_desc));
++}
++
++static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
++ struct tcphdr *tcph, int tcp_data_len)
++{
++ struct sk_buff *parent = lro_desc->parent;
++ u32 *topt;
++
++ lro_desc->pkt_aggr_cnt++;
++ lro_desc->ip_tot_len += tcp_data_len;
++ lro_desc->tcp_next_seq += tcp_data_len;
++ lro_desc->tcp_window = tcph->window;
++ lro_desc->tcp_ack = tcph->ack_seq;
++
++ /* don't update tcp_rcv_tsval, would not work with PAWS */
++ if (lro_desc->tcp_saw_tstamp) {
++ topt = (u32 *) (tcph + 1);
++ lro_desc->tcp_rcv_tsecr = *(topt + 2);
++ }
++
++ if (tcp_data_len)
++ lro_desc->data_csum = csum_block_add(lro_desc->data_csum,
++ lro_tcp_data_csum(iph, tcph,
++ tcp_data_len),
++ parent->len);
++
++ parent->len += tcp_data_len;
++ parent->data_len += tcp_data_len;
++ if (tcp_data_len > lro_desc->mss)
++ lro_desc->mss = tcp_data_len;
++}
++
++static void lro_add_frags(struct net_lro_desc *lro_desc,
++ int len, int hlen, int truesize,
++ struct skb_frag_struct *skb_frags,
++ struct iphdr *iph, struct tcphdr *tcph)
++{
++ struct sk_buff *skb = lro_desc->parent;
++ int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
++
++ lro_add_common(lro_desc, iph, tcph, tcp_data_len);
++
++ skb->truesize += truesize;
++
++ if (!tcp_data_len) {
++ put_page(skb_frags[0].page);
++ lro_desc->ack_cnt++;
++ return;
++ }
++
++ skb_frags[0].page_offset += hlen;
++ skb_frags[0].size -= hlen;
++
++ while (tcp_data_len > 0) {
++ *(lro_desc->next_frag) = *skb_frags;
++ tcp_data_len -= skb_frags->size;
++ lro_desc->next_frag++;
++ skb_frags++;
++ skb_shinfo(skb)->nr_frags++;
++ }
++}
++
++static int lro_check_tcp_conn(struct net_lro_desc *lro_desc,
++ struct iphdr *iph,
++ struct tcphdr *tcph)
++{
++ if ((lro_desc->iph->saddr != iph->saddr)
++ || (lro_desc->iph->daddr != iph->daddr)
++ || (lro_desc->tcph->source != tcph->source)
++ || (lro_desc->tcph->dest != tcph->dest))
++ return -1;
++ return 0;
++}
++
++static struct net_lro_desc *lro_get_desc(struct net_lro_mgr *lro_mgr,
++ struct net_lro_desc *lro_arr,
++ struct iphdr *iph,
++ struct tcphdr *tcph)
++{
++ struct net_lro_desc *lro_desc = NULL;
++ struct net_lro_desc *tmp;
++ int max_desc = lro_mgr->max_desc;
++ int i;
++
++ for (i = 0; i < max_desc; i++) {
++ tmp = &lro_arr[i];
++ if (tmp->active)
++ if (!lro_check_tcp_conn(tmp, iph, tcph)) {
++ lro_desc = tmp;
++ goto out;
++ }
++ }
++
++ for (i = 0; i < max_desc; i++) {
++ if (!lro_arr[i].active) {
++ lro_desc = &lro_arr[i];
++ goto out;
++ }
++ }
++
++ LRO_INC_STATS(lro_mgr, no_desc);
++out:
++ return lro_desc;
++}
++
++static void lro_flush(struct net_lro_mgr *lro_mgr,
++ struct net_lro_desc *lro_desc)
++{
++ struct be_adapter *adapter = netdev_priv(lro_mgr->dev);
++
++ if (lro_desc->pkt_aggr_cnt > 1)
++ lro_update_tcp_ip_header(lro_desc);
++
++ skb_shinfo(lro_desc->parent)->gso_size = lro_desc->mss;
++
++ if (lro_desc->vgrp) {
++ if (test_bit(LRO_F_NAPI, &lro_mgr->features))
++ vlan_hwaccel_receive_skb(lro_desc->parent,
++ lro_desc->vgrp,
++ lro_desc->vlan_tag);
++ else
++ vlan_hwaccel_rx(lro_desc->parent,
++ lro_desc->vgrp,
++ lro_desc->vlan_tag);
++
++ } else {
++ if (test_bit(LRO_F_NAPI, &lro_mgr->features))
++ netif_receive_skb(lro_desc->parent);
++ else
++ netif_rx(lro_desc->parent);
++ }
++
++ LRO_INC_STATS(lro_mgr, flushed);
++ lro_clear_desc(lro_desc);
++}
++
++static struct sk_buff *lro_gen_skb(struct net_lro_mgr *lro_mgr,
++ struct skb_frag_struct *frags,
++ int len, int true_size,
++ void *mac_hdr,
++ int hlen, __wsum sum,
++ u32 ip_summed)
++{
++ struct sk_buff *skb;
++ struct skb_frag_struct *skb_frags;
++ int data_len = len;
++ int hdr_len = min(len, hlen);
++
++ skb = netdev_alloc_skb(lro_mgr->dev, hlen);
++ if (!skb)
++ return NULL;
++
++ skb->len = len;
++ skb->data_len = len - hdr_len;
++ skb->truesize += true_size;
++ skb->tail += hdr_len;
++
++ memcpy(skb->data, mac_hdr, hdr_len);
++
++ if (skb->data_len) {
++ skb_frags = skb_shinfo(skb)->frags;
++ while (data_len > 0) {
++ *skb_frags = *frags;
++ data_len -= frags->size;
++ skb_frags++;
++ frags++;
++ skb_shinfo(skb)->nr_frags++;
++ }
++ skb_shinfo(skb)->frags[0].page_offset += hdr_len;
++ skb_shinfo(skb)->frags[0].size -= hdr_len;
++ } else {
++ put_page(frags[0].page);
++ }
++
++
++ skb->ip_summed = ip_summed;
++ skb->csum = sum;
++ skb->protocol = eth_type_trans(skb, lro_mgr->dev);
++ return skb;
++}
++
++static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr,
++ struct skb_frag_struct *frags,
++ int len, int true_size,
++ struct vlan_group *vgrp,
++ u16 vlan_tag, void *priv, __wsum sum)
++{
++ struct net_lro_desc *lro_desc;
++ struct iphdr *iph;
++ struct tcphdr *tcph;
++ struct sk_buff *skb;
++ u64 flags;
++ void *mac_hdr;
++ int mac_hdr_len;
++ int hdr_len = LRO_MAX_PG_HLEN;
++ int vlan_hdr_len = 0;
++ u8 pad_bytes;
++
++ if (!lro_mgr->get_frag_header
++ || lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph,
++ (void *)&tcph, &flags, priv)) {
++ mac_hdr = page_address(frags->page) + frags->page_offset;
++ goto out1;
++ }
++
++ if (!(flags & LRO_IPV4) || !(flags & LRO_TCP))
++ goto out1;
++
++ hdr_len = (int)((void *)(tcph) + TCP_HDR_LEN(tcph) - mac_hdr);
++ mac_hdr_len = (int)((void *)(iph) - mac_hdr);
++
++ lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph);
++ if (!lro_desc)
++ goto out1;
++
++ pad_bytes = len - (ntohs(iph->tot_len) + mac_hdr_len);
++ if (!TCP_PAYLOAD_LENGTH(iph, tcph) && pad_bytes) {
++ len -= pad_bytes; /* trim the packet */
++ frags[0].size -= pad_bytes;
++ true_size -= pad_bytes;
++ }
++
++ if (!lro_desc->active) { /* start new lro session */
++ if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, NULL))
++ goto out1;
++
++ skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr,
++ hdr_len, 0, lro_mgr->ip_summed_aggr);
++ if (!skb)
++ goto out;
++
++ if ((skb->protocol == htons(ETH_P_8021Q))
++ && !test_bit(LRO_F_EXTRACT_VLAN_ID, &lro_mgr->features))
++ vlan_hdr_len = VLAN_HLEN;
++
++ iph = (void *)(skb->data + vlan_hdr_len);
++ tcph = (void *)((u8 *)skb->data + vlan_hdr_len
++ + IP_HDR_LEN(iph));
++
++ lro_init_desc(lro_desc, skb, iph, tcph, vlan_tag, vgrp);
++ LRO_INC_STATS(lro_mgr, aggregated);
++ return 0;
++ }
++
++ if (lro_desc->tcp_next_seq != ntohl(tcph->seq))
++ goto out2;
++
++ if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, lro_desc))
++ goto out2;
++
++ lro_add_frags(lro_desc, len, hdr_len, true_size, frags, iph, tcph);
++ LRO_INC_STATS(lro_mgr, aggregated);
++
++ if ((skb_shinfo(lro_desc->parent)->nr_frags >= lro_mgr->max_aggr) ||
++ lro_desc->parent->len > (0xFFFF - lro_mgr->dev->mtu))
++ lro_flush(lro_mgr, lro_desc);
++
++ return NULL;
++
++out2: /* send aggregated packets to the stack */
++ lro_flush(lro_mgr, lro_desc);
++
++out1: /* Original packet has to be posted to the stack */
++ skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr,
++ hdr_len, sum, lro_mgr->ip_summed);
++out:
++ return skb;
++}
++
++void lro_receive_frags_compat(struct net_lro_mgr *lro_mgr,
++ struct skb_frag_struct *frags,
++ int len, int true_size, void *priv, __wsum sum)
++{
++ struct sk_buff *skb;
++
++ skb = __lro_proc_segment(lro_mgr, frags, len, true_size, NULL, 0,
++ priv, sum);
++ if (!skb)
++ return;
++
++ if (test_bit(LRO_F_NAPI, &lro_mgr->features))
++ netif_receive_skb(skb);
++ else
++ netif_rx(skb);
++}
++
++void lro_vlan_hwaccel_receive_frags_compat(struct net_lro_mgr *lro_mgr,
++ struct skb_frag_struct *frags,
++ int len, int true_size,
++ struct vlan_group *vgrp,
++ u16 vlan_tag, void *priv, __wsum sum)
++{
++ struct sk_buff *skb;
++
++ skb = __lro_proc_segment(lro_mgr, frags, len, true_size, vgrp,
++ vlan_tag, priv, sum);
++ if (!skb)
++ return;
++
++ if (test_bit(LRO_F_NAPI, &lro_mgr->features))
++ vlan_hwaccel_receive_skb(skb, vgrp, vlan_tag);
++ else
++ vlan_hwaccel_rx(skb, vgrp, vlan_tag);
++}
++
++void lro_flush_all_compat(struct net_lro_mgr *lro_mgr)
++{
++ int i;
++ struct net_lro_desc *lro_desc = lro_mgr->lro_arr;
++
++ for (i = 0; i < lro_mgr->max_desc; i++) {
++ if (lro_desc[i].active)
++ lro_flush(lro_mgr, &lro_desc[i]);
++ }
++}
++#endif /* INET_LRO backport */
++
++#ifndef TX_MQ
++struct net_device *alloc_etherdev_mq_compat(int sizeof_priv,
++ unsigned int queue_count)
++{
++ return alloc_etherdev(sizeof_priv);
++}
++
++void netif_wake_subqueue_compat(struct net_device *dev, u16 queue_index)
++{
++ netif_wake_queue(dev);
++}
++
++void netif_stop_subqueue_compat(struct net_device *dev, u16 queue_index)
++{
++ netif_stop_queue(dev);
++}
++
++int __netif_subqueue_stopped_compat(const struct net_device *dev,
++ u16 queue_index)
++{
++ return netif_queue_stopped(dev);
++}
++
++u16 skb_get_queue_mapping_compat(const struct sk_buff *skb)
++{
++ return 0;
++}
++
++void netif_set_real_num_tx_queues_compat(struct net_device *dev,
++ unsigned int txq)
++{
++ return;
++}
++
++u16 skb_tx_hash_compat(const struct net_device *dev,
++ const struct sk_buff *skb)
++{
++ return 0;
++}
++#endif
+diff --git a/drivers/net/benet/be_compat.h b/drivers/net/benet/be_compat.h
+new file mode 100644
+index 0000000..8ceecc8
+--- /dev/null
++++ b/drivers/net/benet/be_compat.h
+@@ -0,0 +1,621 @@
++/*
++ * Copyright (C) 2005 - 2011 Emulex
++ * 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. The full GNU General
++ * Public License is included in this distribution in the file called COPYING.
++ *
++ * Contact Information:
++ * linux-drivers@emulex.com
++ *
++ * Emulex
++ * 3333 Susan Street
++ * Costa Mesa, CA 92626
++ */
++
++#ifndef BE_COMPAT_H
++#define BE_COMPAT_H
++
++/****************** RHEL5 and SLES10 backport ***************************/
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
++
++#ifndef upper_32_bits
++#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
++#endif
++
++#ifndef CHECKSUM_PARTIAL
++#define CHECKSUM_PARTIAL CHECKSUM_HW
++#define CHECKSUM_COMPLETE CHECKSUM_HW
++#endif
++
++#if !defined(ip_hdr)
++#define ip_hdr(skb) (skb->nh.iph)
++#define ipv6_hdr(skb) (skb->nh.ipv6h)
++#endif
++
++#if !defined(__packed)
++#define __packed __attribute__ ((packed))
++#endif
++
++#if !defined(RHEL_MINOR)
++/* Only for RH5U1 (Maui) and SLES10 NIC driver */
++enum {
++ false = 0,
++ true = 1
++};
++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)
++/* Only for RH5U1 (Maui) NIC driver */
++static inline __attribute__((const))
++int __ilog2_u32(u32 n)
++{
++ return fls(n) - 1;
++}
++#endif
++#endif
++
++#define ETH_FCS_LEN 4
++#define bool u8
++#ifndef PTR_ALIGN
++#define PTR_ALIGN(p, a) ((typeof(p)) \
++ ALIGN((unsigned long)(p), (a)))
++#endif
++#define list_first_entry(ptr, type, member) \
++ list_entry((ptr)->next, type, member)
++
++#if (defined(RHEL_MINOR) && RHEL_MINOR < 6) || \
++ LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
++#define DEFINE_PCI_DEVICE_TABLE(_table) struct pci_device_id _table[] \
++ __devinitdata
++#endif
++
++/* Backport of request_irq */
++typedef irqreturn_t(*backport_irq_handler_t) (int, void *);
++static inline int
++backport_request_irq(unsigned int irq, irqreturn_t(*handler) (int, void *),
++ unsigned long flags, const char *dev_name, void *dev_id)
++{
++ return request_irq(irq,
++ (irqreturn_t(*) (int, void *, struct pt_regs *))handler,
++ flags, dev_name, dev_id);
++}
++#define request_irq backport_request_irq
++
++#endif /*** RHEL5 and SLES10 backport ***/
++
++#if !defined(__packed)
++#define __packed __attribute__ ((packed))
++#endif
++
++/****************** SLES10 only backport ***************************/
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
++
++#include <linux/tifm.h>
++
++#define FIELD_SIZEOF(t, f) (sizeof(((t *)0)->f))
++#define IRQF_SHARED SA_SHIRQ
++#define CHECKSUM_PARTIAL CHECKSUM_HW
++#define CHECKSUM_COMPLETE CHECKSUM_HW
++#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
++#define NETIF_F_IPV6_CSUM NETIF_F_IP_CSUM
++#define NETIF_F_TSO6 NETIF_F_TSO
++
++
++static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev,
++ unsigned int length)
++{
++ /* 16 == NET_PAD_SKB */
++ struct sk_buff *skb;
++ skb = alloc_skb(length + 16, GFP_ATOMIC);
++ if (likely(skb != NULL)) {
++ skb_reserve(skb, 16);
++ skb->dev = dev;
++ }
++ return skb;
++}
++
++#define PCI_SAVE_STATE(x)
++
++#else /* SLES10 only backport */
++
++#define PCI_SAVE_STATE(x) pci_save_state(x)
++
++#endif /* SLES10 only backport */
++
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)
++#define netdev_tx_t int
++#endif
++
++#ifndef VLAN_PRIO_MASK
++#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */
++#define VLAN_PRIO_SHIFT 13
++#endif
++
++/*
++ * Backport of netdev ops struct
++ */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
++struct net_device_ops {
++ int (*ndo_init)(struct net_device *dev);
++ void (*ndo_uninit)(struct net_device *dev);
++ int (*ndo_open)(struct net_device *dev);
++ int (*ndo_stop)(struct net_device *dev);
++ int (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev);
++ u16 (*ndo_select_queue)(struct net_device *dev,
++ struct sk_buff *skb);
++ void (*ndo_change_rx_flags)(struct net_device *dev, int flags);
++ void (*ndo_set_rx_mode)(struct net_device *dev);
++ void (*ndo_set_multicast_list)(struct net_device *dev);
++ int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
++ int (*ndo_validate_addr)(struct net_device *dev);
++ int (*ndo_do_ioctl)(struct net_device *dev,
++ struct ifreq *ifr, int cmd);
++ int (*ndo_set_config)(struct net_device *dev, struct ifmap *map);
++ int (*ndo_change_mtu)(struct net_device *dev, int new_mtu);
++ int (*ndo_neigh_setup)(struct net_device *dev,
++ struct neigh_parms *);
++ void (*ndo_tx_timeout) (struct net_device *dev);
++
++ struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
++
++ void (*ndo_vlan_rx_register)(struct net_device *dev,
++ struct vlan_group *grp);
++ void (*ndo_vlan_rx_add_vid)(struct net_device *dev,
++ unsigned short vid);
++ void (*ndo_vlan_rx_kill_vid)(struct net_device *dev,
++ unsigned short vid);
++#ifdef CONFIG_NET_POLL_CONTROLLER
++#define HAVE_NETDEV_POLL
++ void (*ndo_poll_controller)(struct net_device *dev);
++#endif
++};
++extern void be_netdev_ops_init(struct net_device *netdev,
++ struct net_device_ops *ops);
++extern int eth_validate_addr(struct net_device *);
++
++#endif /* Netdev ops backport */
++
++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 29)
++#undef NETIF_F_GRO
++#endif
++
++#ifdef NO_GRO
++#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 5)))
++#undef NETIF_F_GRO
++#endif
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
++#define HAVE_ETHTOOL_FLASH
++#endif
++
++/*
++ * Backport of NAPI
++ */
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
++
++#if defined(RHEL_MINOR) && (RHEL_MINOR > 3)
++#define RHEL_NEW_NAPI
++#endif
++
++/* We need a new struct that has some meta data beyond rhel 5.4's napi_struct
++ * to fix rhel5.4's half-baked new napi implementation.
++ * We don't want to use rhel 5.4's broken napi_complete; so
++ * define a new be_napi_complete that executes the logic only for Rx
++ */
++
++#ifdef RHEL_NEW_NAPI
++#define napi_complete be_napi_complete
++typedef struct napi_struct rhel_napi_struct;
++#endif
++#define napi_struct be_napi_struct
++#define napi_gro_frags(napi) napi_gro_frags((rhel_napi_struct *) napi)
++#define vlan_gro_frags(napi, vlan_grp, vid)\
++ vlan_gro_frags((rhel_napi_struct *) napi, vlan_grp, vid)
++#define napi_get_frags(napi) napi_get_frags((rhel_napi_struct *) napi)
++
++struct napi_struct {
++#ifdef RHEL_NEW_NAPI
++ rhel_napi_struct napi; /* must be the first member */
++#endif
++ struct net_device *dev;
++ int (*poll) (struct napi_struct *napi, int budget);
++ bool rx;
++};
++
++static inline void napi_complete(struct napi_struct *napi)
++{
++#ifdef NETIF_F_GRO
++ napi_gro_flush((rhel_napi_struct *)napi);
++#endif
++ netif_rx_complete(napi->dev);
++}
++
++static inline void napi_schedule(struct napi_struct *napi)
++{
++ netif_rx_schedule(napi->dev);
++}
++
++static inline void napi_enable(struct napi_struct *napi)
++{
++ netif_poll_enable(napi->dev);
++}
++
++static inline void napi_disable(struct napi_struct *napi)
++{
++ netif_poll_disable(napi->dev);
++}
++
++#if (defined(RHEL_MINOR) && RHEL_MINOR < 6) || \
++ LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
++static inline void vlan_group_set_device(struct vlan_group *vg,
++ u16 vlan_id,
++ struct net_device *dev)
++{
++ struct net_device **array;
++ if (!vg)
++ return;
++ array = vg->vlan_devices;
++ array[vlan_id] = dev;
++}
++#endif
++
++#endif /* New NAPI backport */
++
++extern int be_netif_napi_add(struct net_device *netdev,
++ struct napi_struct *napi,
++ int (*poll) (struct napi_struct *, int), int weight);
++extern void be_netif_napi_del(struct net_device *netdev);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
++#define HAVE_SIMULATED_MULTI_NAPI
++#endif
++
++/************** Backport of Delayed work queues interface ****************/
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
++#if (defined(RHEL_MINOR) && RHEL_MINOR < 6) || \
++ LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)
++struct delayed_work {
++ struct work_struct work;
++};
++#endif
++
++#define INIT_DELAYED_WORK(_work, _func) \
++ INIT_WORK(&(_work)->work, _func, &(_work)->work)
++
++static inline int backport_cancel_delayed_work_sync(struct delayed_work *work)
++{
++ cancel_rearming_delayed_work(&work->work);
++ return 0;
++}
++#define cancel_delayed_work_sync backport_cancel_delayed_work_sync
++
++static inline int backport_schedule_delayed_work(struct delayed_work *work,
++ unsigned long delay)
++{
++ if (unlikely(!delay))
++ return schedule_work(&work->work);
++ else
++ return schedule_delayed_work(&work->work, delay);
++}
++#define schedule_delayed_work backport_schedule_delayed_work
++#endif /* backport delayed workqueue */
++
++
++/************** Backport of INET_LRO **********************************/
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
++
++#include <linux/inet_lro.h>
++
++#else
++
++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)
++
++#if defined(RHEL_MINOR) && RHEL_MINOR < 6
++typedef __u16 __bitwise __sum16;
++typedef __u32 __bitwise __wsum;
++#endif
++
++#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 5) && (RHEL_MINOR <= 3)) || \
++ (!defined(RHEL_MINOR)))
++static inline __wsum csum_unfold(__sum16 n)
++{
++ return (__force __wsum)n;
++}
++#endif
++
++#endif
++
++#define lro_flush_all lro_flush_all_compat
++#define lro_vlan_hwaccel_receive_frags lro_vlan_hwaccel_receive_frags_compat
++#define lro_receive_frags lro_receive_frags_compat
++
++struct net_lro_stats {
++ unsigned long aggregated;
++ unsigned long flushed;
++ unsigned long no_desc;
++};
++
++struct net_lro_desc {
++ struct sk_buff *parent;
++ struct sk_buff *last_skb;
++ struct skb_frag_struct *next_frag;
++ struct iphdr *iph;
++ struct tcphdr *tcph;
++ struct vlan_group *vgrp;
++ __wsum data_csum;
++ u32 tcp_rcv_tsecr;
++ u32 tcp_rcv_tsval;
++ u32 tcp_ack;
++ u32 tcp_next_seq;
++ u32 skb_tot_frags_len;
++ u32 ack_cnt;
++ u16 ip_tot_len;
++ u16 tcp_saw_tstamp; /* timestamps enabled */
++ u16 tcp_window;
++ u16 vlan_tag;
++ int pkt_aggr_cnt; /* counts aggregated packets */
++ int vlan_packet;
++ int mss;
++ int active;
++};
++
++struct net_lro_mgr {
++ struct net_device *dev;
++ struct net_lro_stats stats;
++
++ /* LRO features */
++ unsigned long features;
++#define LRO_F_NAPI 1 /* Pass packets to stack via NAPI */
++#define LRO_F_EXTRACT_VLAN_ID 2 /* Set flag if VLAN IDs are extracted
++ from received packets and eth protocol
++ is still ETH_P_8021Q */
++
++ u32 ip_summed; /* Set in non generated SKBs in page mode */
++ u32 ip_summed_aggr; /* Set in aggregated SKBs: CHECKSUM_UNNECESSARY
++ * or CHECKSUM_NONE */
++
++ int max_desc; /* Max number of LRO descriptors */
++ int max_aggr; /* Max number of LRO packets to be aggregated */
++
++ struct net_lro_desc *lro_arr; /* Array of LRO descriptors */
++
++ /* Optimized driver functions
++ * get_skb_header: returns tcp and ip header for packet in SKB
++ */
++ int (*get_skb_header)(struct sk_buff *skb, void **ip_hdr,
++ void **tcpudp_hdr, u64 *hdr_flags, void *priv);
++
++ /* hdr_flags: */
++#define LRO_IPV4 1 /* ip_hdr is IPv4 header */
++#define LRO_TCP 2 /* tcpudp_hdr is TCP header */
++
++ /*
++ * get_frag_header: returns mac, tcp and ip header for packet in SKB
++ *
++ * @hdr_flags: Indicate what kind of LRO has to be done
++ * (IPv4/IPv6/TCP/UDP)
++ */
++ int (*get_frag_header)(struct skb_frag_struct *frag, void **mac_hdr,
++ void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags,
++ void *priv);
++};
++
++extern void lro_receive_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb,
++ void *priv);
++
++extern void lro_vlan_hwaccel_receive_skb(struct net_lro_mgr *lro_mgr,
++ struct sk_buff *skb, struct vlan_group *vgrp,
++ u16 vlan_tag, void *priv);
++
++/* This functions aggregate fragments and generate SKBs do pass
++ * the packets to the stack.
++ *
++ * @lro_mgr: LRO manager to use
++ * @frags: Fragment to be processed. Must contain entire header in first
++ * element.
++ * @len: Length of received data
++ * @true_size: Actual size of memory the fragment is consuming
++ * @priv: Private data that may be used by driver functions
++ * (for example get_tcp_ip_hdr)
++ */
++extern void lro_receive_frags_compat(struct net_lro_mgr *lro_mgr,
++ struct skb_frag_struct *frags, int len, int true_size,
++ void *priv, __wsum sum);
++
++extern void lro_vlan_hwaccel_receive_frags_compat(struct net_lro_mgr *lro_mgr,
++ struct skb_frag_struct *frags, int len, int true_size,
++ struct vlan_group *vgrp, u16 vlan_tag, void *priv,
++ __wsum sum);
++
++/* Forward all aggregated SKBs held by lro_mgr to network stack */
++extern void lro_flush_all_compat(struct net_lro_mgr *lro_mgr);
++
++extern void lro_flush_pkt(struct net_lro_mgr *lro_mgr, struct iphdr *iph,
++ struct tcphdr *tcph);
++#endif /* backport of inet_lro */
++
++#ifndef ETHTOOL_FLASH_MAX_FILENAME
++#define ETHTOOL_FLASH_MAX_FILENAME 128
++#endif
++
++#if defined(CONFIG_XEN) && !defined(NETIF_F_GRO)
++#define BE_INIT_FRAGS_PER_FRAME (u32) 1
++#else
++#define BE_INIT_FRAGS_PER_FRAME (min((u32) 16, (u32) MAX_SKB_FRAGS))
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
++#ifdef CONFIG_PCI_IOV
++#if (!(defined(RHEL_MAJOR) && (RHEL_MAJOR == 5) && (RHEL_MINOR == 6)))
++#undef CONFIG_PCI_IOV
++#endif
++#endif
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
++#define dev_to_node(dev) -1
++#endif
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
++#if (!(defined(RHEL_MAJOR) && (RHEL_MAJOR == 5) && (RHEL_MINOR > 6)))
++static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
++ unsigned int length)
++{
++ struct sk_buff *skb = netdev_alloc_skb(dev, length + NET_IP_ALIGN);
++
++ if (NET_IP_ALIGN && skb)
++ skb_reserve(skb, NET_IP_ALIGN);
++ return skb;
++}
++#endif
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
++#ifndef netif_set_gso_max_size
++#define netif_set_gso_max_size(netdev, size) do {} while (0)
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18))
++#if defined(RHEL_MINOR) && (RHEL_MINOR <= 4)
++static inline int skb_is_gso_v6(const struct sk_buff *skb)
++{
++ return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6;
++}
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++static inline int skb_is_gso_v6(const struct sk_buff *skb)
++{
++ return (ip_hdr(skb)->version == 6);
++}
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
++#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 6)))
++#define HAVE_SRIOV_CONFIG
++#endif
++#endif
++
++#ifndef NETIF_F_VLAN_SG
++#define NETIF_F_VLAN_SG NETIF_F_SG
++#endif
++
++#ifndef NETIF_F_VLAN_CSUM
++#define NETIF_F_VLAN_CSUM NETIF_F_HW_CSUM
++#endif
++
++#ifndef NETIF_F_VLAN_TSO
++#define NETIF_F_VLAN_TSO NETIF_F_TSO
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27))
++#define vlan_features features
++#endif
++
++#ifndef DEFINE_DMA_UNMAP_ADDR
++#define DEFINE_DMA_UNMAP_ADDR(bus) dma_addr_t bus
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
++
++#ifndef netdev_mc_count
++#define netdev_mc_count(nd) (nd->mc_count)
++#endif
++
++#ifndef netdev_hw_addr
++#define netdev_hw_addr dev_mc_list
++#endif
++
++#ifndef netdev_for_each_mc_addr
++#define netdev_for_each_mc_addr(ha, nd) \
++ for (ha = (nd)->mc_list; ha; ha = ha->next)
++#endif
++
++#define DMI_ADDR dmi_addr
++#else
++#define DMI_ADDR addr
++#endif
++
++#ifndef VLAN_GROUP_ARRAY_LEN
++#define VLAN_GROUP_ARRAY_LEN VLAN_N_VID
++#endif
++/**************************** Multi TXQ Support ******************************/
++
++/* Supported only in RHEL6 and SL11.1 (barring one execption) */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
++#define MQ_TX
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
++#define alloc_etherdev_mq(sz, cnt) alloc_etherdev(sz)
++#define skb_get_queue_mapping(skb) 0
++#define skb_tx_hash(dev, skb) 0
++#define netif_set_real_num_tx_queues(dev, txq) do {} while(0)
++#define netif_wake_subqueue(dev, idx) netif_wake_queue(dev)
++#define netif_stop_subqueue(dev, idx) netif_stop_queue(dev)
++#define __netif_subqueue_stopped(dev, idx) netif_queue_stopped(dev)
++#endif /* < 2.6.27 */
++
++#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && \
++ (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)))
++#define skb_tx_hash(dev, skb) 0
++#define netif_set_real_num_tx_queues(dev, txq) do {} while(0)
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
++#define netif_set_real_num_tx_queues be_set_real_num_tx_queues
++static inline void be_set_real_num_tx_queues(struct net_device *dev,
++ unsigned int txq)
++{
++ dev->real_num_tx_queues = txq;
++}
++#endif
++
++#include <linux/if_vlan.h>
++static inline void be_reset_skb_tx_vlan(struct sk_buff *skb)
++{
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
++ skb->vlan_tci = 0;
++#else
++ struct vlan_skb_tx_cookie *cookie;
++
++ cookie = VLAN_TX_SKB_CB(skb);
++ cookie->magic = 0;
++#endif
++}
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
++static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
++{
++ skb->nh.raw = skb->data + offset;
++}
++#endif
++
++static inline struct sk_buff *be_vlan_put_tag(struct sk_buff *skb,
++ unsigned short vlan_tag)
++{
++ struct sk_buff *new_skb = __vlan_put_tag(skb, vlan_tag);
++ /* On kernel versions < 2.6.27 the __vlan_put_tag() function
++ * distorts the network layer hdr pointer in the skb which
++ * affects the detection of UDP/TCP packets down the line in
++ * wrb_fill_hdr().This work-around sets it right.
++ */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27))
++ skb_set_network_header(new_skb, VLAN_ETH_HLEN);
++#endif
++ return new_skb;
++}
++
++#ifndef ACCESS_ONCE
++#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
++#endif
++
++#endif /* BE_COMPAT_H */
+diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
+index f0fd95b..37bad99 100644
+--- a/drivers/net/benet/be_ethtool.c
++++ b/drivers/net/benet/be_ethtool.c
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (C) 2005 - 2009 ServerEngines
++ * Copyright (C) 2005 - 2011 Emulex
+ * 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. The full GNU General
++ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+- * linux-drivers@serverengines.com
++ * linux-drivers@emulex.com
+ *
+- * ServerEngines
+- * 209 N. Fair Oaks Ave
+- * Sunnyvale, CA 94085
++ * Emulex
++ * 3333 Susan Street
++ * Costa Mesa, CA 92626
+ */
+
+ #include "be.h"
+@@ -26,21 +26,19 @@ struct be_ethtool_stat {
+ int offset;
+ };
+
+-enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT, ERXSTAT};
++enum {NETSTAT, DRVSTAT_TX, DRVSTAT_RX, DRVSTAT};
+ #define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
+ offsetof(_struct, field)
+-#define NETSTAT_INFO(field) #field, NETSTAT,\
++#define NETSTAT_INFO(field) #field, NETSTAT,\
+ FIELDINFO(struct net_device_stats,\
+ field)
+-#define DRVSTAT_INFO(field) #field, DRVSTAT,\
+- FIELDINFO(struct be_drvr_stats, field)
+-#define MISCSTAT_INFO(field) #field, MISCSTAT,\
+- FIELDINFO(struct be_rxf_stats, field)
+-#define PORTSTAT_INFO(field) #field, PORTSTAT,\
+- FIELDINFO(struct be_port_rxf_stats, \
++#define DRVSTAT_TX_INFO(field) #field, DRVSTAT_TX,\
++ FIELDINFO(struct be_tx_stats, field)
++#define DRVSTAT_RX_INFO(field) #field, DRVSTAT_RX,\
++ FIELDINFO(struct be_rx_stats, field)
++#define DRVSTAT_INFO(field) #field, DRVSTAT,\
++ FIELDINFO(struct be_drv_stats, \
+ field)
+-#define ERXSTAT_INFO(field) #field, ERXSTAT,\
+- FIELDINFO(struct be_erx_stats, field)
+
+ static const struct be_ethtool_stat et_stats[] = {
+ {NETSTAT_INFO(rx_packets)},
+@@ -51,70 +49,131 @@ static const struct be_ethtool_stat et_stats[] = {
+ {NETSTAT_INFO(tx_errors)},
+ {NETSTAT_INFO(rx_dropped)},
+ {NETSTAT_INFO(tx_dropped)},
+- {DRVSTAT_INFO(be_tx_reqs)},
+- {DRVSTAT_INFO(be_tx_stops)},
+- {DRVSTAT_INFO(be_fwd_reqs)},
+- {DRVSTAT_INFO(be_tx_wrbs)},
+- {DRVSTAT_INFO(be_polls)},
+ {DRVSTAT_INFO(be_tx_events)},
+- {DRVSTAT_INFO(be_rx_events)},
+- {DRVSTAT_INFO(be_tx_compl)},
+- {DRVSTAT_INFO(be_rx_compl)},
+- {DRVSTAT_INFO(be_ethrx_post_fail)},
+- {DRVSTAT_INFO(be_802_3_dropped_frames)},
+- {DRVSTAT_INFO(be_802_3_malformed_frames)},
+- {DRVSTAT_INFO(be_tx_rate)},
+- {DRVSTAT_INFO(be_rx_rate)},
+- {PORTSTAT_INFO(rx_unicast_frames)},
+- {PORTSTAT_INFO(rx_multicast_frames)},
+- {PORTSTAT_INFO(rx_broadcast_frames)},
+- {PORTSTAT_INFO(rx_crc_errors)},
+- {PORTSTAT_INFO(rx_alignment_symbol_errors)},
+- {PORTSTAT_INFO(rx_pause_frames)},
+- {PORTSTAT_INFO(rx_control_frames)},
+- {PORTSTAT_INFO(rx_in_range_errors)},
+- {PORTSTAT_INFO(rx_out_range_errors)},
+- {PORTSTAT_INFO(rx_frame_too_long)},
+- {PORTSTAT_INFO(rx_address_match_errors)},
+- {PORTSTAT_INFO(rx_vlan_mismatch)},
+- {PORTSTAT_INFO(rx_dropped_too_small)},
+- {PORTSTAT_INFO(rx_dropped_too_short)},
+- {PORTSTAT_INFO(rx_dropped_header_too_small)},
+- {PORTSTAT_INFO(rx_dropped_tcp_length)},
+- {PORTSTAT_INFO(rx_dropped_runt)},
+- {PORTSTAT_INFO(rx_fifo_overflow)},
+- {PORTSTAT_INFO(rx_input_fifo_overflow)},
+- {PORTSTAT_INFO(rx_ip_checksum_errs)},
+- {PORTSTAT_INFO(rx_tcp_checksum_errs)},
+- {PORTSTAT_INFO(rx_udp_checksum_errs)},
+- {PORTSTAT_INFO(rx_non_rss_packets)},
+- {PORTSTAT_INFO(rx_ipv4_packets)},
+- {PORTSTAT_INFO(rx_ipv6_packets)},
+- {PORTSTAT_INFO(tx_unicastframes)},
+- {PORTSTAT_INFO(tx_multicastframes)},
+- {PORTSTAT_INFO(tx_broadcastframes)},
+- {PORTSTAT_INFO(tx_pauseframes)},
+- {PORTSTAT_INFO(tx_controlframes)},
+- {MISCSTAT_INFO(rx_drops_no_pbuf)},
+- {MISCSTAT_INFO(rx_drops_no_txpb)},
+- {MISCSTAT_INFO(rx_drops_no_erx_descr)},
+- {MISCSTAT_INFO(rx_drops_no_tpre_descr)},
+- {MISCSTAT_INFO(rx_drops_too_many_frags)},
+- {MISCSTAT_INFO(rx_drops_invalid_ring)},
+- {MISCSTAT_INFO(forwarded_packets)},
+- {MISCSTAT_INFO(rx_drops_mtu)},
+- {ERXSTAT_INFO(rx_drops_no_fragments)},
++ {DRVSTAT_INFO(rx_crc_errors)},
++ {DRVSTAT_INFO(rx_alignment_symbol_errors)},
++ {DRVSTAT_INFO(rx_pause_frames)},
++ {DRVSTAT_INFO(rx_control_frames)},
++ {DRVSTAT_INFO(rx_in_range_errors)},
++ {DRVSTAT_INFO(rx_out_range_errors)},
++ {DRVSTAT_INFO(rx_frame_too_long)},
++ {DRVSTAT_INFO(rx_address_match_errors)},
++ {DRVSTAT_INFO(rx_dropped_too_small)},
++ {DRVSTAT_INFO(rx_dropped_too_short)},
++ {DRVSTAT_INFO(rx_dropped_header_too_small)},
++ {DRVSTAT_INFO(rx_dropped_tcp_length)},
++ {DRVSTAT_INFO(rx_dropped_runt)},
++ {DRVSTAT_INFO(rxpp_fifo_overflow_drop)},
++ {DRVSTAT_INFO(rx_input_fifo_overflow_drop)},
++ {DRVSTAT_INFO(rx_ip_checksum_errs)},
++ {DRVSTAT_INFO(rx_tcp_checksum_errs)},
++ {DRVSTAT_INFO(rx_udp_checksum_errs)},
++ {DRVSTAT_INFO(rx_switched_unicast_packets)},
++ {DRVSTAT_INFO(rx_switched_multicast_packets)},
++ {DRVSTAT_INFO(rx_switched_broadcast_packets)},
++ {DRVSTAT_INFO(tx_pauseframes)},
++ {DRVSTAT_INFO(tx_controlframes)},
++ {DRVSTAT_INFO(rx_priority_pause_frames)},
++ {DRVSTAT_INFO(pmem_fifo_overflow_drop)},
++ {DRVSTAT_INFO(jabber_events)},
++ {DRVSTAT_INFO(rx_drops_no_pbuf)},
++ {DRVSTAT_INFO(rx_drops_no_txpb)},
++ {DRVSTAT_INFO(rx_drops_no_erx_descr)},
++ {DRVSTAT_INFO(rx_drops_no_tpre_descr)},
++ {DRVSTAT_INFO(rx_drops_too_many_frags)},
++ {DRVSTAT_INFO(rx_drops_invalid_ring)},
++ {DRVSTAT_INFO(forwarded_packets)},
++ {DRVSTAT_INFO(rx_drops_mtu)},
++ {DRVSTAT_INFO(eth_red_drops)},
++ {DRVSTAT_INFO(be_on_die_temperature)}
+ };
+ #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
+
++/* Stats related to multi RX queues */
++static const struct be_ethtool_stat et_rx_stats[] = {
++ {DRVSTAT_RX_INFO(rx_bytes)},
++ {DRVSTAT_RX_INFO(rx_pkts)},
++ {DRVSTAT_RX_INFO(rx_rate)},
++ {DRVSTAT_RX_INFO(rx_polls)},
++ {DRVSTAT_RX_INFO(rx_events)},
++ {DRVSTAT_RX_INFO(rx_compl)},
++ {DRVSTAT_RX_INFO(rx_mcast_pkts)},
++ {DRVSTAT_RX_INFO(rx_post_fail)},
++ {DRVSTAT_RX_INFO(rx_drops_no_frags)}
++};
++#define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats))
++
++/* Stats related to multi TX queues */
++static const struct be_ethtool_stat et_tx_stats[] = {
++ {DRVSTAT_TX_INFO(be_tx_rate)},
++ {DRVSTAT_TX_INFO(be_tx_reqs)},
++ {DRVSTAT_TX_INFO(be_tx_wrbs)},
++ {DRVSTAT_TX_INFO(be_tx_stops)},
++ {DRVSTAT_TX_INFO(be_tx_compl)},
++ {DRVSTAT_TX_INFO(be_ipv6_ext_hdr_tx_drop)}
++};
++#define ETHTOOL_TXSTATS_NUM (ARRAY_SIZE(et_tx_stats))
++
++static const char et_self_tests[][ETH_GSTRING_LEN] = {
++ "MAC Loopback test",
++ "PHY Loopback test",
++ "External Loopback test",
++ "DDR DMA test",
++ "Link test"
++};
++
++#define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests)
++#define BE_MAC_LOOPBACK 0x0
++#define BE_PHY_LOOPBACK 0x1
++#define BE_ONE_PORT_EXT_LOOPBACK 0x2
++#define BE_NO_LOOPBACK 0xff
++
++/* MAC speed valid values */
++#define SPEED_DEFAULT 0x0
++#define SPEED_FORCED_10GB 0x1
++#define SPEED_FORCED_1GB 0x2
++#define SPEED_AUTONEG_10GB 0x3
++#define SPEED_AUTONEG_1GB 0x4
++#define SPEED_AUTONEG_100MB 0x5
++#define SPEED_AUTONEG_10GB_1GB 0x6
++#define SPEED_AUTONEG_10GB_1GB_100MB 0x7
++#define SPEED_AUTONEG_1GB_100MB 0x8
++#define SPEED_AUTONEG_10MB 0x9
++#define SPEED_AUTONEG_1GB_100MB_10MB 0xa
++#define SPEED_AUTONEG_100MB_10MB 0xb
++#define SPEED_FORCED_100MB 0xc
++#define SPEED_FORCED_10MB 0xd
++
++
++
+ static void
+ be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
++ int len;
++ char fw_on_flash[FW_VER_LEN];
++
++ memset(fw_on_flash, 0 , sizeof(fw_on_flash));
++
++ be_cmd_get_fw_ver(adapter, adapter->fw_ver,
++ fw_on_flash);
+
+ strcpy(drvinfo->driver, DRV_NAME);
+ strcpy(drvinfo->version, DRV_VER);
++
+ strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
++ if (memcmp(adapter->fw_ver, fw_on_flash,
++ FW_VER_LEN) != 0) {
++ len = strlen(drvinfo->fw_version);
++ strncpy(drvinfo->fw_version+len, " [",
++ FW_VER_LEN-len-1);
++ len = strlen(drvinfo->fw_version);
++ strncpy(drvinfo->fw_version+len, fw_on_flash,
++ FW_VER_LEN-len-1);
++ len = strlen(drvinfo->fw_version);
++ strncpy(drvinfo->fw_version+len, "]", FW_VER_LEN-len-1);
++ }
++
+ strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
+ drvinfo->testinfo_len = 0;
+ drvinfo->regdump_len = 0;
+@@ -122,12 +181,37 @@ be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+ }
+
+ static int
++be_get_reg_len(struct net_device *netdev)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ u32 log_size = 0;
++
++ if (be_physfn(adapter))
++ be_cmd_get_reg_len(adapter, &log_size);
++
++ return log_size;
++}
++
++static void
++be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++
++ if (be_physfn(adapter)) {
++ memset(buf, 0, regs->len);
++ be_cmd_get_regs(adapter, regs->len, buf);
++ }
++}
++
++static int
+ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+- struct be_eq_obj *rx_eq = &adapter->rx_eq;
++ struct be_eq_obj *rx_eq = &adapter->rx_obj[0].rx_eq;
+ struct be_eq_obj *tx_eq = &adapter->tx_eq;
+
++ coalesce->rx_max_coalesced_frames = adapter->max_rx_coal;
++
+ coalesce->rx_coalesce_usecs = rx_eq->cur_eqd;
+ coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd;
+ coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd;
+@@ -149,25 +233,52 @@ static int
+ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+- struct be_eq_obj *rx_eq = &adapter->rx_eq;
++ struct be_rx_obj *rxo;
++ struct be_eq_obj *rx_eq;
+ struct be_eq_obj *tx_eq = &adapter->tx_eq;
+ u32 tx_max, tx_min, tx_cur;
+ u32 rx_max, rx_min, rx_cur;
+- int status = 0;
++ int status = 0, i;
+
+ if (coalesce->use_adaptive_tx_coalesce == 1)
+ return -EINVAL;
++ adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
++ if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME)
++ adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
+
+- /* if AIC is being turned on now, start with an EQD of 0 */
+- if (rx_eq->enable_aic == 0 &&
+- coalesce->use_adaptive_rx_coalesce == 1) {
+- rx_eq->cur_eqd = 0;
++ for_all_rx_queues(adapter, rxo, i) {
++ rx_eq = &rxo->rx_eq;
++
++ if (!rx_eq->enable_aic && coalesce->use_adaptive_rx_coalesce)
++ rx_eq->cur_eqd = 0;
++ rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce;
++
++ rx_max = coalesce->rx_coalesce_usecs_high;
++ rx_min = coalesce->rx_coalesce_usecs_low;
++ rx_cur = coalesce->rx_coalesce_usecs;
++
++ if (rx_eq->enable_aic) {
++ if (rx_max > BE_MAX_EQD)
++ rx_max = BE_MAX_EQD;
++ if (rx_min > rx_max)
++ rx_min = rx_max;
++ rx_eq->max_eqd = rx_max;
++ rx_eq->min_eqd = rx_min;
++ if (rx_eq->cur_eqd > rx_max)
++ rx_eq->cur_eqd = rx_max;
++ if (rx_eq->cur_eqd < rx_min)
++ rx_eq->cur_eqd = rx_min;
++ } else {
++ if (rx_cur > BE_MAX_EQD)
++ rx_cur = BE_MAX_EQD;
++ if (rx_eq->cur_eqd != rx_cur) {
++ status = be_cmd_modify_eqd(adapter, rx_eq->q.id,
++ rx_cur);
++ if (!status)
++ rx_eq->cur_eqd = rx_cur;
++ }
++ }
+ }
+- rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce;
+-
+- rx_max = coalesce->rx_coalesce_usecs_high;
+- rx_min = coalesce->rx_coalesce_usecs_low;
+- rx_cur = coalesce->rx_coalesce_usecs;
+
+ tx_max = coalesce->tx_coalesce_usecs_high;
+ tx_min = coalesce->tx_coalesce_usecs_low;
+@@ -181,27 +292,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+ tx_eq->cur_eqd = tx_cur;
+ }
+
+- if (rx_eq->enable_aic) {
+- if (rx_max > BE_MAX_EQD)
+- rx_max = BE_MAX_EQD;
+- if (rx_min > rx_max)
+- rx_min = rx_max;
+- rx_eq->max_eqd = rx_max;
+- rx_eq->min_eqd = rx_min;
+- if (rx_eq->cur_eqd > rx_max)
+- rx_eq->cur_eqd = rx_max;
+- if (rx_eq->cur_eqd < rx_min)
+- rx_eq->cur_eqd = rx_min;
+- } else {
+- if (rx_cur > BE_MAX_EQD)
+- rx_cur = BE_MAX_EQD;
+- if (rx_eq->cur_eqd != rx_cur) {
+- status = be_cmd_modify_eqd(adapter, rx_eq->q.id,
+- rx_cur);
+- if (!status)
+- rx_eq->cur_eqd = rx_cur;
+- }
+- }
+ return 0;
+ }
+
+@@ -229,81 +319,294 @@ be_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, uint64_t *data)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+- struct be_drvr_stats *drvr_stats = &adapter->stats.drvr_stats;
+- struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va);
+- struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
+- struct be_port_rxf_stats *port_stats =
+- &rxf_stats->port[adapter->port_num];
+- struct net_device_stats *net_stats = &adapter->stats.net_stats;
+- struct be_erx_stats *erx_stats = &hw_stats->erx;
++ struct be_rx_obj *rxo;
++ struct be_tx_obj *txo;
+ void *p = NULL;
+- int i;
++ int i, j, base;
+
+ for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
+ switch (et_stats[i].type) {
+ case NETSTAT:
+- p = net_stats;
++ p = &adapter->net_stats;
+ break;
+ case DRVSTAT:
+- p = drvr_stats;
+- break;
+- case PORTSTAT:
+- p = port_stats;
+- break;
+- case MISCSTAT:
+- p = rxf_stats;
+- break;
+- case ERXSTAT: /* Currently only one ERX stat is provided */
+- p = (u32 *)erx_stats + adapter->rx_obj.q.id;
++ p = &adapter->drv_stats;
+ break;
+ }
+
+ p = (u8 *)p + et_stats[i].offset;
+ data[i] = (et_stats[i].size == sizeof(u64)) ?
+- *(u64 *)p: *(u32 *)p;
++ *(u64 *)p:(*(u32 *)p);
+ }
+
+- return;
++ base = ETHTOOL_STATS_NUM;
++ for_all_rx_queues(adapter, rxo, j) {
++ for (i = 0; i < ETHTOOL_RXSTATS_NUM; i++) {
++ p = (u8 *)&rxo->stats + et_rx_stats[i].offset;
++ data[base + j * ETHTOOL_RXSTATS_NUM + i] =
++ (et_rx_stats[i].size == sizeof(u64)) ?
++ *(u64 *)p: *(u32 *)p;
++ }
++ }
++
++ base = ETHTOOL_STATS_NUM + adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM;
++ for_all_tx_queues(adapter, txo, j) {
++ for (i = 0; i < ETHTOOL_TXSTATS_NUM; i++) {
++ p = (u8 *)&txo->stats + et_tx_stats[i].offset;
++ data[base + j * ETHTOOL_TXSTATS_NUM + i] =
++ (et_tx_stats[i].size == sizeof(u64)) ?
++ *(u64 *)p: *(u32 *)p;
++ }
++ }
+ }
+
+ static void
+ be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
+ uint8_t *data)
+ {
+- int i;
++ struct be_adapter *adapter = netdev_priv(netdev);
++ int i, j;
++
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
+ memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
++ for (i = 0; i < adapter->num_rx_qs; i++) {
++ for (j = 0; j < ETHTOOL_RXSTATS_NUM; j++) {
++ sprintf(data, "rxq%d: %s", i,
++ et_rx_stats[j].desc);
++ data += ETH_GSTRING_LEN;
++ }
++ }
++ for (i = 0; i < adapter->num_tx_qs; i++) {
++ for (j = 0; j < ETHTOOL_TXSTATS_NUM; j++) {
++ sprintf(data, "txq%d: %s", i,
++ et_tx_stats[j].desc);
++ data += ETH_GSTRING_LEN;
++ }
++ }
++ break;
++ case ETH_SS_TEST:
++ for (i = 0; i < ETHTOOL_TESTS_NUM; i++) {
++ memcpy(data, et_self_tests[i], ETH_GSTRING_LEN);
++ data += ETH_GSTRING_LEN;
++ }
+ break;
+ }
+ }
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
+ static int be_get_stats_count(struct net_device *netdev)
+ {
+- return ETHTOOL_STATS_NUM;
++ struct be_adapter *adapter = netdev_priv(netdev);
++
++ return ETHTOOL_STATS_NUM + adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM
++ + adapter->num_tx_qs * ETHTOOL_TXSTATS_NUM;
+ }
++static int
++be_self_test_count(struct net_device *dev)
++{
++ return ETHTOOL_TESTS_NUM;
++}
++#else
++
++static int be_get_sset_count(struct net_device *netdev, int stringset)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++
++ switch (stringset) {
++ case ETH_SS_TEST:
++ return ETHTOOL_TESTS_NUM;
++ case ETH_SS_STATS:
++ return ETHTOOL_STATS_NUM +
++ adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM +
++ adapter->num_tx_qs * ETHTOOL_TXSTATS_NUM;
++ default:
++ return -EINVAL;
++ }
++}
++#endif
+
+ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+ {
+- ecmd->speed = SPEED_10000;
++ struct be_adapter *adapter = netdev_priv(netdev);
++ struct be_phy_info phy_info;
++ u8 mac_speed = 0;
++ u16 link_speed = 0;
++ int link_status = LINK_DOWN;
++ int status;
++
++ if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) {
++ status = be_cmd_link_status_query(adapter, &link_status,
++ &mac_speed, &link_speed, 0);
++
++ be_link_status_update(adapter, link_status);
++ /* link_speed is in units of 10 Mbps */
++ if (link_speed) {
++ ecmd->speed = link_speed*10;
++ } else {
++ switch (mac_speed) {
++ case PHY_LINK_SPEED_10MBPS:
++ ecmd->speed = SPEED_10;
++ break;
++ case PHY_LINK_SPEED_100MBPS:
++ ecmd->speed = SPEED_100;
++ break;
++ case PHY_LINK_SPEED_1GBPS:
++ ecmd->speed = SPEED_1000;
++ break;
++ case PHY_LINK_SPEED_10GBPS:
++ ecmd->speed = SPEED_10000;
++ break;
++ case PHY_LINK_SPEED_ZERO:
++ ecmd->speed = 0;
++ break;
++ }
++ }
++
++ status = be_cmd_get_phy_info(adapter, &phy_info);
++ if (!status) {
++ switch (phy_info.interface_type) {
++ case PHY_TYPE_XFP_10GB:
++ case PHY_TYPE_SFP_1GB:
++ case PHY_TYPE_SFP_PLUS_10GB:
++ ecmd->port = PORT_FIBRE;
++ break;
++ default:
++ ecmd->port = PORT_TP;
++ break;
++ }
++
++ switch (phy_info.interface_type) {
++ case PHY_TYPE_KR_10GB:
++ case PHY_TYPE_KX4_10GB:
++ ecmd->transceiver = XCVR_INTERNAL;
++ break;
++ default:
++ ecmd->transceiver = XCVR_EXTERNAL;
++ break;
++ }
++
++ if (phy_info.auto_speeds_supported) {
++ ecmd->supported |= SUPPORTED_Autoneg;
++ ecmd->autoneg = AUTONEG_ENABLE;
++ ecmd->advertising |= ADVERTISED_Autoneg;
++ }
++
++ if (phy_info.misc_params & BE_PAUSE_SYM_EN) {
++ ecmd->supported |= SUPPORTED_Pause;
++ ecmd->advertising |= ADVERTISED_Pause;
++ }
++
++ }
++
++ /* Save for future use */
++ adapter->link_speed = ecmd->speed;
++ adapter->port_type = ecmd->port;
++ adapter->transceiver = ecmd->transceiver;
++ adapter->autoneg = ecmd->autoneg;
++ } else {
++ ecmd->speed = adapter->link_speed;
++ ecmd->port = adapter->port_type;
++ ecmd->transceiver = adapter->transceiver;
++ ecmd->autoneg = adapter->autoneg;
++ }
++
+ ecmd->duplex = DUPLEX_FULL;
+- ecmd->autoneg = AUTONEG_DISABLE;
++ ecmd->phy_address = (adapter->hba_port_num << 4) |
++ (adapter->port_name[adapter->hba_port_num]);
++ switch (ecmd->port) {
++ case PORT_FIBRE:
++ ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
++ break;
++ case PORT_TP:
++ ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_TP);
++ break;
++ }
++
++ if (ecmd->autoneg) {
++ ecmd->supported |= SUPPORTED_1000baseT_Full;
++ ecmd->advertising |= (ADVERTISED_10000baseT_Full |
++ ADVERTISED_1000baseT_Full);
++ }
++
+ return 0;
+ }
+
++static int be_set_settings(struct net_device *netdev,
++ struct ethtool_cmd *ecmd)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ struct be_phy_info phy_info;
++ u16 mac_speed=0;
++ u16 dac_cable_len=0;
++ u16 port_speed = 0;
++ int status;
++
++ status = be_cmd_get_phy_info(adapter, &phy_info);
++ if (status) {
++ dev_warn(&adapter->pdev->dev, "port speed set failed.\n");
++ return status;
++ }
++
++ if (ecmd->autoneg == AUTONEG_ENABLE) {
++ switch(phy_info.interface_type) {
++ case PHY_TYPE_SFP_1GB:
++ case PHY_TYPE_BASET_1GB:
++ case PHY_TYPE_BASEX_1GB:
++ case PHY_TYPE_SGMII:
++ mac_speed = SPEED_AUTONEG_1GB_100MB_10MB;
++ break;
++ case PHY_TYPE_SFP_PLUS_10GB:
++ dev_warn(&adapter->pdev->dev,
++ "Autoneg not supported on this module. \n");
++ return -EINVAL;
++ case PHY_TYPE_KR_10GB:
++ case PHY_TYPE_KX4_10GB:
++ mac_speed = SPEED_AUTONEG_10GB_1GB;
++ break;
++ case PHY_TYPE_BASET_10GB:
++ mac_speed = SPEED_AUTONEG_10GB_1GB_100MB;
++ break;
++ }
++ } else if(ecmd->autoneg == AUTONEG_DISABLE) {
++ if(ecmd->speed == SPEED_10) {
++ mac_speed = SPEED_FORCED_10MB;
++ } else if(ecmd->speed == SPEED_100) {
++ mac_speed = SPEED_FORCED_100MB;
++ } else if(ecmd->speed == SPEED_1000) {
++ mac_speed = SPEED_FORCED_1GB;
++ } else if(ecmd->speed == SPEED_10000) {
++ mac_speed = SPEED_FORCED_10GB;
++ }
++ }
++
++ status = be_cmd_get_port_speed(adapter, adapter->hba_port_num,
++ &dac_cable_len, &port_speed);
++
++ if (!status && port_speed != mac_speed)
++ status = be_cmd_set_port_speed_v1(adapter,
++ adapter->hba_port_num, mac_speed,
++ dac_cable_len);
++ if (status)
++ dev_warn(&adapter->pdev->dev, "port speed set failed.\n");
++
++ return status;
++
++}
++
+ static void
+ be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+- ring->rx_max_pending = adapter->rx_obj.q.len;
+- ring->tx_max_pending = adapter->tx_obj.q.len;
++ ring->rx_max_pending = adapter->rx_obj[0].q.len;
++ ring->tx_max_pending = adapter->tx_obj[0].q.len;
+
+- ring->rx_pending = atomic_read(&adapter->rx_obj.q.used);
+- ring->tx_pending = atomic_read(&adapter->tx_obj.q.used);
++ ring->rx_pending = atomic_read(&adapter->rx_obj[0].q.used);
++ ring->tx_pending = atomic_read(&adapter->tx_obj[0].q.used);
+ }
+
+ static void
+@@ -312,7 +615,7 @@ be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause);
+- ecmd->autoneg = 0;
++ ecmd->autoneg = adapter->autoneg;
+ }
+
+ static int
+@@ -334,6 +637,203 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
+ return status;
+ }
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
++static int
++be_phys_id(struct net_device *netdev, u32 data)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ int status;
++ u32 cur;
++
++ be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &cur);
++
++ if (cur == BEACON_STATE_ENABLED)
++ return 0;
++
++ if (data < 2)
++ data = 2;
++
++ status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
++ BEACON_STATE_ENABLED);
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(data*HZ);
++
++ status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
++ BEACON_STATE_DISABLED);
++
++ return status;
++}
++#else
++static int
++be_set_phys_id(struct net_device *netdev,
++ enum ethtool_phys_id_state state)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++
++ switch (state) {
++ case ETHTOOL_ID_ACTIVE:
++ be_cmd_get_beacon_state(adapter, adapter->hba_port_num,
++ &adapter->beacon_state);
++ return 1; /* cycle on/off once per second */
++
++ case ETHTOOL_ID_ON:
++ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
++ BEACON_STATE_ENABLED);
++ break;
++
++ case ETHTOOL_ID_OFF:
++ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
++ BEACON_STATE_DISABLED);
++ break;
++
++ case ETHTOOL_ID_INACTIVE:
++ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
++ adapter->beacon_state);
++ }
++
++ return 0;
++}
++#endif
++
++static bool
++be_is_wol_supported(struct be_adapter *adapter)
++{
++ struct pci_dev *pdev = adapter->pdev;
++
++ if (!be_physfn(adapter))
++ return false;
++
++ switch (pdev->subsystem_device) {
++ case OC_SUBSYS_DEVICE_ID1:
++ case OC_SUBSYS_DEVICE_ID2:
++ case OC_SUBSYS_DEVICE_ID3:
++ case OC_SUBSYS_DEVICE_ID4:
++ return false;
++ default:
++ return true;
++ }
++}
++
++static void
++be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++
++ if (be_is_wol_supported(adapter))
++ wol->supported = WAKE_MAGIC;
++ if (adapter->wol)
++ wol->wolopts = WAKE_MAGIC;
++ else
++ wol->wolopts = 0;
++ memset(&wol->sopass, 0, sizeof(wol->sopass));
++}
++
++static int
++be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++
++ if (wol->wolopts & ~WAKE_MAGIC)
++ return -EOPNOTSUPP;
++
++ if (!be_is_wol_supported(adapter)) {
++ dev_warn(&adapter->pdev->dev,
++ "WOL not supported for this subsystemid: %x\n",
++ adapter->pdev->subsystem_device);
++ return -EOPNOTSUPP;
++ }
++
++ if (wol->wolopts & WAKE_MAGIC)
++ adapter->wol = true;
++ else
++ adapter->wol = false;
++
++ return 0;
++}
++
++static int
++be_test_ddr_dma(struct be_adapter *adapter)
++{
++ int ret, i;
++ struct be_dma_mem ddrdma_cmd;
++ u64 pattern[2] = {0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL};
++
++ ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test);
++ ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size,
++ &ddrdma_cmd.dma);
++ if (!ddrdma_cmd.va) {
++ dev_err(&adapter->pdev->dev, "Memory allocation failure\n");
++ return -ENOMEM;
++ }
++
++ for (i = 0; i < 2; i++) {
++ ret = be_cmd_ddr_dma_test(adapter, pattern[i],
++ 4096, &ddrdma_cmd);
++ if (ret != 0)
++ goto err;
++ }
++
++err:
++ pci_free_consistent(adapter->pdev, ddrdma_cmd.size,
++ ddrdma_cmd.va, ddrdma_cmd.dma);
++ return ret;
++}
++
++static u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type,
++ u64 *status)
++{
++ be_cmd_set_loopback(adapter, adapter->hba_port_num,
++ loopback_type, 1);
++ *status = be_cmd_loopback_test(adapter, adapter->hba_port_num,
++ loopback_type, 1500,
++ 2, 0xabc);
++ be_cmd_set_loopback(adapter, adapter->hba_port_num,
++ BE_NO_LOOPBACK, 1);
++ return *status;
++}
++
++static void
++be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ int link_status;
++ u8 mac_speed = 0;
++ u16 qos_link_speed = 0;
++
++ memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
++
++ if (test->flags & ETH_TEST_FL_OFFLINE) {
++ if (be_loopback_test(adapter, BE_MAC_LOOPBACK,
++ &data[0]) != 0) {
++ test->flags |= ETH_TEST_FL_FAILED;
++ }
++ if (be_loopback_test(adapter, BE_PHY_LOOPBACK,
++ &data[1]) != 0) {
++ test->flags |= ETH_TEST_FL_FAILED;
++ }
++ if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
++ &data[2]) != 0) {
++ test->flags |= ETH_TEST_FL_FAILED;
++ }
++ }
++
++ if (be_test_ddr_dma(adapter) != 0) {
++ data[3] = 1;
++ test->flags |= ETH_TEST_FL_FAILED;
++ }
++
++ if (be_cmd_link_status_query(adapter, &link_status, &mac_speed,
++ &qos_link_speed, 0) != 0) {
++ test->flags |= ETH_TEST_FL_FAILED;
++ data[4] = -1;
++ } else if (!mac_speed) {
++ test->flags |= ETH_TEST_FL_FAILED;
++ data[4] = 1;
++ }
++
++}
++
++#ifdef HAVE_ETHTOOL_FLASH
+ static int
+ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
+ {
+@@ -347,11 +847,73 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
+
+ return be_load_fw(adapter, file_name);
+ }
++#endif
+
+-const struct ethtool_ops be_ethtool_ops = {
++static int
++be_get_eeprom_len(struct net_device *netdev)
++{
++ return BE_READ_SEEPROM_LEN;
++}
++
++static int
++be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
++ uint8_t *data)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ struct be_dma_mem eeprom_cmd;
++ struct be_cmd_resp_seeprom_read *resp;
++ int status;
++
++ if (!eeprom->len)
++ return -EINVAL;
++
++ eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16);
++
++ memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem));
++ eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read);
++ eeprom_cmd.va = pci_alloc_consistent(adapter->pdev, eeprom_cmd.size,
++ &eeprom_cmd.dma);
++
++ if (!eeprom_cmd.va) {
++ dev_err(&adapter->pdev->dev,
++ "Memory allocation failure. Could not read eeprom\n");
++ return -ENOMEM;
++ }
++
++ status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd);
++
++ if (!status) {
++ resp = (struct be_cmd_resp_seeprom_read *) eeprom_cmd.va;
++ memcpy(data, resp->seeprom_data + eeprom->offset, eeprom->len);
++ }
++ pci_free_consistent(adapter->pdev, eeprom_cmd.size, eeprom_cmd.va,
++ eeprom_cmd.dma);
++
++ return status;
++}
++
++static int be_set_tso(struct net_device *netdev, uint32_t data)
++{
++ if (data) {
++ netdev->features |= NETIF_F_TSO;
++ netdev->features |= NETIF_F_TSO6;
++ } else {
++ netdev->features &= ~NETIF_F_TSO;
++ netdev->features &= ~NETIF_F_TSO6;
++ }
++ return 0;
++}
++
++
++struct ethtool_ops be_ethtool_ops = {
+ .get_settings = be_get_settings,
++ .set_settings = be_set_settings,
+ .get_drvinfo = be_get_drvinfo,
++ .get_wol = be_get_wol,
++ .set_wol = be_set_wol,
+ .get_link = ethtool_op_get_link,
++ .get_eeprom_len = be_get_eeprom_len,
++ .get_eeprom = be_read_eeprom,
+ .get_coalesce = be_get_coalesce,
+ .set_coalesce = be_set_coalesce,
+ .get_ringparam = be_get_ringparam,
+@@ -364,9 +926,21 @@ const struct ethtool_ops be_ethtool_ops = {
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+- .set_tso = ethtool_op_set_tso,
++ .set_tso = be_set_tso,
+ .get_strings = be_get_stat_strings,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
++ .phys_id = be_phys_id,
+ .get_stats_count = be_get_stats_count,
++ .self_test_count = be_self_test_count,
++#else
++ .set_phys_id = be_set_phys_id,
++ .get_sset_count = be_get_sset_count,
++#endif
+ .get_ethtool_stats = be_get_ethtool_stats,
++ .get_regs_len = be_get_reg_len,
++ .get_regs = be_get_regs,
++#ifdef HAVE_ETHTOOL_FLASH
+ .flash_device = be_do_flash,
++#endif
++ .self_test = be_self_test
+ };
+diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
+index a3394b4..f871d8c 100644
+--- a/drivers/net/benet/be_hw.h
++++ b/drivers/net/benet/be_hw.h
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (C) 2005 - 2009 ServerEngines
++ * Copyright (C) 2005 - 2011 Emulex
+ * 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. The full GNU General
++ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+- * linux-drivers@serverengines.com
++ * linux-drivers@emulex.com
+ *
+- * ServerEngines
+- * 209 N. Fair Oaks Ave
+- * Sunnyvale, CA 94085
++ * Emulex
++ * 3333 Susan Street
++ * Costa Mesa, CA 92626
+ */
+
+ /********* Mailbox door bell *************/
+@@ -26,24 +26,34 @@
+ * queue entry.
+ */
+ #define MPU_MAILBOX_DB_OFFSET 0x160
+-#define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */
++#define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */
+ #define MPU_MAILBOX_DB_HI_MASK 0x2 /* bit 1 */
+
+-#define MPU_EP_CONTROL 0
++#define MPU_EP_CONTROL 0
+
+ /********** MPU semphore ******************/
+-#define MPU_EP_SEMAPHORE_OFFSET 0xac
++#define MPU_EP_SEMAPHORE_OFFSET 0xac
++#define MPU_EP_SEMAPHORE_IF_TYPE2_OFFSET 0x400
+ #define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF
+ #define EP_SEMAPHORE_POST_ERR_MASK 0x1
+ #define EP_SEMAPHORE_POST_ERR_SHIFT 31
+ /* MPU semphore POST stage values */
+-#define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */
+-#define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */
++#define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */
++#define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */
+ #define POST_STAGE_BE_RESET 0x3 /* Host wants to reset chip */
+ #define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */
+
++/* Lancer SLIPORT_CONTROL SLIPORT_STATUS registers */
++#define SLIPORT_STATUS_OFFSET 0x404
++#define SLIPORT_CONTROL_OFFSET 0x408
++
++#define SLIPORT_STATUS_ERR_MASK 0x80000000
++#define SLIPORT_STATUS_RN_MASK 0x01000000
++#define SLIPORT_STATUS_RDY_MASK 0x00800000
++#define SLI_PORT_CONTROL_IP_MASK 0x08000000
++
+ /********* Memory BAR register ************/
+-#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc
++#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc
+ /* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
+ * Disable" may still globally block interrupts in addition to individual
+ * interrupt masks; a mechanism for the device driver to block all interrupts
+@@ -52,13 +62,70 @@
+ */
+ #define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */
+
++/********* Link Status CSR ****************/
++#define PCICFG_PCIE_LINK_STATUS_OFFSET 0xd0
++#define PCIE_LINK_STATUS_SPEED_MASK 0xFF /* bits 16 - 19 */
++#define PCIE_LINK_STATUS_SPEED_SHIFT 16
++#define PCIE_LINK_STATUS_NEG_WIDTH_MASK 0x3F /* bits 20 - 25 */
++#define PCIE_LINK_STATUS_NEG_WIDTH_SHIFT 20
++
++/********* Link Capability CSR ************/
++#define PCICFG_PCIE_LINK_CAP_OFFSET 0xcc
++#define PCIE_LINK_CAP_MAX_SPEED_MASK 0xFF /* bits 0 - 3 */
++#define PCIE_LINK_CAP_MAX_SPEED_SHIFT 0
++#define PCIE_LINK_CAP_MAX_WIDTH_MASK 0x3F /* bits 4 - 9 */
++#define PCIE_LINK_CAP_MAX_WIDTH_SHIFT 4
++
++/********* PCI Function Capability ************/
++#define BE_FUNCTION_CAPS_UNCLASSIFIED_STATS 0x1
++#define BE_FUNCTION_CAPS_RSS 0x2
++#define BE_FUNCTION_CAPS_PROMISCUOUS 0x4
++#define BE_FUNCTION_CAPS_LEGACY_MODE 0x8
++
++/********* Power managment (WOL) **********/
++#define PCICFG_PM_CONTROL_OFFSET 0x44
++#define PCICFG_PM_CONTROL_MASK 0x108 /* bits 3 & 8 */
++
++/********* Online Control Registers *******/
++#define PCICFG_ONLINE0 0xB0
++#define PCICFG_ONLINE1 0xB4
++
++/********* UE Status and Mask Registers ***/
++#define PCICFG_UE_STATUS_LOW 0xA0
++#define PCICFG_UE_STATUS_HIGH 0xA4
++#define PCICFG_UE_STATUS_LOW_MASK 0xA8
++#define PCICFG_UE_STATUS_HI_MASK 0xAC
++
++/******** SLI_INTF ***********************/
++#define SLI_INTF_REG_OFFSET 0x58
++#define SLI_INTF_VALID_MASK 0xE0000000
++#define SLI_INTF_VALID 0xC0000000
++#define SLI_INTF_HINT2_MASK 0x1F000000
++#define SLI_INTF_HINT2_SHIFT 24
++#define SLI_INTF_HINT1_MASK 0x00FF0000
++#define SLI_INTF_HINT1_SHIFT 16
++#define SLI_INTF_FAMILY_MASK 0x00000F00
++#define SLI_INTF_FAMILY_SHIFT 8
++#define SLI_INTF_IF_TYPE_MASK 0x0000F000
++#define SLI_INTF_IF_TYPE_SHIFT 12
++#define SLI_INTF_REV_MASK 0x000000F0
++#define SLI_INTF_REV_SHIFT 4
++#define SLI_INTF_FT_MASK 0x00000001
++
++/* SLI family */
++#define BE_SLI_FAMILY 0x0
++#define LANCER_A0_SLI_FAMILY 0xA
++
+ /********* ISR0 Register offset **********/
+-#define CEV_ISR0_OFFSET 0xC18
++#define CEV_ISR0_OFFSET 0xC18
+ #define CEV_ISR_SIZE 4
+
+ /********* Event Q door bell *************/
+ #define DB_EQ_OFFSET DB_CQ_OFFSET
+ #define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */
++#define DB_EQ_RING_ID_EXT_MASK 0x3e00 /* bits 9-13 */
++#define DB_EQ_RING_ID_EXT_MASK_SHIFT (2) /* qid bits 9-13 placing at 11-15 */
++
+ /* Clear the interrupt for this eq */
+ #define DB_EQ_CLR_SHIFT (9) /* bit 9 */
+ /* Must be 1 */
+@@ -69,12 +136,16 @@
+ #define DB_EQ_REARM_SHIFT (29) /* bit 29 */
+
+ /********* Compl Q door bell *************/
+-#define DB_CQ_OFFSET 0x120
++#define DB_CQ_OFFSET 0x120
+ #define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
++#define DB_CQ_RING_ID_EXT_MASK 0x7C00 /* bits 10-14 */
++#define DB_CQ_RING_ID_EXT_MASK_SHIFT (1) /* qid bits 10-14
++ placing at 11-15 */
++
+ /* Number of event entries processed */
+-#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
++#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
+ /* Rearm bit */
+-#define DB_CQ_REARM_SHIFT (29) /* bit 29 */
++#define DB_CQ_REARM_SHIFT (29) /* bit 29 */
+
+ /********** TX ULP door bell *************/
+ #define DB_TXULP1_OFFSET 0x60
+@@ -84,25 +155,103 @@
+ #define DB_TXULP_NUM_POSTED_MASK 0x3FFF /* bits 16 - 29 */
+
+ /********** RQ(erx) door bell ************/
+-#define DB_RQ_OFFSET 0x100
++#define DB_RQ_OFFSET 0x100
+ #define DB_RQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
+ /* Number of rx frags posted */
+ #define DB_RQ_NUM_POSTED_SHIFT (24) /* bits 24 - 31 */
+
+ /********** MCC door bell ************/
+-#define DB_MCCQ_OFFSET 0x140
++#define DB_MCCQ_OFFSET 0x140
+ #define DB_MCCQ_RING_ID_MASK 0x7FF /* bits 0 - 10 */
+ /* Number of entries posted */
+ #define DB_MCCQ_NUM_POSTED_SHIFT (16) /* bits 16 - 29 */
+
++/********** SRIOV VF PCICFG OFFSET ********/
++#define SRIOV_VF_PCICFG_OFFSET (4096)
++
++/********** FAT TABLE ********/
++#define RETRIEVE_FAT 0
++#define QUERY_FAT 1
++
++/* Flashrom related descriptors */
++#define IMAGE_TYPE_FIRMWARE 160
++#define IMAGE_TYPE_BOOTCODE 224
++#define IMAGE_TYPE_OPTIONROM 32
++
++#define NUM_FLASHDIR_ENTRIES 32
++
++#define IMG_TYPE_ISCSI_ACTIVE 0
++#define IMG_TYPE_REDBOOT 1
++#define IMG_TYPE_BIOS 2
++#define IMG_TYPE_PXE_BIOS 3
++#define IMG_TYPE_FCOE_BIOS 8
++#define IMG_TYPE_ISCSI_BACKUP 9
++#define IMG_TYPE_FCOE_FW_ACTIVE 10
++#define IMG_TYPE_FCOE_FW_BACKUP 11
++#define IMG_TYPE_NCSI_FW 13
++#define IMG_TYPE_PHY_FW 99
++#define TN_8022 13
++
++#define ILLEGAL_IOCTL_REQ 2
++#define FLASHROM_OPER_PHY_FLASH 9
++#define FLASHROM_OPER_PHY_SAVE 10
++#define FLASHROM_OPER_FLASH 1
++#define FLASHROM_OPER_SAVE 2
++#define FLASHROM_OPER_REPORT 4
++
++#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image size */
++#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM image sz */
++#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */
++#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max firmware image size */
++#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM image sz */
++#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */
++#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144)
++#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 (262144)
++
++#define FLASH_NCSI_MAGIC (0x16032009)
++#define FLASH_NCSI_DISABLED (0)
++#define FLASH_NCSI_ENABLED (1)
++
++#define FLASH_NCSI_BITFILE_HDR_OFFSET (0x600000)
++
++/* Offsets for components on Flash. */
++#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 (1048576)
++#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 (2359296)
++#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 (3670016)
++#define FLASH_FCoE_BACKUP_IMAGE_START_g2 (4980736)
++#define FLASH_iSCSI_BIOS_START_g2 (7340032)
++#define FLASH_PXE_BIOS_START_g2 (7864320)
++#define FLASH_FCoE_BIOS_START_g2 (524288)
++#define FLASH_REDBOOT_START_g2 (0)
++
++#define FLASH_NCSI_START_g3 (15990784)
++#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 (2097152)
++#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 (4194304)
++#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 (6291456)
++#define FLASH_FCoE_BACKUP_IMAGE_START_g3 (8388608)
++#define FLASH_iSCSI_BIOS_START_g3 (12582912)
++#define FLASH_PXE_BIOS_START_g3 (13107200)
++#define FLASH_FCoE_BIOS_START_g3 (13631488)
++#define FLASH_REDBOOT_START_g3 (262144)
++#define FLASH_PHY_FW_START_g3 (1310720)
++
++/************* Rx Packet Type Encoding **************/
++#define BE_UNICAST_PACKET 0
++#define BE_MULTICAST_PACKET 1
++#define BE_BROADCAST_PACKET 2
++#define BE_RSVD_PACKET 3
++
+ /*
+ * BE descriptors: host memory data structures whose formats
+ * are hardwired in BE silicon.
+ */
+ /* Event Queue Descriptor */
+-#define EQ_ENTRY_VALID_MASK 0x1 /* bit 0 */
+-#define EQ_ENTRY_RES_ID_MASK 0xFFFF /* bits 16 - 31 */
+-#define EQ_ENTRY_RES_ID_SHIFT 16
++#define EQ_ENTRY_VALID_MASK 0x1 /* bit 0 */
++#define EQ_ENTRY_RES_ID_MASK 0xFFFF /* bits 16 - 31 */
++#define EQ_ENTRY_RES_ID_SHIFT 16
++
++#define BE_MAC_PROMISCUOUS 62 /* Promiscuous mode */
++
+ struct be_eq_entry {
+ u32 evt;
+ };
+@@ -126,7 +275,7 @@ struct amap_eth_hdr_wrb {
+ u8 event;
+ u8 crc;
+ u8 forward;
+- u8 ipsec;
++ u8 lso6;
+ u8 mgmt;
+ u8 ipcs;
+ u8 udpcs;
+@@ -151,7 +300,7 @@ struct be_eth_hdr_wrb {
+ * offset/shift/mask of each field */
+ struct amap_eth_tx_compl {
+ u8 wrb_index[16]; /* dword 0 */
+- u8 ct[2]; /* dword 0 */
++ u8 ct[2]; /* dword 0 */
+ u8 port[2]; /* dword 0 */
+ u8 rsvd0[8]; /* dword 0 */
+ u8 status[4]; /* dword 0 */
+@@ -179,10 +328,10 @@ struct be_eth_rx_d {
+
+ /* RX Compl Queue Descriptor */
+
+-/* Pseudo amap definition for eth_rx_compl in which each bit of the
+- * actual structure is defined as a byte: used to calculate
++/* Pseudo amap definition for BE2 and BE3 legacy mode eth_rx_compl in which
++ * each bit of the actual structure is defined as a byte: used to calculate
+ * offset/shift/mask of each field */
+-struct amap_eth_rx_compl {
++struct amap_eth_rx_compl_v0 {
+ u8 vlan_tag[16]; /* dword 0 */
+ u8 pktsize[14]; /* dword 0 */
+ u8 port; /* dword 0 */
+@@ -213,39 +362,91 @@ struct amap_eth_rx_compl {
+ u8 rsshash[32]; /* dword 3 */
+ } __packed;
+
++/* Pseudo amap definition for BE3 native mode eth_rx_compl in which
++ * each bit of the actual structure is defined as a byte: used to calculate
++ * offset/shift/mask of each field */
++struct amap_eth_rx_compl_v1 {
++ u8 vlan_tag[16]; /* dword 0 */
++ u8 pktsize[14]; /* dword 0 */
++ u8 vtp; /* dword 0 */
++ u8 ip_opt; /* dword 0 */
++ u8 err; /* dword 1 */
++ u8 rsshp; /* dword 1 */
++ u8 ipf; /* dword 1 */
++ u8 tcpf; /* dword 1 */
++ u8 udpf; /* dword 1 */
++ u8 ipcksm; /* dword 1 */
++ u8 l4_cksm; /* dword 1 */
++ u8 ip_version; /* dword 1 */
++ u8 macdst[7]; /* dword 1 */
++ u8 rsvd0; /* dword 1 */
++ u8 fragndx[10]; /* dword 1 */
++ u8 ct[2]; /* dword 1 */
++ u8 sw; /* dword 1 */
++ u8 numfrags[3]; /* dword 1 */
++ u8 rss_flush; /* dword 2 */
++ u8 cast_enc[2]; /* dword 2 */
++ u8 vtm; /* dword 2 */
++ u8 rss_bank; /* dword 2 */
++ u8 port[2]; /* dword 2 */
++ u8 vntagp; /* dword 2 */
++ u8 header_len[8]; /* dword 2 */
++ u8 header_split[2]; /* dword 2 */
++ u8 rsvd1[13]; /* dword 2 */
++ u8 valid; /* dword 2 */
++ u8 rsshash[32]; /* dword 3 */
++} __packed;
++
+ struct be_eth_rx_compl {
+ u32 dw[4];
+ };
+
+-/* Flashrom related descriptors */
+-#define IMAGE_TYPE_FIRMWARE 160
+-#define IMAGE_TYPE_BOOTCODE 224
+-#define IMAGE_TYPE_OPTIONROM 32
++struct mgmt_hba_attribs {
++ u8 flashrom_version_string[32];
++ u8 manufacturer_name[32];
++ u32 supported_modes;
++ u32 rsvd0[3];
++ u8 ncsi_ver_string[12];
++ u32 default_extended_timeout;
++ u8 controller_model_number[32];
++ u8 controller_description[64];
++ u8 controller_serial_number[32];
++ u8 ip_version_string[32];
++ u8 firmware_version_string[32];
++ u8 bios_version_string[32];
++ u8 redboot_version_string[32];
++ u8 driver_version_string[32];
++ u8 fw_on_flash_version_string[32];
++ u32 functionalities_supported;
++ u16 max_cdblength;
++ u8 asic_revision;
++ u8 generational_guid[16];
++ u8 hba_port_count;
++ u16 default_link_down_timeout;
++ u8 iscsi_ver_min_max;
++ u8 multifunction_device;
++ u8 cache_valid;
++ u8 hba_status;
++ u8 max_domains_supported;
++ u8 phy_port;
++ u32 firmware_post_status;
++ u32 hba_mtu[8];
++ u32 rsvd1[4];
++};
+
+-#define NUM_FLASHDIR_ENTRIES 32
+-
+-#define FLASHROM_TYPE_ISCSI_ACTIVE 0
+-#define FLASHROM_TYPE_BIOS 2
+-#define FLASHROM_TYPE_PXE_BIOS 3
+-#define FLASHROM_TYPE_FCOE_BIOS 8
+-#define FLASHROM_TYPE_ISCSI_BACKUP 9
+-#define FLASHROM_TYPE_FCOE_FW_ACTIVE 10
+-#define FLASHROM_TYPE_FCOE_FW_BACKUP 11
+-
+-#define FLASHROM_OPER_FLASH 1
+-#define FLASHROM_OPER_SAVE 2
+-
+-#define FLASH_IMAGE_MAX_SIZE (1310720) /* Max firmware image size */
+-#define FLASH_BIOS_IMAGE_MAX_SIZE (262144) /* Max OPTION ROM image sz */
+-
+-/* Offsets for components on Flash. */
+-#define FLASH_iSCSI_PRIMARY_IMAGE_START (1048576)
+-#define FLASH_iSCSI_BACKUP_IMAGE_START (2359296)
+-#define FLASH_FCoE_PRIMARY_IMAGE_START (3670016)
+-#define FLASH_FCoE_BACKUP_IMAGE_START (4980736)
+-#define FLASH_iSCSI_BIOS_START (7340032)
+-#define FLASH_PXE_BIOS_START (7864320)
+-#define FLASH_FCoE_BIOS_START (524288)
++struct mgmt_controller_attrib {
++ struct mgmt_hba_attribs hba_attribs;
++ u16 pci_vendor_id;
++ u16 pci_device_id;
++ u16 pci_sub_vendor_id;
++ u16 pci_sub_system_id;
++ u8 pci_bus_number;
++ u8 pci_device_number;
++ u8 pci_function_number;
++ u8 interface_type;
++ u64 unique_identifier;
++ u32 rsvd0[5];
++};
+
+ struct controller_id {
+ u32 vendor;
+@@ -254,7 +455,20 @@ struct controller_id {
+ u32 subdevice;
+ };
+
+-struct flash_file_hdr {
++struct flash_comp {
++ unsigned long offset;
++ int optype;
++ int size;
++};
++
++struct image_hdr {
++ u32 imageid;
++ u32 imageoffset;
++ u32 imagelength;
++ u32 image_checksum;
++ u8 image_version[32];
++};
++struct flash_file_hdr_g2 {
+ u8 sign[32];
+ u32 cksum;
+ u32 antidote;
+@@ -266,6 +480,17 @@ struct flash_file_hdr {
+ u8 build[24];
+ };
+
++struct flash_file_hdr_g3 {
++ u8 sign[52];
++ u8 ufi_version[4];
++ u32 file_len;
++ u32 cksum;
++ u32 antidote;
++ u32 num_imgs;
++ u8 build[24];
++ u8 rsvd[32];
++};
++
+ struct flash_section_hdr {
+ u32 format_rev;
+ u32 cksum;
+@@ -299,3 +524,19 @@ struct flash_section_info {
+ struct flash_section_hdr fsec_hdr;
+ struct flash_section_entry fsec_entry[32];
+ };
++
++struct flash_ncsi_image_hdr {
++ u32 magic;
++ u8 hdr_len;
++ u8 type;
++ u16 hdr_ver;
++ u8 rsvd0[2];
++ u16 load_offset;
++ u32 len;
++ u32 flash_offset;
++ u8 ver[16];
++ u8 name[24];
++ u32 img_cksum;
++ u8 rsvd1[4];
++ u32 hdr_cksum;
++};
+diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
+index 000e377..f501aa3 100644
+--- a/drivers/net/benet/be_main.c
++++ b/drivers/net/benet/be_main.c
+@@ -1,18 +1,18 @@
+ /*
+- * Copyright (C) 2005 - 2009 ServerEngines
++ * Copyright (C) 2005 - 2011 Emulex
+ * 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. The full GNU General
++ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+- * linux-drivers@serverengines.com
++ * linux-drivers@emulex.com
+ *
+- * ServerEngines
+- * 209 N. Fair Oaks Ave
+- * Sunnyvale, CA 94085
++ * Emulex
++ * 3333 Susan Street
++ * Costa Mesa, CA 92626
+ */
+
+ #include "be.h"
+@@ -22,23 +22,119 @@
+ MODULE_VERSION(DRV_VER);
+ MODULE_DEVICE_TABLE(pci, be_dev_ids);
+ MODULE_DESCRIPTION(DRV_DESC " " DRV_VER);
+-MODULE_AUTHOR("ServerEngines Corporation");
++MODULE_AUTHOR("Emulex Corporation");
+ MODULE_LICENSE("GPL");
++MODULE_INFO(supported, "external");
+
+-static unsigned int rx_frag_size = 2048;
+-module_param(rx_frag_size, uint, S_IRUGO);
+-MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data.");
++static ushort rx_frag_size = 2048;
++static unsigned int num_vfs;
++static unsigned int msix = 1;
++module_param(rx_frag_size, ushort, S_IRUGO);
++module_param(num_vfs, uint, S_IRUGO);
++module_param(msix, uint, S_IRUGO);
++MODULE_PARM_DESC(rx_frag_size, "Size of receive fragment buffer"
++ " - 2048 (default), 4096 or 8192");
++MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize");
++MODULE_PARM_DESC(msix, "Enable and disable the MSI"
++ "x (By default MSIx is enabled)");
++static unsigned int gro = 1;
++module_param(gro, uint, S_IRUGO);
++MODULE_PARM_DESC(gro, "Enable or Disable GRO. Enabled by default");
++
++static unsigned int multi_rxq = true;
++module_param(multi_rxq, uint, S_IRUGO);
++MODULE_PARM_DESC(multi_rxq, "Multi Rx Queue support. Enabled by default");
+
+ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
+ { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
+ { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
+- { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) },
++ /*
++ * Lancer is not part of Palau 4.0
++ * { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)},
++ */
+ { 0 }
+ };
+ MODULE_DEVICE_TABLE(pci, be_dev_ids);
+
++/* UE Status Low CSR */
++static char *ue_status_low_desc[] = {
++ "CEV",
++ "CTX",
++ "DBUF",
++ "ERX",
++ "Host",
++ "MPU",
++ "NDMA",
++ "PTC ",
++ "RDMA ",
++ "RXF ",
++ "RXIPS ",
++ "RXULP0 ",
++ "RXULP1 ",
++ "RXULP2 ",
++ "TIM ",
++ "TPOST ",
++ "TPRE ",
++ "TXIPS ",
++ "TXULP0 ",
++ "TXULP1 ",
++ "UC ",
++ "WDMA ",
++ "TXULP2 ",
++ "HOST1 ",
++ "P0_OB_LINK ",
++ "P1_OB_LINK ",
++ "HOST_GPIO ",
++ "MBOX ",
++ "AXGMAC0",
++ "AXGMAC1",
++ "JTAG",
++ "MPU_INTPEND"
++};
++
++/* UE Status High CSR */
++static char *ue_status_hi_desc[] = {
++ "LPCMEMHOST",
++ "MGMT_MAC",
++ "PCS0ONLINE",
++ "MPU_IRAM",
++ "PCS1ONLINE",
++ "PCTL0",
++ "PCTL1",
++ "PMEM",
++ "RR",
++ "TXPB",
++ "RXPP",
++ "XAUI",
++ "TXP",
++ "ARM",
++ "IPC",
++ "HOST2",
++ "HOST3",
++ "HOST4",
++ "HOST5",
++ "HOST6",
++ "HOST7",
++ "HOST8",
++ "HOST9",
++ "NETC",
++ "Unknown",
++ "Unknown",
++ "Unknown",
++ "Unknown",
++ "Unknown",
++ "Unknown",
++ "Unknown",
++ "Unknown"
++};
++
++static inline bool be_multi_rxq(struct be_adapter *adapter)
++{
++ return (adapter->num_rx_qs > 1);
++}
++
+ static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
+ {
+ struct be_dma_mem *mem = &q->dma_mem;
+@@ -69,6 +165,9 @@ static void be_intr_set(struct be_adapter *adapter, bool enable)
+ u32 reg = ioread32(addr);
+ u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+
++ if (adapter->eeh_err)
++ return;
++
+ if (!enabled && enable)
+ reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ else if (enabled && !enable)
+@@ -84,6 +183,8 @@ static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
+ u32 val = 0;
+ val |= qid & DB_RQ_RING_ID_MASK;
+ val |= posted << DB_RQ_NUM_POSTED_SHIFT;
++
++ wmb();
+ iowrite32(val, adapter->db + DB_RQ_OFFSET);
+ }
+
+@@ -92,6 +193,8 @@ static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
+ u32 val = 0;
+ val |= qid & DB_TXULP_RING_ID_MASK;
+ val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT;
++
++ wmb();
+ iowrite32(val, adapter->db + DB_TXULP1_OFFSET);
+ }
+
+@@ -100,6 +203,12 @@ static void be_eq_notify(struct be_adapter *adapter, u16 qid,
+ {
+ u32 val = 0;
+ val |= qid & DB_EQ_RING_ID_MASK;
++ val |= ((qid & DB_EQ_RING_ID_EXT_MASK) <<
++ DB_EQ_RING_ID_EXT_MASK_SHIFT);
++
++ if (adapter->eeh_err)
++ return;
++
+ if (arm)
+ val |= 1 << DB_EQ_REARM_SHIFT;
+ if (clear_int)
+@@ -113,6 +222,12 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped)
+ {
+ u32 val = 0;
+ val |= qid & DB_CQ_RING_ID_MASK;
++ val |= ((qid & DB_CQ_RING_ID_EXT_MASK) <<
++ DB_CQ_RING_ID_EXT_MASK_SHIFT);
++
++ if (adapter->eeh_err)
++ return;
++
+ if (arm)
+ val |= 1 << DB_CQ_REARM_SHIFT;
+ val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
+@@ -124,96 +239,250 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
+ struct be_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+ int status = 0;
++ u8 current_mac[ETH_ALEN];
++ u32 pmac_id = adapter->pmac_id;
+
+- status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id);
++ if (!is_valid_ether_addr(addr->sa_data))
++ return -EADDRNOTAVAIL;
++
++ status = be_cmd_mac_addr_query(adapter, current_mac,
++ MAC_ADDRESS_TYPE_NETWORK, false,
++ adapter->if_handle);
+ if (status)
+- return status;
++ goto err;
++
++ if (!memcmp(addr->sa_data, current_mac, ETH_ALEN))
++ goto done;
+
+ status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
+- adapter->if_handle, &adapter->pmac_id);
+- if (!status)
++ adapter->if_handle, &adapter->pmac_id, 0);
++
++ if (!status) {
++ status = be_cmd_pmac_del(adapter, adapter->if_handle,
++ pmac_id, 0);
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
++ goto done;
++ }
+
+- return status;
++err:
++ if (status == MCC_STATUS_UNAUTHORIZED_REQUEST)
++ return -EPERM;
++ else
++ dev_err(&adapter->pdev->dev, "MAC %pM set Failed\n",
++ addr->sa_data);
++done:
++ return status;
++}
++
++static void populate_be2_stats(struct be_adapter *adapter)
++{
++
++ struct be_drv_stats *drvs = &adapter->drv_stats;
++ struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
++ struct be_port_rxf_stats_v0 *port_stats =
++ be_port_rxf_stats_from_cmd(adapter);
++ struct be_rxf_stats_v0 *rxf_stats =
++ be_rxf_stats_from_cmd(adapter);
++
++ drvs->rx_pause_frames = port_stats->rx_pause_frames;
++ drvs->rx_crc_errors = port_stats->rx_crc_errors;
++ drvs->rx_control_frames = port_stats->rx_control_frames;
++ drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
++ drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
++ drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
++ drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
++ drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
++ drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
++ drvs->rxpp_fifo_overflow_drop = port_stats->rx_fifo_overflow;
++ drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
++ drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
++ drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
++ drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
++ drvs->rx_input_fifo_overflow_drop =
++ port_stats->rx_input_fifo_overflow;
++ drvs->rx_dropped_header_too_small =
++ port_stats->rx_dropped_header_too_small;
++ drvs->rx_address_match_errors =
++ port_stats->rx_address_match_errors;
++ drvs->rx_alignment_symbol_errors =
++ port_stats->rx_alignment_symbol_errors;
++
++ drvs->tx_pauseframes = port_stats->tx_pauseframes;
++ drvs->tx_controlframes = port_stats->tx_controlframes;
++
++ if (adapter->port_num)
++ drvs->jabber_events =
++ rxf_stats->port1_jabber_events;
++ else
++ drvs->jabber_events =
++ rxf_stats->port0_jabber_events;
++ drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
++ drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
++ drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
++ drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
++ drvs->forwarded_packets = rxf_stats->forwarded_packets;
++ drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
++ drvs->rx_drops_no_tpre_descr =
++ rxf_stats->rx_drops_no_tpre_descr;
++ drvs->rx_drops_too_many_frags =
++ rxf_stats->rx_drops_too_many_frags;
++ adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
++}
++
++static void populate_be3_stats(struct be_adapter *adapter)
++{
++ struct be_drv_stats *drvs = &adapter->drv_stats;
++ struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
++
++ struct be_rxf_stats_v1 *rxf_stats =
++ be_rxf_stats_from_cmd(adapter);
++ struct be_port_rxf_stats_v1 *port_stats =
++ be_port_rxf_stats_from_cmd(adapter);
++
++ drvs->pmem_fifo_overflow_drop = port_stats->pmem_fifo_overflow_drop;
++ drvs->rx_priority_pause_frames = port_stats->rx_priority_pause_frames;
++ drvs->rx_pause_frames = port_stats->rx_pause_frames;
++ drvs->rx_crc_errors = port_stats->rx_crc_errors;
++ drvs->rx_control_frames = port_stats->rx_control_frames;
++ drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
++ drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
++ drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
++ drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
++ drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
++ drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
++ drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
++ drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
++ drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
++ drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
++ drvs->rx_dropped_header_too_small =
++ port_stats->rx_dropped_header_too_small;
++ drvs->rx_input_fifo_overflow_drop =
++ port_stats->rx_input_fifo_overflow_drop;
++ drvs->rx_address_match_errors =
++ port_stats->rx_address_match_errors;
++ drvs->rx_alignment_symbol_errors =
++ port_stats->rx_alignment_symbol_errors;
++ drvs->rxpp_fifo_overflow_drop =
++ port_stats->rxpp_fifo_overflow_drop;
++ drvs->tx_pauseframes = port_stats->tx_pauseframes;
++ drvs->tx_controlframes = port_stats->tx_controlframes;
++ drvs->jabber_events = port_stats->jabber_events;
++ drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
++ drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
++ drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
++ drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
++ drvs->forwarded_packets = rxf_stats->forwarded_packets;
++ drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
++ drvs->rx_drops_no_tpre_descr =
++ rxf_stats->rx_drops_no_tpre_descr;
++ drvs->rx_drops_too_many_frags =
++ rxf_stats->rx_drops_too_many_frags;
++ adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
++}
++
++
++static void accumulate_16bit_val(u32 *acc, u16 val)
++{
++#define lo(x) (x & 0xFFFF)
++#define hi(x) (x & 0xFFFF0000)
++ bool wrapped = val < lo(*acc);
++ u32 newacc = hi(*acc) + val;
++
++ if (wrapped)
++ newacc += 65536;
++ ACCESS_ONCE_RW(*acc) = newacc;
++}
++
++void be_parse_stats(struct be_adapter *adapter)
++{
++ struct be_erx_stats_v1 *erx = be_erx_stats_from_cmd(adapter);
++ struct be_rx_obj *rxo;
++ int i;
++
++ if (adapter->generation == BE_GEN3) {
++ populate_be3_stats(adapter);
++ } else {
++ populate_be2_stats(adapter);
++ }
++
++ /* as erx_v1 is longer than v0, ok to use v1 defn for v0 access */
++ for_all_rx_queues(adapter, rxo, i) {
++ /* below erx HW counter can actually wrap around after
++ * 65535. Driver accumulates a 32-bit value
++ */
++ accumulate_16bit_val(&rx_stats(rxo)->rx_drops_no_frags,
++ (u16)erx->rx_drops_no_fragments[rxo->q.id]);
++ }
+ }
+
+ void netdev_stats_update(struct be_adapter *adapter)
+ {
+- struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va);
+- struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
+- struct be_port_rxf_stats *port_stats =
+- &rxf_stats->port[adapter->port_num];
+- struct net_device_stats *dev_stats = &adapter->stats.net_stats;
+- struct be_erx_stats *erx_stats = &hw_stats->erx;
++ struct be_drv_stats *drvs = &adapter->drv_stats;
++ struct net_device_stats *dev_stats = &adapter->net_stats;
++ struct be_rx_obj *rxo;
++ struct be_tx_obj *txo;
++ unsigned long pkts = 0, bytes = 0, mcast = 0, drops = 0;
++ int i;
+
+- dev_stats->rx_packets = drvr_stats(adapter)->be_rx_pkts;
+- dev_stats->tx_packets = drvr_stats(adapter)->be_tx_pkts;
+- dev_stats->rx_bytes = drvr_stats(adapter)->be_rx_bytes;
+- dev_stats->tx_bytes = drvr_stats(adapter)->be_tx_bytes;
++ for_all_rx_queues(adapter, rxo, i) {
++ pkts += rx_stats(rxo)->rx_pkts;
++ bytes += rx_stats(rxo)->rx_bytes;
++ mcast += rx_stats(rxo)->rx_mcast_pkts;
++ drops += rx_stats(rxo)->rx_drops_no_frags;
++ }
++ dev_stats->rx_packets = pkts;
++ dev_stats->rx_bytes = bytes;
++ dev_stats->multicast = mcast;
++ dev_stats->rx_dropped = drops;
++
++ pkts = bytes = 0;
++ for_all_tx_queues(adapter, txo, i) {
++ pkts += tx_stats(txo)->be_tx_pkts;
++ bytes += tx_stats(txo)->be_tx_bytes;
++ }
++ dev_stats->tx_packets = pkts;
++ dev_stats->tx_bytes = bytes;
+
+ /* bad pkts received */
+- dev_stats->rx_errors = port_stats->rx_crc_errors +
+- port_stats->rx_alignment_symbol_errors +
+- port_stats->rx_in_range_errors +
+- port_stats->rx_out_range_errors +
+- port_stats->rx_frame_too_long +
+- port_stats->rx_dropped_too_small +
+- port_stats->rx_dropped_too_short +
+- port_stats->rx_dropped_header_too_small +
+- port_stats->rx_dropped_tcp_length +
+- port_stats->rx_dropped_runt +
+- port_stats->rx_tcp_checksum_errs +
+- port_stats->rx_ip_checksum_errs +
+- port_stats->rx_udp_checksum_errs;
+-
+- /* no space in linux buffers: best possible approximation */
+- dev_stats->rx_dropped = erx_stats->rx_drops_no_fragments[0];
++ dev_stats->rx_errors = drvs->rx_crc_errors +
++ drvs->rx_alignment_symbol_errors +
++ drvs->rx_in_range_errors +
++ drvs->rx_out_range_errors +
++ drvs->rx_frame_too_long +
++ drvs->rx_dropped_too_small +
++ drvs->rx_dropped_too_short +
++ drvs->rx_dropped_header_too_small +
++ drvs->rx_dropped_tcp_length +
++ drvs->rx_dropped_runt +
++ drvs->rx_tcp_checksum_errs +
++ drvs->rx_ip_checksum_errs +
++ drvs->rx_udp_checksum_errs;
+
+ /* detailed rx errors */
+- dev_stats->rx_length_errors = port_stats->rx_in_range_errors +
+- port_stats->rx_out_range_errors +
+- port_stats->rx_frame_too_long;
++ dev_stats->rx_length_errors = drvs->rx_in_range_errors +
++ drvs->rx_out_range_errors +
++ drvs->rx_frame_too_long;
+
+- /* receive ring buffer overflow */
+- dev_stats->rx_over_errors = 0;
+-
+- dev_stats->rx_crc_errors = port_stats->rx_crc_errors;
++ dev_stats->rx_crc_errors = drvs->rx_crc_errors;
+
+ /* frame alignment errors */
+- dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors;
++ dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;
+
+ /* receiver fifo overrun */
+ /* drops_no_pbuf is no per i/f, it's per BE card */
+- dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow +
+- port_stats->rx_input_fifo_overflow +
+- rxf_stats->rx_drops_no_pbuf;
+- /* receiver missed packetd */
+- dev_stats->rx_missed_errors = 0;
+-
+- /* packet transmit problems */
+- dev_stats->tx_errors = 0;
+-
+- /* no space available in linux */
+- dev_stats->tx_dropped = 0;
+-
+- dev_stats->multicast = port_stats->rx_multicast_frames;
+- dev_stats->collisions = 0;
+-
+- /* detailed tx_errors */
+- dev_stats->tx_aborted_errors = 0;
+- dev_stats->tx_carrier_errors = 0;
+- dev_stats->tx_fifo_errors = 0;
+- dev_stats->tx_heartbeat_errors = 0;
+- dev_stats->tx_window_errors = 0;
++ dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop +
++ drvs->rx_input_fifo_overflow_drop +
++ drvs->rx_drops_no_pbuf;
+ }
+
+-void be_link_status_update(struct be_adapter *adapter, bool link_up)
++void be_link_status_update(struct be_adapter *adapter, int link_status)
+ {
+ struct net_device *netdev = adapter->netdev;
+
+ /* If link came up or went down */
+- if (adapter->link_up != link_up) {
+- if (link_up) {
++ if (adapter->link_status != link_status) {
++ adapter->link_speed = -1;
++ if (link_status == LINK_UP) {
+ netif_start_queue(netdev);
+ netif_carrier_on(netdev);
+ printk(KERN_INFO "%s: Link up\n", netdev->name);
+@@ -222,15 +491,15 @@ void be_link_status_update(struct be_adapter *adapter, bool link_up)
+ netif_carrier_off(netdev);
+ printk(KERN_INFO "%s: Link down\n", netdev->name);
+ }
+- adapter->link_up = link_up;
++ adapter->link_status = link_status;
+ }
+ }
+
+ /* Update the EQ delay n BE based on the RX frags consumed / sec */
+-static void be_rx_eqd_update(struct be_adapter *adapter)
++static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
+ {
+- struct be_eq_obj *rx_eq = &adapter->rx_eq;
+- struct be_drvr_stats *stats = &adapter->stats.drvr_stats;
++ struct be_eq_obj *rx_eq = &rxo->rx_eq;
++ struct be_rx_stats *stats = &rxo->stats;
+ ulong now = jiffies;
+ u32 eqd;
+
+@@ -247,19 +516,17 @@ static void be_rx_eqd_update(struct be_adapter *adapter)
+ if ((now - stats->rx_fps_jiffies) < HZ)
+ return;
+
+- stats->be_rx_fps = (stats->be_rx_frags - stats->be_prev_rx_frags) /
++ stats->rx_fps = (stats->rx_frags - stats->prev_rx_frags) /
+ ((now - stats->rx_fps_jiffies) / HZ);
+
+ stats->rx_fps_jiffies = now;
+- stats->be_prev_rx_frags = stats->be_rx_frags;
+- eqd = stats->be_rx_fps / 110000;
++ stats->prev_rx_frags = stats->rx_frags;
++ eqd = stats->rx_fps / 110000;
+ eqd = eqd << 3;
+ if (eqd > rx_eq->max_eqd)
+ eqd = rx_eq->max_eqd;
+ if (eqd < rx_eq->min_eqd)
+ eqd = rx_eq->min_eqd;
+- if (eqd < 10)
+- eqd = 0;
+ if (eqd != rx_eq->cur_eqd)
+ be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd);
+
+@@ -270,7 +537,7 @@ static struct net_device_stats *be_get_stats(struct net_device *dev)
+ {
+ struct be_adapter *adapter = netdev_priv(dev);
+
+- return &adapter->stats.net_stats;
++ return &adapter->net_stats;
+ }
+
+ static u32 be_calc_rate(u64 bytes, unsigned long ticks)
+@@ -284,9 +551,9 @@ static u32 be_calc_rate(u64 bytes, unsigned long ticks)
+ return rate;
+ }
+
+-static void be_tx_rate_update(struct be_adapter *adapter)
++static void be_tx_rate_update(struct be_tx_obj *txo)
+ {
+- struct be_drvr_stats *stats = drvr_stats(adapter);
++ struct be_tx_stats *stats = tx_stats(txo);
+ ulong now = jiffies;
+
+ /* Wrapped around? */
+@@ -305,10 +572,11 @@ static void be_tx_rate_update(struct be_adapter *adapter)
+ }
+ }
+
+-static void be_tx_stats_update(struct be_adapter *adapter,
++static void be_tx_stats_update(struct be_tx_obj *txo,
+ u32 wrb_cnt, u32 copied, u32 gso_segs, bool stopped)
+ {
+- struct be_drvr_stats *stats = drvr_stats(adapter);
++ struct be_tx_stats *stats = tx_stats(txo);
++
+ stats->be_tx_reqs++;
+ stats->be_tx_wrbs += wrb_cnt;
+ stats->be_tx_bytes += copied;
+@@ -318,7 +586,8 @@ static void be_tx_stats_update(struct be_adapter *adapter,
+ }
+
+ /* Determine number of WRB entries needed to xmit data in an skb */
+-static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy)
++static u32 wrb_cnt_for_skb(struct be_adapter *adapter, struct sk_buff *skb,
++ bool *dummy)
+ {
+ int cnt = (skb->len > skb->data_len);
+
+@@ -326,12 +595,13 @@ static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy)
+
+ /* to account for hdr wrb */
+ cnt++;
+- if (cnt & 1) {
++ if (lancer_chip(adapter) || !(cnt & 1)) {
++ *dummy = false;
++ } else {
+ /* add a dummy to make it an even num */
+ cnt++;
+ *dummy = true;
+- } else
+- *dummy = false;
++ }
+ BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT);
+ return cnt;
+ }
+@@ -343,17 +613,31 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
+ wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
+ }
+
+-static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
+- bool vlan, u32 wrb_cnt, u32 len)
++static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
++ struct sk_buff *skb, u32 wrb_cnt, u32 len)
+ {
++ u16 vlan_tag = 0;
++
+ memset(hdr, 0, sizeof(*hdr));
+
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
+
+- if (skb_shinfo(skb)->gso_segs > 1 && skb_shinfo(skb)->gso_size) {
++ if (skb_is_gso(skb)) {
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1);
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss,
+ hdr, skb_shinfo(skb)->gso_size);
++ if (skb_is_gso_v6(skb) && !lancer_chip(adapter))
++ AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
++
++ if (lancer_A0_chip(adapter)) {
++ AMAP_SET_BITS(struct amap_eth_hdr_wrb, ipcs, hdr, 1);
++ if (is_tcp_pkt(skb))
++ AMAP_SET_BITS(struct amap_eth_hdr_wrb,
++ tcpcs, hdr, 1);
++ else if (is_udp_pkt(skb))
++ AMAP_SET_BITS(struct amap_eth_hdr_wrb,
++ udpcs, hdr, 1);
++ }
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (is_tcp_pkt(skb))
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
+@@ -361,10 +645,10 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1);
+ }
+
+- if (vlan && vlan_tx_tag_present(skb)) {
++ if (adapter->vlan_grp && vlan_tx_tag_present(skb)) {
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
+- AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag,
+- hdr, vlan_tx_tag_get(skb));
++ vlan_tag = be_get_tx_vlan_tag(adapter, skb);
++ AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
+ }
+
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1);
+@@ -374,14 +658,13 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
+ }
+
+
+-static int make_tx_wrbs(struct be_adapter *adapter,
++static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq,
+ struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb)
+ {
+- u64 busaddr;
+- u32 i, copied = 0;
++ dma_addr_t busaddr;
++ int i, copied = 0;
+ struct pci_dev *pdev = adapter->pdev;
+ struct sk_buff *first_skb = skb;
+- struct be_queue_info *txq = &adapter->tx_obj.q;
+ struct be_eth_wrb *wrb;
+ struct be_eth_hdr_wrb *hdr;
+
+@@ -389,15 +672,11 @@ static int make_tx_wrbs(struct be_adapter *adapter,
+ atomic_add(wrb_cnt, &txq->used);
+ queue_head_inc(txq);
+
+- if (skb_dma_map(&pdev->dev, skb, DMA_TO_DEVICE)) {
+- dev_err(&pdev->dev, "TX DMA mapping failed\n");
+- return 0;
+- }
+-
+ if (skb->len > skb->data_len) {
+- int len = skb->len - skb->data_len;
++ int len = skb_headlen(skb);
++ busaddr = pci_map_single(pdev, skb->data, len,
++ PCI_DMA_TODEVICE);
+ wrb = queue_head_node(txq);
+- busaddr = skb_shinfo(skb)->dma_head;
+ wrb_fill(wrb, busaddr, len);
+ be_dws_cpu_to_le(wrb, sizeof(*wrb));
+ queue_head_inc(txq);
+@@ -407,8 +686,9 @@ static int make_tx_wrbs(struct be_adapter *adapter,
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ struct skb_frag_struct *frag =
+ &skb_shinfo(skb)->frags[i];
+-
+- busaddr = skb_shinfo(skb)->dma_maps[i];
++ busaddr = pci_map_page(pdev, frag->page,
++ frag->page_offset,
++ frag->size, PCI_DMA_TODEVICE);
+ wrb = queue_head_node(txq);
+ wrb_fill(wrb, busaddr, frag->size);
+ be_dws_cpu_to_le(wrb, sizeof(*wrb));
+@@ -423,8 +703,7 @@ static int make_tx_wrbs(struct be_adapter *adapter,
+ queue_head_inc(txq);
+ }
+
+- wrb_fill_hdr(hdr, first_skb, adapter->vlan_grp ? true : false,
+- wrb_cnt, copied);
++ wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied);
+ be_dws_cpu_to_le(hdr, sizeof(*hdr));
+
+ return copied;
+@@ -434,19 +713,70 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+- struct be_tx_obj *tx_obj = &adapter->tx_obj;
+- struct be_queue_info *txq = &tx_obj->q;
++ struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)];
++ struct be_queue_info *txq = &txo->q;
+ u32 wrb_cnt = 0, copied = 0;
+ u32 start = txq->head;
+ bool dummy_wrb, stopped = false;
+
+- wrb_cnt = wrb_cnt_for_skb(skb, &dummy_wrb);
++ if (unlikely((skb_shinfo(skb)->gso_segs > 1) &&
++ skb_shinfo(skb)->gso_size && is_ipv6_ext_hdr(skb))) {
++ tx_stats(txo)->be_ipv6_ext_hdr_tx_drop++;
++ goto tx_drop;
++ }
+
+- copied = make_tx_wrbs(adapter, skb, wrb_cnt, dummy_wrb);
++ /* If the skb is a large pkt forwarded to this interface
++ * after being LRO'd on another interface, drop the pkt.
++ * HW cannot handle such pkts. LRO must be disabled when
++ * using the server as a router.
++ */
++ if (!skb_is_gso(skb)) {
++ int eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
++ VLAN_ETH_HLEN : ETH_HLEN;
++
++ if ((skb->len - eth_hdr_len) > adapter->netdev->mtu)
++ goto tx_drop;
++ }
++
++ /* The ASIC is calculating checksum for Vlan tagged pkts
++ * though CSO is disabled.
++ * To work around this, insert the Vlan tag in the driver
++ * and donot set the vlan bit, cso bit in the Tx WRB.
++ */
++ if (unlikely(vlan_tx_tag_present(skb) &&
++ ((skb->ip_summed != CHECKSUM_PARTIAL) || (skb->len <= 60)))) {
++ /* Bug 28694: Don't embed the host VLAN tag in SKB
++ * when UMC mode enabled on that interface
++ */
++ if (!(adapter->function_mode & UMC_ENABLED)) {
++ skb = skb_share_check(skb, GFP_ATOMIC);
++ if (unlikely(!skb))
++ goto tx_drop;
++
++ skb = be_vlan_put_tag(skb,
++ be_get_tx_vlan_tag(adapter, skb));
++ if (unlikely(!skb))
++ goto tx_drop;
++
++ be_reset_skb_tx_vlan(skb);
++ }
++ }
++
++ /* Bug 12422: the stack can send us skbs with length more than 65535
++ * BE cannot handle such requests. Hack the extra data out and drop it.
++ */
++ if (skb->len > 65535) {
++ int err = __pskb_trim(skb, 65535);
++ BUG_ON(err);
++ }
++
++ wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
++
++ copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb);
+ if (copied) {
+ /* record the sent skb in the sent_skb table */
+- BUG_ON(tx_obj->sent_skb_list[start]);
+- tx_obj->sent_skb_list[start] = skb;
++ BUG_ON(txo->sent_skb_list[start]);
++ txo->sent_skb_list[start] = skb;
+
+ /* Ensure txq has space for the next skb; Else stop the queue
+ * *BEFORE* ringing the tx doorbell, so that we serialze the
+@@ -454,16 +784,21 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
+ */
+ if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >=
+ txq->len) {
+- netif_stop_queue(netdev);
++ netif_stop_subqueue(netdev, skb_get_queue_mapping(skb));
+ stopped = true;
+ }
+
+ be_txq_notify(adapter, txq->id, wrb_cnt);
+
+- be_tx_stats_update(adapter, wrb_cnt, copied,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
++ netdev->trans_start = jiffies;
++#endif
++
++ be_tx_stats_update(txo, wrb_cnt, copied,
+ skb_shinfo(skb)->gso_segs, stopped);
+ } else {
+ txq->head = start;
++tx_drop:
+ dev_kfree_skb_any(skb);
+ }
+ return NETDEV_TX_OK;
+@@ -473,10 +808,12 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+ if (new_mtu < BE_MIN_MTU ||
+- new_mtu > BE_MAX_JUMBO_FRAME_SIZE) {
++ new_mtu > (BE_MAX_JUMBO_FRAME_SIZE -
++ (ETH_HLEN + ETH_FCS_LEN))) {
+ dev_info(&adapter->pdev->dev,
+ "MTU must be between %d and %d bytes\n",
+- BE_MIN_MTU, BE_MAX_JUMBO_FRAME_SIZE);
++ BE_MIN_MTU,
++ (BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN)));
+ return -EINVAL;
+ }
+ dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n",
+@@ -486,17 +823,19 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
+ }
+
+ /*
+- * if there are BE_NUM_VLANS_SUPPORTED or lesser number of VLANS configured,
+- * program them in BE. If more than BE_NUM_VLANS_SUPPORTED are configured,
+- * set the BE in promiscuous VLAN mode.
++ * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE.
++ * If the user configures more, place BE in vlan promiscuous mode.
+ */
+-static int be_vid_config(struct be_adapter *adapter)
++static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
+ {
+ u16 vtag[BE_NUM_VLANS_SUPPORTED];
+ u16 ntags = 0, i;
+- int status;
++ int status = 0;
+
+- if (adapter->num_vlans <= BE_NUM_VLANS_SUPPORTED) {
++ /* No need to change the VLAN state if the I/F is in promiscous */
++ if (adapter->promiscuous)
++ return 0;
++ if (adapter->vlans_added <= adapter->max_vlans) {
+ /* Construct VLAN Table to give to HW */
+ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ if (adapter->vlan_tag[i]) {
+@@ -504,47 +843,46 @@ static int be_vid_config(struct be_adapter *adapter)
+ ntags++;
+ }
+ }
+- status = be_cmd_vlan_config(adapter, adapter->if_handle,
+- vtag, ntags, 1, 0);
++ /* Send command only if there is something to be programmed */
++ if (ntags)
++ status = be_cmd_vlan_config(adapter, adapter->if_handle,
++ vtag, ntags, 1, 0);
+ } else {
+ status = be_cmd_vlan_config(adapter, adapter->if_handle,
+- NULL, 0, 1, 1);
++ NULL, 0, 1, 1);
+ }
++
+ return status;
+ }
+
+ static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+- struct be_eq_obj *rx_eq = &adapter->rx_eq;
+- struct be_eq_obj *tx_eq = &adapter->tx_eq;
+
+- be_eq_notify(adapter, rx_eq->q.id, false, false, 0);
+- be_eq_notify(adapter, tx_eq->q.id, false, false, 0);
+ adapter->vlan_grp = grp;
+- be_eq_notify(adapter, rx_eq->q.id, true, false, 0);
+- be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
+ }
+
+ static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+- adapter->num_vlans++;
++ adapter->vlans_added++;
++
+ adapter->vlan_tag[vid] = 1;
+-
+- be_vid_config(adapter);
++ if (adapter->vlans_added <= (adapter->max_vlans + 1))
++ be_vid_config(adapter, false, 0);
+ }
+
+ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+- adapter->num_vlans--;
+- adapter->vlan_tag[vid] = 0;
+-
++ adapter->vlans_added--;
+ vlan_group_set_device(adapter->vlan_grp, vid, NULL);
+- be_vid_config(adapter);
++
++ adapter->vlan_tag[vid] = 0;
++ if (adapter->vlans_added <= adapter->max_vlans)
++ be_vid_config(adapter, false, 0);
+ }
+
+ static void be_set_multicast_list(struct net_device *netdev)
+@@ -552,7 +890,7 @@ static void be_set_multicast_list(struct net_device *netdev)
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ if (netdev->flags & IFF_PROMISC) {
+- be_cmd_promiscuous_config(adapter, adapter->port_num, 1);
++ be_cmd_rx_filter(adapter, IFF_PROMISC, ON);
+ adapter->promiscuous = true;
+ goto done;
+ }
+@@ -560,81 +898,244 @@ static void be_set_multicast_list(struct net_device *netdev)
+ /* BE was previously in promiscous mode; disable it */
+ if (adapter->promiscuous) {
+ adapter->promiscuous = false;
+- be_cmd_promiscuous_config(adapter, adapter->port_num, 0);
++ be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
++
++ if (adapter->vlans_added)
++ be_vid_config(adapter, false, 0);
+ }
+
+- if (netdev->flags & IFF_ALLMULTI) {
+- be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0);
++ /* Enable multicast promisc if num configured exceeds what we support */
++ if (netdev->flags & IFF_ALLMULTI ||
++ netdev_mc_count(netdev) > BE_MAX_MC) {
++ be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON);
+ goto done;
+ }
+
+- be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list,
+- netdev->mc_count);
++ be_cmd_rx_filter(adapter, IFF_MULTICAST, ON);
+ done:
+ return;
+ }
+
+-static void be_rx_rate_update(struct be_adapter *adapter)
++#ifdef HAVE_SRIOV_CONFIG
++static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+ {
+- struct be_drvr_stats *stats = drvr_stats(adapter);
++ struct be_adapter *adapter = netdev_priv(netdev);
++ int status;
++
++ if (adapter->num_vfs == 0)
++ return -EPERM;
++
++ if (!is_valid_ether_addr(mac) || (vf >= adapter->num_vfs))
++ return -EINVAL;
++
++ if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
++ status = be_cmd_pmac_del(adapter,
++ adapter->vf_cfg[vf].vf_if_handle,
++ adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
++
++ status = be_cmd_pmac_add(adapter, mac,
++ adapter->vf_cfg[vf].vf_if_handle,
++ &adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
++
++ if (status)
++ dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
++ mac, vf);
++ else
++ memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
++
++ return status;
++}
++
++static int be_get_vf_config(struct net_device *netdev, int vf,
++ struct ifla_vf_info *vi)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++
++ if (adapter->num_vfs == 0)
++ return -EPERM;
++
++ if (vf >= adapter->num_vfs)
++ return -EINVAL;
++
++ vi->vf = vf;
++ vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate;
++ vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag & VLAN_VID_MASK;
++ vi->qos = adapter->vf_cfg[vf].vf_vlan_tag >> VLAN_PRIO_SHIFT;
++ memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN);
++
++ return 0;
++}
++
++/*
++ * Entry point to configure vlan behavior for a VF.
++ * 1. By default a VF is vlan Challenged.
++ * 2. It may or may not have Transparent Tagging enabled.
++ * 3. Vlan privilege for a VF can be toggled using special VID 4095.
++ * 4. When removing the Vlan privilege for a VF there is no need set default vid
++ * 5. Transparent Tagging configured for a VF resets its Vlan privilege
++ * 6. To disable the current Transparet Tagging for a VF:
++ * 6a. run the last iproute command with vlan set to 0.
++ * 6b. programing the default vid will disable Transparent Tagging in ARM/ASIC
++ */
++static int be_set_vf_vlan(struct net_device *netdev,
++ int vf, u16 vlan, u8 qos)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ int status = 0;
++ u32 en = 0;
++
++ if (adapter->num_vfs == 0)
++ return -EPERM;
++
++ if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7))
++ return -EINVAL;
++
++ status = be_cmd_get_fn_privileges(adapter, &en, vf + 1);
++ if (status)
++ goto sts;
++
++ if (vlan == 4095) {
++ if (en & BE_PRIV_FILTMGMT) {
++ /* Knock off filtering privileges */
++ en &= ~BE_PRIV_FILTMGMT;
++ } else {
++ en |= BE_PRIV_FILTMGMT;
++ /* Transparent Tagging is currently enabled, Reset it */
++ if (adapter->vf_cfg[vf].vf_vlan_tag) {
++ adapter->vf_cfg[vf].vf_vlan_tag = 0;
++ vlan = adapter->vf_cfg[vf].vf_def_vid;
++ be_cmd_set_hsw_config(adapter, vlan, vf + 1,
++ adapter->vf_cfg[vf].vf_if_handle);
++ }
++ }
++
++ adapter->vf_cfg[vf].vf_vlan_tag = 0;
++ status = be_cmd_set_fn_privileges(adapter, en, NULL, vf + 1);
++
++ goto sts;
++ }
++
++ if (vlan || qos) {
++ if (en & BE_PRIV_FILTMGMT) {
++ /* Check privilege and reset it to default */
++ en &= ~BE_PRIV_FILTMGMT;
++ be_cmd_set_fn_privileges(adapter, en, NULL, vf + 1);
++ }
++
++ vlan |= qos << VLAN_PRIO_SHIFT;
++ if (adapter->vf_cfg[vf].vf_vlan_tag != vlan) {
++ /* If this is new value, program it. Else skip. */
++ adapter->vf_cfg[vf].vf_vlan_tag = vlan;
++
++ status = be_cmd_set_hsw_config(adapter, vlan,
++ vf + 1, adapter->vf_cfg[vf].vf_if_handle);
++ }
++
++ } else {
++ /* Reset Transparent Vlan Tagging. */
++ adapter->vf_cfg[vf].vf_vlan_tag = 0;
++ vlan = adapter->vf_cfg[vf].vf_def_vid;
++ status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
++ adapter->vf_cfg[vf].vf_if_handle);
++ }
++
++sts:
++ if (status)
++ dev_info(&adapter->pdev->dev,
++ "VLAN %d config on VF %d failed\n", vlan, vf);
++ return status;
++}
++
++static int be_set_vf_tx_rate(struct net_device *netdev,
++ int vf, int rate)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ int status = 0;
++
++ if (adapter->num_vfs == 0)
++ return -EPERM;
++
++ if ((vf >= adapter->num_vfs) || (rate < 0))
++ return -EINVAL;
++
++ if (rate > 10000)
++ rate = 10000;
++
++ adapter->vf_cfg[vf].vf_tx_rate = rate;
++ status = be_cmd_set_qos(adapter, rate / 10, vf + 1);
++
++ if (status)
++ dev_info(&adapter->pdev->dev,
++ "tx rate %d on VF %d failed\n", rate, vf);
++ return status;
++}
++#endif /* HAVE_SRIOV_CONFIG */
++
++static void be_rx_rate_update(struct be_rx_obj *rxo)
++{
++ struct be_rx_stats *stats = &rxo->stats;
+ ulong now = jiffies;
+
+ /* Wrapped around */
+- if (time_before(now, stats->be_rx_jiffies)) {
+- stats->be_rx_jiffies = now;
++ if (time_before(now, stats->rx_jiffies)) {
++ stats->rx_jiffies = now;
+ return;
+ }
+
+ /* Update the rate once in two seconds */
+- if ((now - stats->be_rx_jiffies) < 2 * HZ)
++ if ((now - stats->rx_jiffies) < 2 * HZ)
+ return;
+
+- stats->be_rx_rate = be_calc_rate(stats->be_rx_bytes
+- - stats->be_rx_bytes_prev,
+- now - stats->be_rx_jiffies);
+- stats->be_rx_jiffies = now;
+- stats->be_rx_bytes_prev = stats->be_rx_bytes;
++ stats->rx_rate = be_calc_rate(stats->rx_bytes - stats->rx_bytes_prev,
++ now - stats->rx_jiffies);
++ stats->rx_jiffies = now;
++ stats->rx_bytes_prev = stats->rx_bytes;
+ }
+
+-static void be_rx_stats_update(struct be_adapter *adapter,
+- u32 pktsize, u16 numfrags)
++static void be_rx_stats_update(struct be_rx_obj *rxo,
++ struct be_rx_compl_info *rxcp)
+ {
+- struct be_drvr_stats *stats = drvr_stats(adapter);
++ struct be_rx_stats *stats = &rxo->stats;
+
+- stats->be_rx_compl++;
+- stats->be_rx_frags += numfrags;
+- stats->be_rx_bytes += pktsize;
+- stats->be_rx_pkts++;
++ stats->rx_compl++;
++ stats->rx_frags += rxcp->num_rcvd;
++ stats->rx_bytes += rxcp->pkt_size;
++ stats->rx_pkts++;
++ if (rxcp->pkt_type == BE_MULTICAST_PACKET)
++ stats->rx_mcast_pkts++;
++ if (rxcp->err)
++ stats->rxcp_err++;
+ }
+
+-static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso)
++static inline bool csum_passed(struct be_rx_compl_info *rxcp)
+ {
+- u8 l4_cksm, ip_version, ipcksm, tcpf = 0, udpf = 0, ipv6_chk;
+-
+- l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp);
+- ipcksm = AMAP_GET_BITS(struct amap_eth_rx_compl, ipcksm, rxcp);
+- ip_version = AMAP_GET_BITS(struct amap_eth_rx_compl, ip_version, rxcp);
+- if (ip_version) {
+- tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
+- udpf = AMAP_GET_BITS(struct amap_eth_rx_compl, udpf, rxcp);
+- }
+- ipv6_chk = (ip_version && (tcpf || udpf));
+-
+- return ((l4_cksm && ipv6_chk && ipcksm) && cso) ? false : true;
++ /* L4 checksum is not reliable for non TCP/UDP packets.
++ * Also ignore ipcksm for ipv6 pkts */
++ return (rxcp->tcpf || rxcp->udpf) && rxcp->l4_csum &&
++ (rxcp->ip_csum || rxcp->ipv6);
+ }
+
+ static struct be_rx_page_info *
+-get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
++get_rx_page_info(struct be_adapter *adapter, struct be_rx_obj *rxo,
++ u16 frag_idx)
+ {
+ struct be_rx_page_info *rx_page_info;
+- struct be_queue_info *rxq = &adapter->rx_obj.q;
++ struct be_queue_info *rxq = &rxo->q;
+
+- rx_page_info = &adapter->rx_obj.page_info_tbl[frag_idx];
+- BUG_ON(!rx_page_info->page);
++ rx_page_info = &rxo->page_info_tbl[frag_idx];
++ if (!rx_page_info->page) {
++ printk(KERN_EMERG "curr_idx=%d prev_dix=%d rxq->head=%d\n",
++ frag_idx, rxo->prev_frag_idx, rxq->head);
++ BUG_ON(!rx_page_info->page);
++ }
+
+- if (rx_page_info->last_page_user)
++ if (rx_page_info->last_page_user) {
+ pci_unmap_page(adapter->pdev, pci_unmap_addr(rx_page_info, bus),
+ adapter->big_page_size, PCI_DMA_FROMDEVICE);
++ rx_page_info->last_page_user = false;
++ }
++
++ rxo->prev_frag_idx = frag_idx;
+
+ atomic_dec(&rxq->used);
+ return rx_page_info;
+@@ -642,20 +1143,26 @@ get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
+
+ /* Throwaway the data in the Rx completion */
+ static void be_rx_compl_discard(struct be_adapter *adapter,
+- struct be_eth_rx_compl *rxcp)
++ struct be_rx_obj *rxo,
++ struct be_rx_compl_info *rxcp)
+ {
+- struct be_queue_info *rxq = &adapter->rx_obj.q;
++ struct be_queue_info *rxq = &rxo->q;
+ struct be_rx_page_info *page_info;
+- u16 rxq_idx, i, num_rcvd;
++ u16 i;
++ bool oob_error;
++ u16 num_rcvd = rxcp->num_rcvd;
+
+- rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
++ oob_error = lancer_A0_chip(adapter) && rxcp->err;
++
++ /* In case of OOB error num_rcvd will be 1 more than actual */
++ if (oob_error && num_rcvd)
++ num_rcvd -= 1;
+
+ for (i = 0; i < num_rcvd; i++) {
+- page_info = get_rx_page_info(adapter, rxq_idx);
++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
+ put_page(page_info->page);
+ memset(page_info, 0, sizeof(*page_info));
+- index_inc(&rxq_idx, rxq->len);
++ index_inc(&rxcp->rxq_idx, rxq->len);
+ }
+ }
+
+@@ -663,29 +1170,24 @@ static void be_rx_compl_discard(struct be_adapter *adapter,
+ * skb_fill_rx_data forms a complete skb for an ether frame
+ * indicated by rxcp.
+ */
+-static void skb_fill_rx_data(struct be_adapter *adapter,
+- struct sk_buff *skb, struct be_eth_rx_compl *rxcp)
++static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo,
++ struct sk_buff *skb, struct be_rx_compl_info *rxcp)
+ {
+- struct be_queue_info *rxq = &adapter->rx_obj.q;
++ struct be_queue_info *rxq = &rxo->q;
+ struct be_rx_page_info *page_info;
+- u16 rxq_idx, i, num_rcvd, j;
+- u32 pktsize, hdr_len, curr_frag_len, size;
++ u16 i, j;
++ u16 hdr_len, curr_frag_len, remaining;
+ u8 *start;
+
+- rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+- pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
+- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+-
+- page_info = get_rx_page_info(adapter, rxq_idx);
+-
++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
+ start = page_address(page_info->page) + page_info->page_offset;
+ prefetch(start);
+
+ /* Copy data in the first descriptor of this completion */
+- curr_frag_len = min(pktsize, rx_frag_size);
++ curr_frag_len = min(rxcp->pkt_size, rx_frag_size);
+
+ /* Copy the header portion into skb_data */
+- hdr_len = min((u32)BE_HDR_LEN, curr_frag_len);
++ hdr_len = min(BE_HDR_LEN, curr_frag_len);
+ memcpy(skb->data, start, hdr_len);
+ skb->len = curr_frag_len;
+ if (curr_frag_len <= BE_HDR_LEN) { /* tiny packet */
+@@ -702,21 +1204,19 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
+ skb->data_len = curr_frag_len - hdr_len;
+ skb->tail += hdr_len;
+ }
+- memset(page_info, 0, sizeof(*page_info));
++ page_info->page = NULL;
+
+- if (pktsize <= rx_frag_size) {
+- BUG_ON(num_rcvd != 1);
+- goto done;
++ if (rxcp->pkt_size <= rx_frag_size) {
++ BUG_ON(rxcp->num_rcvd != 1);
++ return;
+ }
+
+ /* More frags present for this completion */
+- size = pktsize;
+- for (i = 1, j = 0; i < num_rcvd; i++) {
+- size -= curr_frag_len;
+- index_inc(&rxq_idx, rxq->len);
+- page_info = get_rx_page_info(adapter, rxq_idx);
+-
+- curr_frag_len = min(size, rx_frag_size);
++ index_inc(&rxcp->rxq_idx, rxq->len);
++ remaining = rxcp->pkt_size - curr_frag_len;
++ for (i = 1, j = 0; i < rxcp->num_rcvd; i++) {
++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
++ curr_frag_len = min(remaining, rx_frag_size);
+
+ /* Coalesce all frags from the same physical page in one slot */
+ if (page_info->page_offset == 0) {
+@@ -735,99 +1235,122 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
+ skb->len += curr_frag_len;
+ skb->data_len += curr_frag_len;
+
+- memset(page_info, 0, sizeof(*page_info));
++ remaining -= curr_frag_len;
++ index_inc(&rxcp->rxq_idx, rxq->len);
++ page_info->page = NULL;
+ }
+ BUG_ON(j > MAX_SKB_FRAGS);
+-
+-done:
+- be_rx_stats_update(adapter, pktsize, num_rcvd);
+- return;
+ }
+
+-/* Process the RX completion indicated by rxcp when GRO is disabled */
++/* Process the RX completion indicated by rxcp when LRO is disabled */
+ static void be_rx_compl_process(struct be_adapter *adapter,
+- struct be_eth_rx_compl *rxcp)
++ struct be_rx_obj *rxo,
++ struct be_rx_compl_info *rxcp)
+ {
+ struct sk_buff *skb;
+- u32 vlanf, vid;
+- u8 vtm;
+
+- vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
+- vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp);
+-
+- /* vlanf could be wrongly set in some cards.
+- * ignore if vtm is not set */
+- if ((adapter->cap == 0x400) && !vtm)
+- vlanf = 0;
+-
+- skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN);
+- if (!skb) {
++ skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
++ if (unlikely(!skb)) {
+ if (net_ratelimit())
+ dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
+- be_rx_compl_discard(adapter, rxcp);
++ be_rx_compl_discard(adapter, rxo, rxcp);
+ return;
+ }
+
+- skb_reserve(skb, NET_IP_ALIGN);
++ skb_fill_rx_data(adapter, rxo, skb, rxcp);
+
+- skb_fill_rx_data(adapter, skb, rxcp);
+-
+- if (do_pkt_csum(rxcp, adapter->rx_csum))
+- skb->ip_summed = CHECKSUM_NONE;
+- else
++ if (likely(adapter->rx_csum && csum_passed(rxcp)))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ else
++ skb->ip_summed = CHECKSUM_NONE;
+
+ skb->truesize = skb->len + sizeof(struct sk_buff);
++ if (unlikely(rxcp->vlanf) &&
++ unlikely(!vlan_configured(adapter))) {
++ __vlan_put_tag(skb, rxcp->vlan_tag);
++ }
+ skb->protocol = eth_type_trans(skb, adapter->netdev);
+ skb->dev = adapter->netdev;
+
+- if (vlanf) {
+- if (!adapter->vlan_grp || adapter->num_vlans == 0) {
+- kfree_skb(skb);
+- return;
+- }
+- vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
+- vid = be16_to_cpu(vid);
+- vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);
+- } else {
++ if (unlikely(rxcp->vlanf) &&
++ vlan_configured(adapter))
++ vlan_hwaccel_receive_skb(skb, adapter->vlan_grp,
++ rxcp->vlan_tag);
++ else
+ netif_receive_skb(skb);
++
++ return;
++}
++
++/* Process the RX completion indicated by rxcp when LRO is enabled */
++static void be_rx_compl_process_lro(struct be_adapter *adapter,
++ struct be_rx_obj *rxo,
++ struct be_rx_compl_info *rxcp)
++{
++ struct be_rx_page_info *page_info;
++ struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME];
++ struct be_queue_info *rxq = &rxo->q;
++ u16 remaining, curr_frag_len;
++ u16 i, j;
++
++ remaining = rxcp->pkt_size;
++ for (i = 0, j = -1; i < rxcp->num_rcvd; i++) {
++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
++
++ curr_frag_len = min(remaining, rx_frag_size);
++
++ /* Coalesce all frags from the same physical page in one slot */
++ if (i == 0 || page_info->page_offset == 0) {
++ /* First frag or Fresh page */
++ j++;
++ rx_frags[j].page = page_info->page;
++ rx_frags[j].page_offset = page_info->page_offset;
++ rx_frags[j].size = 0;
++ } else {
++ put_page(page_info->page);
++ }
++ rx_frags[j].size += curr_frag_len;
++
++ remaining -= curr_frag_len;
++ index_inc(&rxcp->rxq_idx, rxq->len);
++ memset(page_info, 0, sizeof(*page_info));
++ }
++ BUG_ON(j > MAX_SKB_FRAGS);
++
++ if (likely(!rxcp->vlanf)) {
++ lro_receive_frags(&rxo->lro_mgr, rx_frags, rxcp->pkt_size,
++ rxcp->pkt_size, NULL, 0);
++ } else {
++ lro_vlan_hwaccel_receive_frags(&rxo->lro_mgr, rx_frags,
++ rxcp->pkt_size, rxcp->pkt_size, adapter->vlan_grp,
++ rxcp->vlan_tag, NULL, 0);
+ }
+
+ return;
+ }
+
+ /* Process the RX completion indicated by rxcp when GRO is enabled */
+-static void be_rx_compl_process_gro(struct be_adapter *adapter,
+- struct be_eth_rx_compl *rxcp)
++void be_rx_compl_process_gro(struct be_adapter *adapter,
++ struct be_rx_obj *rxo,
++ struct be_rx_compl_info *rxcp)
+ {
++#ifdef NETIF_F_GRO
+ struct be_rx_page_info *page_info;
+ struct sk_buff *skb = NULL;
+- struct be_queue_info *rxq = &adapter->rx_obj.q;
+- struct be_eq_obj *eq_obj = &adapter->rx_eq;
+- u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
+- u16 i, rxq_idx = 0, vid, j;
+- u8 vtm;
+-
+- num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+- pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
+- vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
+- rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+- vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp);
+-
+- /* vlanf could be wrongly set in some cards.
+- * ignore if vtm is not set */
+- if ((adapter->cap == 0x400) && !vtm)
+- vlanf = 0;
++ struct be_queue_info *rxq = &rxo->q;
++ struct be_eq_obj *eq_obj = &rxo->rx_eq;
++ u16 remaining, curr_frag_len;
++ u16 i, j;
+
+ skb = napi_get_frags(&eq_obj->napi);
+ if (!skb) {
+- be_rx_compl_discard(adapter, rxcp);
++ be_rx_compl_discard(adapter, rxo, rxcp);
+ return;
+ }
+
+- remaining = pkt_size;
+- for (i = 0, j = -1; i < num_rcvd; i++) {
+- page_info = get_rx_page_info(adapter, rxq_idx);
++ remaining = rxcp->pkt_size;
++ for (i = 0, j = -1; i < rxcp->num_rcvd; i++) {
++ page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx);
+
+ curr_frag_len = min(remaining, rx_frag_size);
+
+@@ -845,55 +1368,129 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
+ skb_shinfo(skb)->frags[j].size += curr_frag_len;
+
+ remaining -= curr_frag_len;
+- index_inc(&rxq_idx, rxq->len);
++ index_inc(&rxcp->rxq_idx, rxq->len);
+ memset(page_info, 0, sizeof(*page_info));
+ }
+ BUG_ON(j > MAX_SKB_FRAGS);
+
+ skb_shinfo(skb)->nr_frags = j + 1;
+- skb->len = pkt_size;
+- skb->data_len = pkt_size;
+- skb->truesize += pkt_size;
++ skb->len = rxcp->pkt_size;
++ skb->data_len = rxcp->pkt_size;
++ skb->truesize += rxcp->pkt_size;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+- if (likely(!vlanf)) {
++ if (likely(!rxcp->vlanf))
+ napi_gro_frags(&eq_obj->napi);
+- } else {
+- vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
+- vid = be16_to_cpu(vid);
++ else
++ vlan_gro_frags(&eq_obj->napi,
++ adapter->vlan_grp, rxcp->vlan_tag);
++#endif
+
+- if (!adapter->vlan_grp || adapter->num_vlans == 0)
+- return;
+-
+- vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
+- }
+-
+- be_rx_stats_update(adapter, pkt_size, num_rcvd);
+ return;
+ }
+
+-static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
++static void be_parse_rx_compl_v1(struct be_adapter *adapter,
++ struct be_eth_rx_compl *compl,
++ struct be_rx_compl_info *rxcp)
+ {
+- struct be_eth_rx_compl *rxcp = queue_tail_node(&adapter->rx_obj.cq);
++ rxcp->pkt_size =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, pktsize, compl);
++ rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtp, compl);
++ rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, err, compl);
++ rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, tcpf, compl);
++ rxcp->udpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, udpf, compl);
++ rxcp->ip_csum =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ipcksm, compl);
++ rxcp->l4_csum =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, l4_cksm, compl);
++ rxcp->ipv6 =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ip_version, compl);
++ rxcp->rxq_idx =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, fragndx, compl);
++ rxcp->num_rcvd =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl);
++ rxcp->pkt_type =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
++ if (rxcp->vlanf) {
++ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm,
++ compl);
++ rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1,
++ vlan_tag, compl);
++ }
++ rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, port, compl);
++}
+
+- if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0)
++static void be_parse_rx_compl_v0(struct be_adapter *adapter,
++ struct be_eth_rx_compl *compl,
++ struct be_rx_compl_info *rxcp)
++{
++ rxcp->pkt_size =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, pktsize, compl);
++ rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtp, compl);
++ rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, err, compl);
++ rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, tcpf, compl);
++ rxcp->udpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, udpf, compl);
++ rxcp->ip_csum =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ipcksm, compl);
++ rxcp->l4_csum =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, l4_cksm, compl);
++ rxcp->ipv6 =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ip_version, compl);
++ rxcp->rxq_idx =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, fragndx, compl);
++ rxcp->num_rcvd =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl);
++ rxcp->pkt_type =
++ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
++ if (rxcp->vlanf) {
++ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm,
++ compl);
++ rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0,
++ vlan_tag, compl);
++ }
++ rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, port, compl);
++}
++
++static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
++{
++ struct be_eth_rx_compl *compl = queue_tail_node(&rxo->cq);
++ struct be_rx_compl_info *rxcp = &rxo->rxcp;
++ struct be_adapter *adapter = rxo->adapter;
++
++ /* For checking the valid bit it is Ok to use either definition as the
++ * valid bit is at the same position in both v0 and v1 Rx compl */
++ if (compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] == 0)
+ return NULL;
+
+- be_dws_le_to_cpu(rxcp, sizeof(*rxcp));
++ rmb();
++ be_dws_le_to_cpu(compl, sizeof(*compl));
+
+- queue_tail_inc(&adapter->rx_obj.cq);
++ if (adapter->be3_native)
++ be_parse_rx_compl_v1(adapter, compl, rxcp);
++ else
++ be_parse_rx_compl_v0(adapter, compl, rxcp);
++
++ if (rxcp->vlanf) {
++ /* vlanf could be wrongly set in some cards.
++ * ignore if vtm is not set */
++ if ((adapter->function_mode & FLEX10_MODE) && !rxcp->vtm)
++ rxcp->vlanf = 0;
++
++ if (!lancer_chip(adapter))
++ rxcp->vlan_tag = swab16(rxcp->vlan_tag);
++
++ if ((adapter->pvid == (rxcp->vlan_tag & VLAN_VID_MASK)) &&
++ !adapter->vlan_tag[rxcp->vlan_tag])
++ rxcp->vlanf = 0;
++ }
++
++ /* As the compl has been parsed, reset it; we wont touch it again */
++ compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0;
++
++ queue_tail_inc(&rxo->cq);
+ return rxcp;
+ }
+
+-/* To reset the valid bit, we need to reset the whole word as
+- * when walking the queue the valid entries are little-endian
+- * and invalid entries are host endian
+- */
+-static inline void be_rx_compl_reset(struct be_eth_rx_compl *rxcp)
+-{
+- rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0;
+-}
+-
+ static inline struct page *be_alloc_pages(u32 size)
+ {
+ gfp_t alloc_flags = GFP_ATOMIC;
+@@ -907,11 +1504,12 @@ static inline struct page *be_alloc_pages(u32 size)
+ * Allocate a page, split it to fragments of size rx_frag_size and post as
+ * receive buffers to BE
+ */
+-static void be_post_rx_frags(struct be_adapter *adapter)
++static void be_post_rx_frags(struct be_rx_obj *rxo)
+ {
+- struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl;
+- struct be_rx_page_info *page_info = NULL;
+- struct be_queue_info *rxq = &adapter->rx_obj.q;
++ struct be_adapter *adapter = rxo->adapter;
++ struct be_rx_page_info *page_info_tbl = rxo->page_info_tbl;
++ struct be_rx_page_info *page_info = NULL, *prev_page_info = NULL;
++ struct be_queue_info *rxq = &rxo->q;
+ struct page *pagep = NULL;
+ struct be_eth_rx_d *rxd;
+ u64 page_dmaaddr = 0, frag_dmaaddr;
+@@ -922,7 +1520,7 @@ static void be_post_rx_frags(struct be_adapter *adapter)
+ if (!pagep) {
+ pagep = be_alloc_pages(adapter->big_page_size);
+ if (unlikely(!pagep)) {
+- drvr_stats(adapter)->be_ethrx_post_fail++;
++ rxo->stats.rx_post_fail++;
+ break;
+ }
+ page_dmaaddr = pci_map_page(adapter->pdev, pagep, 0,
+@@ -941,7 +1539,6 @@ static void be_post_rx_frags(struct be_adapter *adapter)
+ rxd = queue_head_node(rxq);
+ rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF);
+ rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr));
+- queue_head_inc(rxq);
+
+ /* Any space left in the current big page for another frag? */
+ if ((page_offset + rx_frag_size + rx_frag_size) >
+@@ -949,17 +1546,24 @@ static void be_post_rx_frags(struct be_adapter *adapter)
+ pagep = NULL;
+ page_info->last_page_user = true;
+ }
++
++ prev_page_info = page_info;
++ queue_head_inc(rxq);
+ page_info = &page_info_tbl[rxq->head];
+ }
+ if (pagep)
+- page_info->last_page_user = true;
++ prev_page_info->last_page_user = true;
+
++ /* Ensure that posting buffers is the last thing done by this
++ * routine to avoid racing between rx bottom-half and
++ * be_worker (process) contexts.
++ */
+ if (posted) {
+ atomic_add(posted, &rxq->used);
+ be_rxq_notify(adapter, rxq->id, posted);
+ } else if (atomic_read(&rxq->used) == 0) {
+ /* Let be_worker replenish when memory is available */
+- adapter->rx_post_starved = true;
++ rxo->rx_post_starved = true;
+ }
+
+ return;
+@@ -972,6 +1576,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
+ if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0)
+ return NULL;
+
++ rmb();
+ be_dws_le_to_cpu(txcp, sizeof(*txcp));
+
+ txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0;
+@@ -980,11 +1585,14 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
+ return txcp;
+ }
+
+-static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
++static u16 be_tx_compl_process(struct be_adapter *adapter,
++ struct be_tx_obj *txo, u16 last_index)
+ {
+- struct be_queue_info *txq = &adapter->tx_obj.q;
+- struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
++ struct be_queue_info *txq = &txo->q;
++ struct be_eth_wrb *wrb;
++ struct sk_buff **sent_skbs = txo->sent_skb_list;
+ struct sk_buff *sent_skb;
++ u64 busaddr;
+ u16 cur_index, num_wrbs = 0;
+
+ cur_index = txq->tail;
+@@ -992,15 +1600,31 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
+ BUG_ON(!sent_skb);
+ sent_skbs[cur_index] = NULL;
+
+- do {
++ wrb = queue_tail_node(txq);
++ be_dws_le_to_cpu(wrb, sizeof(*wrb));
++ busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo;
++ if (busaddr != 0) {
++ pci_unmap_single(adapter->pdev, busaddr,
++ wrb->frag_len, PCI_DMA_TODEVICE);
++ }
++ num_wrbs++;
++ queue_tail_inc(txq);
++
++ while (cur_index != last_index) {
+ cur_index = txq->tail;
++ wrb = queue_tail_node(txq);
++ be_dws_le_to_cpu(wrb, sizeof(*wrb));
++ busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo;
++ if (busaddr != 0) {
++ pci_unmap_page(adapter->pdev, busaddr,
++ wrb->frag_len, PCI_DMA_TODEVICE);
++ }
+ num_wrbs++;
+ queue_tail_inc(txq);
+- } while (cur_index != last_index);
++ }
+
+- atomic_sub(num_wrbs, &txq->used);
+- skb_dma_unmap(&adapter->pdev->dev, sent_skb, DMA_TO_DEVICE);
+ kfree_skb(sent_skb);
++ return num_wrbs;
+ }
+
+ static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj)
+@@ -1010,13 +1634,15 @@ static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj)
+ if (!eqe->evt)
+ return NULL;
+
++ rmb();
+ eqe->evt = le32_to_cpu(eqe->evt);
+ queue_tail_inc(&eq_obj->q);
+ return eqe;
+ }
+
+ static int event_handle(struct be_adapter *adapter,
+- struct be_eq_obj *eq_obj)
++ struct be_eq_obj *eq_obj,
++ bool rearm)
+ {
+ struct be_eq_entry *eqe;
+ u16 num = 0;
+@@ -1029,7 +1655,10 @@ static int event_handle(struct be_adapter *adapter,
+ /* Deal with any spurious interrupts that come
+ * without events
+ */
+- be_eq_notify(adapter, eq_obj->q.id, true, true, num);
++ if (!num)
++ rearm = true;
++
++ be_eq_notify(adapter, eq_obj->q.id, rearm, true, num);
+ if (num)
+ napi_schedule(&eq_obj->napi);
+
+@@ -1053,49 +1682,55 @@ static void be_eq_clean(struct be_adapter *adapter,
+ be_eq_notify(adapter, eq_obj->q.id, false, true, num);
+ }
+
+-static void be_rx_q_clean(struct be_adapter *adapter)
++static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo)
+ {
+ struct be_rx_page_info *page_info;
+- struct be_queue_info *rxq = &adapter->rx_obj.q;
+- struct be_queue_info *rx_cq = &adapter->rx_obj.cq;
+- struct be_eth_rx_compl *rxcp;
++ struct be_queue_info *rxq = &rxo->q;
++ struct be_queue_info *rx_cq = &rxo->cq;
++ struct be_rx_compl_info *rxcp;
+ u16 tail;
+
+ /* First cleanup pending rx completions */
+- while ((rxcp = be_rx_compl_get(adapter)) != NULL) {
+- be_rx_compl_discard(adapter, rxcp);
+- be_rx_compl_reset(rxcp);
++ while ((rxcp = be_rx_compl_get(rxo)) != NULL) {
++ be_rx_compl_discard(adapter, rxo, rxcp);
+ be_cq_notify(adapter, rx_cq->id, true, 1);
+ }
+
+ /* Then free posted rx buffer that were not used */
+ tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len;
+ for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) {
+- page_info = get_rx_page_info(adapter, tail);
++ page_info = get_rx_page_info(adapter, rxo, tail);
+ put_page(page_info->page);
+ memset(page_info, 0, sizeof(*page_info));
+ }
+ BUG_ON(atomic_read(&rxq->used));
++ rxq->tail = rxq->head = 0;
+ }
+
+-static void be_tx_compl_clean(struct be_adapter *adapter)
++static void be_tx_compl_clean(struct be_adapter *adapter,
++ struct be_tx_obj *txo)
+ {
+- struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
+- struct be_queue_info *txq = &adapter->tx_obj.q;
++ struct be_queue_info *tx_cq = &txo->cq;
++ struct be_queue_info *txq = &txo->q;
+ struct be_eth_tx_compl *txcp;
+- u16 end_idx, cmpl = 0, timeo = 0;
++ u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
++ struct sk_buff **sent_skbs = txo->sent_skb_list;
++ struct sk_buff *sent_skb;
++ bool dummy_wrb;
+
+ /* Wait for a max of 200ms for all the tx-completions to arrive. */
+ do {
+ while ((txcp = be_tx_compl_get(tx_cq))) {
+ end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
+ wrb_index, txcp);
+- be_tx_compl_process(adapter, end_idx);
++ num_wrbs += be_tx_compl_process(adapter, txo, end_idx);
+ cmpl++;
+ }
+ if (cmpl) {
+ be_cq_notify(adapter, tx_cq->id, false, cmpl);
++ atomic_sub(num_wrbs, &txq->used);
+ cmpl = 0;
++ num_wrbs = 0;
+ }
+
+ if (atomic_read(&txq->used) == 0 || ++timeo > 200)
+@@ -1107,6 +1742,17 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
+ if (atomic_read(&txq->used))
+ dev_err(&adapter->pdev->dev, "%d pending tx-completions\n",
+ atomic_read(&txq->used));
++
++ /* free posted tx for which compls will never arrive */
++ while (atomic_read(&txq->used)) {
++ sent_skb = sent_skbs[txq->tail];
++ end_idx = txq->tail;
++ index_adv(&end_idx,
++ wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1,
++ txq->len);
++ num_wrbs = be_tx_compl_process(adapter, txo, end_idx);
++ atomic_sub(num_wrbs, &txq->used);
++ }
+ }
+
+ static void be_mcc_queues_destroy(struct be_adapter *adapter)
+@@ -1145,8 +1791,9 @@ static int be_mcc_queues_create(struct be_adapter *adapter)
+ goto mcc_cq_destroy;
+
+ /* Ask BE to create MCC queue */
+- if (be_cmd_mccq_create(adapter, q, cq))
++ if (be_cmd_mccq_create(adapter, q, cq)) {
+ goto mcc_q_free;
++ }
+
+ return 0;
+
+@@ -1163,16 +1810,20 @@ err:
+ static void be_tx_queues_destroy(struct be_adapter *adapter)
+ {
+ struct be_queue_info *q;
++ struct be_tx_obj *txo;
++ u8 i;
+
+- q = &adapter->tx_obj.q;
+- if (q->created)
+- be_cmd_q_destroy(adapter, q, QTYPE_TXQ);
+- be_queue_free(adapter, q);
++ for_all_tx_queues(adapter, txo, i) {
++ q = &txo->q;
++ if (q->created)
++ be_cmd_q_destroy(adapter, q, QTYPE_TXQ);
++ be_queue_free(adapter, q);
+
+- q = &adapter->tx_obj.cq;
+- if (q->created)
+- be_cmd_q_destroy(adapter, q, QTYPE_CQ);
+- be_queue_free(adapter, q);
++ q = &txo->cq;
++ if (q->created)
++ be_cmd_q_destroy(adapter, q, QTYPE_CQ);
++ be_queue_free(adapter, q);
++ }
+
+ /* Clear any residual events */
+ be_eq_clean(adapter, &adapter->tx_eq);
+@@ -1183,168 +1834,210 @@ static void be_tx_queues_destroy(struct be_adapter *adapter)
+ be_queue_free(adapter, q);
+ }
+
++/* One TX event queue is shared by all TX compl qs */
+ static int be_tx_queues_create(struct be_adapter *adapter)
+ {
+ struct be_queue_info *eq, *q, *cq;
++ struct be_tx_obj *txo;
++ u8 i, tc_id;
+
+ adapter->tx_eq.max_eqd = 0;
+ adapter->tx_eq.min_eqd = 0;
+ adapter->tx_eq.cur_eqd = 96;
+ adapter->tx_eq.enable_aic = false;
+- /* Alloc Tx Event queue */
++
+ eq = &adapter->tx_eq.q;
+- if (be_queue_alloc(adapter, eq, EVNT_Q_LEN, sizeof(struct be_eq_entry)))
++ if (be_queue_alloc(adapter, eq, EVNT_Q_LEN,
++ sizeof(struct be_eq_entry)))
+ return -1;
+
+- /* Ask BE to create Tx Event queue */
+ if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd))
+- goto tx_eq_free;
+- /* Alloc TX eth compl queue */
+- cq = &adapter->tx_obj.cq;
+- if (be_queue_alloc(adapter, cq, TX_CQ_LEN,
++ goto err;
++ adapter->tx_eq.eq_idx = adapter->eq_next_idx++;
++
++ for_all_tx_queues(adapter, txo, i) {
++ cq = &txo->cq;
++ if (be_queue_alloc(adapter, cq, TX_CQ_LEN,
+ sizeof(struct be_eth_tx_compl)))
+- goto tx_eq_destroy;
++ goto err;
+
+- /* Ask BE to create Tx eth compl queue */
+- if (be_cmd_cq_create(adapter, cq, eq, false, false, 3))
+- goto tx_cq_free;
++ if (be_cmd_cq_create(adapter, cq, eq, false, false, 3))
++ goto err;
+
+- /* Alloc TX eth queue */
+- q = &adapter->tx_obj.q;
+- if (be_queue_alloc(adapter, q, TX_Q_LEN, sizeof(struct be_eth_wrb)))
+- goto tx_cq_destroy;
++ q = &txo->q;
++ if (be_queue_alloc(adapter, q, TX_Q_LEN,
++ sizeof(struct be_eth_wrb)))
++ goto err;
+
+- /* Ask BE to create Tx eth queue */
+- if (be_cmd_txq_create(adapter, q, cq))
+- goto tx_q_free;
++ if (be_cmd_txq_create(adapter, q, cq, &tc_id))
++ goto err;
++
++ if (adapter->flags & BE_FLAGS_DCBX)
++ adapter->tc_txq_map[tc_id] = i;
++ }
+ return 0;
+
+-tx_q_free:
+- be_queue_free(adapter, q);
+-tx_cq_destroy:
+- be_cmd_q_destroy(adapter, cq, QTYPE_CQ);
+-tx_cq_free:
+- be_queue_free(adapter, cq);
+-tx_eq_destroy:
+- be_cmd_q_destroy(adapter, eq, QTYPE_EQ);
+-tx_eq_free:
+- be_queue_free(adapter, eq);
++err:
++ be_tx_queues_destroy(adapter);
+ return -1;
+ }
+
+ static void be_rx_queues_destroy(struct be_adapter *adapter)
+ {
+ struct be_queue_info *q;
++ struct be_rx_obj *rxo;
++ int i;
+
+- q = &adapter->rx_obj.q;
+- if (q->created) {
+- be_cmd_q_destroy(adapter, q, QTYPE_RXQ);
+- be_rx_q_clean(adapter);
+- }
+- be_queue_free(adapter, q);
++ for_all_rx_queues(adapter, rxo, i) {
++ be_queue_free(adapter, &rxo->q);
++
++ q = &rxo->cq;
++ if (q->created)
++ be_cmd_q_destroy(adapter, q, QTYPE_CQ);
++ be_queue_free(adapter, q);
+
+- q = &adapter->rx_obj.cq;
+- if (q->created)
+- be_cmd_q_destroy(adapter, q, QTYPE_CQ);
+- be_queue_free(adapter, q);
++ q = &rxo->rx_eq.q;
++ if (q->created)
++ be_cmd_q_destroy(adapter, q, QTYPE_EQ);
++ be_queue_free(adapter, q);
+
+- /* Clear any residual events */
+- be_eq_clean(adapter, &adapter->rx_eq);
++ kfree(rxo->page_info_tbl);
++ }
++}
+
+- q = &adapter->rx_eq.q;
+- if (q->created)
+- be_cmd_q_destroy(adapter, q, QTYPE_EQ);
+- be_queue_free(adapter, q);
++/* Is BE in a multi-channel mode */
++static inline bool be_is_mc(struct be_adapter *adapter) {
++ return (adapter->function_mode & FLEX10_MODE ||
++ adapter->function_mode & VNIC_MODE ||
++ adapter->function_mode & UMC_ENABLED);
++}
++
++static u32 be_num_rxqs_want(struct be_adapter *adapter)
++{
++ if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
++ adapter->num_vfs == 0 && be_physfn(adapter) &&
++ !be_is_mc(adapter)) {
++ return 1 + MAX_RSS_QS; /* one default non-RSS queue */
++ } else {
++ dev_warn(&adapter->pdev->dev,
++ "No support for multiple RX queues\n");
++ return 1;
++ }
+ }
+
+ static int be_rx_queues_create(struct be_adapter *adapter)
+ {
+ struct be_queue_info *eq, *q, *cq;
+- int rc;
++ struct be_rx_obj *rxo;
++ int rc, i;
+
++ adapter->num_rx_qs = min(be_num_rxqs_want(adapter),
++ msix_enabled(adapter) ?
++ adapter->num_msix_vec - 1 : 1);
++ if (adapter->num_rx_qs != MAX_RX_QS)
++ dev_warn(&adapter->pdev->dev,
++ "Could create only %d receive queues",
++ adapter->num_rx_qs);
++
++ adapter->max_rx_coal = gro ? BE_INIT_FRAGS_PER_FRAME : 1;
+ adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
+- adapter->rx_eq.max_eqd = BE_MAX_EQD;
+- adapter->rx_eq.min_eqd = 0;
+- adapter->rx_eq.cur_eqd = 0;
+- adapter->rx_eq.enable_aic = true;
++ for_all_rx_queues(adapter, rxo, i) {
++ rxo->adapter = adapter;
++ rxo->rx_eq.max_eqd = BE_MAX_EQD;
++ rxo->rx_eq.enable_aic = true;
+
+- /* Alloc Rx Event queue */
+- eq = &adapter->rx_eq.q;
+- rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN,
+- sizeof(struct be_eq_entry));
+- if (rc)
+- return rc;
++ /* EQ */
++ eq = &rxo->rx_eq.q;
++ rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN,
++ sizeof(struct be_eq_entry));
++ if (rc)
++ goto err;
+
+- /* Ask BE to create Rx Event queue */
+- rc = be_cmd_eq_create(adapter, eq, adapter->rx_eq.cur_eqd);
+- if (rc)
+- goto rx_eq_free;
++ rc = be_cmd_eq_create(adapter, eq, rxo->rx_eq.cur_eqd);
++ if (rc)
++ goto err;
+
+- /* Alloc RX eth compl queue */
+- cq = &adapter->rx_obj.cq;
+- rc = be_queue_alloc(adapter, cq, RX_CQ_LEN,
+- sizeof(struct be_eth_rx_compl));
+- if (rc)
+- goto rx_eq_destroy;
++ rxo->rx_eq.eq_idx = adapter->eq_next_idx++;
+
+- /* Ask BE to create Rx eth compl queue */
+- rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3);
+- if (rc)
+- goto rx_cq_free;
++ /* CQ */
++ cq = &rxo->cq;
++ rc = be_queue_alloc(adapter, cq, RX_CQ_LEN,
++ sizeof(struct be_eth_rx_compl));
++ if (rc)
++ goto err;
+
+- /* Alloc RX eth queue */
+- q = &adapter->rx_obj.q;
+- rc = be_queue_alloc(adapter, q, RX_Q_LEN, sizeof(struct be_eth_rx_d));
+- if (rc)
+- goto rx_cq_destroy;
++ rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3);
++ if (rc)
++ goto err;
+
+- /* Ask BE to create Rx eth queue */
+- rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size,
+- BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false);
+- if (rc)
+- goto rx_q_free;
++ /* Rx Q - will be created in be_open() */
++ q = &rxo->q;
++ rc = be_queue_alloc(adapter, q, RX_Q_LEN,
++ sizeof(struct be_eth_rx_d));
++ if (rc)
++ goto err;
++
++ rxo->page_info_tbl = kzalloc(sizeof(struct be_rx_page_info) *
++ RX_Q_LEN, GFP_KERNEL);
++ if (!rxo->page_info_tbl)
++ goto err;
++ }
+
+ return 0;
+-rx_q_free:
+- be_queue_free(adapter, q);
+-rx_cq_destroy:
+- be_cmd_q_destroy(adapter, cq, QTYPE_CQ);
+-rx_cq_free:
+- be_queue_free(adapter, cq);
+-rx_eq_destroy:
+- be_cmd_q_destroy(adapter, eq, QTYPE_EQ);
+-rx_eq_free:
+- be_queue_free(adapter, eq);
+- return rc;
++err:
++ be_rx_queues_destroy(adapter);
++ return -1;
+ }
+
+-/* There are 8 evt ids per func. Retruns the evt id's bit number */
+-static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id)
++static bool event_peek(struct be_eq_obj *eq_obj)
+ {
+- return eq_id - 8 * be_pci_func(adapter);
++ struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q);
++ if (!eqe->evt)
++ return false;
++ else
++ return true;
+ }
+
+ static irqreturn_t be_intx(int irq, void *dev)
+ {
+ struct be_adapter *adapter = dev;
+- int isr;
++ struct be_rx_obj *rxo;
++ int isr, i, tx = 0 , rx = 0;
+
+- isr = ioread32(adapter->csr + CEV_ISR0_OFFSET +
+- be_pci_func(adapter) * CEV_ISR_SIZE);
+- if (!isr)
+- return IRQ_NONE;
++ if (lancer_chip(adapter)) {
++ if (event_peek(&adapter->tx_eq))
++ tx = event_handle(adapter, &adapter->tx_eq, false);
++ for_all_rx_queues(adapter, rxo, i) {
++ if (event_peek(&rxo->rx_eq))
++ rx |= event_handle(adapter, &rxo->rx_eq, true);
++ }
+
+- event_handle(adapter, &adapter->tx_eq);
+- event_handle(adapter, &adapter->rx_eq);
++ if (!(tx || rx))
++ return IRQ_NONE;
++ } else {
++ isr = ioread32(adapter->csr + CEV_ISR0_OFFSET +
++ (adapter->tx_eq.q.id / 8) * CEV_ISR_SIZE);
++ if (!isr)
++ return IRQ_NONE;
++
++ if ((1 << adapter->tx_eq.eq_idx & isr))
++ event_handle(adapter, &adapter->tx_eq, false);
++
++ for_all_rx_queues(adapter, rxo, i) {
++ if ((1 << rxo->rx_eq.eq_idx & isr))
++ event_handle(adapter, &rxo->rx_eq, true);
++ }
++ }
+
+ return IRQ_HANDLED;
+ }
+
+ static irqreturn_t be_msix_rx(int irq, void *dev)
+ {
+- struct be_adapter *adapter = dev;
++ struct be_rx_obj *rxo = dev;
++ struct be_adapter *adapter = rxo->adapter;
+
+- event_handle(adapter, &adapter->rx_eq);
++ event_handle(adapter, &rxo->rx_eq, true);
+
+ return IRQ_HANDLED;
+ }
+@@ -1353,48 +2046,72 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
+ {
+ struct be_adapter *adapter = dev;
+
+- event_handle(adapter, &adapter->tx_eq);
++ event_handle(adapter, &adapter->tx_eq, false);
+
+ return IRQ_HANDLED;
+ }
+
+ static inline bool do_gro(struct be_adapter *adapter,
+- struct be_eth_rx_compl *rxcp)
++ struct be_rx_compl_info *rxcp)
+ {
+- int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
+- int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
+-
+- if (err)
+- drvr_stats(adapter)->be_rxcp_err++;
+-
+- return (tcp_frame && !err) ? true : false;
++ return (!rxcp->tcpf || rxcp->err || adapter->max_rx_coal <= 1 ||
++ (rxcp->vlanf && !vlan_configured(adapter))) ?
++ false : true;
+ }
+
+ int be_poll_rx(struct napi_struct *napi, int budget)
+ {
+ struct be_eq_obj *rx_eq = container_of(napi, struct be_eq_obj, napi);
+- struct be_adapter *adapter =
+- container_of(rx_eq, struct be_adapter, rx_eq);
+- struct be_queue_info *rx_cq = &adapter->rx_obj.cq;
+- struct be_eth_rx_compl *rxcp;
++ struct be_rx_obj *rxo = container_of(rx_eq, struct be_rx_obj, rx_eq);
++ struct be_adapter *adapter = rxo->adapter;
++ struct be_queue_info *rx_cq = &rxo->cq;
++ struct be_rx_compl_info *rxcp;
+ u32 work_done;
++ bool flush_lro = false;
+
++ rxo->stats.rx_polls++;
+ for (work_done = 0; work_done < budget; work_done++) {
+- rxcp = be_rx_compl_get(adapter);
++ rxcp = be_rx_compl_get(rxo);
+ if (!rxcp)
+ break;
+
+- if (do_gro(adapter, rxcp))
+- be_rx_compl_process_gro(adapter, rxcp);
+- else
+- be_rx_compl_process(adapter, rxcp);
++ /* Is it a flush compl that has no data */
++ if (unlikely(rxcp->num_rcvd == 0))
++ continue;
+
+- be_rx_compl_reset(rxcp);
++ if (unlikely(rxcp->port != adapter->port_num)) {
++ be_rx_compl_discard(adapter, rxo, rxcp);
++ be_rx_stats_update(rxo, rxcp);
++ continue;
++ }
++
++ if (likely((lancer_A0_chip(adapter) && !rxcp->err) ||
++ !lancer_A0_chip(adapter))) {
++ if (do_gro(adapter, rxcp)) {
++ if (adapter->gro_supported) {
++ be_rx_compl_process_gro(adapter, rxo,
++ rxcp);
++ } else {
++ be_rx_compl_process_lro(adapter, rxo,
++ rxcp);
++ flush_lro = true;
++ }
++ } else {
++ be_rx_compl_process(adapter, rxo, rxcp);
++ }
++ } else if (lancer_A0_chip(adapter) && rxcp->err) {
++ be_rx_compl_discard(adapter, rxo, rxcp);
++ }
++
++ be_rx_stats_update(rxo, rxcp);
+ }
+
++ if (flush_lro)
++ lro_flush_all(&rxo->lro_mgr);
++
+ /* Refill the queue */
+- if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM)
+- be_post_rx_frags(adapter);
++ if (work_done && atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM)
++ be_post_rx_frags(rxo);
+
+ /* All consumed */
+ if (work_done < budget) {
+@@ -1404,40 +2121,13 @@ int be_poll_rx(struct napi_struct *napi, int budget)
+ /* More to be consumed; continue with interrupts disabled */
+ be_cq_notify(adapter, rx_cq->id, false, work_done);
+ }
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
++ adapter->netdev->last_rx = jiffies;
++#endif
+ return work_done;
+ }
+
+-void be_process_tx(struct be_adapter *adapter)
+-{
+- struct be_queue_info *txq = &adapter->tx_obj.q;
+- struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
+- struct be_eth_tx_compl *txcp;
+- u32 num_cmpl = 0;
+- u16 end_idx;
+-
+- while ((txcp = be_tx_compl_get(tx_cq))) {
+- end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
+- wrb_index, txcp);
+- be_tx_compl_process(adapter, end_idx);
+- num_cmpl++;
+- }
+-
+- if (num_cmpl) {
+- be_cq_notify(adapter, tx_cq->id, true, num_cmpl);
+-
+- /* As Tx wrbs have been freed up, wake up netdev queue if
+- * it was stopped due to lack of tx wrbs.
+- */
+- if (netif_queue_stopped(adapter->netdev) &&
+- atomic_read(&txq->used) < txq->len / 2) {
+- netif_wake_queue(adapter->netdev);
+- }
+-
+- drvr_stats(adapter)->be_tx_events++;
+- drvr_stats(adapter)->be_tx_compl += num_cmpl;
+- }
+-}
+-
+ /* As TX and MCC share the same EQ check for both TX and MCC completions.
+ * For TX/MCC we don't honour budget; consume everything
+ */
+@@ -1446,96 +2136,264 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
+ struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
+ struct be_adapter *adapter =
+ container_of(tx_eq, struct be_adapter, tx_eq);
++ struct be_tx_obj *txo;
++ struct be_eth_tx_compl *txcp;
++ int tx_compl, mcc_compl, status = 0;
++ u8 i;
++ u16 num_wrbs;
++
++ for_all_tx_queues(adapter, txo, i) {
++ tx_compl = 0;
++ num_wrbs = 0;
++ while ((txcp = be_tx_compl_get(&txo->cq))) {
++ num_wrbs += be_tx_compl_process(adapter, txo,
++ AMAP_GET_BITS(struct amap_eth_tx_compl,
++ wrb_index, txcp));
++ tx_compl++;
++ }
++ if (tx_compl) {
++ be_cq_notify(adapter, txo->cq.id, true, tx_compl);
++
++ atomic_sub(num_wrbs, &txo->q.used);
++
++ /* As Tx wrbs have been freed up, wake up netdev queue
++ * if it was stopped due to lack of tx wrbs. */
++ if (__netif_subqueue_stopped(adapter->netdev, i) &&
++ atomic_read(&txo->q.used) < txo->q.len / 2) {
++ netif_wake_subqueue(adapter->netdev, i);
++ }
++
++ adapter->drv_stats.be_tx_events++;
++ txo->stats.be_tx_compl += tx_compl;
++ }
++ }
++
++ mcc_compl = be_process_mcc(adapter, &status);
++
++ if (mcc_compl) {
++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
++ be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl);
++ }
+
+ napi_complete(napi);
+
+- be_process_tx(adapter);
+-
+- be_process_mcc(adapter);
+-
++ be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
+ return 1;
+ }
+
++void be_detect_dump_ue(struct be_adapter *adapter)
++{
++ u32 ue_status_lo, ue_status_hi, ue_status_lo_mask, ue_status_hi_mask;
++ u32 i;
++
++ pci_read_config_dword(adapter->pdev,
++ PCICFG_UE_STATUS_LOW, &ue_status_lo);
++ pci_read_config_dword(adapter->pdev,
++ PCICFG_UE_STATUS_HIGH, &ue_status_hi);
++ pci_read_config_dword(adapter->pdev,
++ PCICFG_UE_STATUS_LOW_MASK, &ue_status_lo_mask);
++ pci_read_config_dword(adapter->pdev,
++ PCICFG_UE_STATUS_HI_MASK, &ue_status_hi_mask);
++
++ ue_status_lo = (ue_status_lo & (~ue_status_lo_mask));
++ ue_status_hi = (ue_status_hi & (~ue_status_hi_mask));
++
++ if (ue_status_lo || ue_status_hi) {
++ adapter->ue_detected = true;
++ adapter->eeh_err = true;
++ dev_err(&adapter->pdev->dev, "UE Detected!!\n");
++ }
++
++ if (ue_status_lo) {
++ for (i = 0; ue_status_lo; ue_status_lo >>= 1, i++) {
++ if (ue_status_lo & 1)
++ dev_err(&adapter->pdev->dev,
++ "UE: %s bit set\n", ue_status_low_desc[i]);
++ }
++ }
++ if (ue_status_hi) {
++ for (i = 0; ue_status_hi; ue_status_hi >>= 1, i++) {
++ if (ue_status_hi & 1)
++ dev_err(&adapter->pdev->dev,
++ "UE: %s bit set\n", ue_status_hi_desc[i]);
++ }
++ }
++
++}
++
+ static void be_worker(struct work_struct *work)
+ {
+ struct be_adapter *adapter =
+ container_of(work, struct be_adapter, work.work);
++ struct be_rx_obj *rxo;
++ struct be_tx_obj *txo;
++ int i;
+
+- be_cmd_get_stats(adapter, &adapter->stats.cmd);
++ if (!adapter->ue_detected && !lancer_chip(adapter))
++ be_detect_dump_ue(adapter);
+
+- /* Set EQ delay */
+- be_rx_eqd_update(adapter);
++ /* when interrupts are not yet enabled, just reap any pending
++ * mcc completions */
++ if (!netif_running(adapter->netdev)) {
++ int mcc_compl, status = 0;
+
+- be_tx_rate_update(adapter);
+- be_rx_rate_update(adapter);
++ mcc_compl = be_process_mcc(adapter, &status);
+
+- if (adapter->rx_post_starved) {
+- adapter->rx_post_starved = false;
+- be_post_rx_frags(adapter);
++ if (mcc_compl) {
++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
++ be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl);
++ }
++
++ goto reschedule;
++ }
++
++ if (!adapter->stats_cmd_sent)
++ be_cmd_get_stats(adapter, &adapter->stats_cmd);
++
++ for_all_tx_queues(adapter, txo, i)
++ be_tx_rate_update(txo);
++
++ for_all_rx_queues(adapter, rxo, i) {
++ be_rx_rate_update(rxo);
++ be_rx_eqd_update(adapter, rxo);
++
++ if (rxo->rx_post_starved) {
++ rxo->rx_post_starved = false;
++ be_post_rx_frags(rxo);
++ }
+ }
+
++reschedule:
++ adapter->work_counter++;
+ schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
+ }
+
++static void be_msix_disable(struct be_adapter *adapter)
++{
++ if (msix_enabled(adapter)) {
++ pci_disable_msix(adapter->pdev);
++ adapter->num_msix_vec = 0;
++ }
++}
++
+ static void be_msix_enable(struct be_adapter *adapter)
+ {
+- int i, status;
++#define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */
++ int i, status, num_vec;
+
+- for (i = 0; i < BE_NUM_MSIX_VECTORS; i++)
++ num_vec = be_num_rxqs_want(adapter) + 1;
++
++ for (i = 0; i < num_vec; i++)
+ adapter->msix_entries[i].entry = i;
+
+- status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
+- BE_NUM_MSIX_VECTORS);
+- if (status == 0)
+- adapter->msix_enabled = true;
++ status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec);
++ if (status == 0) {
++ goto done;
++ } else if (status >= BE_MIN_MSIX_VECTORS) {
++ num_vec = status;
++ if (pci_enable_msix(adapter->pdev, adapter->msix_entries,
++ num_vec) == 0)
++ goto done;
++ }
+ return;
++done:
++ adapter->num_msix_vec = num_vec;
++ return;
++}
++
++static void be_sriov_enable(struct be_adapter *adapter)
++{
++ be_check_sriov_fn_type(adapter);
++#ifdef CONFIG_PCI_IOV
++ if (be_physfn(adapter) && num_vfs) {
++ int status, pos;
++ u16 nvfs;
++
++ pos = pci_find_ext_capability(adapter->pdev,
++ PCI_EXT_CAP_ID_SRIOV);
++ pci_read_config_word(adapter->pdev,
++ pos + PCI_SRIOV_TOTAL_VF, &nvfs);
++ adapter->num_vfs = num_vfs;
++ if (num_vfs > nvfs) {
++ dev_info(&adapter->pdev->dev,
++ "Device supports %d VFs and not %d\n",
++ nvfs, num_vfs);
++ adapter->num_vfs = nvfs;
++ }
++
++ status = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
++ if (status)
++ adapter->num_vfs = 0;
++ }
++#endif
++}
++
++static void be_sriov_disable(struct be_adapter *adapter)
++{
++#ifdef CONFIG_PCI_IOV
++ if (adapter->num_vfs > 0) {
++ pci_disable_sriov(adapter->pdev);
++ adapter->num_vfs = 0;
++ }
++#endif
+ }
+
+-static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id)
++static inline int be_msix_vec_get(struct be_adapter *adapter,
++ struct be_eq_obj *eq_obj)
+ {
+- return adapter->msix_entries[
+- be_evt_bit_get(adapter, eq_id)].vector;
++ return adapter->msix_entries[eq_obj->eq_idx].vector;
+ }
+
+ static int be_request_irq(struct be_adapter *adapter,
+ struct be_eq_obj *eq_obj,
+- void *handler, char *desc)
++ void *handler, char *desc, void *context)
+ {
+ struct net_device *netdev = adapter->netdev;
+ int vec;
+
+ sprintf(eq_obj->desc, "%s-%s", netdev->name, desc);
+- vec = be_msix_vec_get(adapter, eq_obj->q.id);
+- return request_irq(vec, handler, 0, eq_obj->desc, adapter);
++ vec = be_msix_vec_get(adapter, eq_obj);
++ return request_irq(vec, handler, 0, eq_obj->desc, context);
+ }
+
+-static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj)
++static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj,
++ void *context)
+ {
+- int vec = be_msix_vec_get(adapter, eq_obj->q.id);
+- free_irq(vec, adapter);
++ int vec = be_msix_vec_get(adapter, eq_obj);
++ free_irq(vec, context);
+ }
+
+ static int be_msix_register(struct be_adapter *adapter)
+ {
+- int status;
++ struct be_rx_obj *rxo;
++ int status, i;
++ char qname[10];
+
+- status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx");
++ status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx",
++ adapter);
+ if (status)
+ goto err;
+
+- status = be_request_irq(adapter, &adapter->rx_eq, be_msix_rx, "rx");
+- if (status)
+- goto free_tx_irq;
++ for_all_rx_queues(adapter, rxo, i) {
++ sprintf(qname, "rxq%d", i);
++ status = be_request_irq(adapter, &rxo->rx_eq, be_msix_rx,
++ qname, rxo);
++ if (status)
++ goto err_msix;
++ }
+
+ return 0;
+
+-free_tx_irq:
+- be_free_irq(adapter, &adapter->tx_eq);
++err_msix:
++ be_free_irq(adapter, &adapter->tx_eq, adapter);
++
++ for (i--, rxo = &adapter->rx_obj[i]; i >= 0; i--, rxo--)
++ be_free_irq(adapter, &rxo->rx_eq, rxo);
++
+ err:
+ dev_warn(&adapter->pdev->dev,
+ "MSIX Request IRQ failed - err %d\n", status);
+- pci_disable_msix(adapter->pdev);
+- adapter->msix_enabled = false;
++ be_msix_disable(adapter);
+ return status;
+ }
+
+@@ -1544,10 +2402,13 @@ static int be_irq_register(struct be_adapter *adapter)
+ struct net_device *netdev = adapter->netdev;
+ int status;
+
+- if (adapter->msix_enabled) {
++ if (msix_enabled(adapter)) {
+ status = be_msix_register(adapter);
+ if (status == 0)
+ goto done;
++ /* INTx is not supported for VF */
++ if (!be_physfn(adapter))
++ return status;
+ }
+
+ /* INTx */
+@@ -1567,87 +2428,363 @@ done:
+ static void be_irq_unregister(struct be_adapter *adapter)
+ {
+ struct net_device *netdev = adapter->netdev;
++ struct be_rx_obj *rxo;
++ int i;
+
+ if (!adapter->isr_registered)
+ return;
+
+ /* INTx */
+- if (!adapter->msix_enabled) {
++ if (!msix_enabled(adapter)) {
+ free_irq(netdev->irq, adapter);
+ goto done;
+ }
+
+ /* MSIx */
+- be_free_irq(adapter, &adapter->tx_eq);
+- be_free_irq(adapter, &adapter->rx_eq);
++ be_free_irq(adapter, &adapter->tx_eq, adapter);
++
++ for_all_rx_queues(adapter, rxo, i)
++ be_free_irq(adapter, &rxo->rx_eq, rxo);
++
+ done:
+ adapter->isr_registered = false;
+- return;
+ }
+
+-static int be_open(struct net_device *netdev)
++static u16 be_select_queue(struct net_device *netdev,
++ struct sk_buff *skb)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+- struct be_eq_obj *rx_eq = &adapter->rx_eq;
++ u8 prio;
++
++ if (adapter->num_tx_qs == 1)
++ return 0;
++
++ prio = (vlan_tx_tag_get(skb) & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
++ return adapter->tc_txq_map[adapter->prio_tc_map[prio]];
++}
++
++static void be_rx_queues_clear(struct be_adapter *adapter)
++{
++ struct be_queue_info *q;
++ struct be_rx_obj *rxo;
++ int i;
++
++ for_all_rx_queues(adapter, rxo, i) {
++ q = &rxo->q;
++ if (q->created) {
++ be_cmd_rxq_destroy(adapter, q);
++ /* After the rxq is invalidated, wait for a grace time
++ * of 1ms for all dma to end and the flush compl to
++ * arrive
++ */
++ mdelay(1);
++ be_rx_q_clean(adapter, rxo);
++ }
++
++ /* Clear any residual events */
++ q = &rxo->rx_eq.q;
++ if (q->created)
++ be_eq_clean(adapter, &rxo->rx_eq);
++ }
++}
++
++static int be_close(struct net_device *netdev)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ struct be_rx_obj *rxo;
++ struct be_tx_obj *txo;
+ struct be_eq_obj *tx_eq = &adapter->tx_eq;
+- bool link_up;
+- int status;
++ int vec, i;
++
++ be_async_mcc_disable(adapter);
++
++ netif_stop_queue(netdev);
++ netif_carrier_off(netdev);
++ adapter->link_status = LINK_DOWN;
++
++ if (!lancer_chip(adapter))
++ be_intr_set(adapter, false);
++
++ for_all_rx_queues(adapter, rxo, i)
++ napi_disable(&rxo->rx_eq.napi);
++
++ napi_disable(&tx_eq->napi);
++
++ if (lancer_chip(adapter)) {
++ be_cq_notify(adapter, adapter->mcc_obj.cq.id, false, 0);
++ for_all_rx_queues(adapter, rxo, i)
++ be_cq_notify(adapter, rxo->cq.id, false, 0);
++ for_all_tx_queues(adapter, txo, i)
++ be_cq_notify(adapter, txo->cq.id, false, 0);
++ }
++
++ if (msix_enabled(adapter)) {
++ vec = be_msix_vec_get(adapter, tx_eq);
++ synchronize_irq(vec);
++
++ for_all_rx_queues(adapter, rxo, i) {
++ vec = be_msix_vec_get(adapter, &rxo->rx_eq);
++ synchronize_irq(vec);
++ }
++ } else {
++ synchronize_irq(netdev->irq);
++ }
++ be_irq_unregister(adapter);
++
++ /* Wait for all pending tx completions to arrive so that
++ * all tx skbs are freed.
++ */
++ for_all_tx_queues(adapter, txo, i)
++ be_tx_compl_clean(adapter, txo);
++
++ be_rx_queues_clear(adapter);
++ return 0;
++}
++
++static int be_rx_queues_setup(struct be_adapter *adapter)
++{
++ struct be_rx_obj *rxo;
++ int rc, i;
++ u8 rsstable[MAX_RSS_QS];
++
++ for_all_rx_queues(adapter, rxo, i) {
++ rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id,
++ rx_frag_size, BE_MAX_JUMBO_FRAME_SIZE,
++ adapter->if_handle,
++ (i > 0) ? 1 : 0/* rss enable */, &rxo->rss_id);
++ if (rc)
++ return rc;
++ }
++
++ if (be_multi_rxq(adapter)) {
++ for_all_rss_queues(adapter, rxo, i)
++ rsstable[i] = rxo->rss_id;
++
++ rc = be_cmd_rss_config(adapter, rsstable,
++ adapter->num_rx_qs - 1);
++ if (rc)
++ return rc;
++ }
+
+ /* First time posting */
+- be_post_rx_frags(adapter);
++ for_all_rx_queues(adapter, rxo, i) {
++ be_post_rx_frags(rxo);
++ napi_enable(&rxo->rx_eq.napi);
++ }
++ return 0;
++}
++
++static int be_open(struct net_device *netdev)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ struct be_eq_obj *tx_eq = &adapter->tx_eq;
++ struct be_rx_obj *rxo;
++ int link_status;
++ int status, i;
++ u8 mac_speed;
++ u16 link_speed;
++
++ status = be_rx_queues_setup(adapter);
++ if (status)
++ goto err;
+
+- napi_enable(&rx_eq->napi);
+ napi_enable(&tx_eq->napi);
+
+ be_irq_register(adapter);
+
+- be_intr_set(adapter, true);
++ if (!lancer_chip(adapter))
++ be_intr_set(adapter, true);
+
+ /* The evt queues are created in unarmed state; arm them */
+- be_eq_notify(adapter, rx_eq->q.id, true, false, 0);
++ for_all_rx_queues(adapter, rxo, i) {
++ be_eq_notify(adapter, rxo->rx_eq.q.id, true, false, 0);
++ be_cq_notify(adapter, rxo->cq.id, true, 0);
++ }
+ be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
+
+- /* Rx compl queue may be in unarmed state; rearm it */
+- be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0);
++ /* Now that interrupts are on we can process async mcc */
++ be_async_mcc_enable(adapter);
+
+- status = be_cmd_link_status_query(adapter, &link_up);
++ status = be_cmd_link_status_query(adapter, &link_status, &mac_speed,
++ &link_speed, 0);
+ if (status)
+- goto ret_sts;
+- be_link_status_update(adapter, link_up);
++ goto err;
++ be_link_status_update(adapter, link_status);
+
+- status = be_vid_config(adapter);
++ status = be_vid_config(adapter, false, 0);
+ if (status)
+- goto ret_sts;
++ goto err;
+
+- status = be_cmd_set_flow_control(adapter,
+- adapter->tx_fc, adapter->rx_fc);
+- if (status)
+- goto ret_sts;
++ if (be_physfn(adapter)) {
++ status = be_cmd_set_flow_control(adapter,
++ adapter->tx_fc, adapter->rx_fc);
++ if (status)
++ goto err;
++ }
++
++ return 0;
++err:
++ be_close(adapter->netdev);
++ return -EIO;
++}
++
++static int be_setup_wol(struct be_adapter *adapter, bool enable)
++{
++ struct be_dma_mem cmd;
++ int status = 0;
++ u8 mac[ETH_ALEN];
++
++ memset(mac, 0, ETH_ALEN);
++
++ cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config);
++ cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma);
++ if (cmd.va == NULL)
++ return -1;
++ memset(cmd.va, 0, cmd.size);
++
++ if (enable) {
++ status = pci_write_config_dword(adapter->pdev,
++ PCICFG_PM_CONTROL_OFFSET, PCICFG_PM_CONTROL_MASK);
++ if (status) {
++ dev_err(&adapter->pdev->dev,
++ "Could not enable Wake-on-lan\n");
++ pci_free_consistent(adapter->pdev, cmd.size, cmd.va,
++ cmd.dma);
++ return status;
++ }
++ status = be_cmd_enable_magic_wol(adapter,
++ adapter->netdev->dev_addr, &cmd);
++ pci_enable_wake(adapter->pdev, PCI_D3hot, 1);
++ pci_enable_wake(adapter->pdev, PCI_D3cold, 1);
++ } else {
++ status = be_cmd_enable_magic_wol(adapter, mac, &cmd);
++ pci_enable_wake(adapter->pdev, PCI_D3hot, 0);
++ pci_enable_wake(adapter->pdev, PCI_D3cold, 0);
++ }
++
++ pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
++ return status;
++}
++
++/*
++ * Generate a seed MAC address from the PF MAC Address using jhash.
++ * MAC Address for VFs are assigned incrementally starting from the seed.
++ * These addresses are programmed in the ASIC by the PF and the VF driver
++ * queries for the MAC address during its probe.
++ */
++static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
++{
++ u32 vf = 0;
++ int status = 0;
++ u8 mac[ETH_ALEN];
++
++ be_vf_eth_addr_generate(adapter, mac);
++
++ for (vf = 0; vf < adapter->num_vfs; vf++) {
++ status = be_cmd_pmac_add(adapter, mac,
++ adapter->vf_cfg[vf].vf_if_handle,
++ &adapter->vf_cfg[vf].vf_pmac_id,
++ vf + 1);
++ if (status)
++ dev_err(&adapter->pdev->dev,
++ "Mac address add failed for VF %d\n", vf);
++ else
++ memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+
+- schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
+-ret_sts:
++ mac[5] += 1;
++ }
+ return status;
+ }
+
++static inline void be_vf_eth_addr_rem(struct be_adapter *adapter)
++{
++ u32 vf;
++
++ for (vf = 0; vf < adapter->num_vfs; vf++) {
++ if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
++ be_cmd_pmac_del(adapter,
++ adapter->vf_cfg[vf].vf_if_handle,
++ adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
++ }
++}
++
++static int be_num_txqs_want(struct be_adapter *adapter)
++{
++ if (adapter->num_vfs > 0 || be_is_mc(adapter) ||
++ lancer_chip(adapter) || !be_physfn(adapter) ||
++ adapter->generation == BE_GEN2)
++ return 1;
++ else
++ return MAX_TX_QS;
++}
++
+ static int be_setup(struct be_adapter *adapter)
+ {
+ struct net_device *netdev = adapter->netdev;
+- u32 cap_flags, en_flags;
+- int status;
+-
+- cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
+- BE_IF_FLAGS_MCAST_PROMISCUOUS |
+- BE_IF_FLAGS_PROMISCUOUS |
+- BE_IF_FLAGS_PASS_L3L4_ERRORS;
+- en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
+- BE_IF_FLAGS_PASS_L3L4_ERRORS;
++ int status, fw_num_txqs, num_txqs;
++ u32 cap_flags, en_flags, vf = 0;
++ u8 mac[ETH_ALEN];
++
++ num_txqs = be_num_txqs_want(adapter);
++ if (num_txqs > 1) {
++ be_cmd_req_pg_pfc(adapter, &fw_num_txqs);
++ num_txqs = min(num_txqs, fw_num_txqs);
++ }
++ adapter->num_tx_qs = num_txqs;
++ if (adapter->num_tx_qs != MAX_TX_QS)
++ netif_set_real_num_tx_queues(adapter->netdev,
++ adapter->num_tx_qs);
++
++ be_cmd_req_native_mode(adapter);
++
++ cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED |
++ BE_IF_FLAGS_BROADCAST |
++ BE_IF_FLAGS_MULTICAST;
++
++ if (be_physfn(adapter)) {
++ if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) {
++ cap_flags |= BE_IF_FLAGS_RSS;
++ en_flags |= BE_IF_FLAGS_RSS;
++ }
++ cap_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS |
++ BE_IF_FLAGS_PROMISCUOUS;
++ if (!lancer_A0_chip(adapter)) {
++ cap_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
++ en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
++ }
++ }
+
+ status = be_cmd_if_create(adapter, cap_flags, en_flags,
+ netdev->dev_addr, false/* pmac_invalid */,
+- &adapter->if_handle, &adapter->pmac_id);
++ &adapter->if_handle, &adapter->pmac_id, 0);
+ if (status != 0)
+ goto do_none;
+
++ if (be_physfn(adapter)) {
++ while (vf < adapter->num_vfs) {
++ cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED |
++ BE_IF_FLAGS_BROADCAST;
++ status = be_cmd_if_create(adapter, cap_flags,
++ en_flags, mac, true,
++ &adapter->vf_cfg[vf].vf_if_handle,
++ NULL, vf+1);
++ if (status) {
++ dev_err(&adapter->pdev->dev,
++ "Interface Create failed for VF %d\n", vf);
++ goto if_destroy;
++ }
++ adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID;
++ vf++;
++ }
++ } else {
++ status = be_cmd_mac_addr_query(adapter, mac,
++ MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle);
++ if (!status) {
++ memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
++ memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
++ }
++ }
++
+ status = be_tx_queues_create(adapter);
+ if (status != 0)
+ goto if_destroy;
+@@ -1656,10 +2793,15 @@ static int be_setup(struct be_adapter *adapter)
+ if (status != 0)
+ goto tx_qs_destroy;
+
++ /* Allow all priorities by default. A GRP5 evt may modify this */
++ adapter->vlan_prio_bmap = 0xff;
++
+ status = be_mcc_queues_create(adapter);
+ if (status != 0)
+ goto rx_qs_destroy;
+
++ adapter->link_speed = -1;
++
+ return 0;
+
+ rx_qs_destroy:
+@@ -1667,158 +2809,392 @@ rx_qs_destroy:
+ tx_qs_destroy:
+ be_tx_queues_destroy(adapter);
+ if_destroy:
+- be_cmd_if_destroy(adapter, adapter->if_handle);
++ if (be_physfn(adapter)) {
++ for (vf = 0; vf < adapter->num_vfs; vf++)
++ if (adapter->vf_cfg[vf].vf_if_handle)
++ be_cmd_if_destroy(adapter,
++ adapter->vf_cfg[vf].vf_if_handle,
++ vf + 1);
++ }
++ be_cmd_if_destroy(adapter, adapter->if_handle, 0);
+ do_none:
+ return status;
+ }
+
+ static int be_clear(struct be_adapter *adapter)
+ {
++ int vf;
++
++ if (be_physfn(adapter) && adapter->num_vfs)
++ be_vf_eth_addr_rem(adapter);
++
+ be_mcc_queues_destroy(adapter);
+ be_rx_queues_destroy(adapter);
+ be_tx_queues_destroy(adapter);
++ adapter->eq_next_idx = 0;
+
+- be_cmd_if_destroy(adapter, adapter->if_handle);
++ if (be_physfn(adapter)) {
++ for (vf = 0; vf < adapter->num_vfs; vf++)
++ if (adapter->vf_cfg[vf].vf_if_handle)
++ be_cmd_if_destroy(adapter,
++ adapter->vf_cfg[vf].vf_if_handle, vf + 1);
++ }
++ be_cmd_if_destroy(adapter, adapter->if_handle, 0);
+
++ /* tell fw we're done with firing cmds */
++ be_cmd_fw_clean(adapter);
+ return 0;
+ }
+
+-static int be_close(struct net_device *netdev)
++static void be_cpy_drv_ver(struct be_adapter *adapter, void *va)
++{
++ struct mgmt_controller_attrib *attrib =
++ (struct mgmt_controller_attrib *) ((u8*) va +
++ sizeof(struct be_cmd_resp_hdr));
++
++ memcpy(attrib->hba_attribs.driver_version_string,
++ DRV_VER, sizeof(DRV_VER));
++ attrib->pci_bus_number = adapter->pdev->bus->number;
++ attrib->pci_device_number = PCI_SLOT(adapter->pdev->devfn);
++ return;
++}
++
++#define IOCTL_COOKIE "SERVERENGINES CORP"
++static int be_do_ioctl(struct net_device *netdev,
++ struct ifreq *ifr, int cmd)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
+- struct be_eq_obj *rx_eq = &adapter->rx_eq;
+- struct be_eq_obj *tx_eq = &adapter->tx_eq;
+- int vec;
++ struct be_cmd_req_hdr req;
++ struct be_cmd_resp_hdr *resp;
++ void *data = ifr->ifr_data;
++ void *ioctl_ptr;
++ void *va;
++ dma_addr_t dma;
++ u32 req_size;
++ int status, ret = 0;
++ u8 cookie[32];
++
++ switch (cmd) {
++ case SIOCDEVPRIVATE:
++ if (copy_from_user(cookie, data, strlen(IOCTL_COOKIE)))
++ return -EFAULT;
++
++ if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
++ return -EINVAL;
+
+- cancel_delayed_work_sync(&adapter->work);
++ ioctl_ptr = (u8 *)data + strlen(IOCTL_COOKIE);
++ if (copy_from_user(&req, ioctl_ptr,
++ sizeof(struct be_cmd_req_hdr)))
++ return -EFAULT;
+
+- netif_stop_queue(netdev);
+- netif_carrier_off(netdev);
+- adapter->link_up = false;
++ req_size = le32_to_cpu(req.request_length);
++ if (req_size > 65536)
++ return -EINVAL;
+
+- be_intr_set(adapter, false);
++ req_size += sizeof(struct be_cmd_req_hdr);
++ va = pci_alloc_consistent(adapter->pdev, req_size, &dma);
++ if (!va)
++ return -ENOMEM;
++ if (copy_from_user(va, ioctl_ptr, req_size)) {
++ ret = -EFAULT;
++ break;
++ }
+
+- if (adapter->msix_enabled) {
+- vec = be_msix_vec_get(adapter, tx_eq->q.id);
+- synchronize_irq(vec);
+- vec = be_msix_vec_get(adapter, rx_eq->q.id);
+- synchronize_irq(vec);
+- } else {
+- synchronize_irq(netdev->irq);
++ status = be_cmd_pass_ext_ioctl(adapter, dma, req_size, va);
++ if (status == -1) {
++ ret = -EIO;
++ break;
++ }
++
++ resp = (struct be_cmd_resp_hdr *) va;
++ if (!status) {
++ if (req.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES)
++ be_cpy_drv_ver(adapter, va);
++ }
++
++ if (copy_to_user(ioctl_ptr, va, req_size)) {
++ ret = -EFAULT;
++ break;
++ }
++ break;
++ default:
++ return -EOPNOTSUPP;
+ }
+- be_irq_unregister(adapter);
+
+- napi_disable(&rx_eq->napi);
+- napi_disable(&tx_eq->napi);
++ if (va)
++ pci_free_consistent(adapter->pdev, req_size, va, dma);
++
++ return ret;
++}
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++static void be_netpoll(struct net_device *netdev)
++{
++ struct be_adapter *adapter = netdev_priv(netdev);
++ struct be_rx_obj *rxo;
++ int i;
+
+- /* Wait for all pending tx completions to arrive so that
+- * all tx skbs are freed.
+- */
+- be_tx_compl_clean(adapter);
++ event_handle(adapter, &adapter->tx_eq, false);
++ for_all_rx_queues(adapter, rxo, i)
++ event_handle(adapter, &rxo->rx_eq, true);
++
++ return;
++}
++#endif
++
++static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
++ void **ip_hdr, void **tcpudp_hdr,
++ u64 *hdr_flags, void *priv)
++{
++ struct ethhdr *eh;
++ struct vlan_ethhdr *veh;
++ struct iphdr *iph;
++ u8 *va = page_address(frag->page) + frag->page_offset;
++ unsigned long ll_hlen;
++
++ prefetch(va);
++ eh = (struct ethhdr *)va;
++ *mac_hdr = eh;
++ ll_hlen = ETH_HLEN;
++ if (eh->h_proto != htons(ETH_P_IP)) {
++ if (eh->h_proto == htons(ETH_P_8021Q)) {
++ veh = (struct vlan_ethhdr *)va;
++ if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
++ return -1;
++
++ ll_hlen += VLAN_HLEN;
++ } else {
++ return -1;
++ }
++ }
++ *hdr_flags = LRO_IPV4;
++ iph = (struct iphdr *)(va + ll_hlen);
++ *ip_hdr = iph;
++ if (iph->protocol != IPPROTO_TCP)
++ return -1;
++ *hdr_flags |= LRO_TCP;
++ *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
+
+ return 0;
+ }
+
+-#define FW_FILE_HDR_SIGN "ServerEngines Corp. "
++static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev)
++{
++ struct net_lro_mgr *lro_mgr;
++ struct be_rx_obj *rxo;
++ int i;
++
++ for_all_rx_queues(adapter, rxo, i) {
++ lro_mgr = &rxo->lro_mgr;
++ lro_mgr->dev = netdev;
++ lro_mgr->features = LRO_F_NAPI;
++ lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
++ lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
++ lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS;
++ lro_mgr->lro_arr = rxo->lro_desc;
++ lro_mgr->get_frag_header = be_get_frag_header;
++ lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME;
++ }
++
++#ifdef NETIF_F_GRO
++ netdev->features |= NETIF_F_GRO;
++ adapter->gro_supported = true;
++#endif
++}
++
++#define FW_FILE_HDR_SIGN "ServerEngines Corp. "
+ char flash_cookie[2][16] = {"*** SE FLAS",
+ "H DIRECTORY *** "};
+-static int be_flash_image(struct be_adapter *adapter,
++
++static bool be_flash_redboot(struct be_adapter *adapter,
++ const u8 *p, u32 img_start, int image_size,
++ int hdr_size)
++{
++ u32 crc_offset;
++ u8 flashed_crc[4];
++ int status;
++
++ crc_offset = hdr_size + img_start + image_size - 4;
++
++ p += crc_offset;
++
++ status = be_cmd_get_flash_crc(adapter, flashed_crc,
++ (image_size - 4));
++ if (status) {
++ dev_err(&adapter->pdev->dev,
++ "could not get crc from flash, not flashing redboot\n");
++ return false;
++ }
++
++ /*update redboot only if crc does not match*/
++ if (!memcmp(flashed_crc, p, 4))
++ return false;
++ else
++ return true;
++}
++
++static bool phy_flashing_required(struct be_adapter *adapter)
++{
++ int status = 0;
++ struct be_phy_info phy_info;
++
++ status = be_cmd_get_phy_info(adapter, &phy_info);
++ if (status)
++ return false;
++ if ((phy_info.phy_type == TN_8022) &&
++ (phy_info.interface_type == PHY_TYPE_BASET_10GB)) {
++ return true;
++ }
++ return false;
++}
++
++static int be_flash_data(struct be_adapter *adapter,
+ const struct firmware *fw,
+- struct be_dma_mem *flash_cmd, u32 flash_type)
++ struct be_dma_mem *flash_cmd, int num_of_images)
++
+ {
+- int status;
+- u32 flash_op, image_offset = 0, total_bytes, image_size = 0;
++ int status = 0, i, filehdr_size = 0;
++ u32 total_bytes = 0, flash_op;
+ int num_bytes;
+ const u8 *p = fw->data;
+ struct be_cmd_write_flashrom *req = flash_cmd->va;
++ struct flash_comp *pflashcomp;
++ int num_comp;
+
+- switch (flash_type) {
+- case FLASHROM_TYPE_ISCSI_ACTIVE:
+- image_offset = FLASH_iSCSI_PRIMARY_IMAGE_START;
+- image_size = FLASH_IMAGE_MAX_SIZE;
+- break;
+- case FLASHROM_TYPE_ISCSI_BACKUP:
+- image_offset = FLASH_iSCSI_BACKUP_IMAGE_START;
+- image_size = FLASH_IMAGE_MAX_SIZE;
+- break;
+- case FLASHROM_TYPE_FCOE_FW_ACTIVE:
+- image_offset = FLASH_FCoE_PRIMARY_IMAGE_START;
+- image_size = FLASH_IMAGE_MAX_SIZE;
+- break;
+- case FLASHROM_TYPE_FCOE_FW_BACKUP:
+- image_offset = FLASH_FCoE_BACKUP_IMAGE_START;
+- image_size = FLASH_IMAGE_MAX_SIZE;
+- break;
+- case FLASHROM_TYPE_BIOS:
+- image_offset = FLASH_iSCSI_BIOS_START;
+- image_size = FLASH_BIOS_IMAGE_MAX_SIZE;
+- break;
+- case FLASHROM_TYPE_FCOE_BIOS:
+- image_offset = FLASH_FCoE_BIOS_START;
+- image_size = FLASH_BIOS_IMAGE_MAX_SIZE;
+- break;
+- case FLASHROM_TYPE_PXE_BIOS:
+- image_offset = FLASH_PXE_BIOS_START;
+- image_size = FLASH_BIOS_IMAGE_MAX_SIZE;
+- break;
+- default:
+- return 0;
++ struct flash_comp gen3_flash_types[10] = {
++ { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE,
++ FLASH_IMAGE_MAX_SIZE_g3},
++ { FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT,
++ FLASH_REDBOOT_IMAGE_MAX_SIZE_g3},
++ { FLASH_iSCSI_BIOS_START_g3, IMG_TYPE_BIOS,
++ FLASH_BIOS_IMAGE_MAX_SIZE_g3},
++ { FLASH_PXE_BIOS_START_g3, IMG_TYPE_PXE_BIOS,
++ FLASH_BIOS_IMAGE_MAX_SIZE_g3},
++ { FLASH_FCoE_BIOS_START_g3, IMG_TYPE_FCOE_BIOS,
++ FLASH_BIOS_IMAGE_MAX_SIZE_g3},
++ { FLASH_iSCSI_BACKUP_IMAGE_START_g3, IMG_TYPE_ISCSI_BACKUP,
++ FLASH_IMAGE_MAX_SIZE_g3},
++ { FLASH_FCoE_PRIMARY_IMAGE_START_g3, IMG_TYPE_FCOE_FW_ACTIVE,
++ FLASH_IMAGE_MAX_SIZE_g3},
++ { FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP,
++ FLASH_IMAGE_MAX_SIZE_g3},
++ { FLASH_NCSI_START_g3, IMG_TYPE_NCSI_FW,
++ FLASH_NCSI_IMAGE_MAX_SIZE_g3},
++ { FLASH_PHY_FW_START_g3, IMG_TYPE_PHY_FW,
++ FLASH_PHY_FW_IMAGE_MAX_SIZE_g3}
++ };
++ struct flash_comp gen2_flash_types[8] = {
++ { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE,
++ FLASH_IMAGE_MAX_SIZE_g2},
++ { FLASH_REDBOOT_START_g2, IMG_TYPE_REDBOOT,
++ FLASH_REDBOOT_IMAGE_MAX_SIZE_g2},
++ { FLASH_iSCSI_BIOS_START_g2, IMG_TYPE_BIOS,
++ FLASH_BIOS_IMAGE_MAX_SIZE_g2},
++ { FLASH_PXE_BIOS_START_g2, IMG_TYPE_PXE_BIOS,
++ FLASH_BIOS_IMAGE_MAX_SIZE_g2},
++ { FLASH_FCoE_BIOS_START_g2, IMG_TYPE_FCOE_BIOS,
++ FLASH_BIOS_IMAGE_MAX_SIZE_g2},
++ { FLASH_iSCSI_BACKUP_IMAGE_START_g2, IMG_TYPE_ISCSI_BACKUP,
++ FLASH_IMAGE_MAX_SIZE_g2},
++ { FLASH_FCoE_PRIMARY_IMAGE_START_g2, IMG_TYPE_FCOE_FW_ACTIVE,
++ FLASH_IMAGE_MAX_SIZE_g2},
++ { FLASH_FCoE_BACKUP_IMAGE_START_g2, IMG_TYPE_FCOE_FW_BACKUP,
++ FLASH_IMAGE_MAX_SIZE_g2}
++ };
++ if (adapter->generation == BE_GEN3) {
++ pflashcomp = gen3_flash_types;
++ filehdr_size = sizeof(struct flash_file_hdr_g3);
++ num_comp = ARRAY_SIZE(gen3_flash_types);
++ } else {
++ pflashcomp = gen2_flash_types;
++ filehdr_size = sizeof(struct flash_file_hdr_g2);
++ num_comp = ARRAY_SIZE(gen2_flash_types);
+ }
++ for (i = 0; i < num_comp; i++) {
++ if ((pflashcomp[i].optype == IMG_TYPE_NCSI_FW) &&
++ memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0)
++ continue;
++ if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) {
++ if (!phy_flashing_required(adapter))
++ continue;
++ }
++ if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) &&
++ (!be_flash_redboot(adapter, fw->data,
++ pflashcomp[i].offset, pflashcomp[i].size, filehdr_size +
++ (num_of_images * sizeof(struct image_hdr)))))
++ continue;
+
+- p += sizeof(struct flash_file_hdr) + image_offset;
+- if (p + image_size > fw->data + fw->size)
+- return -1;
+-
+- total_bytes = image_size;
+-
+- while (total_bytes) {
+- if (total_bytes > 32*1024)
+- num_bytes = 32*1024;
+- else
+- num_bytes = total_bytes;
+- total_bytes -= num_bytes;
+-
+- if (!total_bytes)
+- flash_op = FLASHROM_OPER_FLASH;
+- else
+- flash_op = FLASHROM_OPER_SAVE;
+- memcpy(req->params.data_buf, p, num_bytes);
+- p += num_bytes;
+- status = be_cmd_write_flashrom(adapter, flash_cmd,
+- flash_type, flash_op, num_bytes);
+- if (status) {
+- dev_err(&adapter->pdev->dev,
+- "cmd to write to flash rom failed. type/op %d/%d\n",
+- flash_type, flash_op);
++ p = fw->data;
++ p += filehdr_size + pflashcomp[i].offset
++ + (num_of_images * sizeof(struct image_hdr));
++ if (p + pflashcomp[i].size > fw->data + fw->size)
+ return -1;
++ total_bytes = pflashcomp[i].size;
++ while (total_bytes) {
++ if (total_bytes > 32*1024)
++ num_bytes = 32*1024;
++ else
++ num_bytes = total_bytes;
++ total_bytes -= num_bytes;
++ if (!total_bytes) {
++ if (pflashcomp[i].optype == IMG_TYPE_PHY_FW)
++ flash_op = FLASHROM_OPER_PHY_FLASH;
++ else
++ flash_op = FLASHROM_OPER_FLASH;
++ } else {
++ if (pflashcomp[i].optype == IMG_TYPE_PHY_FW)
++ flash_op = FLASHROM_OPER_PHY_SAVE;
++ else
++ flash_op = FLASHROM_OPER_SAVE;
++ }
++ memcpy(req->params.data_buf, p, num_bytes);
++ p += num_bytes;
++ status = be_cmd_write_flashrom(adapter, flash_cmd,
++ pflashcomp[i].optype, flash_op, num_bytes);
++ if (status) {
++ if ((status == ILLEGAL_IOCTL_REQ) &&
++ (pflashcomp[i].optype ==
++ IMG_TYPE_PHY_FW))
++ break;
++ dev_err(&adapter->pdev->dev,
++ "cmd to write to flash rom failed.\n");
++ return -1;
++ }
++ yield();
+ }
+- yield();
+ }
+-
+ return 0;
+ }
+
++static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)
++{
++ if (fhdr == NULL)
++ return 0;
++ if (fhdr->build[0] == '3')
++ return BE_GEN3;
++ else if (fhdr->build[0] == '2')
++ return BE_GEN2;
++ else
++ return 0;
++}
++
+ int be_load_fw(struct be_adapter *adapter, u8 *func)
+ {
+ char fw_file[ETHTOOL_FLASH_MAX_FILENAME];
+ const struct firmware *fw;
+- struct flash_file_hdr *fhdr;
+- struct flash_section_info *fsec = NULL;
++ struct flash_file_hdr_g2 *fhdr;
++ struct flash_file_hdr_g3 *fhdr3;
++ struct image_hdr *img_hdr_ptr = NULL;
+ struct be_dma_mem flash_cmd;
+- int status;
++ int status, i = 0, num_imgs = 0;
+ const u8 *p;
+- bool entry_found = false;
+- int flash_type;
+- char fw_ver[FW_VER_LEN];
+- char fw_cfg;
+
+- status = be_cmd_get_fw_ver(adapter, fw_ver);
+- if (status)
+- return status;
++ if (!netif_running(adapter->netdev)) {
++ dev_err(&adapter->pdev->dev,
++ "Firmware load not allowed (interface is down)\n");
++ return -1;
++ }
+
+- fw_cfg = *(fw_ver + 2);
+- if (fw_cfg == '0')
+- fw_cfg = '1';
+ strcpy(fw_file, func);
+
+ status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
+@@ -1826,34 +3202,9 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
+ goto fw_exit;
+
+ p = fw->data;
+- fhdr = (struct flash_file_hdr *) p;
+- if (memcmp(fhdr->sign, FW_FILE_HDR_SIGN, strlen(FW_FILE_HDR_SIGN))) {
+- dev_err(&adapter->pdev->dev,
+- "Firmware(%s) load error (signature did not match)\n",
+- fw_file);
+- status = -1;
+- goto fw_exit;
+- }
+-
++ fhdr = (struct flash_file_hdr_g2 *) p;
+ dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
+
+- p += sizeof(struct flash_file_hdr);
+- while (p < (fw->data + fw->size)) {
+- fsec = (struct flash_section_info *)p;
+- if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) {
+- entry_found = true;
+- break;
+- }
+- p += 32;
+- }
+-
+- if (!entry_found) {
+- status = -1;
+- dev_err(&adapter->pdev->dev,
+- "Flash cookie not found in firmware image\n");
+- goto fw_exit;
+- }
+-
+ flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024;
+ flash_cmd.va = pci_alloc_consistent(adapter->pdev, flash_cmd.size,
+ &flash_cmd.dma);
+@@ -1864,12 +3215,25 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
+ goto fw_exit;
+ }
+
+- for (flash_type = FLASHROM_TYPE_ISCSI_ACTIVE;
+- flash_type <= FLASHROM_TYPE_FCOE_FW_BACKUP; flash_type++) {
+- status = be_flash_image(adapter, fw, &flash_cmd,
+- flash_type);
+- if (status)
+- break;
++ if ((adapter->generation == BE_GEN3) &&
++ (get_ufigen_type(fhdr) == BE_GEN3)) {
++ fhdr3 = (struct flash_file_hdr_g3 *) fw->data;
++ num_imgs = le32_to_cpu(fhdr3->num_imgs);
++ for (i = 0; i < num_imgs; i++) {
++ img_hdr_ptr = (struct image_hdr *) (fw->data +
++ (sizeof(struct flash_file_hdr_g3) +
++ i * sizeof(struct image_hdr)));
++ if (le32_to_cpu(img_hdr_ptr->imageid) == 1)
++ status = be_flash_data(adapter, fw, &flash_cmd,
++ num_imgs);
++ }
++ } else if ((adapter->generation == BE_GEN2) &&
++ (get_ufigen_type(fhdr) == BE_GEN2)) {
++ status = be_flash_data(adapter, fw, &flash_cmd, 0);
++ } else {
++ dev_err(&adapter->pdev->dev,
++ "UFI and Interface are not compatible for flashing\n");
++ status = -1;
+ }
+
+ pci_free_consistent(adapter->pdev, flash_cmd.size, flash_cmd.va,
+@@ -1879,14 +3243,14 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
+ goto fw_exit;
+ }
+
+- dev_info(&adapter->pdev->dev, "Firmware flashed succesfully\n");
++ dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
+
+ fw_exit:
+ release_firmware(fw);
+ return status;
+ }
+
+-static struct net_device_ops be_netdev_ops = {
++static net_device_ops_no_const be_netdev_ops = {
+ .ndo_open = be_open,
+ .ndo_stop = be_close,
+ .ndo_start_xmit = be_xmit,
+@@ -1898,15 +3262,32 @@ static struct net_device_ops be_netdev_ops = {
+ .ndo_vlan_rx_register = be_vlan_register,
+ .ndo_vlan_rx_add_vid = be_vlan_add_vid,
+ .ndo_vlan_rx_kill_vid = be_vlan_rem_vid,
++#ifdef HAVE_SRIOV_CONFIG
++ .ndo_set_vf_mac = be_set_vf_mac,
++ .ndo_set_vf_vlan = be_set_vf_vlan,
++ .ndo_set_vf_tx_rate = be_set_vf_tx_rate,
++ .ndo_get_vf_config = be_get_vf_config,
++#endif
++ .ndo_do_ioctl = be_do_ioctl,
++#ifdef CONFIG_NET_POLL_CONTROLLER
++ .ndo_poll_controller = be_netpoll,
++#endif
+ };
+
+-static void be_netdev_init(struct net_device *netdev)
++static int be_netdev_init(struct net_device *netdev)
+ {
+ struct be_adapter *adapter = netdev_priv(netdev);
++ struct be_rx_obj *rxo;
++ int i, status = 0;
+
+ netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
+- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM |
+- NETIF_F_GRO;
++ NETIF_F_HW_VLAN_TX | NETIF_F_HW_CSUM | NETIF_F_TSO6;
++
++ netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
++ NETIF_F_HW_CSUM;
++
++ netdev->features |= NETIF_F_VLAN_SG | NETIF_F_VLAN_TSO |
++ NETIF_F_VLAN_CSUM;
+
+ netdev->flags |= IFF_MULTICAST;
+
+@@ -1918,17 +3299,30 @@ static void be_netdev_init(struct net_device *netdev)
+
+ netif_set_gso_max_size(netdev, 65535);
+
++ if (adapter->flags & BE_FLAGS_DCBX)
++ be_netdev_ops.ndo_select_queue = be_select_queue;
+ BE_SET_NETDEV_OPS(netdev, &be_netdev_ops);
+-
++
+ SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
+
+- netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
+- BE_NAPI_WEIGHT);
+- netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
++ be_lro_init(adapter, netdev);
++
++ for_all_rx_queues(adapter, rxo, i) {
++ status = be_netif_napi_add(netdev, &rxo->rx_eq.napi, be_poll_rx,
++ BE_NAPI_WEIGHT);
++ if (status) {
++ dev_err(&adapter->pdev->dev, "dummy netdev alloc fail"
++ "for rxo:%d\n", i);
++ return status;
++ }
++ }
++ status = be_netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
+ BE_NAPI_WEIGHT);
++ if (status)
++ dev_err(&adapter->pdev->dev, "dummy netdev alloc fail"
++ "for tx\n");
+
+- netif_carrier_off(netdev);
+- netif_stop_queue(netdev);
++ return status;
+ }
+
+ static void be_unmap_pci_bars(struct be_adapter *adapter)
+@@ -1937,37 +3331,62 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
+ iounmap(adapter->csr);
+ if (adapter->db)
+ iounmap(adapter->db);
+- if (adapter->pcicfg)
++ if (adapter->pcicfg && be_physfn(adapter))
+ iounmap(adapter->pcicfg);
+ }
+
+ static int be_map_pci_bars(struct be_adapter *adapter)
+ {
++ struct pci_dev *pdev = adapter->pdev;
+ u8 __iomem *addr;
+- int pcicfg_reg;
++ int pcicfg_reg, db_reg;
+
+- addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2),
+- pci_resource_len(adapter->pdev, 2));
+- if (addr == NULL)
+- return -ENOMEM;
+- adapter->csr = addr;
++ if (lancer_chip(adapter)) {
++ addr = ioremap_nocache(pci_resource_start(pdev, 0),
++ pci_resource_len(adapter->pdev, 0));
++ if (addr == NULL)
++ return -ENOMEM;
++ adapter->db = addr;
++ return 0;
++ }
+
+- addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4),
+- 128 * 1024);
+- if (addr == NULL)
+- goto pci_map_err;
+- adapter->db = addr;
++ if (be_physfn(adapter)) {
++ addr = ioremap_nocache(pci_resource_start(pdev, 2),
++ pci_resource_len(pdev, 2));
++ if (addr == NULL)
++ return -ENOMEM;
++ adapter->csr = addr;
++ adapter->netdev->mem_start = pci_resource_start(pdev, 2);
++ adapter->netdev->mem_end = pci_resource_start(pdev, 2) +
++ pci_resource_len(pdev, 2);
++ }
+
+- if (adapter->generation == BE_GEN2)
++ if (adapter->generation == BE_GEN2) {
+ pcicfg_reg = 1;
+- else
++ db_reg = 4;
++ } else {
+ pcicfg_reg = 0;
++ if (be_physfn(adapter))
++ db_reg = 4;
++ else
++ db_reg = 0;
++ }
+
+- addr = ioremap_nocache(pci_resource_start(adapter->pdev, pcicfg_reg),
+- pci_resource_len(adapter->pdev, pcicfg_reg));
++ addr = ioremap_nocache(pci_resource_start(pdev, db_reg),
++ pci_resource_len(pdev, db_reg));
+ if (addr == NULL)
+ goto pci_map_err;
+- adapter->pcicfg = addr;
++ adapter->db = addr;
++
++ if (be_physfn(adapter)) {
++ addr = ioremap_nocache(
++ pci_resource_start(pdev, pcicfg_reg),
++ pci_resource_len(pdev, pcicfg_reg));
++ if (addr == NULL)
++ goto pci_map_err;
++ adapter->pcicfg = addr;
++ } else
++ adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
+
+ return 0;
+ pci_map_err:
+@@ -1985,40 +3404,69 @@ static void be_ctrl_cleanup(struct be_adapter *adapter)
+ if (mem->va)
+ pci_free_consistent(adapter->pdev, mem->size,
+ mem->va, mem->dma);
++
++ mem = &adapter->rx_filter;
++ if (mem->va)
++ pci_free_consistent(adapter->pdev, mem->size,
++ mem->va, mem->dma);
+ }
+
+ static int be_ctrl_init(struct be_adapter *adapter)
+ {
+ struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced;
+ struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem;
++ struct be_dma_mem *rx_filter = &adapter->rx_filter;
+ int status;
+
+ status = be_map_pci_bars(adapter);
+ if (status)
+- return status;
++ goto done;
+
+ mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16;
+ mbox_mem_alloc->va = pci_alloc_consistent(adapter->pdev,
+ mbox_mem_alloc->size, &mbox_mem_alloc->dma);
+ if (!mbox_mem_alloc->va) {
+- be_unmap_pci_bars(adapter);
+- return -1;
++ status = -ENOMEM;
++ goto unmap_pci_bars;
+ }
++
+ mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
+ mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
+ mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
+ memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
+- spin_lock_init(&adapter->mbox_lock);
++
++ rx_filter->size = sizeof(struct be_cmd_req_rx_filter);
++ rx_filter->va = pci_alloc_consistent(adapter->pdev, rx_filter->size,
++ &rx_filter->dma);
++ if (rx_filter->va == NULL) {
++ status = -ENOMEM;
++ goto free_mbox;
++ }
++ memset(rx_filter->va, 0, rx_filter->size);
++
++ mutex_init(&adapter->mbox_lock);
+ spin_lock_init(&adapter->mcc_lock);
+ spin_lock_init(&adapter->mcc_cq_lock);
+
++ init_completion(&adapter->flash_compl);
++
++ PCI_SAVE_STATE(adapter->pdev);
+ return 0;
++
++free_mbox:
++ pci_free_consistent(adapter->pdev, mbox_mem_alloc->size,
++ mbox_mem_alloc->va, mbox_mem_alloc->dma);
++
++unmap_pci_bars:
++ be_unmap_pci_bars(adapter);
++
++done:
++ return status;
+ }
+
+ static void be_stats_cleanup(struct be_adapter *adapter)
+ {
+- struct be_stats_obj *stats = &adapter->stats;
+- struct be_dma_mem *cmd = &stats->cmd;
++ struct be_dma_mem *cmd = &adapter->stats_cmd;
+
+ if (cmd->va)
+ pci_free_consistent(adapter->pdev, cmd->size,
+@@ -2027,10 +3475,12 @@ static void be_stats_cleanup(struct be_adapter *adapter)
+
+ static int be_stats_init(struct be_adapter *adapter)
+ {
+- struct be_stats_obj *stats = &adapter->stats;
+- struct be_dma_mem *cmd = &stats->cmd;
++ struct be_dma_mem *cmd = &adapter->stats_cmd;
+
+- cmd->size = sizeof(struct be_cmd_req_get_stats);
++ if (adapter->generation == BE_GEN2)
++ cmd->size = sizeof(struct be_cmd_req_get_stats_v0);
++ else
++ cmd->size = sizeof(struct be_cmd_req_get_stats_v1);
+ cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma);
+ if (cmd->va == NULL)
+ return -1;
+@@ -2041,9 +3491,17 @@ static int be_stats_init(struct be_adapter *adapter)
+ static void __devexit be_remove(struct pci_dev *pdev)
+ {
+ struct be_adapter *adapter = pci_get_drvdata(pdev);
++
+ if (!adapter)
+ return;
+
++ cancel_delayed_work_sync(&adapter->work);
++
++#ifdef CONFIG_PALAU
++ be_sysfs_remove_group(adapter);
++#endif
++
++ /* be_close() gets called if the device is open by unregister */
+ unregister_netdev(adapter->netdev);
+
+ be_clear(adapter);
+@@ -2052,36 +3510,203 @@ static void __devexit be_remove(struct pci_dev *pdev)
+
+ be_ctrl_cleanup(adapter);
+
+- if (adapter->msix_enabled) {
+- pci_disable_msix(adapter->pdev);
+- adapter->msix_enabled = false;
+- }
++ kfree(adapter->vf_cfg);
++ be_sriov_disable(adapter);
++
++ be_msix_disable(adapter);
+
+ pci_set_drvdata(pdev, NULL);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+-
++ be_netif_napi_del(adapter->netdev);
+ free_netdev(adapter->netdev);
+ }
+
+-static int be_hw_up(struct be_adapter *adapter)
++static void be_pcie_slot_check(struct be_adapter *adapter)
++{
++ u32 curr, max, width, max_wd, speed, max_sp;
++
++ pci_read_config_dword(adapter->pdev, PCICFG_PCIE_LINK_STATUS_OFFSET,
++ &curr);
++ width = (curr >> PCIE_LINK_STATUS_NEG_WIDTH_SHIFT) &
++ PCIE_LINK_STATUS_NEG_WIDTH_MASK;
++ speed = (curr >> PCIE_LINK_STATUS_SPEED_SHIFT) &
++ PCIE_LINK_STATUS_SPEED_MASK;
++
++ pci_read_config_dword(adapter->pdev, PCICFG_PCIE_LINK_CAP_OFFSET,
++ &max);
++ max_wd = (max >> PCIE_LINK_CAP_MAX_WIDTH_SHIFT) &
++ PCIE_LINK_CAP_MAX_WIDTH_MASK;
++ max_sp = (max >> PCIE_LINK_CAP_MAX_SPEED_SHIFT) &
++ PCIE_LINK_CAP_MAX_SPEED_MASK;
++
++ if (width < max_wd || speed < max_sp)
++ dev_warn(&adapter->pdev->dev,
++ "Found network device in a Gen%s x%d PCIe slot. It "
++ "should be in a Gen2 x%d slot for best performance\n",
++ speed < max_sp ? "1" : "2", width, max_wd);
++}
++
++static int be_get_ioctl_version(char *fw_version) {
++ char *str[4];
++ int i;
++ int val[4];
++ char *endptr;
++
++ if(!fw_version)
++ return 0;
++ for(i=0; i<3; i++) {
++ str[i] = strsep(&fw_version, ".");
++ val[i] = simple_strtol(str[i], &endptr, 10);
++ }
++
++ if (val[0]>4 || (val[0]>3 && val[2]>143))
++ return 1;
++ return 0;
++}
++
++static int be_get_port_names(struct be_adapter *adapter)
+ {
+ int status;
++ int ver;
+
+- status = be_cmd_POST(adapter);
++ status = be_cmd_get_fw_ver(adapter,
++ adapter->fw_ver, NULL);
+ if (status)
+ return status;
++ ver = be_get_ioctl_version(adapter->fw_ver);
++ if (ver && (adapter->generation == BE_GEN3))
++ status = be_cmd_query_port_names_v1(adapter,
++ adapter->port_name);
++ else
++ status = be_cmd_query_port_names_v0(adapter,
++ adapter->port_name);
++ return status;
++}
+
+- status = be_cmd_reset_function(adapter);
++static int be_get_config(struct be_adapter *adapter)
++{
++ int status;
++ u8 mac[ETH_ALEN];
++
++ status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
++ &adapter->function_mode,
++ &adapter->function_caps);
+ if (status)
+ return status;
+
+- status = be_cmd_get_fw_ver(adapter, adapter->fw_ver);
++ status = be_cmd_get_cntl_attributes(adapter);
+ if (status)
+ return status;
+
+- status = be_cmd_query_fw_cfg(adapter,
+- &adapter->port_num, &adapter->cap);
++ memset(mac, 0, ETH_ALEN);
++ be_pcie_slot_check(adapter);
++
++ if (be_physfn(adapter)) {
++ status = be_cmd_mac_addr_query(adapter, mac,
++ MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0);
++
++ if (status)
++ return status;
++
++ if (!is_valid_ether_addr(mac))
++ return -EADDRNOTAVAIL;
++
++ memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
++ memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
++ }
++
++ if (adapter->function_mode & FLEX10_MODE)
++ adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
++ else
++ adapter->max_vlans = BE_NUM_VLANS_SUPPORTED;
++
++ return 0;
++}
++
++static int be_dev_family_check(struct be_adapter *adapter)
++{
++ struct pci_dev *pdev = adapter->pdev;
++ u32 sli_intf = 0, if_type;
++
++ switch (pdev->device) {
++ case BE_DEVICE_ID1:
++ case OC_DEVICE_ID1:
++ adapter->generation = BE_GEN2;
++ break;
++ case BE_DEVICE_ID2:
++ case OC_DEVICE_ID2:
++ adapter->generation = BE_GEN3;
++ break;
++ case OC_DEVICE_ID3:
++ pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);
++ if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>
++ SLI_INTF_IF_TYPE_SHIFT;
++
++ if (((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) ||
++ if_type != 0x02) {
++ dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");
++ return -EINVAL;
++ }
++ if (num_vfs > 0) {
++ dev_err(&pdev->dev, "VFs not supported\n");
++ return -EINVAL;
++ }
++ adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >>
++ SLI_INTF_FAMILY_SHIFT);
++ adapter->generation = BE_GEN3;
++ break;
++ default:
++ adapter->generation = 0;
++ }
++ return 0;
++}
++
++static int lancer_wait_ready(struct be_adapter *adapter)
++{
++#define SLIPORT_READY_TIMEOUT 500
++ u32 sliport_status;
++ int status = 0, i;
++
++ for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) {
++ sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
++ if (sliport_status & SLIPORT_STATUS_RDY_MASK)
++ break;
++
++ msleep(20);
++ }
++
++ if (i == SLIPORT_READY_TIMEOUT)
++ status = -1;
++
++ return status;
++}
++
++static int lancer_test_and_set_rdy_state(struct be_adapter *adapter)
++{
++ int status;
++ u32 sliport_status, err, reset_needed;
++ status = lancer_wait_ready(adapter);
++ if (!status) {
++ sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
++ err = sliport_status & SLIPORT_STATUS_ERR_MASK;
++ reset_needed = sliport_status & SLIPORT_STATUS_RN_MASK;
++ if (err && reset_needed) {
++ iowrite32(SLI_PORT_CONTROL_IP_MASK,
++ adapter->db + SLIPORT_CONTROL_OFFSET);
++
++ /* check adapter has corrected the error */
++ status = lancer_wait_ready(adapter);
++ sliport_status = ioread32(adapter->db +
++ SLIPORT_STATUS_OFFSET);
++ sliport_status &= (SLIPORT_STATUS_ERR_MASK |
++ SLIPORT_STATUS_RN_MASK);
++ if (status || sliport_status)
++ status = -1;
++ } else if (err || reset_needed) {
++ status = -1;
++ }
++ }
+ return status;
+ }
+
+@@ -2091,7 +3716,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
+ int status = 0;
+ struct be_adapter *adapter;
+ struct net_device *netdev;
+- u8 mac[ETH_ALEN];
++ u32 en;
+
+ status = pci_enable_device(pdev);
+ if (status)
+@@ -2102,31 +3727,22 @@ static int __devinit be_probe(struct pci_dev *pdev,
+ goto disable_dev;
+ pci_set_master(pdev);
+
+- netdev = alloc_etherdev(sizeof(struct be_adapter));
++ netdev = alloc_etherdev_mq(sizeof(struct be_adapter), MAX_TX_QS);
+ if (netdev == NULL) {
+ status = -ENOMEM;
+ goto rel_reg;
+ }
+ adapter = netdev_priv(netdev);
+
+- switch (pdev->device) {
+- case BE_DEVICE_ID1:
+- case OC_DEVICE_ID1:
+- adapter->generation = BE_GEN2;
+- break;
+- case BE_DEVICE_ID2:
+- case OC_DEVICE_ID2:
+- adapter->generation = BE_GEN3;
+- break;
+- default:
+- adapter->generation = 0;
+- }
+-
+ adapter->pdev = pdev;
++
++ status = be_dev_family_check(adapter);
++ if (status)
++ goto free_netdev;
++
+ pci_set_drvdata(pdev, adapter);
+ adapter->netdev = netdev;
+-
+- be_msix_enable(adapter);
++ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ status = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (!status) {
+@@ -2139,46 +3755,150 @@ static int __devinit be_probe(struct pci_dev *pdev,
+ }
+ }
+
++ be_sriov_enable(adapter);
++ if (adapter->num_vfs > 0) {
++ adapter->vf_cfg = kcalloc(adapter->num_vfs,
++ sizeof(struct be_vf_cfg), GFP_KERNEL);
++
++ if (!adapter->vf_cfg)
++ goto free_netdev;
++ }
++
+ status = be_ctrl_init(adapter);
+ if (status)
+- goto free_netdev;
++ goto free_vf_cfg;
++
++ if (lancer_chip(adapter)) {
++ status = lancer_test_and_set_rdy_state(adapter);
++ if (status) {
++ dev_err(&pdev->dev, "Adapter in non recoverable error\n");
++ goto ctrl_clean;
++ }
++ }
++
++ /* sync up with fw's ready state */
++ if (be_physfn(adapter)) {
++ status = be_cmd_POST(adapter);
++ if (status)
++ goto ctrl_clean;
++ }
++
++ /* tell fw we're ready to fire cmds */
++ status = be_cmd_fw_init(adapter);
++ if (status)
++ goto ctrl_clean;
++
++ status = be_cmd_reset_function(adapter);
++ if (status)
++ goto ctrl_clean;
+
+ status = be_stats_init(adapter);
+ if (status)
+ goto ctrl_clean;
+
+- status = be_hw_up(adapter);
++ status = be_get_config(adapter);
+ if (status)
+ goto stats_clean;
+
+- status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK,
+- true /* permanent */, 0);
+- if (status)
+- goto stats_clean;
+- memcpy(netdev->dev_addr, mac, ETH_ALEN);
++ /* This bit is zero in normal boot case, but in crash kernel case this
++ is not cleared. clear this bit here, until we are ready with the irqs
++ i.e in be_open call.*/
++ if (!lancer_chip(adapter))
++ be_intr_set(adapter, false);
++
++ if (msix)
++ be_msix_enable(adapter);
+
+ INIT_DELAYED_WORK(&adapter->work, be_worker);
+- be_netdev_init(netdev);
+- SET_NETDEV_DEV(netdev, &adapter->pdev->dev);
+
+ status = be_setup(adapter);
+ if (status)
+- goto stats_clean;
++ goto msix_disable;
++
++ /* Initilize the link status to -1 */
++ adapter->link_status = -1;
++
++ status = be_netdev_init(netdev);
++ if (status)
++ goto unsetup;
++
+ status = register_netdev(netdev);
+ if (status != 0)
+ goto unsetup;
+
+- dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
++ be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL);
++
++ if (be_physfn(adapter) && adapter->num_vfs) {
++ u8 mac_speed;
++ int link_status;
++ u16 def_vlan, vf, lnk_speed;
++
++ status = be_vf_eth_addr_config(adapter);
++ if (status)
++ goto unreg_netdev;
++
++ for (vf = 0; vf < adapter->num_vfs; vf++) {
++ status = be_cmd_get_hsw_config(adapter, &def_vlan,
++ vf + 1, adapter->vf_cfg[vf].vf_if_handle);
++ if (!status)
++ adapter->vf_cfg[vf].vf_def_vid = def_vlan;
++ else
++ goto unreg_netdev;
++
++ status = be_cmd_link_status_query(adapter, &link_status,
++ &mac_speed, &lnk_speed, vf + 1);
++ if (!status)
++ adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10;
++ else
++ goto unreg_netdev;
++ }
++ }
++ if (be_physfn(adapter)) {
++ /* Temp fix ofr bug# 23034. Till ARM
++ * f/w fixes privilege lvl */
++ be_get_port_names(adapter);
++ }
++
++ /* Enable Vlan capability based on privileges.
++ * PF will have Vlan capability anyway. */
++ be_cmd_get_fn_privileges(adapter, &en, 0);
++
++ if ((en & (BE_PRIV_FILTMGMT | BE_PRIV_VHADM | BE_PRIV_DEVCFG)) ||
++ be_physfn(adapter))
++ netdev->features |= NETIF_F_HW_VLAN_FILTER;
++ else
++ netdev->features |= NETIF_F_VLAN_CHALLENGED;
++
++ dev_info(&pdev->dev, "%s: numa node %d\n", netdev->name,
++ dev_to_node(&pdev->dev));
++ dev_info(&pdev->dev, "%s %s \"%s\" port %d\n", nic_name(pdev),
++ (adapter->port_num > 1 ? "1Gbps NIC" : "10Gbps NIC"),
++ adapter->model_number, adapter->hba_port_num);
++
++
++#ifdef CONFIG_PALAU
++ be_sysfs_create_group(adapter);
++#endif
++ schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
+ return 0;
+
++unreg_netdev:
++ unregister_netdev(netdev);
+ unsetup:
+ be_clear(adapter);
++msix_disable:
++ be_msix_disable(adapter);
+ stats_clean:
+ be_stats_cleanup(adapter);
+ ctrl_clean:
+ be_ctrl_cleanup(adapter);
++free_vf_cfg:
++ kfree(adapter->vf_cfg);
+ free_netdev:
+- free_netdev(adapter->netdev);
++ be_sriov_disable(adapter);
++ be_netif_napi_del(netdev);
++ free_netdev(netdev);
++ pci_set_drvdata(pdev, NULL);
+ rel_reg:
+ pci_release_regions(pdev);
+ disable_dev:
+@@ -2193,6 +3913,10 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
+ struct be_adapter *adapter = pci_get_drvdata(pdev);
+ struct net_device *netdev = adapter->netdev;
+
++ cancel_delayed_work_sync(&adapter->work);
++ if (adapter->wol)
++ be_setup_wol(adapter, true);
++
+ netif_device_detach(netdev);
+ if (netif_running(netdev)) {
+ rtnl_lock();
+@@ -2202,6 +3926,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
+ be_cmd_get_flow_control(adapter, &adapter->tx_fc, &adapter->rx_fc);
+ be_clear(adapter);
+
++ be_msix_disable(adapter);
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+@@ -2223,6 +3948,12 @@ static int be_resume(struct pci_dev *pdev)
+ pci_set_power_state(pdev, 0);
+ pci_restore_state(pdev);
+
++ be_msix_enable(adapter);
++ /* tell fw we're ready to fire cmds */
++ status = be_cmd_fw_init(adapter);
++ if (status)
++ return status;
++
+ be_setup(adapter);
+ if (netif_running(netdev)) {
+ rtnl_lock();
+@@ -2230,28 +3961,152 @@ static int be_resume(struct pci_dev *pdev)
+ rtnl_unlock();
+ }
+ netif_device_attach(netdev);
++
++ if (adapter->wol)
++ be_setup_wol(adapter, false);
++
++ schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
+ return 0;
+ }
+
++/*
++ * An FLR will stop BE from DMAing any data.
++ */
++static void be_shutdown(struct pci_dev *pdev)
++{
++ struct be_adapter *adapter = pci_get_drvdata(pdev);
++
++ if (!adapter)
++ return;
++
++ cancel_delayed_work_sync(&adapter->work);
++
++ netif_device_detach(adapter->netdev);
++
++ if (adapter->wol)
++ be_setup_wol(adapter, true);
++
++ be_cmd_reset_function(adapter);
++
++ pci_disable_device(pdev);
++}
++
++static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,
++ pci_channel_state_t state)
++{
++ struct be_adapter *adapter = pci_get_drvdata(pdev);
++ struct net_device *netdev = adapter->netdev;
++
++ dev_err(&adapter->pdev->dev, "EEH error detected\n");
++
++ adapter->eeh_err = true;
++
++ netif_device_detach(netdev);
++
++ if (netif_running(netdev)) {
++ rtnl_lock();
++ be_close(netdev);
++ rtnl_unlock();
++ }
++ be_clear(adapter);
++
++ if (state == pci_channel_io_perm_failure)
++ return PCI_ERS_RESULT_DISCONNECT;
++
++ pci_disable_device(pdev);
++
++ return PCI_ERS_RESULT_NEED_RESET;
++}
++
++static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
++{
++ struct be_adapter *adapter = pci_get_drvdata(pdev);
++ int status;
++
++ dev_info(&adapter->pdev->dev, "EEH reset\n");
++ adapter->eeh_err = false;
++
++ status = pci_enable_device(pdev);
++ if (status)
++ return PCI_ERS_RESULT_DISCONNECT;
++
++ pci_set_master(pdev);
++ pci_set_power_state(pdev, 0);
++ pci_restore_state(pdev);
++
++ /* Check if card is ok and fw is ready */
++ status = be_cmd_POST(adapter);
++ if (status)
++ return PCI_ERS_RESULT_DISCONNECT;
++
++ return PCI_ERS_RESULT_RECOVERED;
++}
++
++static void be_eeh_resume(struct pci_dev *pdev)
++{
++ int status = 0;
++ struct be_adapter *adapter = pci_get_drvdata(pdev);
++ struct net_device *netdev = adapter->netdev;
++
++ dev_info(&adapter->pdev->dev, "EEH resume\n");
++
++ pci_save_state(pdev);
++
++ /* tell fw we're ready to fire cmds */
++ status = be_cmd_fw_init(adapter);
++ if (status)
++ goto err;
++
++ status = be_setup(adapter);
++ if (status)
++ goto err;
++
++ if (netif_running(netdev)) {
++ status = be_open(netdev);
++ if (status)
++ goto err;
++ }
++ netif_device_attach(netdev);
++ return;
++err:
++ dev_err(&adapter->pdev->dev, "EEH resume failed\n");
++ return;
++}
++
++static struct pci_error_handlers be_eeh_handlers = {
++ .error_detected = be_eeh_err_detected,
++ .slot_reset = be_eeh_reset,
++ .resume = be_eeh_resume,
++};
++
+ static struct pci_driver be_driver = {
+ .name = DRV_NAME,
+ .id_table = be_dev_ids,
+ .probe = be_probe,
+ .remove = be_remove,
+ .suspend = be_suspend,
+- .resume = be_resume
++ .resume = be_resume,
++ .shutdown = be_shutdown,
++ .err_handler = &be_eeh_handlers
+ };
+
+ static int __init be_init_module(void)
+ {
+- if (rx_frag_size != 8192 && rx_frag_size != 4096
+- && rx_frag_size != 2048) {
++ if (rx_frag_size != 8192 && rx_frag_size != 4096 &&
++ rx_frag_size != 2048) {
+ printk(KERN_WARNING DRV_NAME
+ " : Module param rx_frag_size must be 2048/4096/8192."
+ " Using 2048\n");
+ rx_frag_size = 2048;
+ }
+
++ if (!msix && num_vfs > 0) {
++ printk(KERN_WARNING DRV_NAME
++ " : MSIx required for num_vfs > 0. Ignoring msix=0\n");
++ msix = 1;
++ }
++
++
+ return pci_register_driver(&be_driver);
+ }
+ module_init(be_init_module);
+diff --git a/drivers/net/benet/be_misc.c b/drivers/net/benet/be_misc.c
+new file mode 100644
+index 0000000..4ab499f
+--- /dev/null
++++ b/drivers/net/benet/be_misc.c
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (C) 2005 - 2011 Emulex
++ * 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. The full GNU General
++ * Public License is included in this distribution in the file called COPYING.
++ *
++ * Contact Information:
++ * linux-drivers@emulex.com
++ *
++ * Emulex
++ * 3333 Susan Street
++ * Costa Mesa, CA 92626
++ */
++#include "be.h"
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
++static ssize_t
++flash_fw_store(struct class_device *cd, const char *buf, size_t len)
++{
++ struct be_adapter *adapter =
++ netdev_priv(container_of(cd, struct net_device, class_dev));
++ char file_name[ETHTOOL_FLASH_MAX_FILENAME];
++ int status;
++
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
++ strncpy(file_name, buf, (ETHTOOL_FLASH_MAX_FILENAME - 1));
++
++ /* Removing new-line char given by sysfs */
++ file_name[strlen(file_name) - 1] = '\0';
++
++ status = be_load_fw(adapter, file_name);
++ if (!status)
++ return len;
++ else
++ return status;
++}
++
++static CLASS_DEVICE_ATTR(flash_fw, S_IWUSR, NULL, flash_fw_store);
++
++static struct attribute *benet_attrs[] = {
++ &class_device_attr_flash_fw.attr,
++ NULL,
++};
++#else
++
++static ssize_t
++flash_fw_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t len)
++{
++ struct be_adapter *adapter =
++ netdev_priv(container_of(dev, struct net_device, dev));
++ char file_name[ETHTOOL_FLASH_MAX_FILENAME];
++ int status;
++
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
++ strncpy(file_name, buf, (ETHTOOL_FLASH_MAX_FILENAME - 1));
++
++ /* Removing new-line char given by sysfs */
++ file_name[strlen(file_name) - 1] = '\0';
++
++ status = be_load_fw(adapter, file_name);
++ if (!status)
++ return len;
++ else
++ return status;
++}
++
++static DEVICE_ATTR(flash_fw, S_IWUSR, NULL, flash_fw_store);
++
++static struct attribute *benet_attrs[] = {
++ &dev_attr_flash_fw.attr,
++ NULL,
++};
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
++#define CLASS_DEV class_dev
++#else
++#define CLASS_DEV dev
++#endif
++
++static struct attribute_group benet_attr_group = {.attrs = benet_attrs };
++
++void be_sysfs_create_group(struct be_adapter *adapter)
++{
++ int status;
++
++ status = sysfs_create_group(&adapter->netdev->CLASS_DEV.kobj,
++ &benet_attr_group);
++ if (status)
++ dev_err(&adapter->pdev->dev, "Could not create sysfs group\n");
++}
++
++void be_sysfs_remove_group(struct be_adapter *adapter)
++{
++ sysfs_remove_group(&adapter->netdev->CLASS_DEV.kobj, &benet_attr_group);
++}
+diff --git a/drivers/net/benet/be_proc.c b/drivers/net/benet/be_proc.c
+new file mode 100644
+index 0000000..0bfdb3b
+--- /dev/null
++++ b/drivers/net/benet/be_proc.c
+@@ -0,0 +1,513 @@
++/*
++ * Copyright (C) 2005 - 2011 ServerEngines
++ * 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. The full GNU General
++ * Public License is included in this distribution in the file called COPYING.
++ *
++ * Contact Information:
++ * linux-drivers@serverengines.com
++ *
++ * ServerEngines
++ * 209 N. Fair Oaks Ave
++ * Sunnyvale, CA 94085
++ */
++#include <linux/proc_fs.h>
++#include "be.h"
++
++char *be_adpt_name[] = {
++ "driver/be2net0",
++ "driver/be2net1",
++ "driver/be2net2",
++ "driver/be2net3",
++ "driver/be2net4",
++ "driver/be2net5",
++ "driver/be2net6",
++ "driver/be2net7"
++};
++
++#define MAX_BE_DEVICES 8
++struct proc_dir_entry *be_proc_dir[MAX_BE_DEVICES];
++
++/*File to read Eth Ring Information */
++#define BE_ETH_RING_FILE "eth_ring"
++#define BE_DRVR_STAT_FILE "drvr_stat"
++
++/*
++ * this file enables user to read a 32 bit CSR register.
++ * to read 32 bit value of a register at offset 0x1234,
++ * first write the offset 0x1234 (echo "0x1234") in
++ * the file and then read the value from this file.
++ * the written offset is latched until another value is written
++ */
++#define BE_CSR_R_FILE "csrr"
++/*
++ * this file enables user to write to a 32 bit CSR register.
++ * to write a value 0xdeadbeef to a register at offset 0x1234,
++ * write 0x1234 0xdeadbeef (echo "0x1234 0xdeadbeeb") to
++ * the file.
++ */
++#define BE_CSR_W_FILE "csrw"
++
++#define BE_PROC_MODE 0600
++
++static char read_eth_ring_buf[4096];
++static int read_eth_ring_count;
++
++/*
++ * Get Various Eth Ring Properties
++ */
++static int proc_eth_read_ring(char *page, char **start,
++ off_t off, int count, int *eof, void *data)
++{
++ int i, n;
++ char *p = read_eth_ring_buf;
++ struct be_adapter *adapter = (struct be_adapter *) data;
++
++ if (off == 0) {
++ /* Reset read_eth_ring_count */
++ read_eth_ring_count = 0;
++
++ n = sprintf(p, " PhyAddr VirtAddr Size TotalEntries ProducerIndex ConsumerIndex NumUsed\n");
++ p += n;
++ read_eth_ring_count += n;
++
++ n = sprintf(p, " ------- -------- ---- ------------ ------------- ------------- -------\n");
++ p += n;
++ read_eth_ring_count += n;
++
++ n = sprintf(p, "%s", "EthSendRing");
++ p += n;
++ read_eth_ring_count += n;
++
++ n = sprintf(p, " %7lx %8p %4u %12u %13u %13u %7u \n",
++ (long) adapter->tx_obj.q.dma_mem.dma,
++ (void *)adapter->tx_obj.q.dma_mem.va,
++ (u32) (adapter->tx_obj.q.len *
++ sizeof(struct be_eth_wrb)),
++ adapter->tx_obj.q.len, adapter->tx_obj.q.head,
++ adapter->tx_obj.q.tail,
++ atomic_read(&adapter->tx_obj.q.used));
++
++ p += n;
++ read_eth_ring_count += n;
++
++ /* Get Eth Send Compl Queue Details */
++ n = sprintf(p, "%s", "EthSendCmplRing");
++ p += n;
++ read_eth_ring_count += n;
++
++ n = sprintf(p, " %7lx %8p %4u %12u %13s %13u %7s\n",
++ (long)adapter->tx_obj.cq.dma_mem.dma,
++ (void *)adapter->tx_obj.cq.dma_mem.va,
++ (u32) (adapter->tx_obj.cq.len *
++ sizeof(struct be_eth_tx_compl)),
++ adapter->tx_obj.cq.len, "NA",
++ adapter->tx_obj.cq.tail, "NA");
++
++ p += n;
++ read_eth_ring_count += n;
++ /* Get Eth Rx Queue Details */
++ n = sprintf(p, "%s", "EthRxRing");
++ p += n;
++ read_eth_ring_count += n;
++
++ n = sprintf(p, " %7lx %8p %4u %12u %13u %13s %7u \n",
++ (long)adapter->rx_obj.q.dma_mem.dma,
++ (void *)adapter->rx_obj.q.dma_mem.va,
++ (u32) (adapter->rx_obj.q.len *
++ sizeof(struct be_eth_rx_d)),
++ adapter->rx_obj.q.len, adapter->rx_obj.q.head,"NA",
++ atomic_read(&adapter->rx_obj.q.used));
++ p += n;
++ read_eth_ring_count += n;
++
++ /* Get Eth Unicast Rx Compl Queue Details */
++ n = sprintf(p, "%s", "EthRxCmplRing");
++ p += n;
++ read_eth_ring_count += n;
++
++ n = sprintf(p, " %7lx %8p %4u %12u %13s %13u %7s\n",
++ (long)adapter->rx_obj.cq.dma_mem.dma,
++ (void *)adapter->rx_obj.cq.dma_mem.va,
++ (u32) (adapter->rx_obj.cq.len *
++ sizeof(struct be_eth_rx_compl)),
++ adapter->rx_obj.cq.len, "NA",
++ adapter->rx_obj.cq.tail, "NA");
++ p += n;
++ read_eth_ring_count += n;
++
++ /* Get Eth Event Queue Details */
++ n = sprintf(p, "%s", "EthTxEventRing");
++ p += n;
++ read_eth_ring_count += n;
++
++ n = sprintf(p,
++ " %7lx %8p %4u %12u %13s %13u %7s\n",
++ (long) adapter->tx_eq.q.dma_mem.dma,
++ (void *)adapter->tx_eq.q.dma_mem.va,
++ (u32) (adapter->tx_eq.q.len *
++ sizeof(struct be_eq_entry)),
++ adapter->tx_eq.q.len, "NA",
++ adapter->tx_eq.q.tail, "NA");
++
++ p += n;
++ read_eth_ring_count += n;
++
++ /* Get Eth Event Queue Details */
++ n = sprintf(p, "%s", "EthRxEventRing");
++ p += n;
++ read_eth_ring_count += n;
++
++ n = sprintf(p,
++ " %7lx %8p %4u %12u %13s %13u %7s\n",
++ (long) adapter->rx_eq.q.dma_mem.dma,
++ (void *)adapter->rx_eq.q.dma_mem.va,
++ (u32) (adapter->rx_eq.q.len *
++ sizeof(struct be_eq_entry)),
++ adapter->rx_eq.q.len, "NA",
++ adapter->rx_eq.q.tail, "NA");
++
++ p += n;
++ read_eth_ring_count += n;
++ }
++
++ *start = page;
++ /* copy whatever we can */
++ if (count < (read_eth_ring_count - off)) {
++ i = count;
++ *eof = 0; /* More bytes left */
++ } else {
++ i = read_eth_ring_count - off;
++ *eof = 1; /* Nothing left. indicate EOF */
++ }
++
++ memcpy(page, read_eth_ring_buf + off, i);
++ return (i);
++}
++
++static int proc_eth_write_ring(struct file *file,
++ const char *buffer, unsigned long count,
++ void *data)
++{
++ return (count); /* we do not support write */
++}
++
++/*
++ * read the driver stats.
++ */
++static int proc_read_drvr_stat(char *page, char **start,
++ off_t off, int count, int *eof, void *data)
++{
++ int n, lro_cp;
++ char *p = page;
++ struct be_adapter *adapter = (struct be_adapter *) data;
++ struct net_device *netdev = adapter->netdev;
++
++ if (off == 0) {
++ n = sprintf(p, "interface = %s\n", netdev->name);
++ p += n;
++ n = sprintf(p, "tx_reqs = %d\n",
++ drvr_stats(adapter)->be_tx_reqs);
++ p += n;
++ n = sprintf(p, "tx_stops = %d\n",
++ drvr_stats(adapter)->be_tx_stops);
++ p += n;
++ n = sprintf(p, "fwd_reqs = %d\n",
++ drvr_stats(adapter)->be_fwd_reqs);
++ p += n;
++ n = sprintf(p, "tx_wrbs = %d\n",
++ drvr_stats(adapter)->be_tx_wrbs);
++ p += n;
++ n = sprintf(p, "rx_poll = %d\n", drvr_stats(adapter)->be_rx_polls);
++ p += n;
++ n = sprintf(p, "tx_events = %d\n",
++ drvr_stats(adapter)->be_tx_events);
++ p += n;
++ n = sprintf(p, "rx_events = %d\n",
++ drvr_stats(adapter)->be_rx_events);
++ p += n;
++ n = sprintf(p, "tx_compl = %d\n",
++ drvr_stats(adapter)->be_tx_compl);
++ p += n;
++ n = sprintf(p, "rx_compl = %d\n",
++ drvr_stats(adapter)->be_rx_compl);
++ p += n;
++ n = sprintf(p, "ethrx_post_fail = %d\n",
++ drvr_stats(adapter)->be_ethrx_post_fail);
++ p += n;
++ n = sprintf(p, "802.3_dropped_frames = %d\n",
++ drvr_stats(adapter)->be_802_3_dropped_frames);
++ p += n;
++ n = sprintf(p, "802.3_malformed_frames = %d\n",
++ drvr_stats(adapter)->be_802_3_malformed_frames);
++ p += n;
++ n = sprintf(p, "eth_tx_rate = %d\n",
++ drvr_stats(adapter)->be_tx_rate);
++ p += n;
++ n = sprintf(p, "eth_rx_rate = %d\n",
++ drvr_stats(adapter)->be_rx_rate);
++ p += n;
++
++ lro_cp = (drvr_stats(adapter)->be_lro_hgram_data[0] +
++ drvr_stats(adapter)->be_lro_hgram_data[1] +
++ drvr_stats(adapter)->be_lro_hgram_data[2] +
++ drvr_stats(adapter)->be_lro_hgram_data[3] +
++ drvr_stats(adapter)->be_lro_hgram_data[4] +
++ drvr_stats(adapter)->be_lro_hgram_data[5] +
++ drvr_stats(adapter)->be_lro_hgram_data[6] +
++ drvr_stats(adapter)->be_lro_hgram_data[7])/100;
++ lro_cp = (lro_cp == 0) ? 1 : lro_cp; /* avoid divide by 0 */
++ n = sprintf(p,
++ "LRO data count %% histogram (1, 2-3, 4-5,..,>=16) = "
++ "%d, %d, %d, %d - %d, %d, %d, %d\n",
++ drvr_stats(adapter)->be_lro_hgram_data[0]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_data[1]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_data[2]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_data[3]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_data[4]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_data[5]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_data[6]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_data[7]/lro_cp);
++ p += n;
++
++ lro_cp = (drvr_stats(adapter)->be_lro_hgram_ack[0] +
++ drvr_stats(adapter)->be_lro_hgram_ack[1] +
++ drvr_stats(adapter)->be_lro_hgram_ack[2] +
++ drvr_stats(adapter)->be_lro_hgram_ack[3] +
++ drvr_stats(adapter)->be_lro_hgram_ack[4] +
++ drvr_stats(adapter)->be_lro_hgram_ack[5] +
++ drvr_stats(adapter)->be_lro_hgram_ack[6] +
++ drvr_stats(adapter)->be_lro_hgram_ack[7])/100;
++ lro_cp = (lro_cp == 0) ? 1 : lro_cp; /* avoid divide by 0 */
++ n = sprintf(p,
++ "LRO ack count %% histogram (1, 2-3, 4-5,..,>=16) = "
++ "%d, %d, %d, %d - %d, %d, %d, %d\n",
++ drvr_stats(adapter)->be_lro_hgram_ack[0]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_ack[1]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_ack[2]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_ack[3]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_ack[4]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_ack[5]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_ack[6]/lro_cp,
++ drvr_stats(adapter)->be_lro_hgram_ack[7]/lro_cp);
++ p += n;
++ n = sprintf(p, "rx_eq_delay = %d \n", adapter->rx_eq.cur_eqd);
++ p += n;
++ n = sprintf(p, "rx frags per sec=%d \n",
++ drvr_stats(adapter)->be_rx_fps);
++ p += n;
++
++ }
++ *eof = 1;
++ return (p - page);
++}
++
++static int proc_write_drvr_stat(struct file *file,
++ const char *buffer, unsigned long count,
++ void *data)
++{
++ struct be_adapter *adapter = (struct be_adapter *) data;
++
++ memset(&(adapter->stats.drvr_stats), 0,
++ sizeof(adapter->stats.drvr_stats));
++ return (count); /* we do not support write */
++}
++
++#if 0
++/* the following are some of the functions that are needed here
++ * until all initializations are done by MPU.
++ */
++
++u32
++CsrReadDr(void* BaseAddress, u32 Offset)
++{
++ u32 *rp;
++
++ rp = (u32 *) (((u8 *) BaseAddress) + Offset);
++ return (*rp);
++}
++
++/*!
++
++@brief
++ This routine writes to a register located within the CSR
++ space for a given function object.
++
++@param
++ FuncObj - Pointer to the function object to read from.
++
++@param
++ Offset - The Offset (in bytes) to write to within the function's CSR space.
++
++@param
++ Value - The value to write to the register.
++
++@return
++
++@note
++ IRQL: any
++
++*/
++void
++CsrWriteDr(void* BaseAddress, u32 Offset, u32 Value)
++{
++ u32 *Register;
++
++ Register = (u32 *) (((u8 *) BaseAddress) + Offset);
++
++ //TRACE(DL_INFO, "CsrWrite[ %X ] <= %X", Register, Value);
++ *Register = Value;
++}
++u32 be_proc_csrr_offset = -1; /* to latch the offset of next CSR Read req. */
++
++/*
++ * read the csr_r file. return the 32 bit register value from
++ * CSR space at offset latched in the global location
++ * be_proc_csrr_offset
++ */
++static int proc_read_csr_r(char *page, char **start,
++ off_t off, int count, int *eof, void *data)
++{
++ struct be_adapter * adapter = (struct be_adapter *)data;
++ u32 val;
++ int n = 0;
++ if (be_proc_csrr_offset == -1)
++ return -EINVAL;
++
++ if (off == 0) {
++ /* read the CSR at offset be_proc_csrr_offset and return */
++ val = CsrReadDr(adapter->csr_va, be_proc_csrr_offset);
++ n = sprintf(page, "0x%x\n", val);
++ }
++ *eof = 1;
++ return n;
++}
++
++/*
++ * save the written value in be_proc_csrr_offset for next
++ * read from the file
++ */
++static int proc_write_csr_r(struct file *file,
++ const char *buffer, unsigned long count, void *data)
++{
++ char buf[64];
++ u32 n;
++
++ if (count > sizeof(buf) + 1)
++ return -EINVAL;
++ if (copy_from_user(buf, buffer, count))
++ return -EFAULT;
++ buf[count] = '\0';
++
++ n = simple_strtoul(buf, NULL, 16);
++ if (n < 0x50000)
++ be_proc_csrr_offset = n;
++ return (count);
++}
++
++/*
++ * return the latched offset for reading the csr_r file.
++ */
++static int proc_read_csr_w(char *page, char **start,
++ off_t off, int count, int *eof, void *data)
++{
++
++ *eof = 1;
++ return sprintf(page, "0x%x\n", be_proc_csrr_offset);
++}
++
++/*
++ * the incoming string is of the form "<offset> <value>"
++ * where the offset is the offset of the register to be written
++ * and value is the value to be written.
++ */
++static int proc_write_csr_w(struct file *file,
++ const char *buffer, unsigned long count,
++ void *data)
++{
++ char buf[64];
++ char *p;
++ u32 n, val;
++ struct be_adapter * adapter = (struct be_adapter *)data;
++
++ if (count > sizeof(buf) + 1)
++ return -EINVAL;
++ if (copy_from_user(buf, buffer, count))
++ return -EFAULT;
++ buf[count] = '\0';
++
++ n = simple_strtoul(buf, &p, 16);
++ if (n > 0x50000)
++ return -EINVAL;
++
++ /* now get the actual value to be written */
++ while (*p == ' ' || *p == '\t')
++ p++;
++ val = simple_strtoul(p, NULL, 16);
++ CsrWriteDr(adapter->csr_va, n, val);
++ return (count);
++}
++#endif
++
++void be_init_procfs(struct be_adapter *adapter, int adapt_num)
++{
++ static struct proc_dir_entry *pde;
++
++ if (adapt_num > MAX_BE_DEVICES - 1)
++ return;
++
++ /* create directory */
++ be_proc_dir[adapt_num] =
++ proc_mkdir(be_adpt_name[adapt_num], NULL);
++ if (be_proc_dir[adapt_num]) {
++ (be_proc_dir[adapt_num])->owner = THIS_MODULE;
++ }
++
++ pde = create_proc_entry(BE_ETH_RING_FILE, BE_PROC_MODE,
++ be_proc_dir[adapt_num]);
++ if (pde) {
++ pde->read_proc = proc_eth_read_ring;
++ pde->write_proc = proc_eth_write_ring;
++ pde->data = adapter;
++ pde->owner = THIS_MODULE;
++ }
++
++ pde = create_proc_entry(BE_DRVR_STAT_FILE, BE_PROC_MODE,
++ be_proc_dir[adapt_num]);
++ if (pde) {
++ pde->read_proc = proc_read_drvr_stat;
++ pde->write_proc = proc_write_drvr_stat;
++ pde->data = adapter;
++ pde->owner = THIS_MODULE;
++ }
++
++#if 0
++ if ((pde = create_proc_entry(BE_CSR_R_FILE, BE_PROC_MODE, be_proc_dir[adapt_num]))) {
++ pde->read_proc = proc_read_csr_r;
++ pde->write_proc = proc_write_csr_r;
++ pde->data = adapter;
++ pde->owner = THIS_MODULE;
++ }
++
++ if ((pde = create_proc_entry(BE_CSR_W_FILE, BE_PROC_MODE, be_proc_dir[adapt_num]))) {
++ pde->read_proc = proc_read_csr_w;
++ pde->write_proc = proc_write_csr_w;
++ pde->data = adapter;
++ pde->owner = THIS_MODULE;
++ }
++#endif
++}
++
++void be_cleanup_procfs(struct be_adapter *adapter, int adapt_num)
++{
++ if (adapt_num > MAX_BE_DEVICES - 1)
++ return;
++ remove_proc_entry(BE_ETH_RING_FILE, be_proc_dir[adapt_num]);
++ remove_proc_entry(BE_DRVR_STAT_FILE, be_proc_dir[adapt_num]);
++ remove_proc_entry(BE_CSR_R_FILE, be_proc_dir[adapt_num]);
++ remove_proc_entry(BE_CSR_W_FILE, be_proc_dir[adapt_num]);
++ remove_proc_entry(be_adpt_name[adapt_num], NULL);
++}
+diff --git a/drivers/net/benet/version.h b/drivers/net/benet/version.h
+new file mode 100644
+index 0000000..c7ed692
+--- /dev/null
++++ b/drivers/net/benet/version.h
+@@ -0,0 +1,51 @@
++#define STR_BE_BRANCH "0"
++#define STR_BE_BUILD "479"
++#define STR_BE_DOT "0"
++#define STR_BE_MINOR "0"
++#define STR_BE_MAJOR "4"
++
++#define BE_BRANCH 0
++#define BE_BUILD 479
++#define BE_DOT 0
++#define BE_MINOR 0
++#define BE_MAJOR 4
++
++#define MGMT_BRANCH 0
++#define MGMT_BUILDNUM 479
++#define MGMT_MINOR 0
++#define MGMT_MAJOR 4
++
++#define BE_REDBOOT_VERSION "2.0.5.0"
++
++//start-auto
++#define BUILD_MONTH "12"
++#define BUILD_MONTH_NAME "December"
++#define BUILD_DAY "6"
++#define BUILD_YEAR "2011"
++#define BUILD_24HOUR "21"
++#define BUILD_12HOUR "9"
++#define BUILD_AM_PM "PM"
++#define BUILD_MIN "48"
++#define BUILD_SEC "05"
++#define BUILD_MONTH_NUMBER 12
++#define BUILD_DAY_NUMBER 6
++#define BUILD_YEAR_NUMBER 2011
++#define BUILD_24HOUR_NUMBER 21
++#define BUILD_12HOUR_NUMBER 9
++#define BUILD_MIN_NUMBER 48
++#define BUILD_SEC_NUMBER 5
++#undef MAJOR_BUILD
++#undef MINOR_BUILD
++#undef DOT_BUILD
++#define NUMBERED_BUILD
++#undef BRANCH_BUILD
++//end-auto
++
++#define ELX_FCOE_XROM_BIOS_VER "7.03a1"
++#define ELX_FCoE_X86_VER "4.02a1"
++#define ELX_FCoE_EFI_VER "5.01a1"
++#define ELX_FCoE_FCODE_VER "4.01a0"
++#define ELX_PXE_BIOS_VER "3.00a5"
++#define ELX_UEFI_NIC_VER "2.10A10"
++#define ELX_UEFI_FCODE_VER "1.10A0"
++#define ELX_ISCSI_BIOS_VER "1.00A8"
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 4874b2b..67f8526 100644
--- a/drivers/net/bnx2.c
@@ -40852,6 +54385,2347 @@ index ff4504c..b3604c3 100644
}
int qdio_setup_perf_stats(void);
+diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c
+new file mode 100644
+index 0000000..7d18a18
+--- /dev/null
++++ b/drivers/scsi/3w-sas.c
+@@ -0,0 +1,1933 @@
++/*
++ 3w-sas.c -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux.
++
++ Written By: Adam Radford <linuxraid@lsi.com>
++
++ Copyright (C) 2009 LSI 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
++
++ Controllers supported by this driver:
++
++ LSI 3ware 9750 6Gb/s SAS/SATA-RAID
++
++ Bugs/Comments/Suggestions should be mailed to:
++ linuxraid@lsi.com
++
++ For more information, goto:
++ http://www.lsi.com
++
++ History
++ -------
++ 3.26.00.000 - Initial driver release.
++*/
++
++#include <linux/module.h>
++#include <linux/reboot.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/moduleparam.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include <linux/time.h>
++#include <linux/mutex.h>
++#include <linux/smp_lock.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <scsi/scsi.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_tcq.h>
++#include <scsi/scsi_cmnd.h>
++#include "3w-sas.h"
++
++/* Globals */
++#define TW_DRIVER_VERSION "3.26.00.028-2.6.32RH"
++static TW_Device_Extension *twl_device_extension_list[TW_MAX_SLOT];
++static unsigned int twl_device_extension_count;
++static int twl_major = -1;
++extern struct timezone sys_tz;
++
++/* Module parameters */
++MODULE_AUTHOR ("LSI");
++MODULE_DESCRIPTION ("LSI 3ware SAS/SATA-RAID Linux Driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(TW_DRIVER_VERSION);
++
++static int use_msi = 0;
++module_param(use_msi, int, S_IRUGO);
++MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0");
++
++/* Function prototypes */
++static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
++
++/* Functions */
++
++/* This function returns AENs through sysfs */
++static ssize_t twl_sysfs_aen_read(struct file *filp, struct kobject *kobj,
++ struct bin_attribute *bin_attr,
++ char *outbuf, loff_t offset, size_t count)
++{
++ struct device *dev = container_of(kobj, struct device, kobj);
++ struct Scsi_Host *shost = class_to_shost(dev);
++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata;
++ unsigned long flags = 0;
++ ssize_t ret;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ spin_lock_irqsave(tw_dev->host->host_lock, flags);
++ ret = memory_read_from_buffer(outbuf, count, &offset, tw_dev->event_queue[0], sizeof(TW_Event) * TW_Q_LENGTH);
++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
++
++ return ret;
++} /* End twl_sysfs_aen_read() */
++
++/* aen_read sysfs attribute initializer */
++static struct bin_attribute twl_sysfs_aen_read_attr = {
++ .attr = {
++ .name = "3ware_aen_read",
++ .mode = S_IRUSR,
++ },
++ .size = 0,
++ .read = twl_sysfs_aen_read
++};
++
++/* This function returns driver compatibility info through sysfs */
++static ssize_t twl_sysfs_compat_info(struct file *filp, struct kobject *kobj,
++ struct bin_attribute *bin_attr,
++ char *outbuf, loff_t offset, size_t count)
++{
++ struct device *dev = container_of(kobj, struct device, kobj);
++ struct Scsi_Host *shost = class_to_shost(dev);
++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata;
++ unsigned long flags = 0;
++ ssize_t ret;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++
++ spin_lock_irqsave(tw_dev->host->host_lock, flags);
++ ret = memory_read_from_buffer(outbuf, count, &offset, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info));
++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
++
++ return ret;
++} /* End twl_sysfs_compat_info() */
++
++/* compat_info sysfs attribute initializer */
++static struct bin_attribute twl_sysfs_compat_info_attr = {
++ .attr = {
++ .name = "3ware_compat_info",
++ .mode = S_IRUSR,
++ },
++ .size = 0,
++ .read = twl_sysfs_compat_info
++};
++
++/* Show some statistics about the card */
++static ssize_t twl_show_stats(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct Scsi_Host *host = class_to_shost(dev);
++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
++ unsigned long flags = 0;
++ ssize_t len;
++
++ spin_lock_irqsave(tw_dev->host->host_lock, flags);
++ len = snprintf(buf, PAGE_SIZE, "3w-sas Driver version: %s\n"
++ "Current commands posted: %4d\n"
++ "Max commands posted: %4d\n"
++ "Last sgl length: %4d\n"
++ "Max sgl length: %4d\n"
++ "Last sector count: %4d\n"
++ "Max sector count: %4d\n"
++ "SCSI Host Resets: %4d\n"
++ "AEN's: %4d\n",
++ TW_DRIVER_VERSION,
++ tw_dev->posted_request_count,
++ tw_dev->max_posted_request_count,
++ tw_dev->sgl_entries,
++ tw_dev->max_sgl_entries,
++ tw_dev->sector_count,
++ tw_dev->max_sector_count,
++ tw_dev->num_resets,
++ tw_dev->aen_count);
++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
++ return len;
++} /* End twl_show_stats() */
++
++/* This function will set a devices queue depth */
++static int twl_change_queue_depth(struct scsi_device *sdev, int queue_depth,
++ int reason)
++{
++ if (reason != SCSI_QDEPTH_DEFAULT)
++ return -EOPNOTSUPP;
++
++ if (queue_depth > TW_Q_LENGTH-2)
++ queue_depth = TW_Q_LENGTH-2;
++ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
++ return queue_depth;
++} /* End twl_change_queue_depth() */
++
++/* stats sysfs attribute initializer */
++static struct device_attribute twl_host_stats_attr = {
++ .attr = {
++ .name = "3ware_stats",
++ .mode = S_IRUGO,
++ },
++ .show = twl_show_stats
++};
++
++/* Host attributes initializer */
++static struct device_attribute *twl_host_attrs[] = {
++ &twl_host_stats_attr,
++ NULL,
++};
++
++/* This function will look up an AEN severity string */
++static char *twl_aen_severity_lookup(unsigned char severity_code)
++{
++ char *retval = NULL;
++
++ if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
++ (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
++ goto out;
++
++ retval = twl_aen_severity_table[severity_code];
++out:
++ return retval;
++} /* End twl_aen_severity_lookup() */
++
++/* This function will queue an event */
++static void twl_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
++{
++ u32 local_time;
++ struct timeval time;
++ TW_Event *event;
++ unsigned short aen;
++ char host[16];
++ char *error_str;
++
++ tw_dev->aen_count++;
++
++ /* Fill out event info */
++ event = tw_dev->event_queue[tw_dev->error_index];
++
++ host[0] = '\0';
++ if (tw_dev->host)
++ sprintf(host, " scsi%d:", tw_dev->host->host_no);
++
++ aen = le16_to_cpu(header->status_block.error);
++ memset(event, 0, sizeof(TW_Event));
++
++ event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
++ do_gettimeofday(&time);
++ local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
++ event->time_stamp_sec = local_time;
++ event->aen_code = aen;
++ event->retrieved = TW_AEN_NOT_RETRIEVED;
++ event->sequence_id = tw_dev->error_sequence_id;
++ tw_dev->error_sequence_id++;
++
++ /* Check for embedded error string */
++ error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]);
++
++ header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
++ event->parameter_len = strlen(header->err_specific_desc);
++ memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len + 1 + strlen(error_str));
++ if (event->severity != TW_AEN_SEVERITY_DEBUG)
++ printk(KERN_WARNING "3w-sas:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
++ host,
++ twl_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
++ TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen, error_str,
++ header->err_specific_desc);
++ else
++ tw_dev->aen_count--;
++
++ tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
++} /* End twl_aen_queue_event() */
++
++/* This function will attempt to post a command packet to the board */
++static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
++{
++ dma_addr_t command_que_value;
++
++ command_que_value = tw_dev->command_packet_phys[request_id];
++ command_que_value += TW_COMMAND_OFFSET;
++
++ /* First write upper 4 bytes */
++ writel((u32)((u64)command_que_value >> 32), TWL_HIBQPH_REG_ADDR(tw_dev));
++ /* Then the lower 4 bytes */
++ writel((u32)(command_que_value | TWL_PULL_MODE), TWL_HIBQPL_REG_ADDR(tw_dev));
++
++ tw_dev->state[request_id] = TW_S_POSTED;
++ tw_dev->posted_request_count++;
++ if (tw_dev->posted_request_count > tw_dev->max_posted_request_count)
++ tw_dev->max_posted_request_count = tw_dev->posted_request_count;
++
++ return 0;
++} /* End twl_post_command_packet() */
++
++/* This function will perform a pci-dma mapping for a scatter gather list */
++static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
++{
++ int use_sg;
++ struct scsi_cmnd *cmd = tw_dev->srb[request_id];
++
++ use_sg = scsi_dma_map(cmd);
++ if (!use_sg)
++ return 0;
++ else if (use_sg < 0) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list");
++ return 0;
++ }
++
++ cmd->SCp.phase = TW_PHASE_SGLIST;
++ cmd->SCp.have_data_in = use_sg;
++
++ return use_sg;
++} /* End twl_map_scsi_sg_data() */
++
++/* This function hands scsi cdb's to the firmware */
++static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg)
++{
++ TW_Command_Full *full_command_packet;
++ TW_Command_Apache *command_packet;
++ int i, sg_count;
++ struct scsi_cmnd *srb = NULL;
++ struct scatterlist *sglist = NULL, *sg;
++ int retval = 1;
++
++ if (tw_dev->srb[request_id]) {
++ srb = tw_dev->srb[request_id];
++ if (scsi_sglist(srb))
++ sglist = scsi_sglist(srb);
++ }
++
++ /* Initialize command packet */
++ full_command_packet = tw_dev->command_packet_virt[request_id];
++ full_command_packet->header.header_desc.size_header = 128;
++ full_command_packet->header.status_block.error = 0;
++ full_command_packet->header.status_block.severity__reserved = 0;
++
++ command_packet = &full_command_packet->command.newcommand;
++ command_packet->status = 0;
++ command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI);
++
++ /* We forced 16 byte cdb use earlier */
++ if (!cdb)
++ memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
++ else
++ memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
++
++ if (srb) {
++ command_packet->unit = srb->device->id;
++ command_packet->request_id__lunl =
++ cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id));
++ } else {
++ command_packet->request_id__lunl =
++ cpu_to_le16(TW_REQ_LUN_IN(0, request_id));
++ command_packet->unit = 0;
++ }
++
++ command_packet->sgl_offset = 16;
++
++ if (!sglistarg) {
++ /* Map sglist from scsi layer to cmd packet */
++ if (scsi_sg_count(srb)) {
++ sg_count = twl_map_scsi_sg_data(tw_dev, request_id);
++ if (sg_count == 0)
++ goto out;
++
++ scsi_for_each_sg(srb, sg, sg_count, i) {
++ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg));
++ command_packet->sg_list[i].length = TW_CPU_TO_SGL(sg_dma_len(sg));
++ }
++ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id])));
++ }
++ } else {
++ /* Internal cdb post */
++ for (i = 0; i < use_sg; i++) {
++ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address);
++ command_packet->sg_list[i].length = TW_CPU_TO_SGL(sglistarg[i].length);
++ }
++ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg));
++ }
++
++ /* Update some stats */
++ if (srb) {
++ tw_dev->sector_count = scsi_bufflen(srb) / 512;
++ if (tw_dev->sector_count > tw_dev->max_sector_count)
++ tw_dev->max_sector_count = tw_dev->sector_count;
++ tw_dev->sgl_entries = scsi_sg_count(srb);
++ if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
++ tw_dev->max_sgl_entries = tw_dev->sgl_entries;
++ }
++
++ /* Now post the command to the board */
++ retval = twl_post_command_packet(tw_dev, request_id);
++
++out:
++ return retval;
++} /* End twl_scsiop_execute_scsi() */
++
++/* This function will read the aen queue from the isr */
++static int twl_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
++{
++ char cdb[TW_MAX_CDB_LEN];
++ TW_SG_Entry_ISO sglist[1];
++ TW_Command_Full *full_command_packet;
++ int retval = 1;
++
++ full_command_packet = tw_dev->command_packet_virt[request_id];
++ memset(full_command_packet, 0, sizeof(TW_Command_Full));
++
++ /* Initialize cdb */
++ memset(&cdb, 0, TW_MAX_CDB_LEN);
++ cdb[0] = REQUEST_SENSE; /* opcode */
++ cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
++
++ /* Initialize sglist */
++ memset(&sglist, 0, sizeof(TW_SG_Entry_ISO));
++ sglist[0].length = TW_SECTOR_SIZE;
++ sglist[0].address = tw_dev->generic_buffer_phys[request_id];
++
++ /* Mark internal command */
++ tw_dev->srb[request_id] = NULL;
++
++ /* Now post the command packet */
++ if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Post failed while reading AEN queue");
++ goto out;
++ }
++ retval = 0;
++out:
++ return retval;
++} /* End twl_aen_read_queue() */
++
++/* This function will sync firmware time with the host time */
++static void twl_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
++{
++ u32 schedulertime;
++ struct timeval utc;
++ TW_Command_Full *full_command_packet;
++ TW_Command *command_packet;
++ TW_Param_Apache *param;
++ u32 local_time;
++
++ /* Fill out the command packet */
++ full_command_packet = tw_dev->command_packet_virt[request_id];
++ memset(full_command_packet, 0, sizeof(TW_Command_Full));
++ command_packet = &full_command_packet->command.oldcommand;
++ command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
++ command_packet->request_id = request_id;
++ command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
++ command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE);
++ command_packet->size = TW_COMMAND_SIZE;
++ command_packet->byte6_offset.parameter_count = cpu_to_le16(1);
++
++ /* Setup the param */
++ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
++ memset(param, 0, TW_SECTOR_SIZE);
++ param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */
++ param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */
++ param->parameter_size_bytes = cpu_to_le16(4);
++
++ /* Convert system time in UTC to local time seconds since last
++ Sunday 12:00AM */
++ do_gettimeofday(&utc);
++ local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
++ schedulertime = local_time - (3 * 86400);
++ schedulertime = cpu_to_le32(schedulertime % 604800);
++
++ memcpy(param->data, &schedulertime, sizeof(u32));
++
++ /* Mark internal command */
++ tw_dev->srb[request_id] = NULL;
++
++ /* Now post the command */
++ twl_post_command_packet(tw_dev, request_id);
++} /* End twl_aen_sync_time() */
++
++/* This function will assign an available request id */
++static void twl_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
++{
++ *request_id = tw_dev->free_queue[tw_dev->free_head];
++ tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
++ tw_dev->state[*request_id] = TW_S_STARTED;
++} /* End twl_get_request_id() */
++
++/* This function will free a request id */
++static void twl_free_request_id(TW_Device_Extension *tw_dev, int request_id)
++{
++ tw_dev->free_queue[tw_dev->free_tail] = request_id;
++ tw_dev->state[request_id] = TW_S_FINISHED;
++ tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
++} /* End twl_free_request_id() */
++
++/* This function will complete an aen request from the isr */
++static int twl_aen_complete(TW_Device_Extension *tw_dev, int request_id)
++{
++ TW_Command_Full *full_command_packet;
++ TW_Command *command_packet;
++ TW_Command_Apache_Header *header;
++ unsigned short aen;
++ int retval = 1;
++
++ header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
++ tw_dev->posted_request_count--;
++ aen = le16_to_cpu(header->status_block.error);
++ full_command_packet = tw_dev->command_packet_virt[request_id];
++ command_packet = &full_command_packet->command.oldcommand;
++
++ /* First check for internal completion of set param for time sync */
++ if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) {
++ /* Keep reading the queue in case there are more aen's */
++ if (twl_aen_read_queue(tw_dev, request_id))
++ goto out2;
++ else {
++ retval = 0;
++ goto out;
++ }
++ }
++
++ switch (aen) {
++ case TW_AEN_QUEUE_EMPTY:
++ /* Quit reading the queue if this is the last one */
++ break;
++ case TW_AEN_SYNC_TIME_WITH_HOST:
++ twl_aen_sync_time(tw_dev, request_id);
++ retval = 0;
++ goto out;
++ default:
++ twl_aen_queue_event(tw_dev, header);
++
++ /* If there are more aen's, keep reading the queue */
++ if (twl_aen_read_queue(tw_dev, request_id))
++ goto out2;
++ else {
++ retval = 0;
++ goto out;
++ }
++ }
++ retval = 0;
++out2:
++ tw_dev->state[request_id] = TW_S_COMPLETED;
++ twl_free_request_id(tw_dev, request_id);
++ clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
++out:
++ return retval;
++} /* End twl_aen_complete() */
++
++/* This function will poll for a response */
++static int twl_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
++{
++ unsigned long before;
++ dma_addr_t mfa;
++ u32 regh, regl;
++ u32 response;
++ int retval = 1;
++ int found = 0;
++
++ before = jiffies;
++
++ while (!found) {
++ if (sizeof(dma_addr_t) > 4) {
++ regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev));
++ regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev));
++ mfa = ((u64)regh << 32) | regl;
++ } else
++ mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev));
++
++ response = (u32)mfa;
++
++ if (TW_RESID_OUT(response) == request_id)
++ found = 1;
++
++ if (time_after(jiffies, before + HZ * seconds))
++ goto out;
++
++ msleep(50);
++ }
++ retval = 0;
++out:
++ return retval;
++} /* End twl_poll_response() */
++
++/* This function will drain the aen queue */
++static int twl_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
++{
++ int request_id = 0;
++ char cdb[TW_MAX_CDB_LEN];
++ TW_SG_Entry_ISO sglist[1];
++ int finished = 0, count = 0;
++ TW_Command_Full *full_command_packet;
++ TW_Command_Apache_Header *header;
++ unsigned short aen;
++ int first_reset = 0, queue = 0, retval = 1;
++
++ if (no_check_reset)
++ first_reset = 0;
++ else
++ first_reset = 1;
++
++ full_command_packet = tw_dev->command_packet_virt[request_id];
++ memset(full_command_packet, 0, sizeof(TW_Command_Full));
++
++ /* Initialize cdb */
++ memset(&cdb, 0, TW_MAX_CDB_LEN);
++ cdb[0] = REQUEST_SENSE; /* opcode */
++ cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
++
++ /* Initialize sglist */
++ memset(&sglist, 0, sizeof(TW_SG_Entry_ISO));
++ sglist[0].length = TW_SECTOR_SIZE;
++ sglist[0].address = tw_dev->generic_buffer_phys[request_id];
++
++ /* Mark internal command */
++ tw_dev->srb[request_id] = NULL;
++
++ do {
++ /* Send command to the board */
++ if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "Error posting request sense");
++ goto out;
++ }
++
++ /* Now poll for completion */
++ if (twl_poll_response(tw_dev, request_id, 30)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "No valid response while draining AEN queue");
++ tw_dev->posted_request_count--;
++ goto out;
++ }
++
++ tw_dev->posted_request_count--;
++ header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
++ aen = le16_to_cpu(header->status_block.error);
++ queue = 0;
++ count++;
++
++ switch (aen) {
++ case TW_AEN_QUEUE_EMPTY:
++ if (first_reset != 1)
++ goto out;
++ else
++ finished = 1;
++ break;
++ case TW_AEN_SOFT_RESET:
++ if (first_reset == 0)
++ first_reset = 1;
++ else
++ queue = 1;
++ break;
++ case TW_AEN_SYNC_TIME_WITH_HOST:
++ break;
++ default:
++ queue = 1;
++ }
++
++ /* Now queue an event info */
++ if (queue)
++ twl_aen_queue_event(tw_dev, header);
++ } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
++
++ if (count == TW_MAX_AEN_DRAIN)
++ goto out;
++
++ retval = 0;
++out:
++ tw_dev->state[request_id] = TW_S_INITIAL;
++ return retval;
++} /* End twl_aen_drain_queue() */
++
++/* This function will allocate memory and check if it is correctly aligned */
++static int twl_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
++{
++ int i;
++ dma_addr_t dma_handle;
++ unsigned long *cpu_addr;
++ int retval = 1;
++
++ cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
++ if (!cpu_addr) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
++ goto out;
++ }
++
++ memset(cpu_addr, 0, size*TW_Q_LENGTH);
++
++ for (i = 0; i < TW_Q_LENGTH; i++) {
++ switch(which) {
++ case 0:
++ tw_dev->command_packet_phys[i] = dma_handle+(i*size);
++ tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));
++ break;
++ case 1:
++ tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
++ tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
++ break;
++ case 2:
++ tw_dev->sense_buffer_phys[i] = dma_handle+(i*size);
++ tw_dev->sense_buffer_virt[i] = (TW_Command_Apache_Header *)((unsigned char *)cpu_addr + (i*size));
++ break;
++ }
++ }
++ retval = 0;
++out:
++ return retval;
++} /* End twl_allocate_memory() */
++
++/* This function will load the request id and various sgls for ioctls */
++static void twl_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
++{
++ TW_Command *oldcommand;
++ TW_Command_Apache *newcommand;
++ TW_SG_Entry_ISO *sgl;
++ unsigned int pae = 0;
++
++ if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
++ pae = 1;
++
++ if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
++ newcommand = &full_command_packet->command.newcommand;
++ newcommand->request_id__lunl =
++ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
++ if (length) {
++ newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
++ newcommand->sg_list[0].length = TW_CPU_TO_SGL(length);
++ }
++ newcommand->sgl_entries__lunh =
++ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0));
++ } else {
++ oldcommand = &full_command_packet->command.oldcommand;
++ oldcommand->request_id = request_id;
++
++ if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
++ /* Load the sg list */
++ sgl = (TW_SG_Entry_ISO *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry_ISO)/4) + pae + (sizeof(dma_addr_t) > 4 ? 1 : 0));
++ sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
++ sgl->length = TW_CPU_TO_SGL(length);
++ oldcommand->size += pae;
++ oldcommand->size += sizeof(dma_addr_t) > 4 ? 1 : 0;
++ }
++ }
++} /* End twl_load_sgl() */
++
++/* This function handles ioctl for the character device
++ This interface is used by smartmontools open source software */
++static int twl_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long timeout;
++ unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
++ dma_addr_t dma_handle;
++ int request_id = 0;
++ TW_Ioctl_Driver_Command driver_command;
++ TW_Ioctl_Buf_Apache *tw_ioctl;
++ TW_Command_Full *full_command_packet;
++ TW_Device_Extension *tw_dev = twl_device_extension_list[iminor(inode)];
++ int retval = -EFAULT;
++ void __user *argp = (void __user *)arg;
++
++ /* Only let one of these through at a time */
++ if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
++ retval = -EINTR;
++ goto out;
++ }
++
++ /* First copy down the driver command */
++ if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command)))
++ goto out2;
++
++ /* Check data buffer size */
++ if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) {
++ retval = -EINVAL;
++ goto out2;
++ }
++
++ /* Hardware can only do multiple of 512 byte transfers */
++ data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
++
++ /* Now allocate ioctl buf memory */
++ cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL);
++ if (!cpu_addr) {
++ retval = -ENOMEM;
++ goto out2;
++ }
++
++ tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
++
++ /* Now copy down the entire ioctl */
++ if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
++ goto out3;
++
++ /* See which ioctl we are doing */
++ switch (cmd) {
++ case TW_IOCTL_FIRMWARE_PASS_THROUGH:
++ spin_lock_irqsave(tw_dev->host->host_lock, flags);
++ twl_get_request_id(tw_dev, &request_id);
++
++ /* Flag internal command */
++ tw_dev->srb[request_id] = NULL;
++
++ /* Flag chrdev ioctl */
++ tw_dev->chrdev_request_id = request_id;
++
++ full_command_packet = (TW_Command_Full *)&tw_ioctl->firmware_command;
++
++ /* Load request id and sglist for both command types */
++ twl_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
++
++ memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
++
++ /* Now post the command packet to the controller */
++ twl_post_command_packet(tw_dev, request_id);
++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
++
++ timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
++
++ /* Now wait for command to complete */
++ timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
++
++ /* We timed out, and didn't get an interrupt */
++ if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
++ /* Now we need to reset the board */
++ printk(KERN_WARNING "3w-sas: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
++ tw_dev->host->host_no, TW_DRIVER, 0x6,
++ cmd);
++ retval = -EIO;
++ twl_reset_device_extension(tw_dev, 1);
++ goto out3;
++ }
++
++ /* Now copy in the command packet response */
++ memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
++
++ /* Now complete the io */
++ spin_lock_irqsave(tw_dev->host->host_lock, flags);
++ tw_dev->posted_request_count--;
++ tw_dev->state[request_id] = TW_S_COMPLETED;
++ twl_free_request_id(tw_dev, request_id);
++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
++ break;
++ default:
++ retval = -ENOTTY;
++ goto out3;
++ }
++
++ /* Now copy the entire response to userspace */
++ if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
++ retval = 0;
++out3:
++ /* Now free ioctl buf memory */
++ dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
++out2:
++ mutex_unlock(&tw_dev->ioctl_lock);
++out:
++ return retval;
++} /* End twl_chrdev_ioctl() */
++
++/* This function handles open for the character device */
++static int twl_chrdev_open(struct inode *inode, struct file *file)
++{
++ unsigned int minor_number;
++ int retval = -ENODEV;
++
++ if (!capable(CAP_SYS_ADMIN)) {
++ retval = -EACCES;
++ goto out;
++ }
++
++ cycle_kernel_lock();
++ minor_number = iminor(inode);
++ if (minor_number >= twl_device_extension_count)
++ goto out;
++ retval = 0;
++out:
++ return retval;
++} /* End twl_chrdev_open() */
++
++/* File operations struct for character device */
++static const struct file_operations twl_fops = {
++ .owner = THIS_MODULE,
++ .ioctl = twl_chrdev_ioctl,
++ .open = twl_chrdev_open,
++ .release = NULL
++};
++
++/* This function passes sense data from firmware to scsi layer */
++static int twl_fill_sense(TW_Device_Extension *tw_dev, int i, int request_id, int copy_sense, int print_host)
++{
++ TW_Command_Apache_Header *header;
++ TW_Command_Full *full_command_packet;
++ unsigned short error;
++ char *error_str;
++ int retval = 1;
++
++ header = tw_dev->sense_buffer_virt[i];
++ full_command_packet = tw_dev->command_packet_virt[request_id];
++
++ /* Get embedded firmware error string */
++ error_str = &(header->err_specific_desc[strlen(header->err_specific_desc) + 1]);
++
++ /* Don't print error for Logical unit not supported during rollcall */
++ error = le16_to_cpu(header->status_block.error);
++ if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE) && (error != TW_ERROR_INVALID_FIELD_IN_CDB)) {
++ if (print_host)
++ printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
++ tw_dev->host->host_no,
++ TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
++ header->status_block.error,
++ error_str,
++ header->err_specific_desc);
++ else
++ printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s:%s.\n",
++ TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
++ header->status_block.error,
++ error_str,
++ header->err_specific_desc);
++ }
++
++ if (copy_sense) {
++ memcpy(tw_dev->srb[request_id]->sense_buffer, header->sense_data, TW_SENSE_DATA_LENGTH);
++ tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
++ goto out;
++ }
++out:
++ return retval;
++} /* End twl_fill_sense() */
++
++/* This function will free up device extension resources */
++static void twl_free_device_extension(TW_Device_Extension *tw_dev)
++{
++ if (tw_dev->command_packet_virt[0])
++ pci_free_consistent(tw_dev->tw_pci_dev,
++ sizeof(TW_Command_Full)*TW_Q_LENGTH,
++ tw_dev->command_packet_virt[0],
++ tw_dev->command_packet_phys[0]);
++
++ if (tw_dev->generic_buffer_virt[0])
++ pci_free_consistent(tw_dev->tw_pci_dev,
++ TW_SECTOR_SIZE*TW_Q_LENGTH,
++ tw_dev->generic_buffer_virt[0],
++ tw_dev->generic_buffer_phys[0]);
++
++ if (tw_dev->sense_buffer_virt[0])
++ pci_free_consistent(tw_dev->tw_pci_dev,
++ sizeof(TW_Command_Apache_Header)*
++ TW_Q_LENGTH,
++ tw_dev->sense_buffer_virt[0],
++ tw_dev->sense_buffer_phys[0]);
++
++ kfree(tw_dev->event_queue[0]);
++} /* End twl_free_device_extension() */
++
++/* This function will get parameter table entries from the firmware */
++static void *twl_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
++{
++ TW_Command_Full *full_command_packet;
++ TW_Command *command_packet;
++ TW_Param_Apache *param;
++ void *retval = NULL;
++
++ /* Setup the command packet */
++ full_command_packet = tw_dev->command_packet_virt[request_id];
++ memset(full_command_packet, 0, sizeof(TW_Command_Full));
++ command_packet = &full_command_packet->command.oldcommand;
++
++ command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
++ command_packet->size = TW_COMMAND_SIZE;
++ command_packet->request_id = request_id;
++ command_packet->byte6_offset.block_count = cpu_to_le16(1);
++
++ /* Now setup the param */
++ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
++ memset(param, 0, TW_SECTOR_SIZE);
++ param->table_id = cpu_to_le16(table_id | 0x8000);
++ param->parameter_id = cpu_to_le16(parameter_id);
++ param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
++
++ command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
++ command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE);
++
++ /* Post the command packet to the board */
++ twl_post_command_packet(tw_dev, request_id);
++
++ /* Poll for completion */
++ if (twl_poll_response(tw_dev, request_id, 30))
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "No valid response during get param")
++ else
++ retval = (void *)&(param->data[0]);
++
++ tw_dev->posted_request_count--;
++ tw_dev->state[request_id] = TW_S_INITIAL;
++
++ return retval;
++} /* End twl_get_param() */
++
++/* This function will send an initconnection command to controller */
++static int twl_initconnection(TW_Device_Extension *tw_dev, int message_credits,
++ u32 set_features, unsigned short current_fw_srl,
++ unsigned short current_fw_arch_id,
++ unsigned short current_fw_branch,
++ unsigned short current_fw_build,
++ unsigned short *fw_on_ctlr_srl,
++ unsigned short *fw_on_ctlr_arch_id,
++ unsigned short *fw_on_ctlr_branch,
++ unsigned short *fw_on_ctlr_build,
++ u32 *init_connect_result)
++{
++ TW_Command_Full *full_command_packet;
++ TW_Initconnect *tw_initconnect;
++ int request_id = 0, retval = 1;
++
++ /* Initialize InitConnection command packet */
++ full_command_packet = tw_dev->command_packet_virt[request_id];
++ memset(full_command_packet, 0, sizeof(TW_Command_Full));
++ full_command_packet->header.header_desc.size_header = 128;
++
++ tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
++ tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
++ tw_initconnect->request_id = request_id;
++ tw_initconnect->message_credits = cpu_to_le16(message_credits);
++ tw_initconnect->features = set_features;
++
++ /* Turn on 64-bit sgl support if we need to */
++ tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
++
++ tw_initconnect->features = cpu_to_le32(tw_initconnect->features);
++
++ if (set_features & TW_EXTENDED_INIT_CONNECT) {
++ tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
++ tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl);
++ tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id);
++ tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch);
++ tw_initconnect->fw_build = cpu_to_le16(current_fw_build);
++ } else
++ tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
++
++ /* Send command packet to the board */
++ twl_post_command_packet(tw_dev, request_id);
++
++ /* Poll for completion */
++ if (twl_poll_response(tw_dev, request_id, 30)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x8, "No valid response during init connection");
++ } else {
++ if (set_features & TW_EXTENDED_INIT_CONNECT) {
++ *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl);
++ *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id);
++ *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch);
++ *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build);
++ *init_connect_result = le32_to_cpu(tw_initconnect->result);
++ }
++ retval = 0;
++ }
++
++ tw_dev->posted_request_count--;
++ tw_dev->state[request_id] = TW_S_INITIAL;
++
++ return retval;
++} /* End twl_initconnection() */
++
++/* This function will initialize the fields of a device extension */
++static int twl_initialize_device_extension(TW_Device_Extension *tw_dev)
++{
++ int i, retval = 1;
++
++ /* Initialize command packet buffers */
++ if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x9, "Command packet memory allocation failed");
++ goto out;
++ }
++
++ /* Initialize generic buffer */
++ if (twl_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Generic memory allocation failed");
++ goto out;
++ }
++
++ /* Allocate sense buffers */
++ if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Apache_Header), 2)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xb, "Sense buffer allocation failed");
++ goto out;
++ }
++
++ /* Allocate event info space */
++ tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
++ if (!tw_dev->event_queue[0]) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "Event info memory allocation failed");
++ goto out;
++ }
++
++ for (i = 0; i < TW_Q_LENGTH; i++) {
++ tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
++ tw_dev->free_queue[i] = i;
++ tw_dev->state[i] = TW_S_INITIAL;
++ }
++
++ tw_dev->free_head = TW_Q_START;
++ tw_dev->free_tail = TW_Q_START;
++ tw_dev->error_sequence_id = 1;
++ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
++
++ mutex_init(&tw_dev->ioctl_lock);
++ init_waitqueue_head(&tw_dev->ioctl_wqueue);
++
++ retval = 0;
++out:
++ return retval;
++} /* End twl_initialize_device_extension() */
++
++/* This function will perform a pci-dma unmap */
++static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
++{
++ struct scsi_cmnd *cmd = tw_dev->srb[request_id];
++
++ if (cmd->SCp.phase == TW_PHASE_SGLIST)
++ scsi_dma_unmap(cmd);
++} /* End twl_unmap_scsi_data() */
++
++/* This function will handle attention interrupts */
++static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev)
++{
++ int retval = 1;
++ u32 request_id, doorbell;
++
++ /* Read doorbell status */
++ doorbell = readl(TWL_HOBDB_REG_ADDR(tw_dev));
++
++ /* Check for controller errors */
++ if (doorbell & TWL_DOORBELL_CONTROLLER_ERROR) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "Microcontroller Error: clearing");
++ goto out;
++ }
++
++ /* Check if we need to perform an AEN drain */
++ if (doorbell & TWL_DOORBELL_ATTENTION_INTERRUPT) {
++ if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
++ twl_get_request_id(tw_dev, &request_id);
++ if (twl_aen_read_queue(tw_dev, request_id)) {
++ tw_dev->state[request_id] = TW_S_COMPLETED;
++ twl_free_request_id(tw_dev, request_id);
++ clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
++ }
++ }
++ }
++
++ retval = 0;
++out:
++ /* Clear doorbell interrupt */
++ TWL_CLEAR_DB_INTERRUPT(tw_dev);
++
++ /* Make sure the clear was flushed by reading it back */
++ readl(TWL_HOBDBC_REG_ADDR(tw_dev));
++
++ return retval;
++} /* End twl_handle_attention_interrupt() */
++
++/* Interrupt service routine */
++static irqreturn_t twl_interrupt(int irq, void *dev_instance)
++{
++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
++ int i, handled = 0, error = 0;
++ dma_addr_t mfa = 0;
++ u32 reg, regl, regh, response, request_id = 0;
++ struct scsi_cmnd *cmd;
++ TW_Command_Full *full_command_packet;
++
++ spin_lock(tw_dev->host->host_lock);
++
++ /* Read host interrupt status */
++ reg = readl(TWL_HISTAT_REG_ADDR(tw_dev));
++
++ /* Check if this is our interrupt, otherwise bail */
++ if (!(reg & TWL_HISTATUS_VALID_INTERRUPT))
++ goto twl_interrupt_bail;
++
++ handled = 1;
++
++ /* If we are resetting, bail */
++ if (test_bit(TW_IN_RESET, &tw_dev->flags))
++ goto twl_interrupt_bail;
++
++ /* Attention interrupt */
++ if (reg & TWL_HISTATUS_ATTENTION_INTERRUPT) {
++ if (twl_handle_attention_interrupt(tw_dev)) {
++ TWL_MASK_INTERRUPTS(tw_dev);
++ goto twl_interrupt_bail;
++ }
++ }
++
++ /* Response interrupt */
++ while (reg & TWL_HISTATUS_RESPONSE_INTERRUPT) {
++ if (sizeof(dma_addr_t) > 4) {
++ regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev));
++ regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev));
++ mfa = ((u64)regh << 32) | regl;
++ } else
++ mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev));
++
++ error = 0;
++ response = (u32)mfa;
++
++ /* Check for command packet error */
++ if (!TW_NOTMFA_OUT(response)) {
++ for (i=0;i<TW_Q_LENGTH;i++) {
++ if (tw_dev->sense_buffer_phys[i] == mfa) {
++ request_id = le16_to_cpu(tw_dev->sense_buffer_virt[i]->header_desc.request_id);
++ if (tw_dev->srb[request_id] != NULL)
++ error = twl_fill_sense(tw_dev, i, request_id, 1, 1);
++ else {
++ /* Skip ioctl error prints */
++ if (request_id != tw_dev->chrdev_request_id)
++ error = twl_fill_sense(tw_dev, i, request_id, 0, 1);
++ else
++ memcpy(tw_dev->command_packet_virt[request_id], tw_dev->sense_buffer_virt[i], sizeof(TW_Command_Apache_Header));
++ }
++
++ /* Now re-post the sense buffer */
++ writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev));
++ writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev));
++ break;
++ }
++ }
++ } else
++ request_id = TW_RESID_OUT(response);
++
++ full_command_packet = tw_dev->command_packet_virt[request_id];
++
++ /* Check for correct state */
++ if (tw_dev->state[request_id] != TW_S_POSTED) {
++ if (tw_dev->srb[request_id] != NULL) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Received a request id that wasn't posted");
++ TWL_MASK_INTERRUPTS(tw_dev);
++ goto twl_interrupt_bail;
++ }
++ }
++
++ /* Check for internal command completion */
++ if (tw_dev->srb[request_id] == NULL) {
++ if (request_id != tw_dev->chrdev_request_id) {
++ if (twl_aen_complete(tw_dev, request_id))
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "Error completing AEN during attention interrupt");
++ } else {
++ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
++ wake_up(&tw_dev->ioctl_wqueue);
++ }
++ } else {
++ cmd = tw_dev->srb[request_id];
++
++ if (!error)
++ cmd->result = (DID_OK << 16);
++
++ /* Report residual bytes for single sgl */
++ if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) {
++ if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id]))
++ scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length);
++ }
++
++ /* Now complete the io */
++ tw_dev->state[request_id] = TW_S_COMPLETED;
++ twl_free_request_id(tw_dev, request_id);
++ tw_dev->posted_request_count--;
++ tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
++ twl_unmap_scsi_data(tw_dev, request_id);
++ }
++
++ /* Check for another response interrupt */
++ reg = readl(TWL_HISTAT_REG_ADDR(tw_dev));
++ }
++
++twl_interrupt_bail:
++ spin_unlock(tw_dev->host->host_lock);
++ return IRQ_RETVAL(handled);
++} /* End twl_interrupt() */
++
++/* This function will poll for a register change */
++static int twl_poll_register(TW_Device_Extension *tw_dev, void *reg, u32 value, u32 result, int seconds)
++{
++ unsigned long before;
++ int retval = 1;
++ u32 reg_value;
++
++ reg_value = readl(reg);
++ before = jiffies;
++
++ while ((reg_value & value) != result) {
++ reg_value = readl(reg);
++ if (time_after(jiffies, before + HZ * seconds))
++ goto out;
++ msleep(50);
++ }
++ retval = 0;
++out:
++ return retval;
++} /* End twl_poll_register() */
++
++/* This function will reset a controller */
++static int twl_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
++{
++ int retval = 1;
++ int i = 0;
++ u32 status = 0;
++ unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
++ unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
++ u32 init_connect_result = 0;
++ int tries = 0;
++ int do_soft_reset = soft_reset;
++
++ while (tries < TW_MAX_RESET_TRIES) {
++ /* Do a soft reset if one is needed */
++ if (do_soft_reset) {
++ TWL_SOFT_RESET(tw_dev);
++
++ /* Make sure controller is in a good state */
++ if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, 0x0, 30)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Controller never went non-ready during reset sequence");
++ tries++;
++ continue;
++ }
++ if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, TWL_CONTROLLER_READY, 60)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x11, "Controller not ready during reset sequence");
++ tries++;
++ continue;
++ }
++ }
++
++ /* Initconnect */
++ if (twl_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
++ TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL,
++ TW_9750_ARCH_ID, TW_CURRENT_DRIVER_BRANCH,
++ TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl,
++ &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
++ &fw_on_ctlr_build, &init_connect_result)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x12, "Initconnection failed while checking SRL");
++ do_soft_reset = 1;
++ tries++;
++ continue;
++ }
++
++ /* Load sense buffers */
++ while (i < TW_Q_LENGTH) {
++ writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev));
++ writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev));
++
++ /* Check status for over-run after each write */
++ status = readl(TWL_STATUS_REG_ADDR(tw_dev));
++ if (!(status & TWL_STATUS_OVERRUN_SUBMIT))
++ i++;
++ }
++
++ /* Now check status */
++ status = readl(TWL_STATUS_REG_ADDR(tw_dev));
++ if (status) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "Bad controller status after loading sense buffers");
++ do_soft_reset = 1;
++ tries++;
++ continue;
++ }
++
++ /* Drain the AEN queue */
++ if (twl_aen_drain_queue(tw_dev, soft_reset)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x14, "AEN drain failed during reset sequence");
++ do_soft_reset = 1;
++ tries++;
++ continue;
++ }
++
++ /* Load rest of compatibility struct */
++ strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
++ tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL;
++ tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
++ tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD;
++ tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL;
++ tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH;
++ tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD;
++ tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl;
++ tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch;
++ tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build;
++
++ /* If we got here, controller is in a good state */
++ retval = 0;
++ goto out;
++ }
++out:
++ return retval;
++} /* End twl_reset_sequence() */
++
++/* This function will reset a device extension */
++static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
++{
++ int i = 0, retval = 1;
++ unsigned long flags = 0;
++
++ /* Block SCSI requests while we are resetting */
++ if (ioctl_reset)
++ scsi_block_requests(tw_dev->host);
++
++ set_bit(TW_IN_RESET, &tw_dev->flags);
++ TWL_MASK_INTERRUPTS(tw_dev);
++ TWL_CLEAR_DB_INTERRUPT(tw_dev);
++
++ spin_lock_irqsave(tw_dev->host->host_lock, flags);
++
++ /* Abort all requests that are in progress */
++ for (i = 0; i < TW_Q_LENGTH; i++) {
++ if ((tw_dev->state[i] != TW_S_FINISHED) &&
++ (tw_dev->state[i] != TW_S_INITIAL) &&
++ (tw_dev->state[i] != TW_S_COMPLETED)) {
++ if (tw_dev->srb[i]) {
++ tw_dev->srb[i]->result = (DID_RESET << 16);
++ tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
++ twl_unmap_scsi_data(tw_dev, i);
++ }
++ }
++ }
++
++ /* Reset queues and counts */
++ for (i = 0; i < TW_Q_LENGTH; i++) {
++ tw_dev->free_queue[i] = i;
++ tw_dev->state[i] = TW_S_INITIAL;
++ }
++ tw_dev->free_head = TW_Q_START;
++ tw_dev->free_tail = TW_Q_START;
++ tw_dev->posted_request_count = 0;
++
++ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
++
++ if (twl_reset_sequence(tw_dev, 1))
++ goto out;
++
++ TWL_UNMASK_INTERRUPTS(tw_dev);
++
++ clear_bit(TW_IN_RESET, &tw_dev->flags);
++ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
++
++ retval = 0;
++out:
++ if (ioctl_reset)
++ scsi_unblock_requests(tw_dev->host);
++ return retval;
++} /* End twl_reset_device_extension() */
++
++/* This funciton returns unit geometry in cylinders/heads/sectors */
++static int twl_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
++{
++ int heads, sectors, cylinders;
++ TW_Device_Extension *tw_dev;
++
++ tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
++
++ if (capacity >= 0x200000) {
++ heads = 255;
++ sectors = 63;
++ cylinders = sector_div(capacity, heads * sectors);
++ } else {
++ heads = 64;
++ sectors = 32;
++ cylinders = sector_div(capacity, heads * sectors);
++ }
++
++ geom[0] = heads;
++ geom[1] = sectors;
++ geom[2] = cylinders;
++
++ return 0;
++} /* End twl_scsi_biosparam() */
++
++/* This is the new scsi eh reset function */
++static int twl_scsi_eh_reset(struct scsi_cmnd *SCpnt)
++{
++ TW_Device_Extension *tw_dev = NULL;
++ int retval = FAILED;
++
++ tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
++
++ tw_dev->num_resets++;
++
++ sdev_printk(KERN_WARNING, SCpnt->device,
++ "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n",
++ TW_DRIVER, 0x2c, SCpnt->cmnd[0]);
++
++ /* Make sure we are not issuing an ioctl or resetting from ioctl */
++ mutex_lock(&tw_dev->ioctl_lock);
++
++ /* Now reset the card and some of the device extension data */
++ if (twl_reset_device_extension(tw_dev, 0)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "Controller reset failed during scsi host reset");
++ goto out;
++ }
++
++ retval = SUCCESS;
++out:
++ mutex_unlock(&tw_dev->ioctl_lock);
++ return retval;
++} /* End twl_scsi_eh_reset() */
++
++/* This is the main scsi queue function to handle scsi opcodes */
++static int twl_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
++{
++ int request_id, retval;
++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
++
++ /* If we are resetting due to timed out ioctl, report as busy */
++ if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
++ retval = SCSI_MLQUEUE_HOST_BUSY;
++ goto out;
++ }
++
++ /* Save done function into scsi_cmnd struct */
++ SCpnt->scsi_done = done;
++
++ /* Get a free request id */
++ twl_get_request_id(tw_dev, &request_id);
++
++ /* Save the scsi command for use by the ISR */
++ tw_dev->srb[request_id] = SCpnt;
++
++ /* Initialize phase to zero */
++ SCpnt->SCp.phase = TW_PHASE_INITIAL;
++
++ retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
++ if (retval) {
++ tw_dev->state[request_id] = TW_S_COMPLETED;
++ twl_free_request_id(tw_dev, request_id);
++ SCpnt->result = (DID_ERROR << 16);
++ done(SCpnt);
++ retval = 0;
++ }
++out:
++ return retval;
++} /* End twl_scsi_queue() */
++
++/* This function tells the controller to shut down */
++static void __twl_shutdown(TW_Device_Extension *tw_dev)
++{
++ /* Disable interrupts */
++ TWL_MASK_INTERRUPTS(tw_dev);
++
++ /* Free up the IRQ */
++ free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
++
++ printk(KERN_WARNING "3w-sas: Shutting down host %d.\n", tw_dev->host->host_no);
++
++ /* Tell the card we are shutting down */
++ if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Connection shutdown failed");
++ } else {
++ printk(KERN_WARNING "3w-sas: Shutdown complete.\n");
++ }
++
++ /* Clear doorbell interrupt just before exit */
++ TWL_CLEAR_DB_INTERRUPT(tw_dev);
++} /* End __twl_shutdown() */
++
++/* Wrapper for __twl_shutdown */
++static void twl_shutdown(struct pci_dev *pdev)
++{
++ struct Scsi_Host *host = pci_get_drvdata(pdev);
++ TW_Device_Extension *tw_dev;
++
++ if (!host)
++ return;
++
++ tw_dev = (TW_Device_Extension *)host->hostdata;
++
++ if (tw_dev->online)
++ __twl_shutdown(tw_dev);
++} /* End twl_shutdown() */
++
++/* This function configures unit settings when a unit is coming on-line */
++static int twl_slave_configure(struct scsi_device *sdev)
++{
++ /* Force 60 second timeout */
++ blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
++
++ return 0;
++} /* End twl_slave_configure() */
++
++/* scsi_host_template initializer */
++static struct scsi_host_template driver_template = {
++ .module = THIS_MODULE,
++ .name = "3w-sas",
++ .queuecommand = twl_scsi_queue,
++ .eh_host_reset_handler = twl_scsi_eh_reset,
++ .bios_param = twl_scsi_biosparam,
++ .change_queue_depth = twl_change_queue_depth,
++ .can_queue = TW_Q_LENGTH-2,
++ .slave_configure = twl_slave_configure,
++ .this_id = -1,
++ .sg_tablesize = TW_LIBERATOR_MAX_SGL_LENGTH,
++ .max_sectors = TW_MAX_SECTORS,
++ .cmd_per_lun = TW_MAX_CMDS_PER_LUN,
++ .use_clustering = ENABLE_CLUSTERING,
++ .shost_attrs = twl_host_attrs,
++ .emulated = 1
++};
++
++/* This function will probe and initialize a card */
++static int __devinit twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
++{
++ struct Scsi_Host *host = NULL;
++ TW_Device_Extension *tw_dev;
++ resource_size_t mem_addr, mem_len;
++ int retval = -ENODEV;
++ int *ptr_phycount, phycount=0;
++
++ retval = pci_enable_device(pdev);
++ if (retval) {
++ TW_PRINTK(host, TW_DRIVER, 0x17, "Failed to enable pci device");
++ goto out_disable_device;
++ }
++
++ pci_set_master(pdev);
++ pci_try_set_mwi(pdev);
++
++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
++ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
++ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
++ TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask");
++ retval = -ENODEV;
++ goto out_disable_device;
++ }
++
++ host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
++ if (!host) {
++ TW_PRINTK(host, TW_DRIVER, 0x19, "Failed to allocate memory for device extension");
++ retval = -ENOMEM;
++ goto out_disable_device;
++ }
++ tw_dev = (TW_Device_Extension *)host->hostdata;
++
++ /* Save values to device extension */
++ tw_dev->host = host;
++ tw_dev->tw_pci_dev = pdev;
++
++ if (twl_initialize_device_extension(tw_dev)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Failed to initialize device extension");
++ goto out_free_device_extension;
++ }
++
++ /* Request IO regions */
++ retval = pci_request_regions(pdev, "3w-sas");
++ if (retval) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Failed to get mem region");
++ goto out_free_device_extension;
++ }
++
++ /* Use region 1 */
++ mem_addr = pci_resource_start(pdev, 1);
++ mem_len = pci_resource_len(pdev, 1);
++
++ /* Save base address */
++ tw_dev->base_addr = ioremap(mem_addr, mem_len);
++
++ if (!tw_dev->base_addr) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to ioremap");
++ goto out_release_mem_region;
++ }
++
++ /* Disable interrupts on the card */
++ TWL_MASK_INTERRUPTS(tw_dev);
++
++ /* Initialize the card */
++ if (twl_reset_sequence(tw_dev, 0)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Controller reset failed during probe");
++ goto out_iounmap;
++ }
++
++ /* Set host specific parameters */
++ host->max_id = TW_MAX_UNITS;
++ host->max_cmd_len = TW_MAX_CDB_LEN;
++ host->max_lun = TW_MAX_LUNS;
++ host->max_channel = 0;
++
++ /* Register the card with the kernel SCSI layer */
++ retval = scsi_add_host(host, &pdev->dev);
++ if (retval) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "scsi add host failed");
++ goto out_iounmap;
++ }
++
++ pci_set_drvdata(pdev, host);
++
++ printk(KERN_WARNING "3w-sas: scsi%d: Found an LSI 3ware %s Controller at 0x%llx, IRQ: %d.\n",
++ host->host_no,
++ (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE,
++ TW_PARAM_MODEL, TW_PARAM_MODEL_LENGTH),
++ (u64)mem_addr, pdev->irq);
++
++ ptr_phycount = twl_get_param(tw_dev, 2, TW_PARAM_PHY_SUMMARY_TABLE,
++ TW_PARAM_PHYCOUNT, TW_PARAM_PHYCOUNT_LENGTH);
++ if (ptr_phycount)
++ phycount = le32_to_cpu(*(int *)ptr_phycount);
++
++ printk(KERN_WARNING "3w-sas: scsi%d: Firmware %s, BIOS %s, Phys: %d.\n",
++ host->host_no,
++ (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE,
++ TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
++ (char *)twl_get_param(tw_dev, 2, TW_VERSION_TABLE,
++ TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
++ phycount);
++
++ /* Try to enable MSI */
++ if (use_msi && !pci_enable_msi(pdev))
++ set_bit(TW_USING_MSI, &tw_dev->flags);
++
++ /* Now setup the interrupt handler */
++ retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev);
++ if (retval) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Error requesting IRQ");
++ goto out_remove_host;
++ }
++
++ twl_device_extension_list[twl_device_extension_count] = tw_dev;
++ twl_device_extension_count++;
++
++ /* Re-enable interrupts on the card */
++ TWL_UNMASK_INTERRUPTS(tw_dev);
++
++ /* Finally, scan the host */
++ scsi_scan_host(host);
++
++ /* Add sysfs binary files */
++ if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr))
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Failed to create sysfs binary file: 3ware_aen_read");
++ if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr))
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Failed to create sysfs binary file: 3ware_compat_info");
++
++ if (twl_major == -1) {
++ if ((twl_major = register_chrdev (0, "twl", &twl_fops)) < 0)
++ TW_PRINTK(host, TW_DRIVER, 0x22, "Failed to register character device");
++ }
++ tw_dev->online = 1;
++ return 0;
++
++out_remove_host:
++ if (test_bit(TW_USING_MSI, &tw_dev->flags))
++ pci_disable_msi(pdev);
++ scsi_remove_host(host);
++out_iounmap:
++ iounmap(tw_dev->base_addr);
++out_release_mem_region:
++ pci_release_regions(pdev);
++out_free_device_extension:
++ twl_free_device_extension(tw_dev);
++ scsi_host_put(host);
++out_disable_device:
++ pci_disable_device(pdev);
++
++ return retval;
++} /* End twl_probe() */
++
++/* This function is called to remove a device */
++static void twl_remove(struct pci_dev *pdev)
++{
++ struct Scsi_Host *host = pci_get_drvdata(pdev);
++ TW_Device_Extension *tw_dev;
++
++ if (!host)
++ return;
++
++ tw_dev = (TW_Device_Extension *)host->hostdata;
++
++ if (!tw_dev->online)
++ return;
++
++ /* Remove sysfs binary files */
++ sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr);
++ sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr);
++
++ scsi_remove_host(tw_dev->host);
++
++ /* Unregister character device */
++ if (twl_major >= 0) {
++ unregister_chrdev(twl_major, "twl");
++ twl_major = -1;
++ }
++
++ /* Shutdown the card */
++ __twl_shutdown(tw_dev);
++
++ /* Disable MSI if enabled */
++ if (test_bit(TW_USING_MSI, &tw_dev->flags))
++ pci_disable_msi(pdev);
++
++ /* Free IO remapping */
++ iounmap(tw_dev->base_addr);
++
++ /* Free up the mem region */
++ pci_release_regions(pdev);
++
++ /* Free up device extension resources */
++ twl_free_device_extension(tw_dev);
++
++ scsi_host_put(tw_dev->host);
++ pci_disable_device(pdev);
++ twl_device_extension_count--;
++} /* End twl_remove() */
++
++#ifdef CONFIG_PM
++/* This function is called on PCI suspend */
++static int twl_suspend(struct pci_dev *pdev, pm_message_t state)
++{
++ struct Scsi_Host *host = pci_get_drvdata(pdev);
++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
++
++ printk(KERN_WARNING "3w-sas: Suspending host %d.\n", tw_dev->host->host_no);
++ /* Disable interrupts */
++ TWL_MASK_INTERRUPTS(tw_dev);
++
++ free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
++
++ /* Tell the card we are shutting down */
++ if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x23, "Connection shutdown failed during suspend");
++ } else {
++ printk(KERN_WARNING "3w-sas: Suspend complete.\n");
++ }
++
++ /* Clear doorbell interrupt */
++ TWL_CLEAR_DB_INTERRUPT(tw_dev);
++
++ pci_save_state(pdev);
++ pci_disable_device(pdev);
++ pci_set_power_state(pdev, pci_choose_state(pdev, state));
++
++ return 0;
++} /* End twl_suspend() */
++
++/* This function is called on PCI resume */
++static int twl_resume(struct pci_dev *pdev)
++{
++ int retval = 0;
++ struct Scsi_Host *host = pci_get_drvdata(pdev);
++ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
++
++ printk(KERN_WARNING "3w-sas: Resuming host %d.\n", tw_dev->host->host_no);
++ pci_set_power_state(pdev, PCI_D0);
++ pci_enable_wake(pdev, PCI_D0, 0);
++ pci_restore_state(pdev);
++
++ retval = pci_enable_device(pdev);
++ if (retval) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x24, "Enable device failed during resume");
++ return retval;
++ }
++
++ pci_set_master(pdev);
++ pci_try_set_mwi(pdev);
++
++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
++ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
++ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
++ TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume");
++ retval = -ENODEV;
++ goto out_disable_device;
++ }
++
++ /* Initialize the card */
++ if (twl_reset_sequence(tw_dev, 0)) {
++ retval = -ENODEV;
++ goto out_disable_device;
++ }
++
++ /* Now setup the interrupt handler */
++ retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev);
++ if (retval) {
++ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Error requesting IRQ during resume");
++ retval = -ENODEV;
++ goto out_disable_device;
++ }
++
++ /* Now enable MSI if enabled */
++ if (test_bit(TW_USING_MSI, &tw_dev->flags))
++ pci_enable_msi(pdev);
++
++ /* Re-enable interrupts on the card */
++ TWL_UNMASK_INTERRUPTS(tw_dev);
++
++ printk(KERN_WARNING "3w-sas: Resume complete.\n");
++ return 0;
++
++out_disable_device:
++ scsi_remove_host(host);
++ pci_disable_device(pdev);
++
++ return retval;
++} /* End twl_resume() */
++#endif
++
++/* PCI Devices supported by this driver */
++static struct pci_device_id twl_pci_tbl[] __devinitdata = {
++ { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9750,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { }
++};
++MODULE_DEVICE_TABLE(pci, twl_pci_tbl);
++
++/* pci_driver initializer */
++static struct pci_driver twl_driver = {
++ .name = "3w-sas",
++ .id_table = twl_pci_tbl,
++ .probe = twl_probe,
++ .remove = twl_remove,
++#ifdef CONFIG_PM
++ .suspend = twl_suspend,
++ .resume = twl_resume,
++#endif
++ .shutdown = twl_shutdown
++};
++
++/* This function is called on driver initialization */
++static int __init twl_init(void)
++{
++ printk(KERN_WARNING "LSI 3ware SAS/SATA-RAID Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
++
++ return pci_register_driver(&twl_driver);
++} /* End twl_init() */
++
++/* This function is called on driver exit */
++static void __exit twl_exit(void)
++{
++ pci_unregister_driver(&twl_driver);
++} /* End twl_exit() */
++
++module_init(twl_init);
++module_exit(twl_exit);
++
+diff --git a/drivers/scsi/3w-sas.h b/drivers/scsi/3w-sas.h
+new file mode 100644
+index 0000000..e620505
+--- /dev/null
++++ b/drivers/scsi/3w-sas.h
+@@ -0,0 +1,396 @@
++/*
++ 3w-sas.h -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux.
++
++ Written By: Adam Radford <linuxraid@lsi.com>
++
++ Copyright (C) 2009 LSI 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
++
++ Bugs/Comments/Suggestions should be mailed to:
++ linuxraid@lsi.com
++
++ For more information, goto:
++ http://www.lsi.com
++*/
++
++#ifndef _3W_SAS_H
++#define _3W_SAS_H
++
++/* AEN severity table */
++static char *twl_aen_severity_table[] =
++{
++ "None", "ERROR", "WARNING", "INFO", "DEBUG", (char*) 0
++};
++
++/* Liberator register offsets */
++#define TWL_STATUS 0x0 /* Status */
++#define TWL_HIBDB 0x20 /* Inbound doorbell */
++#define TWL_HISTAT 0x30 /* Host interrupt status */
++#define TWL_HIMASK 0x34 /* Host interrupt mask */
++#define TWL_HOBDB 0x9C /* Outbound doorbell */
++#define TWL_HOBDBC 0xA0 /* Outbound doorbell clear */
++#define TWL_SCRPD3 0xBC /* Scratchpad */
++#define TWL_HIBQPL 0xC0 /* Host inbound Q low */
++#define TWL_HIBQPH 0xC4 /* Host inbound Q high */
++#define TWL_HOBQPL 0xC8 /* Host outbound Q low */
++#define TWL_HOBQPH 0xCC /* Host outbound Q high */
++#define TWL_HISTATUS_VALID_INTERRUPT 0xC
++#define TWL_HISTATUS_ATTENTION_INTERRUPT 0x4
++#define TWL_HISTATUS_RESPONSE_INTERRUPT 0x8
++#define TWL_STATUS_OVERRUN_SUBMIT 0x2000
++#define TWL_ISSUE_SOFT_RESET 0x100
++#define TWL_CONTROLLER_READY 0x2000
++#define TWL_DOORBELL_CONTROLLER_ERROR 0x200000
++#define TWL_DOORBELL_ATTENTION_INTERRUPT 0x40000
++#define TWL_PULL_MODE 0x1
++
++/* Command packet opcodes used by the driver */
++#define TW_OP_INIT_CONNECTION 0x1
++#define TW_OP_GET_PARAM 0x12
++#define TW_OP_SET_PARAM 0x13
++#define TW_OP_EXECUTE_SCSI 0x10
++
++/* Asynchronous Event Notification (AEN) codes used by the driver */
++#define TW_AEN_QUEUE_EMPTY 0x0000
++#define TW_AEN_SOFT_RESET 0x0001
++#define TW_AEN_SYNC_TIME_WITH_HOST 0x031
++#define TW_AEN_SEVERITY_ERROR 0x1
++#define TW_AEN_SEVERITY_DEBUG 0x4
++#define TW_AEN_NOT_RETRIEVED 0x1
++
++/* Command state defines */
++#define TW_S_INITIAL 0x1 /* Initial state */
++#define TW_S_STARTED 0x2 /* Id in use */
++#define TW_S_POSTED 0x4 /* Posted to the controller */
++#define TW_S_COMPLETED 0x8 /* Completed by isr */
++#define TW_S_FINISHED 0x10 /* I/O completely done */
++
++/* Compatibility defines */
++#define TW_9750_ARCH_ID 10
++#define TW_CURRENT_DRIVER_SRL 40
++#define TW_CURRENT_DRIVER_BUILD 0
++#define TW_CURRENT_DRIVER_BRANCH 0
++
++/* Phase defines */
++#define TW_PHASE_INITIAL 0
++#define TW_PHASE_SGLIST 2
++
++/* Misc defines */
++#define TW_SECTOR_SIZE 512
++#define TW_MAX_UNITS 32
++#define TW_INIT_MESSAGE_CREDITS 0x100
++#define TW_INIT_COMMAND_PACKET_SIZE 0x3
++#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6
++#define TW_EXTENDED_INIT_CONNECT 0x2
++#define TW_BASE_FW_SRL 24
++#define TW_BASE_FW_BRANCH 0
++#define TW_BASE_FW_BUILD 1
++#define TW_Q_LENGTH 256
++#define TW_Q_START 0
++#define TW_MAX_SLOT 32
++#define TW_MAX_RESET_TRIES 2
++#define TW_MAX_CMDS_PER_LUN 254
++#define TW_MAX_AEN_DRAIN 255
++#define TW_IN_RESET 2
++#define TW_USING_MSI 3
++#define TW_IN_ATTENTION_LOOP 4
++#define TW_MAX_SECTORS 256
++#define TW_MAX_CDB_LEN 16
++#define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */
++#define TW_IOCTL_CHRDEV_FREE -1
++#define TW_COMMAND_OFFSET 128 /* 128 bytes */
++#define TW_VERSION_TABLE 0x0402
++#define TW_TIMEKEEP_TABLE 0x040A
++#define TW_INFORMATION_TABLE 0x0403
++#define TW_PARAM_FWVER 3
++#define TW_PARAM_FWVER_LENGTH 16
++#define TW_PARAM_BIOSVER 4
++#define TW_PARAM_BIOSVER_LENGTH 16
++#define TW_PARAM_MODEL 8
++#define TW_PARAM_MODEL_LENGTH 16
++#define TW_PARAM_PHY_SUMMARY_TABLE 1
++#define TW_PARAM_PHYCOUNT 2
++#define TW_PARAM_PHYCOUNT_LENGTH 1
++#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108 // Used by smartmontools
++#define TW_ALLOCATION_LENGTH 128
++#define TW_SENSE_DATA_LENGTH 18
++#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED 0x10a
++#define TW_ERROR_INVALID_FIELD_IN_CDB 0x10d
++#define TW_ERROR_UNIT_OFFLINE 0x128
++#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR 3
++#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT 4
++#define TW_DRIVER 6
++#ifndef PCI_DEVICE_ID_3WARE_9750
++#define PCI_DEVICE_ID_3WARE_9750 0x1010
++#endif
++
++/* Bitmask macros to eliminate bitfields */
++
++/* opcode: 5, reserved: 3 */
++#define TW_OPRES_IN(x,y) ((x << 5) | (y & 0x1f))
++#define TW_OP_OUT(x) (x & 0x1f)
++
++/* opcode: 5, sgloffset: 3 */
++#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f))
++#define TW_SGL_OUT(x) ((x >> 5) & 0x7)
++
++/* severity: 3, reserved: 5 */
++#define TW_SEV_OUT(x) (x & 0x7)
++
++/* not_mfa: 1, reserved: 7, status: 8, request_id: 16 */
++#define TW_RESID_OUT(x) ((x >> 16) & 0xffff)
++#define TW_NOTMFA_OUT(x) (x & 0x1)
++
++/* request_id: 12, lun: 4 */
++#define TW_REQ_LUN_IN(lun, request_id) (((lun << 12) & 0xf000) | (request_id & 0xfff))
++#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf)
++
++/* Register access macros */
++#define TWL_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_STATUS)
++#define TWL_HOBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPL)
++#define TWL_HOBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPH)
++#define TWL_HOBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDB)
++#define TWL_HOBDBC_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDBC)
++#define TWL_HIMASK_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIMASK)
++#define TWL_HISTAT_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HISTAT)
++#define TWL_HIBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPH)
++#define TWL_HIBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPL)
++#define TWL_HIBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBDB)
++#define TWL_SCRPD3_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_SCRPD3)
++#define TWL_MASK_INTERRUPTS(x) (writel(~0, TWL_HIMASK_REG_ADDR(tw_dev)))
++#define TWL_UNMASK_INTERRUPTS(x) (writel(~TWL_HISTATUS_VALID_INTERRUPT, TWL_HIMASK_REG_ADDR(tw_dev)))
++#define TWL_CLEAR_DB_INTERRUPT(x) (writel(~0, TWL_HOBDBC_REG_ADDR(tw_dev)))
++#define TWL_SOFT_RESET(x) (writel(TWL_ISSUE_SOFT_RESET, TWL_HIBDB_REG_ADDR(tw_dev)))
++
++/* Macros */
++#define TW_PRINTK(h,a,b,c) { \
++if (h) \
++printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \
++else \
++printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \
++}
++#define TW_MAX_LUNS 16
++#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 6 : 4)
++#define TW_LIBERATOR_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 46 : 92)
++#define TW_LIBERATOR_MAX_SGL_LENGTH_OLD (sizeof(dma_addr_t) > 4 ? 47 : 94)
++#define TW_PADDING_LENGTH_LIBERATOR 136
++#define TW_PADDING_LENGTH_LIBERATOR_OLD 132
++#define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) : cpu_to_le32(x))
++
++#pragma pack(1)
++
++/* SGL entry */
++typedef struct TAG_TW_SG_Entry_ISO {
++ dma_addr_t address;
++ dma_addr_t length;
++} TW_SG_Entry_ISO;
++
++/* Old Command Packet with ISO SGL */
++typedef struct TW_Command {
++ unsigned char opcode__sgloffset;
++ unsigned char size;
++ unsigned char request_id;
++ unsigned char unit__hostid;
++ /* Second DWORD */
++ unsigned char status;
++ unsigned char flags;
++ union {
++ unsigned short block_count;
++ unsigned short parameter_count;
++ } byte6_offset;
++ union {
++ struct {
++ u32 lba;
++ TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD];
++ unsigned char padding[TW_PADDING_LENGTH_LIBERATOR_OLD];
++ } io;
++ struct {
++ TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD];
++ u32 padding;
++ unsigned char padding2[TW_PADDING_LENGTH_LIBERATOR_OLD];
++ } param;
++ } byte8_offset;
++} TW_Command;
++
++/* New Command Packet with ISO SGL */
++typedef struct TAG_TW_Command_Apache {
++ unsigned char opcode__reserved;
++ unsigned char unit;
++ unsigned short request_id__lunl;
++ unsigned char status;
++ unsigned char sgl_offset;
++ unsigned short sgl_entries__lunh;
++ unsigned char cdb[16];
++ TW_SG_Entry_ISO sg_list[TW_LIBERATOR_MAX_SGL_LENGTH];
++ unsigned char padding[TW_PADDING_LENGTH_LIBERATOR];
++} TW_Command_Apache;
++
++/* New command packet header */
++typedef struct TAG_TW_Command_Apache_Header {
++ unsigned char sense_data[TW_SENSE_DATA_LENGTH];
++ struct {
++ char reserved[4];
++ unsigned short error;
++ unsigned char padding;
++ unsigned char severity__reserved;
++ } status_block;
++ unsigned char err_specific_desc[98];
++ struct {
++ unsigned char size_header;
++ unsigned short request_id;
++ unsigned char size_sense;
++ } header_desc;
++} TW_Command_Apache_Header;
++
++/* This struct is a union of the 2 command packets */
++typedef struct TAG_TW_Command_Full {
++ TW_Command_Apache_Header header;
++ union {
++ TW_Command oldcommand;
++ TW_Command_Apache newcommand;
++ } command;
++} TW_Command_Full;
++
++/* Initconnection structure */
++typedef struct TAG_TW_Initconnect {
++ unsigned char opcode__reserved;
++ unsigned char size;
++ unsigned char request_id;
++ unsigned char res2;
++ unsigned char status;
++ unsigned char flags;
++ unsigned short message_credits;
++ u32 features;
++ unsigned short fw_srl;
++ unsigned short fw_arch_id;
++ unsigned short fw_branch;
++ unsigned short fw_build;
++ u32 result;
++} TW_Initconnect;
++
++/* Event info structure */
++typedef struct TAG_TW_Event
++{
++ unsigned int sequence_id;
++ unsigned int time_stamp_sec;
++ unsigned short aen_code;
++ unsigned char severity;
++ unsigned char retrieved;
++ unsigned char repeat_count;
++ unsigned char parameter_len;
++ unsigned char parameter_data[98];
++} TW_Event;
++
++typedef struct TAG_TW_Ioctl_Driver_Command {
++ unsigned int control_code;
++ unsigned int status;
++ unsigned int unique_id;
++ unsigned int sequence_id;
++ unsigned int os_specific;
++ unsigned int buffer_length;
++} TW_Ioctl_Driver_Command;
++
++typedef struct TAG_TW_Ioctl_Apache {
++ TW_Ioctl_Driver_Command driver_command;
++ char padding[488];
++ TW_Command_Full firmware_command;
++ char data_buffer[1];
++} TW_Ioctl_Buf_Apache;
++
++/* GetParam descriptor */
++typedef struct {
++ unsigned short table_id;
++ unsigned short parameter_id;
++ unsigned short parameter_size_bytes;
++ unsigned short actual_parameter_size_bytes;
++ unsigned char data[1];
++} TW_Param_Apache;
++
++/* Compatibility information structure */
++typedef struct TAG_TW_Compatibility_Info
++{
++ char driver_version[32];
++ unsigned short working_srl;
++ unsigned short working_branch;
++ unsigned short working_build;
++ unsigned short driver_srl_high;
++ unsigned short driver_branch_high;
++ unsigned short driver_build_high;
++ unsigned short driver_srl_low;
++ unsigned short driver_branch_low;
++ unsigned short driver_build_low;
++ unsigned short fw_on_ctlr_srl;
++ unsigned short fw_on_ctlr_branch;
++ unsigned short fw_on_ctlr_build;
++} TW_Compatibility_Info;
++
++#pragma pack()
++
++typedef struct TAG_TW_Device_Extension {
++ void __iomem *base_addr;
++ unsigned long *generic_buffer_virt[TW_Q_LENGTH];
++ dma_addr_t generic_buffer_phys[TW_Q_LENGTH];
++ TW_Command_Full *command_packet_virt[TW_Q_LENGTH];
++ dma_addr_t command_packet_phys[TW_Q_LENGTH];
++ TW_Command_Apache_Header *sense_buffer_virt[TW_Q_LENGTH];
++ dma_addr_t sense_buffer_phys[TW_Q_LENGTH];
++ struct pci_dev *tw_pci_dev;
++ struct scsi_cmnd *srb[TW_Q_LENGTH];
++ unsigned char free_queue[TW_Q_LENGTH];
++ unsigned char free_head;
++ unsigned char free_tail;
++ int state[TW_Q_LENGTH];
++ unsigned int posted_request_count;
++ unsigned int max_posted_request_count;
++ unsigned int max_sgl_entries;
++ unsigned int sgl_entries;
++ unsigned int num_resets;
++ unsigned int sector_count;
++ unsigned int max_sector_count;
++ unsigned int aen_count;
++ struct Scsi_Host *host;
++ long flags;
++ TW_Event *event_queue[TW_Q_LENGTH];
++ unsigned char error_index;
++ unsigned int error_sequence_id;
++ int chrdev_request_id;
++ wait_queue_head_t ioctl_wqueue;
++ struct mutex ioctl_lock;
++ TW_Compatibility_Info tw_compat_info;
++ char online;
++} TW_Device_Extension;
++
++#endif /* _3W_SAS_H */
++
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 1ddcf40..a85f062 100644
--- a/drivers/scsi/BusLogic.c
@@ -40865,6 +56739,63 @@ index 1ddcf40..a85f062 100644
/*
If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint
Host Adapters; otherwise, default to the standard ISA MultiMaster probe.
+diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
+index e11cca4..4295679 100644
+--- a/drivers/scsi/Kconfig
++++ b/drivers/scsi/Kconfig
+@@ -399,6 +399,17 @@ config SCSI_3W_9XXX
+ Please read the comments at the top of
+ <file:drivers/scsi/3w-9xxx.c>.
+
++config SCSI_3W_SAS
++ tristate "3ware 97xx SAS/SATA-RAID support"
++ depends on PCI && SCSI
++ help
++ This driver supports the LSI 3ware 9750 6Gb/s SAS/SATA-RAID cards.
++
++ <http://www.lsi.com>
++
++ Please read the comments at the top of
++ <file:drivers/scsi/3w-sas.c>.
++
+ config SCSI_7000FASST
+ tristate "7000FASST SCSI support"
+ depends on ISA && SCSI && ISA_DMA_API
+@@ -621,6 +632,14 @@ config SCSI_FLASHPOINT
+ substantial, so users of MultiMaster Host Adapters may not
+ wish to include it.
+
++config VMWARE_PVSCSI
++ tristate "VMware PVSCSI driver support"
++ depends on PCI && SCSI && X86
++ help
++ This driver supports VMware's para virtualized SCSI HBA.
++ To compile this driver as a module, choose M here: the
++ module will be called vmw_pvscsi.
++
+ config LIBFC
+ tristate "LibFC module"
+ select SCSI_FC_ATTRS
+diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
+index 3ad61db..c938975 100644
+--- a/drivers/scsi/Makefile
++++ b/drivers/scsi/Makefile
+@@ -113,6 +113,7 @@ obj-$(CONFIG_SCSI_MESH) += mesh.o
+ obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o
+ obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
+ obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o
++obj-$(CONFIG_SCSI_3W_SAS) += 3w-sas.o
+ obj-$(CONFIG_SCSI_PPA) += ppa.o
+ obj-$(CONFIG_SCSI_IMM) += imm.o
+ obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o
+@@ -133,6 +134,7 @@ obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/
+ obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
+ obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
+ obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
++obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
+
+ obj-$(CONFIG_ARM) += arm/
+
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index cdbdec9..b7d560b 100644
--- a/drivers/scsi/aacraid/aacraid.h
@@ -41854,6 +57785,1816 @@ index c19ca5e..3eb5959 100644
memset(&sym_dev, 0, sizeof(sym_dev));
memset(&nvram, 0, sizeof(nvram));
sym_dev.pdev = pdev;
+diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
+new file mode 100644
+index 0000000..eabb432
+--- /dev/null
++++ b/drivers/scsi/vmw_pvscsi.c
+@@ -0,0 +1,1401 @@
++/*
++ * Linux driver for VMware's para-virtualized SCSI HBA.
++ *
++ * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; version 2 of the License and no later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
++ * NON INFRINGEMENT. See the GNU General Public License for more
++ * details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Maintained by: Alok N Kataria <akataria@vmware.com>
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/workqueue.h>
++#include <linux/pci.h>
++
++#include <scsi/scsi.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_device.h>
++
++#include "vmw_pvscsi.h"
++
++#define PVSCSI_LINUX_DRIVER_DESC "VMware PVSCSI driver"
++
++MODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC);
++MODULE_AUTHOR("VMware, Inc.");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING);
++
++#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8
++#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1
++#define PVSCSI_DEFAULT_QUEUE_DEPTH 64
++#define SGL_SIZE PAGE_SIZE
++
++#define pvscsi_dev(adapter) (&(adapter->dev->dev))
++
++struct pvscsi_sg_list {
++ struct PVSCSISGElement sge[PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT];
++};
++
++struct pvscsi_ctx {
++ /*
++ * The index of the context in cmd_map serves as the context ID for a
++ * 1-to-1 mapping completions back to requests.
++ */
++ struct scsi_cmnd *cmd;
++ struct pvscsi_sg_list *sgl;
++ struct list_head list;
++ dma_addr_t dataPA;
++ dma_addr_t sensePA;
++ dma_addr_t sglPA;
++};
++
++struct pvscsi_adapter {
++ char *mmioBase;
++ unsigned int irq;
++ u8 rev;
++ bool use_msi;
++ bool use_msix;
++ bool use_msg;
++
++ spinlock_t hw_lock;
++
++ struct workqueue_struct *workqueue;
++ struct work_struct work;
++
++ struct PVSCSIRingReqDesc *req_ring;
++ unsigned req_pages;
++ unsigned req_depth;
++ dma_addr_t reqRingPA;
++
++ struct PVSCSIRingCmpDesc *cmp_ring;
++ unsigned cmp_pages;
++ dma_addr_t cmpRingPA;
++
++ struct PVSCSIRingMsgDesc *msg_ring;
++ unsigned msg_pages;
++ dma_addr_t msgRingPA;
++
++ struct PVSCSIRingsState *rings_state;
++ dma_addr_t ringStatePA;
++
++ struct pci_dev *dev;
++ struct Scsi_Host *host;
++
++ struct list_head cmd_pool;
++ struct pvscsi_ctx *cmd_map;
++};
++
++
++/* Command line parameters */
++static int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING;
++static int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING;
++static int pvscsi_cmd_per_lun = PVSCSI_DEFAULT_QUEUE_DEPTH;
++static bool pvscsi_disable_msi;
++static bool pvscsi_disable_msix;
++static bool pvscsi_use_msg = true;
++
++#define PVSCSI_RW (S_IRUSR | S_IWUSR)
++
++module_param_named(ring_pages, pvscsi_ring_pages, int, PVSCSI_RW);
++MODULE_PARM_DESC(ring_pages, "Number of pages per req/cmp ring - (default="
++ __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) ")");
++
++module_param_named(msg_ring_pages, pvscsi_msg_ring_pages, int, PVSCSI_RW);
++MODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default="
++ __stringify(PVSCSI_DEFAULT_NUM_PAGES_MSG_RING) ")");
++
++module_param_named(cmd_per_lun, pvscsi_cmd_per_lun, int, PVSCSI_RW);
++MODULE_PARM_DESC(cmd_per_lun, "Maximum commands per lun - (default="
++ __stringify(PVSCSI_MAX_REQ_QUEUE_DEPTH) ")");
++
++module_param_named(disable_msi, pvscsi_disable_msi, bool, PVSCSI_RW);
++MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)");
++
++module_param_named(disable_msix, pvscsi_disable_msix, bool, PVSCSI_RW);
++MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)");
++
++module_param_named(use_msg, pvscsi_use_msg, bool, PVSCSI_RW);
++MODULE_PARM_DESC(use_msg, "Use msg ring when available - (default=1)");
++
++static const struct pci_device_id pvscsi_pci_tbl[] = {
++ { PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI) },
++ { 0 }
++};
++
++MODULE_DEVICE_TABLE(pci, pvscsi_pci_tbl);
++
++static struct pvscsi_ctx *
++pvscsi_find_context(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
++{
++ struct pvscsi_ctx *ctx, *end;
++
++ end = &adapter->cmd_map[adapter->req_depth];
++ for (ctx = adapter->cmd_map; ctx < end; ctx++)
++ if (ctx->cmd == cmd)
++ return ctx;
++
++ return NULL;
++}
++
++static struct pvscsi_ctx *
++pvscsi_acquire_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
++{
++ struct pvscsi_ctx *ctx;
++
++ if (list_empty(&adapter->cmd_pool))
++ return NULL;
++
++ ctx = list_first_entry(&adapter->cmd_pool, struct pvscsi_ctx, list);
++ ctx->cmd = cmd;
++ list_del(&ctx->list);
++
++ return ctx;
++}
++
++static void pvscsi_release_context(struct pvscsi_adapter *adapter,
++ struct pvscsi_ctx *ctx)
++{
++ ctx->cmd = NULL;
++ list_add(&ctx->list, &adapter->cmd_pool);
++}
++
++/*
++ * Map a pvscsi_ctx struct to a context ID field value; we map to a simple
++ * non-zero integer. ctx always points to an entry in cmd_map array, hence
++ * the return value is always >=1.
++ */
++static u64 pvscsi_map_context(const struct pvscsi_adapter *adapter,
++ const struct pvscsi_ctx *ctx)
++{
++ return ctx - adapter->cmd_map + 1;
++}
++
++static struct pvscsi_ctx *
++pvscsi_get_context(const struct pvscsi_adapter *adapter, u64 context)
++{
++ return &adapter->cmd_map[context - 1];
++}
++
++static void pvscsi_reg_write(const struct pvscsi_adapter *adapter,
++ u32 offset, u32 val)
++{
++ writel(val, adapter->mmioBase + offset);
++}
++
++static u32 pvscsi_reg_read(const struct pvscsi_adapter *adapter, u32 offset)
++{
++ return readl(adapter->mmioBase + offset);
++}
++
++static u32 pvscsi_read_intr_status(const struct pvscsi_adapter *adapter)
++{
++ return pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_INTR_STATUS);
++}
++
++static void pvscsi_write_intr_status(const struct pvscsi_adapter *adapter,
++ u32 val)
++{
++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_STATUS, val);
++}
++
++static void pvscsi_unmask_intr(const struct pvscsi_adapter *adapter)
++{
++ u32 intr_bits;
++
++ intr_bits = PVSCSI_INTR_CMPL_MASK;
++ if (adapter->use_msg)
++ intr_bits |= PVSCSI_INTR_MSG_MASK;
++
++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, intr_bits);
++}
++
++static void pvscsi_mask_intr(const struct pvscsi_adapter *adapter)
++{
++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, 0);
++}
++
++static void pvscsi_write_cmd_desc(const struct pvscsi_adapter *adapter,
++ u32 cmd, const void *desc, size_t len)
++{
++ const u32 *ptr = desc;
++ size_t i;
++
++ len /= sizeof(*ptr);
++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, cmd);
++ for (i = 0; i < len; i++)
++ pvscsi_reg_write(adapter,
++ PVSCSI_REG_OFFSET_COMMAND_DATA, ptr[i]);
++}
++
++static void pvscsi_abort_cmd(const struct pvscsi_adapter *adapter,
++ const struct pvscsi_ctx *ctx)
++{
++ struct PVSCSICmdDescAbortCmd cmd = { 0 };
++
++ cmd.target = ctx->cmd->device->id;
++ cmd.context = pvscsi_map_context(adapter, ctx);
++
++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ABORT_CMD, &cmd, sizeof(cmd));
++}
++
++static void pvscsi_kick_rw_io(const struct pvscsi_adapter *adapter)
++{
++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
++}
++
++static void pvscsi_process_request_ring(const struct pvscsi_adapter *adapter)
++{
++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0);
++}
++
++static int scsi_is_rw(unsigned char op)
++{
++ return op == READ_6 || op == WRITE_6 ||
++ op == READ_10 || op == WRITE_10 ||
++ op == READ_12 || op == WRITE_12 ||
++ op == READ_16 || op == WRITE_16;
++}
++
++static void pvscsi_kick_io(const struct pvscsi_adapter *adapter,
++ unsigned char op)
++{
++ if (scsi_is_rw(op))
++ pvscsi_kick_rw_io(adapter);
++ else
++ pvscsi_process_request_ring(adapter);
++}
++
++static void ll_adapter_reset(const struct pvscsi_adapter *adapter)
++{
++ dev_dbg(pvscsi_dev(adapter), "Adapter Reset on %p\n", adapter);
++
++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
++}
++
++static void ll_bus_reset(const struct pvscsi_adapter *adapter)
++{
++ dev_dbg(pvscsi_dev(adapter), "Reseting bus on %p\n", adapter);
++
++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0);
++}
++
++static void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target)
++{
++ struct PVSCSICmdDescResetDevice cmd = { 0 };
++
++ dev_dbg(pvscsi_dev(adapter), "Reseting device: target=%u\n", target);
++
++ cmd.target = target;
++
++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_DEVICE,
++ &cmd, sizeof(cmd));
++}
++
++static void pvscsi_create_sg(struct pvscsi_ctx *ctx,
++ struct scatterlist *sg, unsigned count)
++{
++ unsigned i;
++ struct PVSCSISGElement *sge;
++
++ BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT);
++
++ sge = &ctx->sgl->sge[0];
++ for (i = 0; i < count; i++, sg++) {
++ sge[i].addr = sg_dma_address(sg);
++ sge[i].length = sg_dma_len(sg);
++ sge[i].flags = 0;
++ }
++}
++
++/*
++ * Map all data buffers for a command into PCI space and
++ * setup the scatter/gather list if needed.
++ */
++static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
++ struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
++ struct PVSCSIRingReqDesc *e)
++{
++ unsigned count;
++ unsigned bufflen = scsi_bufflen(cmd);
++ struct scatterlist *sg;
++
++ e->dataLen = bufflen;
++ e->dataAddr = 0;
++ if (bufflen == 0)
++ return;
++
++ sg = scsi_sglist(cmd);
++ count = scsi_sg_count(cmd);
++ if (count != 0) {
++ int segs = scsi_dma_map(cmd);
++ if (segs > 1) {
++ pvscsi_create_sg(ctx, sg, segs);
++
++ e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
++ ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl,
++ SGL_SIZE, PCI_DMA_TODEVICE);
++ e->dataAddr = ctx->sglPA;
++ } else
++ e->dataAddr = sg_dma_address(sg);
++ } else {
++ /*
++ * In case there is no S/G list, scsi_sglist points
++ * directly to the buffer.
++ */
++ ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen,
++ cmd->sc_data_direction);
++ e->dataAddr = ctx->dataPA;
++ }
++}
++
++static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter,
++ struct pvscsi_ctx *ctx)
++{
++ struct scsi_cmnd *cmd;
++ unsigned bufflen;
++
++ cmd = ctx->cmd;
++ bufflen = scsi_bufflen(cmd);
++
++ if (bufflen != 0) {
++ unsigned count = scsi_sg_count(cmd);
++
++ if (count != 0) {
++ scsi_dma_unmap(cmd);
++ if (ctx->sglPA) {
++ pci_unmap_single(adapter->dev, ctx->sglPA,
++ SGL_SIZE, PCI_DMA_TODEVICE);
++ ctx->sglPA = 0;
++ }
++ } else
++ pci_unmap_single(adapter->dev, ctx->dataPA, bufflen,
++ cmd->sc_data_direction);
++ }
++ if (cmd->sense_buffer)
++ pci_unmap_single(adapter->dev, ctx->sensePA,
++ SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
++}
++
++static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
++{
++ adapter->rings_state = pci_alloc_consistent(adapter->dev, PAGE_SIZE,
++ &adapter->ringStatePA);
++ if (!adapter->rings_state)
++ return -ENOMEM;
++
++ adapter->req_pages = min(PVSCSI_MAX_NUM_PAGES_REQ_RING,
++ pvscsi_ring_pages);
++ adapter->req_depth = adapter->req_pages
++ * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
++ adapter->req_ring = pci_alloc_consistent(adapter->dev,
++ adapter->req_pages * PAGE_SIZE,
++ &adapter->reqRingPA);
++ if (!adapter->req_ring)
++ return -ENOMEM;
++
++ adapter->cmp_pages = min(PVSCSI_MAX_NUM_PAGES_CMP_RING,
++ pvscsi_ring_pages);
++ adapter->cmp_ring = pci_alloc_consistent(adapter->dev,
++ adapter->cmp_pages * PAGE_SIZE,
++ &adapter->cmpRingPA);
++ if (!adapter->cmp_ring)
++ return -ENOMEM;
++
++ BUG_ON(!IS_ALIGNED(adapter->ringStatePA, PAGE_SIZE));
++ BUG_ON(!IS_ALIGNED(adapter->reqRingPA, PAGE_SIZE));
++ BUG_ON(!IS_ALIGNED(adapter->cmpRingPA, PAGE_SIZE));
++
++ if (!adapter->use_msg)
++ return 0;
++
++ adapter->msg_pages = min(PVSCSI_MAX_NUM_PAGES_MSG_RING,
++ pvscsi_msg_ring_pages);
++ adapter->msg_ring = pci_alloc_consistent(adapter->dev,
++ adapter->msg_pages * PAGE_SIZE,
++ &adapter->msgRingPA);
++ if (!adapter->msg_ring)
++ return -ENOMEM;
++ BUG_ON(!IS_ALIGNED(adapter->msgRingPA, PAGE_SIZE));
++
++ return 0;
++}
++
++static void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter)
++{
++ struct PVSCSICmdDescSetupRings cmd = { 0 };
++ dma_addr_t base;
++ unsigned i;
++
++ cmd.ringsStatePPN = adapter->ringStatePA >> PAGE_SHIFT;
++ cmd.reqRingNumPages = adapter->req_pages;
++ cmd.cmpRingNumPages = adapter->cmp_pages;
++
++ base = adapter->reqRingPA;
++ for (i = 0; i < adapter->req_pages; i++) {
++ cmd.reqRingPPNs[i] = base >> PAGE_SHIFT;
++ base += PAGE_SIZE;
++ }
++
++ base = adapter->cmpRingPA;
++ for (i = 0; i < adapter->cmp_pages; i++) {
++ cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT;
++ base += PAGE_SIZE;
++ }
++
++ memset(adapter->rings_state, 0, PAGE_SIZE);
++ memset(adapter->req_ring, 0, adapter->req_pages * PAGE_SIZE);
++ memset(adapter->cmp_ring, 0, adapter->cmp_pages * PAGE_SIZE);
++
++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_RINGS,
++ &cmd, sizeof(cmd));
++
++ if (adapter->use_msg) {
++ struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 };
++
++ cmd_msg.numPages = adapter->msg_pages;
++
++ base = adapter->msgRingPA;
++ for (i = 0; i < adapter->msg_pages; i++) {
++ cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT;
++ base += PAGE_SIZE;
++ }
++ memset(adapter->msg_ring, 0, adapter->msg_pages * PAGE_SIZE);
++
++ pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_MSG_RING,
++ &cmd_msg, sizeof(cmd_msg));
++ }
++}
++
++/*
++ * Pull a completion descriptor off and pass the completion back
++ * to the SCSI mid layer.
++ */
++static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
++ const struct PVSCSIRingCmpDesc *e)
++{
++ struct pvscsi_ctx *ctx;
++ struct scsi_cmnd *cmd;
++ u32 btstat = e->hostStatus;
++ u32 sdstat = e->scsiStatus;
++
++ ctx = pvscsi_get_context(adapter, e->context);
++ cmd = ctx->cmd;
++ pvscsi_unmap_buffers(adapter, ctx);
++ pvscsi_release_context(adapter, ctx);
++ cmd->result = 0;
++
++ if (sdstat != SAM_STAT_GOOD &&
++ (btstat == BTSTAT_SUCCESS ||
++ btstat == BTSTAT_LINKED_COMMAND_COMPLETED ||
++ btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) {
++ cmd->result = (DID_OK << 16) | sdstat;
++ if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer)
++ cmd->result |= (DRIVER_SENSE << 24);
++ } else
++ switch (btstat) {
++ case BTSTAT_SUCCESS:
++ case BTSTAT_LINKED_COMMAND_COMPLETED:
++ case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG:
++ /* If everything went fine, let's move on.. */
++ cmd->result = (DID_OK << 16);
++ break;
++
++ case BTSTAT_DATARUN:
++ case BTSTAT_DATA_UNDERRUN:
++ /* Report residual data in underruns */
++ scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen);
++ cmd->result = (DID_ERROR << 16);
++ break;
++
++ case BTSTAT_SELTIMEO:
++ /* Our emulation returns this for non-connected devs */
++ cmd->result = (DID_BAD_TARGET << 16);
++ break;
++
++ case BTSTAT_LUNMISMATCH:
++ case BTSTAT_TAGREJECT:
++ case BTSTAT_BADMSG:
++ cmd->result = (DRIVER_INVALID << 24);
++ /* fall through */
++
++ case BTSTAT_HAHARDWARE:
++ case BTSTAT_INVPHASE:
++ case BTSTAT_HATIMEOUT:
++ case BTSTAT_NORESPONSE:
++ case BTSTAT_DISCONNECT:
++ case BTSTAT_HASOFTWARE:
++ case BTSTAT_BUSFREE:
++ case BTSTAT_SENSFAILED:
++ cmd->result |= (DID_ERROR << 16);
++ break;
++
++ case BTSTAT_SENTRST:
++ case BTSTAT_RECVRST:
++ case BTSTAT_BUSRESET:
++ cmd->result = (DID_RESET << 16);
++ break;
++
++ case BTSTAT_ABORTQUEUE:
++ cmd->result = (DID_ABORT << 16);
++ break;
++
++ case BTSTAT_SCSIPARITY:
++ cmd->result = (DID_PARITY << 16);
++ break;
++
++ default:
++ cmd->result = (DID_ERROR << 16);
++ scmd_printk(KERN_DEBUG, cmd,
++ "Unknown completion status: 0x%x\n",
++ btstat);
++ }
++
++ dev_dbg(&cmd->device->sdev_gendev,
++ "cmd=%p %x ctx=%p result=0x%x status=0x%x,%x\n",
++ cmd, cmd->cmnd[0], ctx, cmd->result, btstat, sdstat);
++
++ cmd->scsi_done(cmd);
++}
++
++/*
++ * barrier usage : Since the PVSCSI device is emulated, there could be cases
++ * where we may want to serialize some accesses between the driver and the
++ * emulation layer. We use compiler barriers instead of the more expensive
++ * memory barriers because PVSCSI is only supported on X86 which has strong
++ * memory access ordering.
++ */
++static void pvscsi_process_completion_ring(struct pvscsi_adapter *adapter)
++{
++ struct PVSCSIRingsState *s = adapter->rings_state;
++ struct PVSCSIRingCmpDesc *ring = adapter->cmp_ring;
++ u32 cmp_entries = s->cmpNumEntriesLog2;
++
++ while (s->cmpConsIdx != s->cmpProdIdx) {
++ struct PVSCSIRingCmpDesc *e = ring + (s->cmpConsIdx &
++ MASK(cmp_entries));
++ /*
++ * This barrier() ensures that *e is not dereferenced while
++ * the device emulation still writes data into the slot.
++ * Since the device emulation advances s->cmpProdIdx only after
++ * updating the slot we want to check it first.
++ */
++ barrier();
++ pvscsi_complete_request(adapter, e);
++ /*
++ * This barrier() ensures that compiler doesn't reorder write
++ * to s->cmpConsIdx before the read of (*e) inside
++ * pvscsi_complete_request. Otherwise, device emulation may
++ * overwrite *e before we had a chance to read it.
++ */
++ barrier();
++ s->cmpConsIdx++;
++ }
++}
++
++/*
++ * Translate a Linux SCSI request into a request ring entry.
++ */
++static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
++ struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd)
++{
++ struct PVSCSIRingsState *s;
++ struct PVSCSIRingReqDesc *e;
++ struct scsi_device *sdev;
++ u32 req_entries;
++
++ s = adapter->rings_state;
++ sdev = cmd->device;
++ req_entries = s->reqNumEntriesLog2;
++
++ /*
++ * If this condition holds, we might have room on the request ring, but
++ * we might not have room on the completion ring for the response.
++ * However, we have already ruled out this possibility - we would not
++ * have successfully allocated a context if it were true, since we only
++ * have one context per request entry. Check for it anyway, since it
++ * would be a serious bug.
++ */
++ if (s->reqProdIdx - s->cmpConsIdx >= 1 << req_entries) {
++ scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: "
++ "ring full: reqProdIdx=%d cmpConsIdx=%d\n",
++ s->reqProdIdx, s->cmpConsIdx);
++ return -1;
++ }
++
++ e = adapter->req_ring + (s->reqProdIdx & MASK(req_entries));
++
++ e->bus = sdev->channel;
++ e->target = sdev->id;
++ memset(e->lun, 0, sizeof(e->lun));
++ e->lun[1] = sdev->lun;
++
++ if (cmd->sense_buffer) {
++ ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer,
++ SCSI_SENSE_BUFFERSIZE,
++ PCI_DMA_FROMDEVICE);
++ e->senseAddr = ctx->sensePA;
++ e->senseLen = SCSI_SENSE_BUFFERSIZE;
++ } else {
++ e->senseLen = 0;
++ e->senseAddr = 0;
++ }
++ e->cdbLen = cmd->cmd_len;
++ e->vcpuHint = smp_processor_id();
++ memcpy(e->cdb, cmd->cmnd, e->cdbLen);
++
++ e->tag = SIMPLE_QUEUE_TAG;
++ if (sdev->tagged_supported &&
++ (cmd->tag == HEAD_OF_QUEUE_TAG ||
++ cmd->tag == ORDERED_QUEUE_TAG))
++ e->tag = cmd->tag;
++
++ if (cmd->sc_data_direction == DMA_FROM_DEVICE)
++ e->flags = PVSCSI_FLAG_CMD_DIR_TOHOST;
++ else if (cmd->sc_data_direction == DMA_TO_DEVICE)
++ e->flags = PVSCSI_FLAG_CMD_DIR_TODEVICE;
++ else if (cmd->sc_data_direction == DMA_NONE)
++ e->flags = PVSCSI_FLAG_CMD_DIR_NONE;
++ else
++ e->flags = 0;
++
++ pvscsi_map_buffers(adapter, ctx, cmd, e);
++
++ e->context = pvscsi_map_context(adapter, ctx);
++
++ barrier();
++
++ s->reqProdIdx++;
++
++ return 0;
++}
++
++static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
++{
++ struct Scsi_Host *host = cmd->device->host;
++ struct pvscsi_adapter *adapter = shost_priv(host);
++ struct pvscsi_ctx *ctx;
++ unsigned long flags;
++
++ spin_lock_irqsave(&adapter->hw_lock, flags);
++
++ ctx = pvscsi_acquire_context(adapter, cmd);
++ if (!ctx || pvscsi_queue_ring(adapter, ctx, cmd) != 0) {
++ if (ctx)
++ pvscsi_release_context(adapter, ctx);
++ spin_unlock_irqrestore(&adapter->hw_lock, flags);
++ return SCSI_MLQUEUE_HOST_BUSY;
++ }
++
++ cmd->scsi_done = done;
++
++ dev_dbg(&cmd->device->sdev_gendev,
++ "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]);
++
++ spin_unlock_irqrestore(&adapter->hw_lock, flags);
++
++ pvscsi_kick_io(adapter, cmd->cmnd[0]);
++
++ return 0;
++}
++
++static int pvscsi_abort(struct scsi_cmnd *cmd)
++{
++ struct pvscsi_adapter *adapter = shost_priv(cmd->device->host);
++ struct pvscsi_ctx *ctx;
++ unsigned long flags;
++
++ scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n",
++ adapter->host->host_no, cmd);
++
++ spin_lock_irqsave(&adapter->hw_lock, flags);
++
++ /*
++ * Poll the completion ring first - we might be trying to abort
++ * a command that is waiting to be dispatched in the completion ring.
++ */
++ pvscsi_process_completion_ring(adapter);
++
++ /*
++ * If there is no context for the command, it either already succeeded
++ * or else was never properly issued. Not our problem.
++ */
++ ctx = pvscsi_find_context(adapter, cmd);
++ if (!ctx) {
++ scmd_printk(KERN_DEBUG, cmd, "Failed to abort cmd %p\n", cmd);
++ goto out;
++ }
++
++ pvscsi_abort_cmd(adapter, ctx);
++
++ pvscsi_process_completion_ring(adapter);
++
++out:
++ spin_unlock_irqrestore(&adapter->hw_lock, flags);
++ return SUCCESS;
++}
++
++/*
++ * Abort all outstanding requests. This is only safe to use if the completion
++ * ring will never be walked again or the device has been reset, because it
++ * destroys the 1-1 mapping between context field passed to emulation and our
++ * request structure.
++ */
++static void pvscsi_reset_all(struct pvscsi_adapter *adapter)
++{
++ unsigned i;
++
++ for (i = 0; i < adapter->req_depth; i++) {
++ struct pvscsi_ctx *ctx = &adapter->cmd_map[i];
++ struct scsi_cmnd *cmd = ctx->cmd;
++ if (cmd) {
++ scmd_printk(KERN_ERR, cmd,
++ "Forced reset on cmd %p\n", cmd);
++ pvscsi_unmap_buffers(adapter, ctx);
++ pvscsi_release_context(adapter, ctx);
++ cmd->result = (DID_RESET << 16);
++ cmd->scsi_done(cmd);
++ }
++ }
++}
++
++static int pvscsi_host_reset(struct scsi_cmnd *cmd)
++{
++ struct Scsi_Host *host = cmd->device->host;
++ struct pvscsi_adapter *adapter = shost_priv(host);
++ unsigned long flags;
++ bool use_msg;
++
++ scmd_printk(KERN_INFO, cmd, "SCSI Host reset\n");
++
++ spin_lock_irqsave(&adapter->hw_lock, flags);
++
++ use_msg = adapter->use_msg;
++
++ if (use_msg) {
++ adapter->use_msg = 0;
++ spin_unlock_irqrestore(&adapter->hw_lock, flags);
++
++ /*
++ * Now that we know that the ISR won't add more work on the
++ * workqueue we can safely flush any outstanding work.
++ */
++ flush_workqueue(adapter->workqueue);
++ spin_lock_irqsave(&adapter->hw_lock, flags);
++ }
++
++ /*
++ * We're going to tear down the entire ring structure and set it back
++ * up, so stalling new requests until all completions are flushed and
++ * the rings are back in place.
++ */
++
++ pvscsi_process_request_ring(adapter);
++
++ ll_adapter_reset(adapter);
++
++ /*
++ * Now process any completions. Note we do this AFTER adapter reset,
++ * which is strange, but stops races where completions get posted
++ * between processing the ring and issuing the reset. The backend will
++ * not touch the ring memory after reset, so the immediately pre-reset
++ * completion ring state is still valid.
++ */
++ pvscsi_process_completion_ring(adapter);
++
++ pvscsi_reset_all(adapter);
++ adapter->use_msg = use_msg;
++ pvscsi_setup_all_rings(adapter);
++ pvscsi_unmask_intr(adapter);
++
++ spin_unlock_irqrestore(&adapter->hw_lock, flags);
++
++ return SUCCESS;
++}
++
++static int pvscsi_bus_reset(struct scsi_cmnd *cmd)
++{
++ struct Scsi_Host *host = cmd->device->host;
++ struct pvscsi_adapter *adapter = shost_priv(host);
++ unsigned long flags;
++
++ scmd_printk(KERN_INFO, cmd, "SCSI Bus reset\n");
++
++ /*
++ * We don't want to queue new requests for this bus after
++ * flushing all pending requests to emulation, since new
++ * requests could then sneak in during this bus reset phase,
++ * so take the lock now.
++ */
++ spin_lock_irqsave(&adapter->hw_lock, flags);
++
++ pvscsi_process_request_ring(adapter);
++ ll_bus_reset(adapter);
++ pvscsi_process_completion_ring(adapter);
++
++ spin_unlock_irqrestore(&adapter->hw_lock, flags);
++
++ return SUCCESS;
++}
++
++static int pvscsi_device_reset(struct scsi_cmnd *cmd)
++{
++ struct Scsi_Host *host = cmd->device->host;
++ struct pvscsi_adapter *adapter = shost_priv(host);
++ unsigned long flags;
++
++ scmd_printk(KERN_INFO, cmd, "SCSI device reset on scsi%u:%u\n",
++ host->host_no, cmd->device->id);
++
++ /*
++ * We don't want to queue new requests for this device after flushing
++ * all pending requests to emulation, since new requests could then
++ * sneak in during this device reset phase, so take the lock now.
++ */
++ spin_lock_irqsave(&adapter->hw_lock, flags);
++
++ pvscsi_process_request_ring(adapter);
++ ll_device_reset(adapter, cmd->device->id);
++ pvscsi_process_completion_ring(adapter);
++
++ spin_unlock_irqrestore(&adapter->hw_lock, flags);
++
++ return SUCCESS;
++}
++
++static struct scsi_host_template pvscsi_template;
++
++static const char *pvscsi_info(struct Scsi_Host *host)
++{
++ struct pvscsi_adapter *adapter = shost_priv(host);
++ static char buf[256];
++
++ sprintf(buf, "VMware PVSCSI storage adapter rev %d, req/cmp/msg rings: "
++ "%u/%u/%u pages, cmd_per_lun=%u", adapter->rev,
++ adapter->req_pages, adapter->cmp_pages, adapter->msg_pages,
++ pvscsi_template.cmd_per_lun);
++
++ return buf;
++}
++
++static struct scsi_host_template pvscsi_template = {
++ .module = THIS_MODULE,
++ .name = "VMware PVSCSI Host Adapter",
++ .proc_name = "vmw_pvscsi",
++ .info = pvscsi_info,
++ .queuecommand = pvscsi_queue,
++ .this_id = -1,
++ .sg_tablesize = PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT,
++ .dma_boundary = UINT_MAX,
++ .max_sectors = 0xffff,
++ .use_clustering = ENABLE_CLUSTERING,
++ .eh_abort_handler = pvscsi_abort,
++ .eh_device_reset_handler = pvscsi_device_reset,
++ .eh_bus_reset_handler = pvscsi_bus_reset,
++ .eh_host_reset_handler = pvscsi_host_reset,
++};
++
++static void pvscsi_process_msg(const struct pvscsi_adapter *adapter,
++ const struct PVSCSIRingMsgDesc *e)
++{
++ struct PVSCSIRingsState *s = adapter->rings_state;
++ struct Scsi_Host *host = adapter->host;
++ struct scsi_device *sdev;
++
++ printk(KERN_INFO "vmw_pvscsi: msg type: 0x%x - MSG RING: %u/%u (%u) \n",
++ e->type, s->msgProdIdx, s->msgConsIdx, s->msgNumEntriesLog2);
++
++ BUILD_BUG_ON(PVSCSI_MSG_LAST != 2);
++
++ if (e->type == PVSCSI_MSG_DEV_ADDED) {
++ struct PVSCSIMsgDescDevStatusChanged *desc;
++ desc = (struct PVSCSIMsgDescDevStatusChanged *)e;
++
++ printk(KERN_INFO
++ "vmw_pvscsi: msg: device added at scsi%u:%u:%u\n",
++ desc->bus, desc->target, desc->lun[1]);
++
++ if (!scsi_host_get(host))
++ return;
++
++ sdev = scsi_device_lookup(host, desc->bus, desc->target,
++ desc->lun[1]);
++ if (sdev) {
++ printk(KERN_INFO "vmw_pvscsi: device already exists\n");
++ scsi_device_put(sdev);
++ } else
++ scsi_add_device(adapter->host, desc->bus,
++ desc->target, desc->lun[1]);
++
++ scsi_host_put(host);
++ } else if (e->type == PVSCSI_MSG_DEV_REMOVED) {
++ struct PVSCSIMsgDescDevStatusChanged *desc;
++ desc = (struct PVSCSIMsgDescDevStatusChanged *)e;
++
++ printk(KERN_INFO
++ "vmw_pvscsi: msg: device removed at scsi%u:%u:%u\n",
++ desc->bus, desc->target, desc->lun[1]);
++
++ if (!scsi_host_get(host))
++ return;
++
++ sdev = scsi_device_lookup(host, desc->bus, desc->target,
++ desc->lun[1]);
++ if (sdev) {
++ scsi_remove_device(sdev);
++ scsi_device_put(sdev);
++ } else
++ printk(KERN_INFO
++ "vmw_pvscsi: failed to lookup scsi%u:%u:%u\n",
++ desc->bus, desc->target, desc->lun[1]);
++
++ scsi_host_put(host);
++ }
++}
++
++static int pvscsi_msg_pending(const struct pvscsi_adapter *adapter)
++{
++ struct PVSCSIRingsState *s = adapter->rings_state;
++
++ return s->msgProdIdx != s->msgConsIdx;
++}
++
++static void pvscsi_process_msg_ring(const struct pvscsi_adapter *adapter)
++{
++ struct PVSCSIRingsState *s = adapter->rings_state;
++ struct PVSCSIRingMsgDesc *ring = adapter->msg_ring;
++ u32 msg_entries = s->msgNumEntriesLog2;
++
++ while (pvscsi_msg_pending(adapter)) {
++ struct PVSCSIRingMsgDesc *e = ring + (s->msgConsIdx &
++ MASK(msg_entries));
++
++ barrier();
++ pvscsi_process_msg(adapter, e);
++ barrier();
++ s->msgConsIdx++;
++ }
++}
++
++static void pvscsi_msg_workqueue_handler(struct work_struct *data)
++{
++ struct pvscsi_adapter *adapter;
++
++ adapter = container_of(data, struct pvscsi_adapter, work);
++
++ pvscsi_process_msg_ring(adapter);
++}
++
++static int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter)
++{
++ char name[32];
++
++ if (!pvscsi_use_msg)
++ return 0;
++
++ pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND,
++ PVSCSI_CMD_SETUP_MSG_RING);
++
++ if (pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS) == -1)
++ return 0;
++
++ snprintf(name, sizeof(name),
++ "vmw_pvscsi_wq_%u", adapter->host->host_no);
++
++ adapter->workqueue = create_singlethread_workqueue(name);
++ if (!adapter->workqueue) {
++ printk(KERN_ERR "vmw_pvscsi: failed to create work queue\n");
++ return 0;
++ }
++ INIT_WORK(&adapter->work, pvscsi_msg_workqueue_handler);
++
++ return 1;
++}
++
++static irqreturn_t pvscsi_isr(int irq, void *devp)
++{
++ struct pvscsi_adapter *adapter = devp;
++ int handled;
++
++ if (adapter->use_msi || adapter->use_msix)
++ handled = true;
++ else {
++ u32 val = pvscsi_read_intr_status(adapter);
++ handled = (val & PVSCSI_INTR_ALL_SUPPORTED) != 0;
++ if (handled)
++ pvscsi_write_intr_status(devp, val);
++ }
++
++ if (handled) {
++ unsigned long flags;
++
++ spin_lock_irqsave(&adapter->hw_lock, flags);
++
++ pvscsi_process_completion_ring(adapter);
++ if (adapter->use_msg && pvscsi_msg_pending(adapter))
++ queue_work(adapter->workqueue, &adapter->work);
++
++ spin_unlock_irqrestore(&adapter->hw_lock, flags);
++ }
++
++ return IRQ_RETVAL(handled);
++}
++
++static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter)
++{
++ struct pvscsi_ctx *ctx = adapter->cmd_map;
++ unsigned i;
++
++ for (i = 0; i < adapter->req_depth; ++i, ++ctx)
++ kfree(ctx->sgl);
++}
++
++static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, int *irq)
++{
++ struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION };
++ int ret;
++
++ ret = pci_enable_msix(adapter->dev, &entry, 1);
++ if (ret)
++ return ret;
++
++ *irq = entry.vector;
++
++ return 0;
++}
++
++static void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter)
++{
++ if (adapter->irq) {
++ free_irq(adapter->irq, adapter);
++ adapter->irq = 0;
++ }
++ if (adapter->use_msi) {
++ pci_disable_msi(adapter->dev);
++ adapter->use_msi = 0;
++ } else if (adapter->use_msix) {
++ pci_disable_msix(adapter->dev);
++ adapter->use_msix = 0;
++ }
++}
++
++static void pvscsi_release_resources(struct pvscsi_adapter *adapter)
++{
++ pvscsi_shutdown_intr(adapter);
++
++ if (adapter->workqueue)
++ destroy_workqueue(adapter->workqueue);
++
++ if (adapter->mmioBase)
++ pci_iounmap(adapter->dev, adapter->mmioBase);
++
++ pci_release_regions(adapter->dev);
++
++ if (adapter->cmd_map) {
++ pvscsi_free_sgls(adapter);
++ kfree(adapter->cmd_map);
++ }
++
++ if (adapter->rings_state)
++ pci_free_consistent(adapter->dev, PAGE_SIZE,
++ adapter->rings_state, adapter->ringStatePA);
++
++ if (adapter->req_ring)
++ pci_free_consistent(adapter->dev,
++ adapter->req_pages * PAGE_SIZE,
++ adapter->req_ring, adapter->reqRingPA);
++
++ if (adapter->cmp_ring)
++ pci_free_consistent(adapter->dev,
++ adapter->cmp_pages * PAGE_SIZE,
++ adapter->cmp_ring, adapter->cmpRingPA);
++
++ if (adapter->msg_ring)
++ pci_free_consistent(adapter->dev,
++ adapter->msg_pages * PAGE_SIZE,
++ adapter->msg_ring, adapter->msgRingPA);
++}
++
++/*
++ * Allocate scatter gather lists.
++ *
++ * These are statically allocated. Trying to be clever was not worth it.
++ *
++ * Dynamic allocation can fail, and we can't go deeep into the memory
++ * allocator, since we're a SCSI driver, and trying too hard to allocate
++ * memory might generate disk I/O. We also don't want to fail disk I/O
++ * in that case because we can't get an allocation - the I/O could be
++ * trying to swap out data to free memory. Since that is pathological,
++ * just use a statically allocated scatter list.
++ *
++ */
++static int __devinit pvscsi_allocate_sg(struct pvscsi_adapter *adapter)
++{
++ struct pvscsi_ctx *ctx;
++ int i;
++
++ ctx = adapter->cmd_map;
++ BUILD_BUG_ON(sizeof(struct pvscsi_sg_list) > SGL_SIZE);
++
++ for (i = 0; i < adapter->req_depth; ++i, ++ctx) {
++ ctx->sgl = kmalloc(SGL_SIZE, GFP_KERNEL);
++ ctx->sglPA = 0;
++ BUG_ON(!IS_ALIGNED(((unsigned long)ctx->sgl), PAGE_SIZE));
++ if (!ctx->sgl) {
++ for (; i >= 0; --i, --ctx) {
++ kfree(ctx->sgl);
++ ctx->sgl = NULL;
++ }
++ return -ENOMEM;
++ }
++ }
++
++ return 0;
++}
++
++static int __devinit pvscsi_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ struct pvscsi_adapter *adapter;
++ struct Scsi_Host *host;
++ unsigned int i;
++ int error;
++
++ error = -ENODEV;
++
++ if (pci_enable_device(pdev))
++ return error;
++
++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 &&
++ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
++ printk(KERN_INFO "vmw_pvscsi: using 64bit dma\n");
++ } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 &&
++ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) {
++ printk(KERN_INFO "vmw_pvscsi: using 32bit dma\n");
++ } else {
++ printk(KERN_ERR "vmw_pvscsi: failed to set DMA mask\n");
++ goto out_disable_device;
++ }
++
++ pvscsi_template.can_queue =
++ min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) *
++ PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
++ pvscsi_template.cmd_per_lun =
++ min(pvscsi_template.can_queue, pvscsi_cmd_per_lun);
++ host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter));
++ if (!host) {
++ printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n");
++ goto out_disable_device;
++ }
++
++ adapter = shost_priv(host);
++ memset(adapter, 0, sizeof(*adapter));
++ adapter->dev = pdev;
++ adapter->host = host;
++
++ spin_lock_init(&adapter->hw_lock);
++
++ host->max_channel = 0;
++ host->max_id = 16;
++ host->max_lun = 1;
++ host->max_cmd_len = 16;
++
++ adapter->rev = pdev->revision;
++
++ if (pci_request_regions(pdev, "vmw_pvscsi")) {
++ printk(KERN_ERR "vmw_pvscsi: pci memory selection failed\n");
++ goto out_free_host;
++ }
++
++ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
++ if ((pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO))
++ continue;
++
++ if (pci_resource_len(pdev, i) < PVSCSI_MEM_SPACE_SIZE)
++ continue;
++
++ break;
++ }
++
++ if (i == DEVICE_COUNT_RESOURCE) {
++ printk(KERN_ERR
++ "vmw_pvscsi: adapter has no suitable MMIO region\n");
++ goto out_release_resources;
++ }
++
++ adapter->mmioBase = pci_iomap(pdev, i, PVSCSI_MEM_SPACE_SIZE);
++
++ if (!adapter->mmioBase) {
++ printk(KERN_ERR
++ "vmw_pvscsi: can't iomap for BAR %d memsize %lu\n",
++ i, PVSCSI_MEM_SPACE_SIZE);
++ goto out_release_resources;
++ }
++
++ pci_set_master(pdev);
++ pci_set_drvdata(pdev, host);
++
++ ll_adapter_reset(adapter);
++
++ adapter->use_msg = pvscsi_setup_msg_workqueue(adapter);
++
++ error = pvscsi_allocate_rings(adapter);
++ if (error) {
++ printk(KERN_ERR "vmw_pvscsi: unable to allocate ring memory\n");
++ goto out_release_resources;
++ }
++
++ /*
++ * From this point on we should reset the adapter if anything goes
++ * wrong.
++ */
++ pvscsi_setup_all_rings(adapter);
++
++ adapter->cmd_map = kcalloc(adapter->req_depth,
++ sizeof(struct pvscsi_ctx), GFP_KERNEL);
++ if (!adapter->cmd_map) {
++ printk(KERN_ERR "vmw_pvscsi: failed to allocate memory.\n");
++ error = -ENOMEM;
++ goto out_reset_adapter;
++ }
++
++ INIT_LIST_HEAD(&adapter->cmd_pool);
++ for (i = 0; i < adapter->req_depth; i++) {
++ struct pvscsi_ctx *ctx = adapter->cmd_map + i;
++ list_add(&ctx->list, &adapter->cmd_pool);
++ }
++
++ error = pvscsi_allocate_sg(adapter);
++ if (error) {
++ printk(KERN_ERR "vmw_pvscsi: unable to allocate s/g table\n");
++ goto out_reset_adapter;
++ }
++
++ if (!pvscsi_disable_msix &&
++ pvscsi_setup_msix(adapter, &adapter->irq) == 0) {
++ printk(KERN_INFO "vmw_pvscsi: using MSI-X\n");
++ adapter->use_msix = 1;
++ } else if (!pvscsi_disable_msi && pci_enable_msi(pdev) == 0) {
++ printk(KERN_INFO "vmw_pvscsi: using MSI\n");
++ adapter->use_msi = 1;
++ adapter->irq = pdev->irq;
++ } else {
++ printk(KERN_INFO "vmw_pvscsi: using INTx\n");
++ adapter->irq = pdev->irq;
++ }
++
++ error = request_irq(adapter->irq, pvscsi_isr, IRQF_SHARED,
++ "vmw_pvscsi", adapter);
++ if (error) {
++ printk(KERN_ERR
++ "vmw_pvscsi: unable to request IRQ: %d\n", error);
++ adapter->irq = 0;
++ goto out_reset_adapter;
++ }
++
++ error = scsi_add_host(host, &pdev->dev);
++ if (error) {
++ printk(KERN_ERR
++ "vmw_pvscsi: scsi_add_host failed: %d\n", error);
++ goto out_reset_adapter;
++ }
++
++ dev_info(&pdev->dev, "VMware PVSCSI rev %d host #%u\n",
++ adapter->rev, host->host_no);
++
++ pvscsi_unmask_intr(adapter);
++
++ scsi_scan_host(host);
++
++ return 0;
++
++out_reset_adapter:
++ ll_adapter_reset(adapter);
++out_release_resources:
++ pvscsi_release_resources(adapter);
++out_free_host:
++ scsi_host_put(host);
++out_disable_device:
++ pci_set_drvdata(pdev, NULL);
++ pci_disable_device(pdev);
++
++ return error;
++}
++
++static void __pvscsi_shutdown(struct pvscsi_adapter *adapter)
++{
++ pvscsi_mask_intr(adapter);
++
++ if (adapter->workqueue)
++ flush_workqueue(adapter->workqueue);
++
++ pvscsi_shutdown_intr(adapter);
++
++ pvscsi_process_request_ring(adapter);
++ pvscsi_process_completion_ring(adapter);
++ ll_adapter_reset(adapter);
++}
++
++static void pvscsi_shutdown(struct pci_dev *dev)
++{
++ struct Scsi_Host *host = pci_get_drvdata(dev);
++ struct pvscsi_adapter *adapter = shost_priv(host);
++
++ __pvscsi_shutdown(adapter);
++}
++
++static void pvscsi_remove(struct pci_dev *pdev)
++{
++ struct Scsi_Host *host = pci_get_drvdata(pdev);
++ struct pvscsi_adapter *adapter = shost_priv(host);
++
++ scsi_remove_host(host);
++
++ __pvscsi_shutdown(adapter);
++ pvscsi_release_resources(adapter);
++
++ scsi_host_put(host);
++
++ pci_set_drvdata(pdev, NULL);
++ pci_disable_device(pdev);
++}
++
++static struct pci_driver pvscsi_pci_driver = {
++ .name = "vmw_pvscsi",
++ .id_table = pvscsi_pci_tbl,
++ .probe = pvscsi_probe,
++ .remove = __devexit_p(pvscsi_remove),
++ .shutdown = pvscsi_shutdown,
++};
++
++static int __init pvscsi_init(void)
++{
++ pr_info("%s - version %s\n",
++ PVSCSI_LINUX_DRIVER_DESC, PVSCSI_DRIVER_VERSION_STRING);
++ return pci_register_driver(&pvscsi_pci_driver);
++}
++
++static void __exit pvscsi_exit(void)
++{
++ pci_unregister_driver(&pvscsi_pci_driver);
++}
++
++module_init(pvscsi_init);
++module_exit(pvscsi_exit);
+diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h
+new file mode 100644
+index 0000000..62e36e7
+--- /dev/null
++++ b/drivers/scsi/vmw_pvscsi.h
+@@ -0,0 +1,397 @@
++/*
++ * VMware PVSCSI header file
++ *
++ * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; version 2 of the License and no later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
++ * NON INFRINGEMENT. See the GNU General Public License for more
++ * details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Maintained by: Alok N Kataria <akataria@vmware.com>
++ *
++ */
++
++#ifndef _VMW_PVSCSI_H_
++#define _VMW_PVSCSI_H_
++
++#include <linux/types.h>
++
++#define PVSCSI_DRIVER_VERSION_STRING "1.0.1.0-k"
++
++#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128
++
++#define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */
++
++#define PCI_VENDOR_ID_VMWARE 0x15AD
++#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0
++
++/*
++ * host adapter status/error codes
++ */
++enum HostBusAdapterStatus {
++ BTSTAT_SUCCESS = 0x00, /* CCB complete normally with no errors */
++ BTSTAT_LINKED_COMMAND_COMPLETED = 0x0a,
++ BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b,
++ BTSTAT_DATA_UNDERRUN = 0x0c,
++ BTSTAT_SELTIMEO = 0x11, /* SCSI selection timeout */
++ BTSTAT_DATARUN = 0x12, /* data overrun/underrun */
++ BTSTAT_BUSFREE = 0x13, /* unexpected bus free */
++ BTSTAT_INVPHASE = 0x14, /* invalid bus phase or sequence requested by target */
++ BTSTAT_LUNMISMATCH = 0x17, /* linked CCB has different LUN from first CCB */
++ BTSTAT_SENSFAILED = 0x1b, /* auto request sense failed */
++ BTSTAT_TAGREJECT = 0x1c, /* SCSI II tagged queueing message rejected by target */
++ BTSTAT_BADMSG = 0x1d, /* unsupported message received by the host adapter */
++ BTSTAT_HAHARDWARE = 0x20, /* host adapter hardware failed */
++ BTSTAT_NORESPONSE = 0x21, /* target did not respond to SCSI ATN, sent a SCSI RST */
++ BTSTAT_SENTRST = 0x22, /* host adapter asserted a SCSI RST */
++ BTSTAT_RECVRST = 0x23, /* other SCSI devices asserted a SCSI RST */
++ BTSTAT_DISCONNECT = 0x24, /* target device reconnected improperly (w/o tag) */
++ BTSTAT_BUSRESET = 0x25, /* host adapter issued BUS device reset */
++ BTSTAT_ABORTQUEUE = 0x26, /* abort queue generated */
++ BTSTAT_HASOFTWARE = 0x27, /* host adapter software error */
++ BTSTAT_HATIMEOUT = 0x30, /* host adapter hardware timeout error */
++ BTSTAT_SCSIPARITY = 0x34, /* SCSI parity error detected */
++};
++
++/*
++ * Register offsets.
++ *
++ * These registers are accessible both via i/o space and mm i/o.
++ */
++
++enum PVSCSIRegOffset {
++ PVSCSI_REG_OFFSET_COMMAND = 0x0,
++ PVSCSI_REG_OFFSET_COMMAND_DATA = 0x4,
++ PVSCSI_REG_OFFSET_COMMAND_STATUS = 0x8,
++ PVSCSI_REG_OFFSET_LAST_STS_0 = 0x100,
++ PVSCSI_REG_OFFSET_LAST_STS_1 = 0x104,
++ PVSCSI_REG_OFFSET_LAST_STS_2 = 0x108,
++ PVSCSI_REG_OFFSET_LAST_STS_3 = 0x10c,
++ PVSCSI_REG_OFFSET_INTR_STATUS = 0x100c,
++ PVSCSI_REG_OFFSET_INTR_MASK = 0x2010,
++ PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
++ PVSCSI_REG_OFFSET_DEBUG = 0x3018,
++ PVSCSI_REG_OFFSET_KICK_RW_IO = 0x4018,
++};
++
++/*
++ * Virtual h/w commands.
++ */
++
++enum PVSCSICommands {
++ PVSCSI_CMD_FIRST = 0, /* has to be first */
++
++ PVSCSI_CMD_ADAPTER_RESET = 1,
++ PVSCSI_CMD_ISSUE_SCSI = 2,
++ PVSCSI_CMD_SETUP_RINGS = 3,
++ PVSCSI_CMD_RESET_BUS = 4,
++ PVSCSI_CMD_RESET_DEVICE = 5,
++ PVSCSI_CMD_ABORT_CMD = 6,
++ PVSCSI_CMD_CONFIG = 7,
++ PVSCSI_CMD_SETUP_MSG_RING = 8,
++ PVSCSI_CMD_DEVICE_UNPLUG = 9,
++
++ PVSCSI_CMD_LAST = 10 /* has to be last */
++};
++
++/*
++ * Command descriptor for PVSCSI_CMD_RESET_DEVICE --
++ */
++
++struct PVSCSICmdDescResetDevice {
++ u32 target;
++ u8 lun[8];
++} __packed;
++
++/*
++ * Command descriptor for PVSCSI_CMD_ABORT_CMD --
++ *
++ * - currently does not support specifying the LUN.
++ * - _pad should be 0.
++ */
++
++struct PVSCSICmdDescAbortCmd {
++ u64 context;
++ u32 target;
++ u32 _pad;
++} __packed;
++
++/*
++ * Command descriptor for PVSCSI_CMD_SETUP_RINGS --
++ *
++ * Notes:
++ * - reqRingNumPages and cmpRingNumPages need to be power of two.
++ * - reqRingNumPages and cmpRingNumPages need to be different from 0,
++ * - reqRingNumPages and cmpRingNumPages need to be inferior to
++ * PVSCSI_SETUP_RINGS_MAX_NUM_PAGES.
++ */
++
++#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES 32
++struct PVSCSICmdDescSetupRings {
++ u32 reqRingNumPages;
++ u32 cmpRingNumPages;
++ u64 ringsStatePPN;
++ u64 reqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
++ u64 cmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
++} __packed;
++
++/*
++ * Command descriptor for PVSCSI_CMD_SETUP_MSG_RING --
++ *
++ * Notes:
++ * - this command was not supported in the initial revision of the h/w
++ * interface. Before using it, you need to check that it is supported by
++ * writing PVSCSI_CMD_SETUP_MSG_RING to the 'command' register, then
++ * immediately after read the 'command status' register:
++ * * a value of -1 means that the cmd is NOT supported,
++ * * a value != -1 means that the cmd IS supported.
++ * If it's supported the 'command status' register should return:
++ * sizeof(PVSCSICmdDescSetupMsgRing) / sizeof(u32).
++ * - this command should be issued _after_ the usual SETUP_RINGS so that the
++ * RingsState page is already setup. If not, the command is a nop.
++ * - numPages needs to be a power of two,
++ * - numPages needs to be different from 0,
++ * - _pad should be zero.
++ */
++
++#define PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES 16
++
++struct PVSCSICmdDescSetupMsgRing {
++ u32 numPages;
++ u32 _pad;
++ u64 ringPPNs[PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES];
++} __packed;
++
++enum PVSCSIMsgType {
++ PVSCSI_MSG_DEV_ADDED = 0,
++ PVSCSI_MSG_DEV_REMOVED = 1,
++ PVSCSI_MSG_LAST = 2,
++};
++
++/*
++ * Msg descriptor.
++ *
++ * sizeof(struct PVSCSIRingMsgDesc) == 128.
++ *
++ * - type is of type enum PVSCSIMsgType.
++ * - the content of args depend on the type of event being delivered.
++ */
++
++struct PVSCSIRingMsgDesc {
++ u32 type;
++ u32 args[31];
++} __packed;
++
++struct PVSCSIMsgDescDevStatusChanged {
++ u32 type; /* PVSCSI_MSG_DEV _ADDED / _REMOVED */
++ u32 bus;
++ u32 target;
++ u8 lun[8];
++ u32 pad[27];
++} __packed;
++
++/*
++ * Rings state.
++ *
++ * - the fields:
++ * . msgProdIdx,
++ * . msgConsIdx,
++ * . msgNumEntriesLog2,
++ * .. are only used once the SETUP_MSG_RING cmd has been issued.
++ * - '_pad' helps to ensure that the msg related fields are on their own
++ * cache-line.
++ */
++
++struct PVSCSIRingsState {
++ u32 reqProdIdx;
++ u32 reqConsIdx;
++ u32 reqNumEntriesLog2;
++
++ u32 cmpProdIdx;
++ u32 cmpConsIdx;
++ u32 cmpNumEntriesLog2;
++
++ u8 _pad[104];
++
++ u32 msgProdIdx;
++ u32 msgConsIdx;
++ u32 msgNumEntriesLog2;
++} __packed;
++
++/*
++ * Request descriptor.
++ *
++ * sizeof(RingReqDesc) = 128
++ *
++ * - context: is a unique identifier of a command. It could normally be any
++ * 64bit value, however we currently store it in the serialNumber variable
++ * of struct SCSI_Command, so we have the following restrictions due to the
++ * way this field is handled in the vmkernel storage stack:
++ * * this value can't be 0,
++ * * the upper 32bit need to be 0 since serialNumber is as a u32.
++ * Currently tracked as PR 292060.
++ * - dataLen: contains the total number of bytes that need to be transferred.
++ * - dataAddr:
++ * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is set: dataAddr is the PA of the first
++ * s/g table segment, each s/g segment is entirely contained on a single
++ * page of physical memory,
++ * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is NOT set, then dataAddr is the PA of
++ * the buffer used for the DMA transfer,
++ * - flags:
++ * * PVSCSI_FLAG_CMD_WITH_SG_LIST: see dataAddr above,
++ * * PVSCSI_FLAG_CMD_DIR_NONE: no DMA involved,
++ * * PVSCSI_FLAG_CMD_DIR_TOHOST: transfer from device to main memory,
++ * * PVSCSI_FLAG_CMD_DIR_TODEVICE: transfer from main memory to device,
++ * * PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB: reserved to handle CDBs larger than
++ * 16bytes. To be specified.
++ * - vcpuHint: vcpuId of the processor that will be most likely waiting for the
++ * completion of the i/o. For guest OSes that use lowest priority message
++ * delivery mode (such as windows), we use this "hint" to deliver the
++ * completion action to the proper vcpu. For now, we can use the vcpuId of
++ * the processor that initiated the i/o as a likely candidate for the vcpu
++ * that will be waiting for the completion..
++ * - bus should be 0: we currently only support bus 0 for now.
++ * - unused should be zero'd.
++ */
++
++#define PVSCSI_FLAG_CMD_WITH_SG_LIST (1 << 0)
++#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB (1 << 1)
++#define PVSCSI_FLAG_CMD_DIR_NONE (1 << 2)
++#define PVSCSI_FLAG_CMD_DIR_TOHOST (1 << 3)
++#define PVSCSI_FLAG_CMD_DIR_TODEVICE (1 << 4)
++
++struct PVSCSIRingReqDesc {
++ u64 context;
++ u64 dataAddr;
++ u64 dataLen;
++ u64 senseAddr;
++ u32 senseLen;
++ u32 flags;
++ u8 cdb[16];
++ u8 cdbLen;
++ u8 lun[8];
++ u8 tag;
++ u8 bus;
++ u8 target;
++ u8 vcpuHint;
++ u8 unused[59];
++} __packed;
++
++/*
++ * Scatter-gather list management.
++ *
++ * As described above, when PVSCSI_FLAG_CMD_WITH_SG_LIST is set in the
++ * RingReqDesc.flags, then RingReqDesc.dataAddr is the PA of the first s/g
++ * table segment.
++ *
++ * - each segment of the s/g table contain a succession of struct
++ * PVSCSISGElement.
++ * - each segment is entirely contained on a single physical page of memory.
++ * - a "chain" s/g element has the flag PVSCSI_SGE_FLAG_CHAIN_ELEMENT set in
++ * PVSCSISGElement.flags and in this case:
++ * * addr is the PA of the next s/g segment,
++ * * length is undefined, assumed to be 0.
++ */
++
++struct PVSCSISGElement {
++ u64 addr;
++ u32 length;
++ u32 flags;
++} __packed;
++
++/*
++ * Completion descriptor.
++ *
++ * sizeof(RingCmpDesc) = 32
++ *
++ * - context: identifier of the command. The same thing that was specified
++ * under "context" as part of struct RingReqDesc at initiation time,
++ * - dataLen: number of bytes transferred for the actual i/o operation,
++ * - senseLen: number of bytes written into the sense buffer,
++ * - hostStatus: adapter status,
++ * - scsiStatus: device status,
++ * - _pad should be zero.
++ */
++
++struct PVSCSIRingCmpDesc {
++ u64 context;
++ u64 dataLen;
++ u32 senseLen;
++ u16 hostStatus;
++ u16 scsiStatus;
++ u32 _pad[2];
++} __packed;
++
++/*
++ * Interrupt status / IRQ bits.
++ */
++
++#define PVSCSI_INTR_CMPL_0 (1 << 0)
++#define PVSCSI_INTR_CMPL_1 (1 << 1)
++#define PVSCSI_INTR_CMPL_MASK MASK(2)
++
++#define PVSCSI_INTR_MSG_0 (1 << 2)
++#define PVSCSI_INTR_MSG_1 (1 << 3)
++#define PVSCSI_INTR_MSG_MASK (MASK(2) << 2)
++
++#define PVSCSI_INTR_ALL_SUPPORTED MASK(4)
++
++/*
++ * Number of MSI-X vectors supported.
++ */
++#define PVSCSI_MAX_INTRS 24
++
++/*
++ * Enumeration of supported MSI-X vectors
++ */
++#define PVSCSI_VECTOR_COMPLETION 0
++
++/*
++ * Misc constants for the rings.
++ */
++
++#define PVSCSI_MAX_NUM_PAGES_REQ_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
++#define PVSCSI_MAX_NUM_PAGES_CMP_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
++#define PVSCSI_MAX_NUM_PAGES_MSG_RING PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES
++
++#define PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE \
++ (PAGE_SIZE / sizeof(struct PVSCSIRingReqDesc))
++
++#define PVSCSI_MAX_REQ_QUEUE_DEPTH \
++ (PVSCSI_MAX_NUM_PAGES_REQ_RING * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE)
++
++#define PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES 1
++#define PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES 1
++#define PVSCSI_MEM_SPACE_MISC_NUM_PAGES 2
++#define PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES 2
++#define PVSCSI_MEM_SPACE_MSIX_NUM_PAGES 2
++
++enum PVSCSIMemSpace {
++ PVSCSI_MEM_SPACE_COMMAND_PAGE = 0,
++ PVSCSI_MEM_SPACE_INTR_STATUS_PAGE = 1,
++ PVSCSI_MEM_SPACE_MISC_PAGE = 2,
++ PVSCSI_MEM_SPACE_KICK_IO_PAGE = 4,
++ PVSCSI_MEM_SPACE_MSIX_TABLE_PAGE = 6,
++ PVSCSI_MEM_SPACE_MSIX_PBA_PAGE = 7,
++};
++
++#define PVSCSI_MEM_SPACE_NUM_PAGES \
++ (PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES + \
++ PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES + \
++ PVSCSI_MEM_SPACE_MISC_NUM_PAGES + \
++ PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES + \
++ PVSCSI_MEM_SPACE_MSIX_NUM_PAGES)
++
++#define PVSCSI_MEM_SPACE_SIZE (PVSCSI_MEM_SPACE_NUM_PAGES * PAGE_SIZE)
++
++#endif /* _VMW_PVSCSI_H_ */
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index eadc1ab..2d81457 100644
--- a/drivers/serial/kgdboc.c
@@ -48256,7 +65997,7 @@ index a5bf577..6d19845 100644
return hit;
}
diff --git a/fs/compat.c b/fs/compat.c
-index d1e2411..c2ef8ed 100644
+index d1e2411..9a958d2 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -133,8 +133,8 @@ asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval _
@@ -48377,18 +66118,7 @@ index d1e2411..c2ef8ed 100644
goto out;
if (!file->f_op)
goto out;
-@@ -1454,6 +1472,10 @@ out:
- return ret;
- }
-
-+#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
-+extern atomic64_unchecked_t global_exec_counter;
-+#endif
-+
- /*
- * compat_do_execve() is mostly a copy of do_execve(), with the exception
- * that it processes 32 bit argv and envp pointers.
-@@ -1463,11 +1485,35 @@ int compat_do_execve(char * filename,
+@@ -1463,11 +1481,35 @@ int compat_do_execve(char * filename,
compat_uptr_t __user *envp,
struct pt_regs * regs)
{
@@ -48424,7 +66154,7 @@ index d1e2411..c2ef8ed 100644
retval = unshare_files(&displaced);
if (retval)
-@@ -1493,12 +1539,26 @@ int compat_do_execve(char * filename,
+@@ -1493,12 +1535,26 @@ int compat_do_execve(char * filename,
if (IS_ERR(file))
goto out_unmark;
@@ -48451,24 +66181,10 @@ index d1e2411..c2ef8ed 100644
retval = bprm_mm_init(bprm);
if (retval)
goto out_file;
-@@ -1528,11 +1588,45 @@ int compat_do_execve(char * filename,
+@@ -1515,24 +1571,63 @@ int compat_do_execve(char * filename,
if (retval < 0)
goto out;
-+ if (!gr_tpe_allow(file)) {
-+ retval = -EACCES;
-+ goto out;
-+ }
-+
-+ if (gr_check_crash_exec(file)) {
-+ retval = -EACCES;
-+ goto out;
-+ }
-+
-+ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt);
-+
-+ gr_handle_exec_args_compat(bprm, argv);
-+
+#ifdef CONFIG_GRKERNSEC
+ old_acl = current->acl;
+ memcpy(old_rlim, current->signal->rlim, sizeof(old_rlim));
@@ -48476,12 +66192,49 @@ index d1e2411..c2ef8ed 100644
+ get_file(file);
+ current->exec_file = file;
+#endif
++#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
++ /* limit suid stack to 8MB
++ we saved the old limits above and will restore them if this exec fails
++ */
++ if ((bprm->cred->euid != current_euid()) || (bprm->cred->egid != current_egid()))
++ current->signal->rlim[RLIMIT_STACK].rlim_cur = 8 * 1024 * 1024;
++#endif
++
++ if (!gr_tpe_allow(file)) {
++ retval = -EACCES;
++ goto out_fail;
++ }
++
++ if (gr_check_crash_exec(file)) {
++ retval = -EACCES;
++ goto out_fail;
++ }
+
+ retval = gr_set_proc_label(file->f_dentry, file->f_vfsmnt,
+ bprm->unsafe);
+ if (retval < 0)
+ goto out_fail;
+
+ retval = copy_strings_kernel(1, &bprm->filename, bprm);
+ if (retval < 0)
+- goto out;
++ goto out_fail;
+
+ bprm->exec = bprm->p;
+ retval = compat_copy_strings(bprm->envc, envp, bprm);
+ if (retval < 0)
+- goto out;
++ goto out_fail;
+
+ retval = compat_copy_strings(bprm->argc, argv, bprm);
+ if (retval < 0)
+- goto out;
++ goto out_fail;
++
++ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt);
++
++ gr_handle_exec_args_compat(bprm, argv);
+
retval = search_binary_handler(bprm, regs);
if (retval < 0)
- goto out;
@@ -48492,13 +66245,11 @@ index d1e2411..c2ef8ed 100644
+#endif
/* execve succeeded */
-+#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
-+ current->exec_id = atomic64_inc_return_unchecked(&global_exec_counter);
-+#endif
++ increment_exec_counter();
current->fs->in_exec = 0;
current->in_execve = 0;
acct_update_integrals(current);
-@@ -1541,6 +1635,14 @@ int compat_do_execve(char * filename,
+@@ -1541,6 +1636,14 @@ int compat_do_execve(char * filename,
put_files_struct(displaced);
return retval;
@@ -48513,7 +66264,7 @@ index d1e2411..c2ef8ed 100644
out:
if (bprm->mm) {
acct_arg_size(bprm, 0);
-@@ -1711,6 +1813,8 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
+@@ -1711,6 +1814,8 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
struct fdtable *fdt;
long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
@@ -48522,7 +66273,7 @@ index d1e2411..c2ef8ed 100644
if (n < 0)
goto out_nofds;
-@@ -2151,7 +2255,7 @@ asmlinkage long compat_sys_nfsservctl(int cmd,
+@@ -2151,7 +2256,7 @@ asmlinkage long compat_sys_nfsservctl(int cmd,
oldfs = get_fs();
set_fs(KERNEL_DS);
/* The __user pointer casts are valid because of the set_fs() */
@@ -48871,7 +66622,7 @@ index 4434e8f..fa05803 100644
}
mutex_unlock(&crypt_stat->cs_mutex);
diff --git a/fs/exec.c b/fs/exec.c
-index 86fafc6..6272c0e 100644
+index 86fafc6..6a041a8 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -56,12 +56,28 @@
@@ -48930,11 +66681,11 @@ index 86fafc6..6272c0e 100644
return page;
+#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
-+ // only allow 1MB for argv+env on suid/sgid binaries
++ // only allow 512KB for argv+env on suid/sgid binaries
+ // to prevent easy ASLR exhaustion
+ if (((bprm->cred->euid != current_euid()) ||
+ (bprm->cred->egid != current_egid())) &&
-+ (size > (1024 * 1024))) {
++ (size > (512 * 1024))) {
+ put_page(page);
+ return NULL;
+ }
@@ -48962,7 +66713,7 @@ index 86fafc6..6272c0e 100644
+
+#ifdef CONFIG_PAX_RANDUSTACK
+ if (randomize_va_space)
-+ bprm->p ^= (pax_get_random_long() & ~15) & ~PAGE_MASK;
++ bprm->p ^= random32() & ~PAGE_MASK;
+#endif
+
return 0;
@@ -49135,18 +66886,29 @@ index 86fafc6..6272c0e 100644
bprm->unsafe |= LSM_UNSAFE_SHARE;
} else {
res = -EAGAIN;
-@@ -1339,6 +1384,10 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
+@@ -1339,6 +1384,21 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
EXPORT_SYMBOL(search_binary_handler);
+#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
-+atomic64_unchecked_t global_exec_counter = ATOMIC64_INIT(0);
++DEFINE_PER_CPU(u64, exec_counter);
++static int __init init_exec_counters(void)
++{
++ unsigned int cpu;
++
++ for_each_possible_cpu(cpu) {
++ per_cpu(exec_counter, cpu) = (u64)cpu;
++ }
++
++ return 0;
++}
++early_initcall(init_exec_counters);
+#endif
+
/*
* sys_execve() executes a new program.
*/
-@@ -1347,11 +1396,35 @@ int do_execve(char * filename,
+@@ -1347,11 +1407,35 @@ int do_execve(char * filename,
char __user *__user *envp,
struct pt_regs * regs)
{
@@ -49182,7 +66944,7 @@ index 86fafc6..6272c0e 100644
retval = unshare_files(&displaced);
if (retval)
-@@ -1377,12 +1450,27 @@ int do_execve(char * filename,
+@@ -1377,12 +1461,27 @@ int do_execve(char * filename,
if (IS_ERR(file))
goto out_unmark;
@@ -49210,24 +66972,10 @@ index 86fafc6..6272c0e 100644
retval = bprm_mm_init(bprm);
if (retval)
goto out_file;
-@@ -1412,12 +1500,47 @@ int do_execve(char * filename,
+@@ -1399,25 +1498,66 @@ int do_execve(char * filename,
if (retval < 0)
goto out;
-+ if (!gr_tpe_allow(file)) {
-+ retval = -EACCES;
-+ goto out;
-+ }
-+
-+ if (gr_check_crash_exec(file)) {
-+ retval = -EACCES;
-+ goto out;
-+ }
-+
-+ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt);
-+
-+ gr_handle_exec_args(bprm, (const char __user *const __user *)argv);
-+
+#ifdef CONFIG_GRKERNSEC
+ old_acl = current->acl;
+ memcpy(old_rlim, current->signal->rlim, sizeof(old_rlim));
@@ -49235,12 +66983,50 @@ index 86fafc6..6272c0e 100644
+ get_file(file);
+ current->exec_file = file;
+#endif
++#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
++ /* limit suid stack to 8MB
++ we saved the old limits above and will restore them if this exec fails
++ */
++ if (((bprm->cred->euid != current_euid()) || (bprm->cred->egid != current_egid())) &&
++ (old_rlim[RLIMIT_STACK].rlim_cur > (8 * 1024 * 1024)))
++ current->signal->rlim[RLIMIT_STACK].rlim_cur = 8 * 1024 * 1024;
++#endif
++
++ if (!gr_tpe_allow(file)) {
++ retval = -EACCES;
++ goto out_fail;
++ }
++
++ if (gr_check_crash_exec(file)) {
++ retval = -EACCES;
++ goto out_fail;
++ }
+
+ retval = gr_set_proc_label(file->f_dentry, file->f_vfsmnt,
+ bprm->unsafe);
+ if (retval < 0)
+ goto out_fail;
+
+ retval = copy_strings_kernel(1, &bprm->filename, bprm);
+ if (retval < 0)
+- goto out;
++ goto out_fail;
+
+ bprm->exec = bprm->p;
+ retval = copy_strings(bprm->envc, envp, bprm);
+ if (retval < 0)
+- goto out;
++ goto out_fail;
+
+ retval = copy_strings(bprm->argc, argv, bprm);
+ if (retval < 0)
+- goto out;
++ goto out_fail;
++
++ gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt);
++
++ gr_handle_exec_args(bprm, (const char __user *const __user *)argv);
+
current->flags &= ~PF_KTHREAD;
retval = search_binary_handler(bprm,regs);
if (retval < 0)
@@ -49252,14 +67038,12 @@ index 86fafc6..6272c0e 100644
+#endif
/* execve succeeded */
-+#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
-+ current->exec_id = atomic64_inc_return_unchecked(&global_exec_counter);
-+#endif
+
++ increment_exec_counter();
current->fs->in_exec = 0;
current->in_execve = 0;
acct_update_integrals(current);
-@@ -1426,6 +1549,14 @@ int do_execve(char * filename,
+@@ -1426,6 +1566,14 @@ int do_execve(char * filename,
put_files_struct(displaced);
return retval;
@@ -49274,7 +67058,7 @@ index 86fafc6..6272c0e 100644
out:
if (bprm->mm) {
acct_arg_size(bprm, 0);
-@@ -1591,6 +1722,220 @@ out:
+@@ -1591,6 +1739,219 @@ out:
return ispipe;
}
@@ -49465,8 +67249,7 @@ index 86fafc6..6272c0e 100644
+#endif
+}
+
-+
-+NORET_TYPE void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type)
++__noreturn void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type)
+{
+ if (current->signal->curr_ip)
+ printk(KERN_ERR "PAX: From %pI4: kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
@@ -49495,7 +67278,7 @@ index 86fafc6..6272c0e 100644
static int zap_process(struct task_struct *start)
{
struct task_struct *t;
-@@ -1793,17 +2138,17 @@ static void wait_for_dump_helpers(struct file *file)
+@@ -1793,17 +2154,17 @@ static void wait_for_dump_helpers(struct file *file)
pipe = file->f_path.dentry->d_inode->i_pipe;
pipe_lock(pipe);
@@ -49518,7 +67301,7 @@ index 86fafc6..6272c0e 100644
pipe_unlock(pipe);
}
-@@ -1826,10 +2171,13 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
+@@ -1826,10 +2187,13 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
char **helper_argv = NULL;
int helper_argc = 0;
int dump_count = 0;
@@ -49533,7 +67316,7 @@ index 86fafc6..6272c0e 100644
binfmt = mm->binfmt;
if (!binfmt || !binfmt->core_dump)
goto fail;
-@@ -1874,6 +2222,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
+@@ -1874,6 +2238,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
*/
clear_thread_flag(TIF_SIGPENDING);
@@ -49542,7 +67325,7 @@ index 86fafc6..6272c0e 100644
/*
* lock_kernel() because format_corename() is controlled by sysctl, which
* uses lock_kernel()
-@@ -1908,7 +2258,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
+@@ -1908,7 +2274,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
goto fail_unlock;
}
@@ -49551,7 +67334,7 @@ index 86fafc6..6272c0e 100644
if (core_pipe_limit && (core_pipe_limit < dump_count)) {
printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n",
task_tgid_vnr(current), current->comm);
-@@ -1972,7 +2322,7 @@ close_fail:
+@@ -1972,7 +2338,7 @@ close_fail:
filp_close(file, NULL);
fail_dropcount:
if (dump_count)
@@ -55467,10 +73250,10 @@ index 8f32f50..b6a41e8 100644
link[pathlen] = '\0';
diff --git a/grsecurity/Kconfig b/grsecurity/Kconfig
new file mode 100644
-index 0000000..7026cbd
+index 0000000..50819f8
--- /dev/null
+++ b/grsecurity/Kconfig
-@@ -0,0 +1,1074 @@
+@@ -0,0 +1,1077 @@
+#
+# grecurity configuration
+#
@@ -55745,11 +73528,13 @@ index 0000000..7026cbd
+ dangerous sources of information, this option causes reads of sensitive
+ /proc/<pid> entries where the file descriptor was opened in a different
+ task than the one performing the read. Such attempts are logged.
-+ Finally, this option limits argv/env strings for suid/sgid binaries
-+ to 1MB to prevent a complete exhaustion of the stack entropy provided
-+ by ASLR.
++ This option also limits argv/env strings for suid/sgid binaries
++ to 512KB to prevent a complete exhaustion of the stack entropy provided
++ by ASLR. Finally, it places an 8MB stack resource limit on suid/sgid
++ binaries to prevent alternative mmap layouts from being abused.
++
+ If you use PaX it is essential that you say Y here as it closes up
-+ several holes that make full ASLR useless for suid/sgid binaries.
++ several holes that make full ASLR useless locally.
+
+config GRKERNSEC_BRUTE
+ bool "Deter exploit bruteforcing"
@@ -55888,8 +73673,9 @@ index 0000000..7026cbd
+ Depending upon the option you choose, you can either restrict users to
+ see only the processes they themselves run, or choose a group that can
+ view all processes and files normally restricted to root if you choose
-+ the "restrict to user only" option. NOTE: If you're running identd as
-+ a non-root user, you will have to run it as the group you specify here.
++ the "restrict to user only" option. NOTE: If you're running identd or
++ ntpd as a non-root user, you will have to run it as the group you
++ specify here.
+
+config GRKERNSEC_PROC_USER
+ bool "Restrict /proc to user only"
@@ -69115,6 +86901,18 @@ index 81c9689..a567a55 100644
/*
* Protect attach/detach and child_list:
+diff --git a/include/linux/personality.h b/include/linux/personality.h
+index 1261208..ddef96f 100644
+--- a/include/linux/personality.h
++++ b/include/linux/personality.h
+@@ -43,6 +43,7 @@ enum {
+ #define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC | \
+ ADDR_NO_RANDOMIZE | \
+ ADDR_COMPAT_LAYOUT | \
++ ADDR_LIMIT_3GB | \
+ MMAP_PAGE_ZERO)
+
+ /*
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index b43a9e0..b77d869 100644
--- a/include/linux/pipe_fs_i.h
@@ -69174,6 +86972,18 @@ index 72b1a10..13303a9 100644
/**
* preempt_notifier - key for installing preemption notifiers
+diff --git a/include/linux/prefetch.h b/include/linux/prefetch.h
+index af7c36a..a93005c 100644
+--- a/include/linux/prefetch.h
++++ b/include/linux/prefetch.h
+@@ -11,6 +11,7 @@
+ #define _LINUX_PREFETCH_H
+
+ #include <linux/types.h>
++#include <linux/const.h>
+ #include <asm/processor.h>
+ #include <asm/cache.h>
+
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 379eaed..1bf73e3 100644
--- a/include/linux/proc_fs.h
@@ -69392,7 +87202,7 @@ index 3392c59..a746428 100644
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/**
diff --git a/include/linux/sched.h b/include/linux/sched.h
-index 71849bf..2ef383dc3 100644
+index 71849bf..8cf9dd2 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -101,6 +101,7 @@ struct bio;
@@ -69594,7 +87404,7 @@ index 71849bf..2ef383dc3 100644
+extern void pax_report_fault(struct pt_regs *regs, void *pc, void *sp);
+extern void pax_report_insns(struct pt_regs *regs, void *pc, void *sp);
+extern void pax_report_refcount_overflow(struct pt_regs *regs);
-+extern NORET_TYPE void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type) ATTRIB_NORET;
++extern __noreturn void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type);
+
+#ifdef CONFIG_PAX_MEMORY_STACKLEAK
+extern void pax_track_stack(void);
@@ -69637,7 +87447,7 @@ index 71849bf..2ef383dc3 100644
extern void flush_itimer_signals(void);
-extern NORET_TYPE void do_group_exit(int);
-+extern NORET_TYPE void do_group_exit(int) ATTRIB_NORET;
++extern __noreturn void do_group_exit(int);
extern void daemonize(const char *, ...);
extern int allow_signal(int);
@@ -69661,6 +87471,30 @@ index 71849bf..2ef383dc3 100644
extern void thread_info_cache_init(void);
#ifdef CONFIG_DEBUG_STACK_USAGE
+@@ -2616,6 +2720,23 @@ static inline unsigned long rlimit_max(unsigned int limit)
+ return task_rlimit_max(current, limit);
+ }
+
++#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
++DECLARE_PER_CPU(u64, exec_counter);
++static inline void increment_exec_counter(void)
++{
++ unsigned int cpu;
++ u64 *exec_id_ptr;
++ BUILD_BUG_ON(NR_CPUS > (1 << 16));
++ cpu = get_cpu();
++ exec_id_ptr = &per_cpu(exec_counter, cpu);
++ *exec_id_ptr += 1ULL << 16;
++ current->exec_id = *exec_id_ptr;
++ put_cpu();
++}
++#else
++static inline void increment_exec_counter(void) {}
++#endif
++
+ #endif /* __KERNEL__ */
+
+ #endif
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index 1ee2c05..81b7ec4 100644
--- a/include/linux/screen_info.h
@@ -69772,7 +87606,7 @@ index eca6235..c7417ed 100644
/* shm_mode upper byte flags */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
-index bcdd660..6e12e11 100644
+index bcdd660..fd2e332 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -14,6 +14,7 @@
@@ -69819,6 +87653,29 @@ index bcdd660..6e12e11 100644
#endif
extern int ___pskb_trim(struct sk_buff *skb, unsigned int len);
+@@ -1489,6 +1490,22 @@ static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev,
+ return __netdev_alloc_skb(dev, length, GFP_ATOMIC);
+ }
+
++static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++ unsigned int length, gfp_t gfp)
++{
++ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
++
++ if (NET_IP_ALIGN && skb)
++ skb_reserve(skb, NET_IP_ALIGN);
++ return skb;
++}
++
++static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
++ unsigned int length)
++{
++ return __netdev_alloc_skb_ip_align(dev, length, GFP_ATOMIC);
++}
++
+ extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask);
+
+ /**
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 2da8372..a3be824 100644
--- a/include/linux/slab.h
@@ -71002,6 +88859,23 @@ index de8e180..f15e0d7 100644
struct device sdev_gendev,
sdev_dev;
+diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
+index 0b4baba..0106e9e 100644
+--- a/include/scsi/scsi_host.h
++++ b/include/scsi/scsi_host.h
+@@ -43,6 +43,12 @@ struct blk_queue_tags;
+ #define DISABLE_CLUSTERING 0
+ #define ENABLE_CLUSTERING 1
+
++enum {
++ SCSI_QDEPTH_DEFAULT, /* default requested change, e.g. from sysfs */
++ SCSI_QDEPTH_QFULL, /* scsi-ml requested due to queue full */
++ SCSI_QDEPTH_RAMP_UP, /* scsi-ml requested due to threshhold event */
++};
++
+ struct scsi_host_template {
+ struct module *module;
+ const char *name;
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index fc50bd6..81ba9cb 100644
--- a/include/scsi/scsi_transport_fc.h
@@ -72479,7 +90353,7 @@ index 0b5b5fc..f7fe51a 100644
if (ret < 0)
return ret;
diff --git a/kernel/exit.c b/kernel/exit.c
-index 0f8fae3..7916abf 100644
+index 0f8fae3..66af9b1 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -55,6 +55,10 @@
@@ -72589,6 +90463,15 @@ index 0f8fae3..7916abf 100644
if (tsk->splice_pipe)
__free_pipe_info(tsk->splice_pipe);
+@@ -1059,7 +1088,7 @@ SYSCALL_DEFINE1(exit, int, error_code)
+ * Take down every thread in the group. This is called by fatal signals
+ * as well as by sys_exit_group (below).
+ */
+-NORET_TYPE void
++__noreturn void
+ do_group_exit(int exit_code)
+ {
+ struct signal_struct *sig = current->signal;
@@ -1188,7 +1217,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
if (unlikely(wo->wo_flags & WNOWAIT)) {
@@ -73405,7 +91288,7 @@ index d4aba4f..02a353f 100644
if (!name) {
diff --git a/kernel/module.c b/kernel/module.c
-index 4b270e6..2226274 100644
+index 4b270e6..2efdb65 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -55,6 +55,7 @@
@@ -73736,7 +91619,7 @@ index 4b270e6..2226274 100644
+ license = get_modinfo(sechdrs, infoindex, "license");
+#ifdef CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR
+ if (!license || !license_is_gpl_compatible(license)) {
-+ err -ENOEXEC;
++ err = -ENOEXEC;
+ goto free_hdr;
+ }
+#endif
@@ -82899,6 +100782,19 @@ index 9cc6289..052c521 100644
}
int udp6_seq_show(struct seq_file *seq, void *v)
+diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
+index 48bb1e3..5980e6e 100644
+--- a/net/ipv6/xfrm6_tunnel.c
++++ b/net/ipv6/xfrm6_tunnel.c
+@@ -258,7 +258,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb)
+ __be32 spi;
+
+ spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
+- return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0;
++ return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi);
+ }
+
+ static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 811984d..11f59b7 100644
--- a/net/irda/ircomm/ircomm_tty.c
@@ -85334,7 +103230,7 @@ index d52f7a0..269eb1b 100755
rm -f tags
xtags ctags
diff --git a/security/Kconfig b/security/Kconfig
-index fb363cd..886ace4 100644
+index fb363cd..90fc8f4 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -4,6 +4,626 @@
@@ -85910,7 +103806,7 @@ index fb363cd..886ace4 100644
+
+config PAX_REFCOUNT
+ bool "Prevent various kernel object reference counter overflows"
-+ depends on GRKERNSEC && (X86 || SPARC64)
++ depends on GRKERNSEC && ((ARM && (CPU_32v6 || CPU_32v6K || CPU_32v7)) || SPARC64 || X86)
+ help
+ By saying Y here the kernel will detect and prevent overflowing
+ various (but not all) kinds of object reference counters. Such
@@ -87245,10 +105141,10 @@ index 79633ea..9732e90 100644
}
diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile
new file mode 100644
-index 0000000..469b06a
+index 0000000..894c8bf
--- /dev/null
+++ b/tools/gcc/Makefile
-@@ -0,0 +1,21 @@
+@@ -0,0 +1,23 @@
+#CC := gcc
+#PLUGIN_SOURCE_FILES := pax_plugin.c
+#PLUGIN_OBJECT_FILES := $(patsubst %.c,%.o,$(PLUGIN_SOURCE_FILES))
@@ -87262,6 +105158,7 @@ index 0000000..469b06a
+hostlibs-$(CONFIG_KALLOCSTAT_PLUGIN) += kallocstat_plugin.so
+hostlibs-$(CONFIG_PAX_KERNEXEC_PLUGIN) += kernexec_plugin.so
+hostlibs-$(CONFIG_CHECKER_PLUGIN) += checker_plugin.so
++hostlibs-y += colorize_plugin.so
+
+always := $(hostlibs-y)
+
@@ -87270,6 +105167,7 @@ index 0000000..469b06a
+kallocstat_plugin-objs := kallocstat_plugin.o
+kernexec_plugin-objs := kernexec_plugin.o
+checker_plugin-objs := checker_plugin.o
++colorize_plugin-objs := colorize_plugin.o
diff --git a/tools/gcc/checker_plugin.c b/tools/gcc/checker_plugin.c
new file mode 100644
index 0000000..d41b5af
@@ -87447,6 +105345,159 @@ index 0000000..d41b5af
+
+ return 0;
+}
+diff --git a/tools/gcc/colorize_plugin.c b/tools/gcc/colorize_plugin.c
+new file mode 100644
+index 0000000..ee950d0
+--- /dev/null
++++ b/tools/gcc/colorize_plugin.c
+@@ -0,0 +1,147 @@
++/*
++ * Copyright 2012 by PaX Team <pageexec@freemail.hu>
++ * Licensed under the GPL v2
++ *
++ * Note: the choice of the license means that the compilation process is
++ * NOT 'eligible' as defined by gcc's library exception to the GPL v3,
++ * but for the kernel it doesn't matter since it doesn't link against
++ * any of the gcc libraries
++ *
++ * gcc plugin to colorize diagnostic output
++ *
++ */
++
++#include "gcc-plugin.h"
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "tree.h"
++#include "tree-pass.h"
++#include "flags.h"
++#include "intl.h"
++#include "toplev.h"
++#include "plugin.h"
++#include "diagnostic.h"
++#include "plugin-version.h"
++#include "tm.h"
++
++int plugin_is_GPL_compatible;
++
++static struct plugin_info colorize_plugin_info = {
++ .version = "201203092200",
++};
++
++#define GREEN "\033[32m\033[2m"
++#define LIGHTGREEN "\033[32m\033[1m"
++#define YELLOW "\033[33m\033[2m"
++#define LIGHTYELLOW "\033[33m\033[1m"
++#define RED "\033[31m\033[2m"
++#define LIGHTRED "\033[31m\033[1m"
++#define BLUE "\033[34m\033[2m"
++#define LIGHTBLUE "\033[34m\033[1m"
++#define BRIGHT "\033[m\033[1m"
++#define NORMAL "\033[m"
++
++static diagnostic_starter_fn old_starter;
++static diagnostic_finalizer_fn old_finalizer;
++
++static void start_colorize(diagnostic_context *context, diagnostic_info *diagnostic)
++{
++ const char *color;
++ char *newprefix;
++
++ switch (diagnostic->kind) {
++ case DK_NOTE:
++ color = LIGHTBLUE;
++ break;
++
++ case DK_PEDWARN:
++ case DK_WARNING:
++ color = LIGHTYELLOW;
++ break;
++
++ case DK_ERROR:
++ case DK_FATAL:
++ case DK_ICE:
++ case DK_PERMERROR:
++ case DK_SORRY:
++ color = LIGHTRED;
++ break;
++
++ default:
++ color = NORMAL;
++ }
++
++ old_starter(context, diagnostic);
++ if (-1 == asprintf(&newprefix, "%s%s" NORMAL, color, context->printer->prefix))
++ return;
++ pp_destroy_prefix(context->printer);
++ pp_set_prefix(context->printer, newprefix);
++}
++
++static void finalize_colorize(diagnostic_context *context, diagnostic_info *diagnostic)
++{
++ old_finalizer(context, diagnostic);
++}
++
++static void colorize_arm(void)
++{
++ old_starter = diagnostic_starter(global_dc);
++ old_finalizer = diagnostic_finalizer(global_dc);
++
++ diagnostic_starter(global_dc) = start_colorize;
++ diagnostic_finalizer(global_dc) = finalize_colorize;
++}
++
++static unsigned int execute_colorize_rearm(void)
++{
++ if (diagnostic_starter(global_dc) == start_colorize)
++ return 0;
++
++ colorize_arm();
++ return 0;
++}
++
++struct simple_ipa_opt_pass pass_ipa_colorize_rearm = {
++ .pass = {
++ .type = SIMPLE_IPA_PASS,
++ .name = "colorize_rearm",
++ .gate = NULL,
++ .execute = execute_colorize_rearm,
++ .sub = NULL,
++ .next = NULL,
++ .static_pass_number = 0,
++ .tv_id = TV_NONE,
++ .properties_required = 0,
++ .properties_provided = 0,
++ .properties_destroyed = 0,
++ .todo_flags_start = 0,
++ .todo_flags_finish = 0
++ }
++};
++
++static void colorize_start_unit(void *gcc_data, void *user_data)
++{
++ colorize_arm();
++}
++
++int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
++{
++ const char * const plugin_name = plugin_info->base_name;
++ struct register_pass_info colorize_rearm_pass_info = {
++ .pass = &pass_ipa_colorize_rearm.pass,
++ .reference_pass_name = "*free_lang_data",
++ .ref_pass_instance_number = 0,
++ .pos_op = PASS_POS_INSERT_AFTER
++ };
++
++ if (!plugin_default_version_check(version, &gcc_version)) {
++ error(G_("incompatible gcc/plugin versions"));
++ return 1;
++ }
++
++ register_callback(plugin_name, PLUGIN_INFO, NULL, &colorize_plugin_info);
++ register_callback(plugin_name, PLUGIN_START_UNIT, &colorize_start_unit, NULL);
++ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &colorize_rearm_pass_info);
++ return 0;
++}
diff --git a/tools/gcc/constify_plugin.c b/tools/gcc/constify_plugin.c
new file mode 100644
index 0000000..704a564
@@ -88364,7 +106415,7 @@ index 0000000..008f159
+}
diff --git a/tools/gcc/stackleak_plugin.c b/tools/gcc/stackleak_plugin.c
new file mode 100644
-index 0000000..4a9b187
+index 0000000..ea79948
--- /dev/null
+++ b/tools/gcc/stackleak_plugin.c
@@ -0,0 +1,326 @@
@@ -88618,7 +106669,7 @@ index 0000000..4a9b187
+ return 0;
+}
+
-+static void stackleak_start_unit(void *gcc_data, void *user_dat)
++static void stackleak_start_unit(void *gcc_data, void *user_data)
+{
+ tree fntype;
+
@@ -88688,7 +106739,7 @@ index 0000000..4a9b187
+ error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
+ }
+
-+ register_callback("start_unit", PLUGIN_START_UNIT, &stackleak_start_unit, NULL);
++ register_callback(plugin_name, PLUGIN_START_UNIT, &stackleak_start_unit, NULL);
+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_tree_instrument_pass_info);
+ register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &stackleak_final_pass_info);
+
diff --git a/2.6.32/4445_grsec-pax-without-grsec.patch b/2.6.32/4445_grsec-pax-without-grsec.patch
index 591a120..f07b2df 100644
--- a/2.6.32/4445_grsec-pax-without-grsec.patch
+++ b/2.6.32/4445_grsec-pax-without-grsec.patch
@@ -3,6 +3,9 @@ From: Anthony G. Basile <blueness@gentoo.org>
With grsecurity-2.2.2-2.6.32.38-201104171745, the functions pax_report_leak_to_user and
pax_report_overflow_from_user in fs/exec.c were consolidated into pax_report_usercopy.
This patch has been updated to reflect that change.
+
+With grsecurity-2.9-2.6.32.58-201203131839, NORET_TYPE has been replaced by __noreturn.
+This patch has been updated to reflect that change.
--
From: Jory Pratt <anarchy@gentoo.org>
Updated patch for kernel 2.6.32
@@ -36,7 +39,7 @@ diff -Naur a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
diff -Naur a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c 2011-04-17 18:15:55.000000000 -0400
+++ b/fs/exec.c 2011-04-17 18:29:40.000000000 -0400
-@@ -1832,9 +1832,11 @@
+@@ -1849,9 +1849,11 @@
}
up_read(&mm->mmap_sem);
}
@@ -48,7 +51,7 @@ diff -Naur a/fs/exec.c b/fs/exec.c
printk(KERN_ERR "PAX: execution attempt in: %s, %08lx-%08lx %08lx\n", path_fault, start, end, offset);
printk(KERN_ERR "PAX: terminating task: %s(%s):%d, uid/euid: %u/%u, "
"PC: %p, SP: %p\n", path_exec, tsk->comm, task_pid_nr(tsk),
-@@ -1849,10 +1851,12 @@
+@@ -1866,10 +1868,12 @@
#ifdef CONFIG_PAX_REFCOUNT
void pax_report_refcount_overflow(struct pt_regs *regs)
{
@@ -61,9 +64,9 @@ diff -Naur a/fs/exec.c b/fs/exec.c
printk(KERN_ERR "PAX: refcount overflow detected in: %s:%d, uid/euid: %u/%u\n",
current->comm, task_pid_nr(current), current_uid(), current_euid());
print_symbol(KERN_ERR "PAX: refcount overflow occured at: %s\n", instruction_pointer(regs));
-@@ -1912,10 +1916,12 @@
+@@ -1928,10 +1932,12 @@
- NORET_TYPE void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type)
+ __noreturn void pax_report_usercopy(const void *ptr, unsigned long len, bool to, const char *type)
{
+#ifdef CONFIG_GRKERNSEC
if (current->signal->curr_ip)
diff --git a/2.6.32/4450_grsec-kconfig-default-gids.patch b/2.6.32/4450_grsec-kconfig-default-gids.patch
index 498adb6..8c6f609 100644
--- a/2.6.32/4450_grsec-kconfig-default-gids.patch
+++ b/2.6.32/4450_grsec-kconfig-default-gids.patch
@@ -12,7 +12,7 @@ from shooting themselves in the foot.
diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig
--- a/grsecurity/Kconfig 2011-12-12 15:11:47.000000000 -0500
+++ b/grsecurity/Kconfig 2011-12-12 15:13:17.000000000 -0500
-@@ -439,7 +439,7 @@
+@@ -442,7 +442,7 @@
config GRKERNSEC_PROC_GID
int "GID for special group"
depends on GRKERNSEC_PROC_USERGROUP
@@ -21,7 +21,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig
config GRKERNSEC_PROC_ADD
bool "Additional restrictions"
-@@ -667,7 +667,7 @@
+@@ -670,7 +670,7 @@
config GRKERNSEC_AUDIT_GID
int "GID for auditing"
depends on GRKERNSEC_AUDIT_GROUP
@@ -30,7 +30,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig
config GRKERNSEC_EXECLOG
bool "Exec logging"
-@@ -871,7 +871,7 @@
+@@ -874,7 +874,7 @@
config GRKERNSEC_TPE_GID
int "GID for untrusted users"
depends on GRKERNSEC_TPE && !GRKERNSEC_TPE_INVERT
@@ -39,7 +39,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig
help
Setting this GID determines what group TPE restrictions will be
*enabled* for. If the sysctl option is enabled, a sysctl option
-@@ -880,7 +880,7 @@
+@@ -883,7 +883,7 @@
config GRKERNSEC_TPE_GID
int "GID for trusted users"
depends on GRKERNSEC_TPE && GRKERNSEC_TPE_INVERT
@@ -48,7 +48,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig
help
Setting this GID determines what group TPE restrictions will be
*disabled* for. If the sysctl option is enabled, a sysctl option
-@@ -953,7 +953,7 @@
+@@ -956,7 +956,7 @@
config GRKERNSEC_SOCKET_ALL_GID
int "GID to deny all sockets for"
depends on GRKERNSEC_SOCKET_ALL
@@ -57,7 +57,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig
help
Here you can choose the GID to disable socket access for. Remember to
add the users you want socket access disabled for to the GID
-@@ -974,7 +974,7 @@
+@@ -977,7 +977,7 @@
config GRKERNSEC_SOCKET_CLIENT_GID
int "GID to deny client sockets for"
depends on GRKERNSEC_SOCKET_CLIENT
@@ -66,7 +66,7 @@ diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig
help
Here you can choose the GID to disable client socket access for.
Remember to add the users you want client socket access disabled for to
-@@ -992,7 +992,7 @@
+@@ -995,7 +995,7 @@
config GRKERNSEC_SOCKET_SERVER_GID
int "GID to deny server sockets for"
depends on GRKERNSEC_SOCKET_SERVER
diff --git a/2.6.32/4460-grsec-kconfig-proc-user.patch b/2.6.32/4460-grsec-kconfig-proc-user.patch
index 1e181f3..b94ee69 100644
--- a/2.6.32/4460-grsec-kconfig-proc-user.patch
+++ b/2.6.32/4460-grsec-kconfig-proc-user.patch
@@ -6,7 +6,7 @@ in a different way to avoid bug #366019. This patch should eventually go upstre
diff -Naur a/grsecurity/Kconfig b/grsecurity/Kconfig</