Netdev List
 help / color / mirror / Atom feed
* [PATCH v3 0/8] cgroup: Assign subsystem IDs during compile time
From: Daniel Wagner @ 2012-09-11 16:26 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA, cgroups-u79uwXL29TY76Z2rM5mHXA
  Cc: Daniel Wagner, David S. Miller, Andrew Morton, Eric Dumazet,
	Gao feng, Glauber Costa, Jamal Hadi Salim, John Fastabend,
	Kamezawa Hiroyuki, Li Zefan, Neil Horman, Tejun Heo

From: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>

Hi,

In this version I tried to concentrate on the main topic of this
series, so I removed some of the things which were not really needed
and I have to admit the result looks much better. So I hope that will
simplify the review for you.

I reordered some of the patches and dropped the jump label
optimization for now. When this series is applied, then I can follow
up with those changes.

Overall, I tried to address all comments I got from v2. I didn't address
Tejun comment on 

  cgroup: Assign subsystem IDs during compile time

to split the net_cls and net_prio changes from that patch.  But I
tried to 'fix' this by beeing a bit more verbose.

The last patch is then the sweet one which gives some memory
back. 

This patches are against net-next

cheers,
daniel

Original cover letters:

v2:

Most notable changes are, that enabling/disabling of the jump labels
are not inside the cgroup_lock anymore (create/destroy cb). Instead
the corresponding functions will be called on module load or unload.

CGROUP_BUILTIN_SUBSYS_COUNT is also gone in this version.  This time I
trade space for speed. Some extra cycles are spend to identify the
modules in the for loops, e.g.

for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
	struct cgroup_subsys_state *ss = cgrp->subsys[i];

	/* at bootup time, we don't worry about modular subsystems */
	if (!ss || (ss && ss->module))
		continue;

	[...]
}

CGROUP_SUBSYS_COUNT is currently 12 if all controllers are built.  I
haven't found any other way to get rid of CGROUP_BUILTIN_SUBSYS_COUNT
without real dirty preprocessor tricks.

Finally, the two versions of task_cls_classid() and task_netprioidx()
are merged together.

v1:

I was able to 'fix' CGROUP_BUILTIN_SUBSYS_COUNT defition. With this
version there is no unused subsys_id. 

The number of builtin subsystem are counted with gcc's predefined
__COUNTER__ macro. This is a bit fragile, because __COUNTER__
is only reset to 0 per compile unit. There is a workaround for this.
When starting to enumate we need to store the current value of
__COUNTER__ and then subtract that from all enums we define. 

Not sure if that is okay or not.

v0:

The patch #1 and #2 are there to be able to introduce (#3, #4) the 
jump labels in task_cls_classid() and task_netprioidx(). The jump
labels are needed to know when it is safe to access the controller. 
For example not safe means the module is not yet loaded.

All those patches are just preparation for the center piece (#5) 
of these series. This one will remove the dynamic subsystem ID
generation and falls back to compile time generated IDs. 

This is the first result from the discussion around on the
"cgroup cls & netprio 'cleanups'" patches.

This patches are against net-next

v3: - dropping unrelated patches such as the jump label patch
    - reordered the patches
    - splitted "cgroup: Assign subsystem IDs during compile time" patch a bit
    - fixed the ordering dependency when assigning the subsystems
    - removed synchronize_rcu() calls
    - more verbose commit messages
v2: - do not use dirty precompiler tricks:
      use ss->module to identify modules in the loops.
    - enable/disable jump labels in module load/unload functions
    - merge builtin/module versions of task_cls_classid() and task_netprioidx
v1: - only use jump labels when built as module (#3, #4)
    - get rid of the additional 'pointer' (#5)
v0: - initial version

Signed-off-by: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
Cc: "David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Cc: Andrew Morton <akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
Cc: Eric Dumazet <edumazet-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Cc: Gao feng <gaofeng-BthXqXjhjHXQFUHtdCDX3A@public.gmane.org>
Cc: Glauber Costa <glommer-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
Cc: Jamal Hadi Salim <jhs-jkUAjuhPggJWk0Htik3J/w@public.gmane.org>
Cc: John Fastabend <john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Cc: Kamezawa Hiroyuki <kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
Cc: Li Zefan <lizefan-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
Cc: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
Cc: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

Daniel Wagner (8):
  cgroup: net_cls: Move sock_update_classid() declaration to
    cls_cgroup.h
  cgroup: net_cls: Do not define task_cls_classid() when not selected
  cgroup: net_prio: Do not define task_netpioidx() when not selected
  cgroup: Remove CGROUP_BUILTIN_SUBSYS_COUNT
  cgroup: Wrap subsystem selection macro
  cgroup: Do not depend on a given order when populating the subsys
    array
  cgroup: Assign subsystem IDs during compile time
  cgroup: Define CGROUP_SUBSYS_COUNT according the configuration

 include/linux/cgroup.h        | 12 +++---
 include/linux/cgroup_subsys.h | 24 +++++------
 include/net/cls_cgroup.h      | 29 +++++++------
 include/net/netprio_cgroup.h  | 26 ++++--------
 include/net/sock.h            |  8 ----
 kernel/cgroup.c               | 98 ++++++++++++++++++++++---------------------
 net/core/netprio_cgroup.c     | 11 -----
 net/core/sock.c               | 15 ++-----
 net/sched/cls_cgroup.c        | 13 ------
 9 files changed, 96 insertions(+), 140 deletions(-)

-- 
1.7.12.315.g682ce8b

^ permalink raw reply

* Re: [PATCH] iproute: Add ability to save, restore and show the interfaces' addresses (resend)
From: Stephen Hemminger @ 2012-09-11 16:18 UTC (permalink / raw)
  To: Pavel Emelyanov; +Cc: Stephen Hemminger, Linux Netdev List
In-Reply-To: <504F5CF4.1040202@parallels.com>

On Tue, 11 Sep 2012 19:47:00 +0400
Pavel Emelyanov <xemul@parallels.com> wrote:

> This functionality is required by checkpoint-restore project. Since the
> dump and restore for routes is already done in ip tool it's naturally to
> dump and restore addresses in the ip tool as well.
> 
> The implementation logic is the same as for the respective one for routes.
> The magic number digits are taken from the Seattle coordinates.
> 
> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

Applied.

^ permalink raw reply

* [PATCH] rtlwifi: rtl8192ce: Log message that B_CUT device may not work
From: Larry Finger @ 2012-09-11 16:11 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, Larry Finger, netdev, Stable, Anisse Astier,
	Li Chaoming

There are a number of problems that occur for the latest version
of the Realtek RTL8188CE device with the in-kernel driver. These
include selection of the wrong firmware, and system lockup. A full
fix is known, but is too invasive for inclusion in stable. This patch
fixes the problem with loading the wrong firmware, and logs a message
that the device may not work for kernels 3.6 and older.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org>
Cc: Anisse Astier <anisse@astier.eu>
Cc: Li Chaoming <chaoming_li@realsil.com.cn>
---
 drivers/net/wireless/rtlwifi/rtl8192ce/def.h |    1 +
 drivers/net/wireless/rtlwifi/rtl8192ce/hw.c  |   12 ++++++++++--
 drivers/net/wireless/rtlwifi/rtl8192ce/sw.c  |    6 ++++--
 3 files changed, 15 insertions(+), 4 deletions(-)
---

John,

Although this patch does not fix a regression, it should prevent the
system freezes that are associated with selecting the wrong firmware
for the new devices. I hope it can be included in 3.6.

A full patch to fix the problems is nearly ready, and will be submitted
for -next later today.

Thanks,

Larry
---

diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
index 04c3aef..2925094 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
@@ -117,6 +117,7 @@
 
 #define CHIP_VER_B			BIT(4)
 #define CHIP_92C_BITMASK		BIT(0)
+#define CHIP_UNKNOWN			BIT(7)
 #define CHIP_92C_1T2R			0x03
 #define CHIP_92C			0x01
 #define CHIP_88C			0x00
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index cc89582..86d73b3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -994,8 +994,16 @@ static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw)
 		version = (value32 & TYPE_ID) ? VERSION_A_CHIP_92C :
 			   VERSION_A_CHIP_88C;
 	} else {
-		version = (value32 & TYPE_ID) ? VERSION_B_CHIP_92C :
-			   VERSION_B_CHIP_88C;
+		version = (enum version_8192c) (CHIP_VER_B |
+				((value32 & TYPE_ID) ? CHIP_92C_BITMASK : 0) |
+				((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0));
+		if ((!IS_CHIP_VENDOR_UMC(version)) && (value32 &
+		     CHIP_VER_RTL_MASK)) {
+			version = (enum version_8192c)(version |
+				   ((((value32 & CHIP_VER_RTL_MASK) == BIT(12))
+				   ? CHIP_VENDOR_UMC_B_CUT : CHIP_UNKNOWN) |
+				   CHIP_VENDOR_UMC));
+		}
 	}
 
 	switch (version) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index 60451ee..ea2e1bd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -162,10 +162,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
 
 	/* request fw */
 	if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
-	    !IS_92C_SERIAL(rtlhal->version))
+	    !IS_92C_SERIAL(rtlhal->version)) {
 		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin";
-	else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
+	} else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
 		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin";
+		pr_info("****** This B_CUT device may not work with kernels 3.6 and earlier\n");
+	}
 
 	rtlpriv->max_fw_size = 0x4000;
 	pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
-- 
1.7.10.4

^ permalink raw reply related

* Re: [PATCH v2 2/2] iproute2: use libgenl in ipl2tp
From: Stephen Hemminger @ 2012-09-11 16:09 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: netdev
In-Reply-To: <1347354274-3119-3-git-send-email-ja@ssi.bg>

On Tue, 11 Sep 2012 12:04:34 +0300
Julian Anastasov <ja@ssi.bg> wrote:

> 	Use the common code from libgenl.c to parse family.
> 
> Signed-off-by: Julian Anastasov <ja@ssi.bg>

I applied these two but made some modifications:
  1. change to GENL_INITIALIZER
  2. use GENL_INITIALIZER

^ permalink raw reply

* [PATCH] iproute: Add ability to save, restore and show the interfaces' addresses (resend)
From: Pavel Emelyanov @ 2012-09-11 15:47 UTC (permalink / raw)
  To: Stephen Hemminger, Linux Netdev List
In-Reply-To: <5012211A.4040307@parallels.com>

This functionality is required by checkpoint-restore project. Since the
dump and restore for routes is already done in ip tool it's naturally to
dump and restore addresses in the ip tool as well.

The implementation logic is the same as for the respective one for routes.
The magic number digits are taken from the Seattle coordinates.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---

diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index cbff143..6c11ce4 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -34,6 +34,11 @@
 #include "ll_map.h"
 #include "ip_common.h"
 
+enum {
+	IPADD_LIST,
+	IPADD_FLUSH,
+	IPADD_SAVE,
+};
 
 static struct
 {
@@ -65,8 +70,9 @@ static void usage(void)
 	fprintf(stderr, "Usage: ip addr {add|change|replace} IFADDR dev STRING [ LIFETIME ]\n");
 	fprintf(stderr, "                                                      [ CONFFLAG-LIST ]\n");
 	fprintf(stderr, "       ip addr del IFADDR dev STRING\n");
-	fprintf(stderr, "       ip addr {show|flush} [ dev STRING ] [ scope SCOPE-ID ]\n");
+	fprintf(stderr, "       ip addr {show|save|flush} [ dev STRING ] [ scope SCOPE-ID ]\n");
 	fprintf(stderr, "                            [ to PREFIX ] [ FLAG-LIST ] [ label PATTERN ]\n");
+	fprintf(stderr, "       ip addr {showdump|restore}\n");
 	fprintf(stderr, "IFADDR := PREFIX | ADDR peer PREFIX\n");
 	fprintf(stderr, "          [ broadcast ADDR ] [ anycast ADDR ]\n");
 	fprintf(stderr, "          [ label STRING ] [ scope SCOPE-ID ]\n");
@@ -768,6 +774,99 @@ static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n,
 	return 0;
 }
 
+static __u32 ipadd_dump_magic = 0x47361222;
+
+static int ipadd_save_prep(void)
+{
+	int ret;
+
+	if (isatty(STDOUT_FILENO)) {
+		fprintf(stderr, "Not sending binary stream to stdout\n");
+		return -1;
+	}
+
+	ret = write(STDOUT_FILENO, &ipadd_dump_magic, sizeof(ipadd_dump_magic));
+	if (ret != sizeof(ipadd_dump_magic)) {
+		fprintf(stderr, "Can't write magic to dump file\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int ipadd_dump_check_magic(void)
+{
+	int ret;
+	__u32 magic = 0;
+
+	if (isatty(STDIN_FILENO)) {
+		fprintf(stderr, "Can't restore addr dump from a terminal\n");
+		return -1;
+	}
+
+	ret = fread(&magic, sizeof(magic), 1, stdin);
+	if (magic != ipadd_dump_magic) {
+		fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n", ret, magic);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int save_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n,
+		       void *arg)
+{
+	int ret;
+
+	ret = write(STDOUT_FILENO, n, n->nlmsg_len);
+	if ((ret > 0) && (ret != n->nlmsg_len)) {
+		fprintf(stderr, "Short write while saving nlmsg\n");
+		ret = -EIO;
+	}
+
+	return ret == n->nlmsg_len ? 0 : ret;
+}
+
+static int show_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
+{
+	struct ifaddrmsg *ifa = NLMSG_DATA(n);
+
+	printf("if%d:\n", ifa->ifa_index);
+	print_addrinfo(NULL, n, stdout);
+	return 0;
+}
+
+static int ipaddr_showdump(void)
+{
+	if (ipadd_dump_check_magic())
+		exit(-1);
+
+	exit(rtnl_from_file(stdin, &show_handler, NULL));
+}
+
+static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
+{
+	int ret;
+
+	n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
+
+	ll_init_map(&rth);
+
+	ret = rtnl_talk(&rth, n, 0, 0, n);
+	if ((ret < 0) && (errno == EEXIST))
+		ret = 0;
+
+	return ret;
+}
+
+static int ipaddr_restore(void)
+{
+	if (ipadd_dump_check_magic())
+		exit(-1);
+
+	exit(rtnl_from_file(stdin, &restore_handler, NULL));
+}
+
 static void free_nlmsg_chain(struct nlmsg_chain *info)
 {
 	struct nlmsg_list *l, *n;
@@ -902,7 +1001,7 @@ static int ipaddr_flush(void)
 	return 1;
 }
 
-static int ipaddr_list_or_flush(int argc, char **argv, int flush)
+static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
 {
 	struct nlmsg_chain linfo = { NULL, NULL};
 	struct nlmsg_chain ainfo = { NULL, NULL};
@@ -918,7 +1017,7 @@ static int ipaddr_list_or_flush(int argc, char **argv, int flush)
 
 	filter.group = INIT_NETDEV_GROUP;
 
-	if (flush) {
+	if (action == IPADD_FLUSH) {
 		if (argc <= 0) {
 			fprintf(stderr, "Flush requires arguments.\n");
 
@@ -1005,9 +1104,26 @@ static int ipaddr_list_or_flush(int argc, char **argv, int flush)
 		}
 	}
 
-	if (flush)
+	if (action == IPADD_FLUSH)
 		return ipaddr_flush();
 
+	if (action == IPADD_SAVE) {
+		if (ipadd_save_prep())
+			exit(1);
+
+		if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETADDR) < 0) {
+			perror("Cannot send dump request");
+			exit(1);
+		}
+
+		if (rtnl_dump_filter(&rth, save_nlmsg, stdout) < 0) {
+			fprintf(stderr, "Save terminated\n");
+			exit(1);
+		}
+
+		exit(0);
+	}
+
 	if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
 		perror("Cannot send dump request");
 		exit(1);
@@ -1055,7 +1171,7 @@ int ipaddr_list_link(int argc, char **argv)
 {
 	preferred_family = AF_PACKET;
 	do_link = 1;
-	return ipaddr_list_or_flush(argc, argv, 0);
+	return ipaddr_list_flush_or_save(argc, argv, IPADD_LIST);
 }
 
 void ipaddr_reset_filter(int oneline)
@@ -1271,7 +1387,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
 int do_ipaddr(int argc, char **argv)
 {
 	if (argc < 1)
-		return ipaddr_list_or_flush(0, NULL, 0);
+		return ipaddr_list_flush_or_save(0, NULL, IPADD_LIST);
 	if (matches(*argv, "add") == 0)
 		return ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
 	if (matches(*argv, "change") == 0 ||
@@ -1283,9 +1399,15 @@ int do_ipaddr(int argc, char **argv)
 		return ipaddr_modify(RTM_DELADDR, 0, argc-1, argv+1);
 	if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
 	    || matches(*argv, "lst") == 0)
-		return ipaddr_list_or_flush(argc-1, argv+1, 0);
+		return ipaddr_list_flush_or_save(argc-1, argv+1, IPADD_LIST);
 	if (matches(*argv, "flush") == 0)
-		return ipaddr_list_or_flush(argc-1, argv+1, 1);
+		return ipaddr_list_flush_or_save(argc-1, argv+1, IPADD_FLUSH);
+	if (matches(*argv, "save") == 0)
+		return ipaddr_list_flush_or_save(argc-1, argv+1, IPADD_SAVE);
+	if (matches(*argv, "showdump") == 0)
+		return ipaddr_showdump();
+	if (matches(*argv, "restore") == 0)
+		return ipaddr_restore();
 	if (matches(*argv, "help") == 0)
 		usage();
 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip addr help\".\n", *argv);

^ permalink raw reply related

* Re: [PATCH 2/2] netprio_cgroup: Optimize the priomap copy loop slightly
From: Neil Horman @ 2012-09-11 15:33 UTC (permalink / raw)
  To: David Laight
  Cc: Srivatsa S. Bhat, davem, john.r.fastabend, gaofeng, eric.dumazet,
	mark.d.rustad, lizefan, netdev, linux-kernel
In-Reply-To: <AE90C24D6B3A694183C094C60CF0A2F6026B6FE9@saturn3.aculab.com>

On Tue, Sep 11, 2012 at 12:42:23PM +0100, David Laight wrote:
> > -	for (i = 0;
> > -	     old_priomap && (i < old_priomap->priomap_len);
> > -	     i++)
> > -		new_priomap->priomap[i] = old_priomap->priomap[i];
> > +	if (old_priomap) {
> > +		old_len = old_priomap->priomap_len;
> > +
> > +		for (i = 0; i < old_len; i++)
> > +			new_priomap->priomap[i] = old_priomap->priomap[i];
> > +	}
> 
> Or:
> 	memcpy(new_priomap->priomap, old_priomap->priomap,
> 		old_priomap->priomap_len * sizeof old_priomap->priomap[0]);
> 
> 	David
> 
Yes, the memcpy would be better here.
Neil

^ permalink raw reply

* [net PATCH v2 7/7] bnx2x: Add missing afex code
From: Yuval Mintz @ 2012-09-11 14:34 UTC (permalink / raw)
  To: davem, netdev
  Cc: Yuval Mintz, Barak Witkowski, Dmitry Kravkov, Eilon Greenstein
In-Reply-To: <1347374054-16730-1-git-send-email-yuvalmin@broadcom.com>

Commit a334872224a67b614dc888460377862621f3dac7 added afex support but lacked
several logical changes. This lack can cause afex to crash, and also
have a slight effect on other flows (i.e., driver always assumes the Tx ring
has less available buffers than what it actually has).

This patch adds the missing segments, fixing said issues.

Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Barak Witkowski <barak@broadcom.com>
Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h  |   11 +++++------
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c |   21 ++++++++++++++++-----
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 21b5532..dfd86a5 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -710,17 +710,15 @@ static inline u16 bnx2x_tx_avail(struct bnx2x *bp,
 	prod = txdata->tx_bd_prod;
 	cons = txdata->tx_bd_cons;
 
-	/* NUM_TX_RINGS = number of "next-page" entries
-	   It will be used as a threshold */
-	used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS;
+	used = SUB_S16(prod, cons);
 
 #ifdef BNX2X_STOP_ON_ERROR
 	WARN_ON(used < 0);
-	WARN_ON(used > bp->tx_ring_size);
-	WARN_ON((bp->tx_ring_size - used) > MAX_TX_AVAIL);
+	WARN_ON(used > txdata->tx_ring_size);
+	WARN_ON((txdata->tx_ring_size - used) > MAX_TX_AVAIL);
 #endif
 
-	return (s16)(bp->tx_ring_size) - used;
+	return (s16)(txdata->tx_ring_size) - used;
 }
 
 static inline int bnx2x_tx_queue_has_work(struct bnx2x_fp_txdata *txdata)
@@ -1088,6 +1086,7 @@ static inline void bnx2x_init_txdata(struct bnx2x *bp,
 	txdata->txq_index = txq_index;
 	txdata->tx_cons_sb = tx_cons_sb;
 	txdata->parent_fp = fp;
+	txdata->tx_ring_size = IS_FCOE_FP(fp) ? MAX_TX_AVAIL : bp->tx_ring_size;
 
 	DP(NETIF_MSG_IFUP, "created tx data cid %d, txq %d\n",
 	   txdata->cid, txdata->txq_index);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 2105498..211753e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -7561,8 +7561,14 @@ int bnx2x_set_mac_one(struct bnx2x *bp, u8 *mac,
 	}
 
 	rc = bnx2x_config_vlan_mac(bp, &ramrod_param);
-	if (rc < 0)
+
+	if (rc == -EEXIST) {
+		DP(BNX2X_MSG_SP, "Failed to schedule ADD operations: %d\n", rc);
+		/* do not treat adding same MAC as error */
+		rc = 0;
+	} else if (rc < 0)
 		BNX2X_ERR("%s MAC failed\n", (set ? "Set" : "Del"));
+
 	return rc;
 }
 
@@ -10294,13 +10300,11 @@ static void __devinit bnx2x_get_fcoe_info(struct bnx2x *bp)
 				dev_info.port_hw_config[port].
 				 fcoe_wwn_node_name_lower);
 	} else if (!IS_MF_SD(bp)) {
-		u32 cfg = MF_CFG_RD(bp, func_ext_config[func].func_cfg);
-
 		/*
 		 * Read the WWN info only if the FCoE feature is enabled for
 		 * this function.
 		 */
-		if (cfg & MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD)
+		if (BNX2X_MF_EXT_PROTOCOL_FCOE(bp) && !CHIP_IS_E1x(bp))
 			bnx2x_get_ext_wwn_info(bp, func);
 
 	} else if (IS_MF_FCOE_SD(bp))
@@ -11073,7 +11077,14 @@ static int bnx2x_set_uc_list(struct bnx2x *bp)
 	netdev_for_each_uc_addr(ha, dev) {
 		rc = bnx2x_set_mac_one(bp, bnx2x_uc_addr(ha), mac_obj, true,
 				       BNX2X_UC_LIST_MAC, &ramrod_flags);
-		if (rc < 0) {
+		if (rc == -EEXIST) {
+			DP(BNX2X_MSG_SP,
+			   "Failed to schedule ADD operations: %d\n", rc);
+			/* do not treat adding same MAC as error */
+			rc = 0;
+
+		} else if (rc < 0) {
+
 			BNX2X_ERR("Failed to schedule ADD operations: %d\n",
 				  rc);
 			return rc;
-- 
1.7.9.rc2

^ permalink raw reply related

* [net PATCH v2 6/7] bnx2x: fix registers dumped
From: Yuval Mintz @ 2012-09-11 14:34 UTC (permalink / raw)
  To: davem, netdev; +Cc: Dmitry Kravkov, Yuval Mintz, Eilon Greenstein
In-Reply-To: <1347374054-16730-1-git-send-email-yuvalmin@broadcom.com>

From: Dmitry Kravkov <dmitry@broadcom.com>

Under traffic, there are several registers that when read (e.g., via
'ethtool -d') may cause the chip to stall.
This patch corrects the registers read in such flows.

Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h   |   25 ++++++-------------
 .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c    |    2 +-
 2 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
index 3e4cff9..b926f58 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
@@ -401,11 +401,11 @@ static const struct reg_addr reg_addrs[] = {
 	{ 0x70000, 8, RI_ALL_ONLINE },
 	{ 0x70020, 8184, RI_ALL_OFFLINE },
 	{ 0x78000, 8192, RI_E3E3B0_OFFLINE },
-	{ 0x85000, 3, RI_ALL_ONLINE },
-	{ 0x8501c, 7, RI_ALL_ONLINE },
-	{ 0x85048, 1, RI_ALL_ONLINE },
-	{ 0x85200, 32, RI_ALL_ONLINE },
-	{ 0xb0000, 16384, RI_E1H_ONLINE },
+	{ 0x85000, 3, RI_ALL_OFFLINE },
+	{ 0x8501c, 7, RI_ALL_OFFLINE },
+	{ 0x85048, 1, RI_ALL_OFFLINE },
+	{ 0x85200, 32, RI_ALL_OFFLINE },
+	{ 0xb0000, 16384, RI_E1H_OFFLINE },
 	{ 0xc1000, 7, RI_ALL_ONLINE },
 	{ 0xc103c, 2, RI_E2E3E3B0_ONLINE },
 	{ 0xc1800, 2, RI_ALL_ONLINE },
@@ -581,17 +581,12 @@ static const struct reg_addr reg_addrs[] = {
 	{ 0x140188, 3, RI_E1E1HE2E3_ONLINE },
 	{ 0x140194, 13, RI_ALL_ONLINE },
 	{ 0x140200, 6, RI_E1E1HE2E3_ONLINE },
-	{ 0x140220, 4, RI_E2E3_ONLINE },
-	{ 0x140240, 4, RI_E2E3_ONLINE },
 	{ 0x140260, 4, RI_E2E3_ONLINE },
 	{ 0x140280, 4, RI_E2E3_ONLINE },
-	{ 0x1402a0, 4, RI_E2E3_ONLINE },
-	{ 0x1402c0, 4, RI_E2E3_ONLINE },
 	{ 0x1402e0, 2, RI_E2E3_ONLINE },
 	{ 0x1402e8, 2, RI_E2E3E3B0_ONLINE },
 	{ 0x1402f0, 9, RI_E2E3_ONLINE },
 	{ 0x140314, 44, RI_E3B0_ONLINE },
-	{ 0x1403d0, 70, RI_E3B0_ONLINE },
 	{ 0x144000, 4, RI_E1E1H_ONLINE },
 	{ 0x148000, 4, RI_E1E1H_ONLINE },
 	{ 0x14c000, 4, RI_E1E1H_ONLINE },
@@ -704,7 +699,6 @@ static const struct reg_addr reg_addrs[] = {
 	{ 0x180398, 1, RI_E2E3E3B0_ONLINE },
 	{ 0x1803a0, 5, RI_E2E3E3B0_ONLINE },
 	{ 0x1803b4, 2, RI_E3E3B0_ONLINE },
-	{ 0x180400, 1, RI_ALL_ONLINE },
 	{ 0x180404, 255, RI_E1E1H_OFFLINE },
 	{ 0x181000, 4, RI_ALL_ONLINE },
 	{ 0x181010, 1020, RI_ALL_OFFLINE },
@@ -800,9 +794,9 @@ static const struct reg_addr reg_addrs[] = {
 	{ 0x1b905c, 1, RI_E3E3B0_ONLINE },
 	{ 0x1b9064, 1, RI_E3B0_ONLINE },
 	{ 0x1b9080, 10, RI_E3B0_ONLINE },
-	{ 0x1b9400, 14, RI_E2E3E3B0_ONLINE },
-	{ 0x1b943c, 19, RI_E2E3E3B0_ONLINE },
-	{ 0x1b9490, 10, RI_E2E3E3B0_ONLINE },
+	{ 0x1b9400, 14, RI_E2E3E3B0_OFFLINE },
+	{ 0x1b943c, 19, RI_E2E3E3B0_OFFLINE },
+	{ 0x1b9490, 10, RI_E2E3E3B0_OFFLINE },
 	{ 0x1c0000, 2, RI_ALL_ONLINE },
 	{ 0x200000, 65, RI_ALL_ONLINE },
 	{ 0x20014c, 2, RI_E1HE2E3E3B0_ONLINE },
@@ -814,7 +808,6 @@ static const struct reg_addr reg_addrs[] = {
 	{ 0x200398, 1, RI_E2E3E3B0_ONLINE },
 	{ 0x2003a0, 1, RI_E2E3E3B0_ONLINE },
 	{ 0x2003a8, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x200400, 1, RI_ALL_ONLINE },
 	{ 0x200404, 255, RI_E1E1H_OFFLINE },
 	{ 0x202000, 4, RI_ALL_ONLINE },
 	{ 0x202010, 2044, RI_ALL_OFFLINE },
@@ -921,7 +914,6 @@ static const struct reg_addr reg_addrs[] = {
 	{ 0x280398, 1, RI_E2E3E3B0_ONLINE },
 	{ 0x2803a0, 1, RI_E2E3E3B0_ONLINE },
 	{ 0x2803a8, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x280400, 1, RI_ALL_ONLINE },
 	{ 0x280404, 255, RI_E1E1H_OFFLINE },
 	{ 0x282000, 4, RI_ALL_ONLINE },
 	{ 0x282010, 2044, RI_ALL_OFFLINE },
@@ -1031,7 +1023,6 @@ static const struct reg_addr reg_addrs[] = {
 	{ 0x300398, 1, RI_E2E3E3B0_ONLINE },
 	{ 0x3003a0, 1, RI_E2E3E3B0_ONLINE },
 	{ 0x3003a8, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x300400, 1, RI_ALL_ONLINE },
 	{ 0x300404, 255, RI_E1E1H_OFFLINE },
 	{ 0x302000, 4, RI_ALL_ONLINE },
 	{ 0x302010, 2044, RI_ALL_OFFLINE },
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index bbf4cf0..ebf40cd 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -775,7 +775,7 @@ static void bnx2x_get_regs(struct net_device *dev,
 	struct bnx2x *bp = netdev_priv(dev);
 	struct dump_hdr dump_hdr = {0};
 
-	regs->version = 0;
+	regs->version = 1;
 	memset(p, 0, regs->len);
 
 	if (!netif_running(bp->dev))
-- 
1.7.9.rc2

^ permalink raw reply related

* [net PATCH v2 2/7] bnx2x: fix stats copying logic
From: Yuval Mintz @ 2012-09-11 14:34 UTC (permalink / raw)
  To: davem, netdev; +Cc: Yuval Mintz, Eilon Greenstein
In-Reply-To: <1347374054-16730-1-git-send-email-yuvalmin@broadcom.com>

FW needs the driver statistics for management. Current logic is broken
in that the function that gathers the port statistics does not copy
its own statistics to a place where the FW can use it.
This patch causes every function that can pass statistics to the FW to
do so.

Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c |    7 +++++--
 1 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index d848dc9..a1d0446 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -101,6 +101,11 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp)
 	if (CHIP_REV_IS_SLOW(bp))
 		return;
 
+	/* Update MCP's statistics if possible */
+	if (bp->func_stx)
+		memcpy(bnx2x_sp(bp, func_stats), &bp->func_stats,
+		       sizeof(bp->func_stats));
+
 	/* loader */
 	if (bp->executer_idx) {
 		int loader_idx = PMF_DMAE_C(bp);
@@ -128,8 +133,6 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp)
 
 	} else if (bp->func_stx) {
 		*stats_comp = 0;
-		memcpy(bnx2x_sp(bp, func_stats), &bp->func_stats,
-		       sizeof(bp->func_stats));
 		bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
 	}
 }
-- 
1.7.9.rc2

^ permalink raw reply related

* [net PATCH v2 0/7] bnx2x: bug fixes for net
From: Yuval Mintz @ 2012-09-11 14:34 UTC (permalink / raw)
  To: davem, netdev; +Cc: Yuval Mintz

Hi Dave,

This patch series contains various bug fixes for the bnx2x driver -
about half of them are link related, while the other either add
code missing in previous git commits or fix erroneous flows.

Changes from v1:
----------------
  -  Patch 06/07 - update returned version to 1 (from 0), when changing
     the registered dumped. Corrected patch description.

Please consider applying this patch series to 'net'.

Thanks,
Yuval Mintz

^ permalink raw reply

* [net PATCH v2 5/7] bnx2x: correct advertisement of pause capabilities
From: Yuval Mintz @ 2012-09-11 14:34 UTC (permalink / raw)
  To: davem, netdev; +Cc: Yaniv Rosner, Yuval Mintz, Eilon Greenstein
In-Reply-To: <1347374054-16730-1-git-send-email-yuvalmin@broadcom.com>

From: Yaniv Rosner <yaniv.rosner@broadcom.com>

This patch propagates users' requested flow-control into the link layer,
which will later be used to advertise this flow-control for auto-negotiation
(until now these values were ignored).

Signed-off-by: Yaniv Rosner <yaniv.rosner@broadcom.com>
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c    |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index c37a68d..bbf4cf0 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -1587,6 +1587,12 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
 			bp->link_params.req_flow_ctrl[cfg_idx] =
 				BNX2X_FLOW_CTRL_AUTO;
 		}
+		bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_NONE;
+		if (epause->rx_pause)
+			bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_RX;
+
+		if (epause->tx_pause)
+			bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_TX;
 	}
 
 	DP(BNX2X_MSG_ETHTOOL,
-- 
1.7.9.rc2

^ permalink raw reply related

* [net PATCH v2 4/7] bnx2x: display the correct duplex value
From: Yuval Mintz @ 2012-09-11 14:34 UTC (permalink / raw)
  To: davem, netdev; +Cc: Yaniv Rosner, Yuval Mintz, Eilon Greenstein
In-Reply-To: <1347374054-16730-1-git-send-email-yuvalmin@broadcom.com>

From: Yaniv Rosner <yaniv.rosner@broadcom.com>

Prior to this fix, the driver reported the chip's active duplex state
is always 'full', even if using half-duplex mode.

Signed-off-by: Yaniv Rosner <yaniv.rosner@broadcom.com>
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index 40a7b8d..b046beb 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -5434,7 +5434,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
 		switch (speed_mask) {
 		case GP_STATUS_10M:
 			vars->line_speed = SPEED_10;
-			if (vars->duplex == DUPLEX_FULL)
+			if (is_duplex == DUPLEX_FULL)
 				vars->link_status |= LINK_10TFD;
 			else
 				vars->link_status |= LINK_10THD;
@@ -5442,7 +5442,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
 
 		case GP_STATUS_100M:
 			vars->line_speed = SPEED_100;
-			if (vars->duplex == DUPLEX_FULL)
+			if (is_duplex == DUPLEX_FULL)
 				vars->link_status |= LINK_100TXFD;
 			else
 				vars->link_status |= LINK_100TXHD;
@@ -5451,7 +5451,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
 		case GP_STATUS_1G:
 		case GP_STATUS_1G_KX:
 			vars->line_speed = SPEED_1000;
-			if (vars->duplex == DUPLEX_FULL)
+			if (is_duplex == DUPLEX_FULL)
 				vars->link_status |= LINK_1000TFD;
 			else
 				vars->link_status |= LINK_1000THD;
@@ -5459,7 +5459,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
 
 		case GP_STATUS_2_5G:
 			vars->line_speed = SPEED_2500;
-			if (vars->duplex == DUPLEX_FULL)
+			if (is_duplex == DUPLEX_FULL)
 				vars->link_status |= LINK_2500TFD;
 			else
 				vars->link_status |= LINK_2500THD;
@@ -5533,6 +5533,7 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
 
 	if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
 		if (SINGLE_MEDIA_DIRECT(params)) {
+			vars->duplex = duplex;
 			bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
 			if (phy->req_line_speed == SPEED_AUTO_NEG)
 				bnx2x_xgxs_an_resolve(phy, params, vars,
@@ -5627,6 +5628,7 @@ static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
 					LINK_STATUS_PARALLEL_DETECTION_USED;
 			}
 			bnx2x_ext_phy_resolve_fc(phy, params, vars);
+			vars->duplex = duplex;
 		}
 	}
 
-- 
1.7.9.rc2

^ permalink raw reply related

* [net PATCH v2 3/7] bnx2x: prevent timeouts when using PFC
From: Yuval Mintz @ 2012-09-11 14:34 UTC (permalink / raw)
  To: davem, netdev; +Cc: Yaniv Rosner, Yuval Mintz, Eilon Greenstein
In-Reply-To: <1347374054-16730-1-git-send-email-yuvalmin@broadcom.com>

From: Yaniv Rosner <yaniv.rosner@broadcom.com>

Prevent updating the xmac PFC configuration when using a link speed
slower than 10G -the umac block is responsible for 1G or slower connections,
therefore it is possible the xmac block is reset when connection is slower.

Signed-off-by: Yaniv Rosner <yaniv.rosner@broadcom.com>
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index f4beb46..40a7b8d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -2667,9 +2667,11 @@ int bnx2x_update_pfc(struct link_params *params,
 		return bnx2x_status;
 
 	DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
-	if (CHIP_IS_E3(bp))
-		bnx2x_update_pfc_xmac(params, vars, 0);
-	else {
+
+	if (CHIP_IS_E3(bp)) {
+		if (vars->mac_type == MAC_TYPE_XMAC)
+			bnx2x_update_pfc_xmac(params, vars, 0);
+	} else {
 		val = REG_RD(bp, MISC_REG_RESET_REG_2);
 		if ((val &
 		     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
-- 
1.7.9.rc2

^ permalink raw reply related

* [net PATCH v2 1/7] bnx2x: Avoid sending multiple statistics queries
From: Yuval Mintz @ 2012-09-11 14:34 UTC (permalink / raw)
  To: davem, netdev; +Cc: Dmitry Kravkov, Yuval Mintz, Eilon Greenstein
In-Reply-To: <1347374054-16730-1-git-send-email-yuvalmin@broadcom.com>

From: Dmitry Kravkov <dmitry@broadcom.com>

During traffic when DCB is enabled, it is possible for multiple instances
of statistics queries to be sent to the chip - this may cause the FW to assert.

This patch prevents the sending of an additional instance of statistics query
while the previous query hasn't completed.

Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 332db64..d848dc9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -1151,9 +1151,11 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 	if (bp->port.pmf)
 		bnx2x_hw_stats_update(bp);
 
-	if (bnx2x_storm_stats_update(bp) && (bp->stats_pending++ == 3)) {
-		BNX2X_ERR("storm stats were not updated for 3 times\n");
-		bnx2x_panic();
+	if (bnx2x_storm_stats_update(bp)) {
+		if (bp->stats_pending++ == 3) {
+			BNX2X_ERR("storm stats were not updated for 3 times\n");
+			bnx2x_panic();
+		}
 		return;
 	}
 
-- 
1.7.9.rc2

^ permalink raw reply related

* [V3 PATCH 8/9] cxgb4: Chelsio FCoE offload driver submission (cxgb4 common header updates).
From: Naresh Kumar Inna @ 2012-09-11 14:39 UTC (permalink / raw)
  To: JBottomley, linux-scsi, dm, leedom; +Cc: netdev, naresh, chethan
In-Reply-To: <1347374347-3852-1-git-send-email-naresh@chelsio.com>

This patch contains updates to firmware/hardware header files shared
between csiostor and cxgb4/cxgb4vf, and the resulting changes to the cxgb4
source files.

Signed-off-by: Naresh Kumar Inna <naresh@chelsio.com>
---
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |    2 +-
 drivers/net/ethernet/chelsio/cxgb4/sge.c        |   10 +-
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.c      |   16 ++--
 drivers/net/ethernet/chelsio/cxgb4/t4_msg.h     |    1 +
 drivers/net/ethernet/chelsio/cxgb4/t4_regs.h    |   69 ++++++++++++++-
 drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h   |  104 +++++++++++++++++++---
 6 files changed, 170 insertions(+), 32 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 5ed49af..b56d96c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3102,7 +3102,7 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
 	memset(c, 0, sizeof(*c));
 	c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
 			       FW_CMD_REQUEST | FW_CMD_READ);
-	c->retval_len16 = htonl(FW_LEN16(*c));
+	c->cfvalid_to_len16 = htonl(FW_LEN16(*c));
 	ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), c);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index d49933e..121b1e9 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -455,7 +455,7 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
 {
 	if (q->pend_cred >= 8) {
 		wmb();
-		t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), DBPRIO |
+		t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), DBPRIO(1) |
 			     QID(q->cntxt_id) | PIDX(q->pend_cred / 8));
 		q->pend_cred &= 7;
 	}
@@ -2020,10 +2020,10 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
 			goto fl_nomem;
 
 		flsz = fl->size / 8 + STAT_LEN / sizeof(struct tx_desc);
-		c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN |
+		c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN(1) |
 					    FW_IQ_CMD_FL0FETCHRO(1) |
 					    FW_IQ_CMD_FL0DATARO(1) |
-					    FW_IQ_CMD_FL0PADEN);
+					    FW_IQ_CMD_FL0PADEN(1));
 		c.fl0dcaen_to_fl0cidxfthresh = htons(FW_IQ_CMD_FL0FBMIN(2) |
 				FW_IQ_CMD_FL0FBMAX(3));
 		c.fl0size = htons(flsz);
@@ -2416,10 +2416,10 @@ void t4_sge_init(struct adapter *adap)
 	unsigned int fl_align_log = ilog2(FL_ALIGN);
 
 	t4_set_reg_field(adap, SGE_CONTROL, PKTSHIFT_MASK |
-			 INGPADBOUNDARY_MASK | EGRSTATUSPAGESIZE,
+			 INGPADBOUNDARY_MASK | EGRSTATUSPAGESIZE(1),
 			 INGPADBOUNDARY(fl_align_log - 5) | PKTSHIFT(2) |
 			 RXPKTCPLMODE |
-			 (STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0));
+			 (STAT_LEN == 128 ? EGRSTATUSPAGESIZE(1) : 0));
 
 	/*
 	 * Set up to drop DOORBELL writes when the DOORBELL FIFO overflows
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index fa947df..a943faa 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -456,12 +456,12 @@ static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
 
 	if (!byte_cnt || byte_cnt > 4)
 		return -EINVAL;
-	if (t4_read_reg(adapter, SF_OP) & BUSY)
+	if (t4_read_reg(adapter, SF_OP) & SF_BUSY)
 		return -EBUSY;
 	cont = cont ? SF_CONT : 0;
 	lock = lock ? SF_LOCK : 0;
 	t4_write_reg(adapter, SF_OP, lock | cont | BYTECNT(byte_cnt - 1));
-	ret = t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5);
+	ret = t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5);
 	if (!ret)
 		*valp = t4_read_reg(adapter, SF_DATA);
 	return ret;
@@ -484,14 +484,14 @@ static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
 {
 	if (!byte_cnt || byte_cnt > 4)
 		return -EINVAL;
-	if (t4_read_reg(adapter, SF_OP) & BUSY)
+	if (t4_read_reg(adapter, SF_OP) & SF_BUSY)
 		return -EBUSY;
 	cont = cont ? SF_CONT : 0;
 	lock = lock ? SF_LOCK : 0;
 	t4_write_reg(adapter, SF_DATA, val);
 	t4_write_reg(adapter, SF_OP, lock |
 		     cont | BYTECNT(byte_cnt - 1) | OP_WR);
-	return t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5);
+	return t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5);
 }
 
 /**
@@ -1972,14 +1972,14 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
 		t4_write_reg(adap, EPIO_REG(DATA0), mask0);
 		t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i) | EPIOWR);
 		t4_read_reg(adap, EPIO_REG(OP));                /* flush */
-		if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY)
+		if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY)
 			return -ETIMEDOUT;
 
 		/* write CRC */
 		t4_write_reg(adap, EPIO_REG(DATA0), crc);
 		t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i + 32) | EPIOWR);
 		t4_read_reg(adap, EPIO_REG(OP));                /* flush */
-		if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY)
+		if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY)
 			return -ETIMEDOUT;
 	}
 #undef EPIO_REG
@@ -2118,7 +2118,7 @@ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
 	struct fw_hello_cmd c;
 
 	INIT_CMD(c, HELLO, WRITE);
-	c.err_to_mbasyncnot = htonl(
+	c.err_to_clearinit = htonl(
 		FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) |
 		FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) |
 		FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox : 0xff) |
@@ -2126,7 +2126,7 @@ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
 
 	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
 	if (ret == 0 && state) {
-		u32 v = ntohl(c.err_to_mbasyncnot);
+		u32 v = ntohl(c.err_to_clearinit);
 		if (v & FW_HELLO_CMD_INIT)
 			*state = DEV_STATE_INIT;
 		else if (v & FW_HELLO_CMD_ERR)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index eb71b82..b760808 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
@@ -658,6 +658,7 @@ struct ulptx_sgl {
 	__be32 cmd_nsge;
 #define ULPTX_CMD(x) ((x) << 24)
 #define ULPTX_NSGE(x) ((x) << 0)
+#define ULPTX_MORE (1U << 23)
 	__be32 len0;
 	__be64 addr0;
 	struct ulptx_sge_pair sge[0];
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index 111fc32..6bace75 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -67,7 +67,7 @@
 #define  QID_MASK    0xffff8000U
 #define  QID_SHIFT   15
 #define  QID(x)      ((x) << QID_SHIFT)
-#define  DBPRIO      0x00004000U
+#define  DBPRIO(x)   ((x) << 14)
 #define  PIDX_MASK   0x00003fffU
 #define  PIDX_SHIFT  0
 #define  PIDX(x)     ((x) << PIDX_SHIFT)
@@ -89,7 +89,7 @@
 #define SGE_CONTROL 0x1008
 #define  DCASYSTYPE             0x00080000U
 #define  RXPKTCPLMODE           0x00040000U
-#define  EGRSTATUSPAGESIZE      0x00020000U
+#define  EGRSTATUSPAGESIZE(x)   ((x) << 17)
 #define  PKTSHIFT_MASK          0x00001c00U
 #define  PKTSHIFT_SHIFT         10
 #define  PKTSHIFT(x)            ((x) << PKTSHIFT_SHIFT)
@@ -111,6 +111,13 @@
 #define  HOSTPAGESIZEPF0_MASK   0x0000000fU
 #define  HOSTPAGESIZEPF0_SHIFT  0
 #define  HOSTPAGESIZEPF0(x)     ((x) << HOSTPAGESIZEPF0_SHIFT)
+#define  HOSTPAGESIZEPF1(x)     ((x) << 4)
+#define  HOSTPAGESIZEPF2(x)     ((x) << 8)
+#define  HOSTPAGESIZEPF3(x)     ((x) << 12)
+#define  HOSTPAGESIZEPF4(x)     ((x) << 16)
+#define  HOSTPAGESIZEPF5(x)     ((x) << 20)
+#define  HOSTPAGESIZEPF6(x)     ((x) << 24)
+#define  HOSTPAGESIZEPF7(x)     ((x) << 28)
 
 #define SGE_EGRESS_QUEUES_PER_PAGE_PF 0x1010
 #define  QUEUESPERPAGEPF0_MASK   0x0000000fU
@@ -155,6 +162,14 @@
 #define SGE_INT_ENABLE3 0x1040
 #define SGE_FL_BUFFER_SIZE0 0x1044
 #define SGE_FL_BUFFER_SIZE1 0x1048
+#define SGE_FL_BUFFER_SIZE2 0x104c
+#define SGE_FL_BUFFER_SIZE3 0x1050
+#define SGE_FL_BUFFER_SIZE4 0x1054
+#define SGE_FL_BUFFER_SIZE5 0x1058
+#define SGE_FL_BUFFER_SIZE6 0x105c
+#define SGE_FL_BUFFER_SIZE7 0x1060
+#define SGE_FL_BUFFER_SIZE8 0x1064
+
 #define SGE_INGRESS_RX_THRESHOLD 0x10a0
 #define  THRESHOLD_0_MASK   0x3f000000U
 #define  THRESHOLD_0_SHIFT  24
@@ -173,6 +188,17 @@
 #define  THRESHOLD_3(x)     ((x) << THRESHOLD_3_SHIFT)
 #define  THRESHOLD_3_GET(x) (((x) & THRESHOLD_3_MASK) >> THRESHOLD_3_SHIFT)
 
+#define SGE_DBFIFO_STATUS 0x10a4
+#define  HP_INT_THRESH_SHIFT 28
+#define  HP_INT_THRESH_MASK  0xfU
+#define  HP_INT_THRESH(x)    ((x) << HP_INT_THRESH_SHIFT)
+#define  LP_INT_THRESH_SHIFT 12
+#define  LP_INT_THRESH_MASK  0xfU
+#define  LP_INT_THRESH(x)    ((x) << LP_INT_THRESH_SHIFT)
+
+#define SGE_DOORBELL_CONTROL 0x10a8
+#define  ENABLE_DROP        (1 << 13)
+
 #define SGE_TIMER_VALUE_0_AND_1 0x10b8
 #define  TIMERVALUE0_MASK   0xffff0000U
 #define  TIMERVALUE0_SHIFT  16
@@ -184,7 +210,25 @@
 #define  TIMERVALUE1_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT)
 
 #define SGE_TIMER_VALUE_2_AND_3 0x10bc
+#define  TIMERVALUE2_MASK   0xffff0000U
+#define  TIMERVALUE2_SHIFT  16
+#define  TIMERVALUE2(x)     ((x) << TIMERVALUE0_SHIFT)
+#define  TIMERVALUE2_GET(x) (((x) & TIMERVALUE0_MASK) >> TIMERVALUE0_SHIFT)
+#define  TIMERVALUE3_MASK   0x0000ffffU
+#define  TIMERVALUE3_SHIFT  0
+#define  TIMERVALUE3(x)     ((x) << TIMERVALUE1_SHIFT)
+#define  TIMERVALUE3_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT)
+
 #define SGE_TIMER_VALUE_4_AND_5 0x10c0
+#define  TIMERVALUE4_MASK   0xffff0000U
+#define  TIMERVALUE4_SHIFT  16
+#define  TIMERVALUE4(x)     ((x) << TIMERVALUE0_SHIFT)
+#define  TIMERVALUE4_GET(x) (((x) & TIMERVALUE0_MASK) >> TIMERVALUE0_SHIFT)
+#define  TIMERVALUE5_MASK   0x0000ffffU
+#define  TIMERVALUE5_SHIFT  0
+#define  TIMERVALUE5(x)     ((x) << TIMERVALUE1_SHIFT)
+#define  TIMERVALUE5_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT)
+
 #define SGE_DEBUG_INDEX 0x10cc
 #define SGE_DEBUG_DATA_HIGH 0x10d0
 #define SGE_DEBUG_DATA_LOW 0x10d4
@@ -243,6 +287,10 @@
 #define M_HP_INT_THRESH 0xfU
 #define M_LP_INT_THRESH 0xfU
 
+#define PCIE_PF_CFG 0x40
+#define  AIVEC(x)	((x) << 4)
+#define  AIVEC_MASK	0x3ffU
+
 #define PCIE_PF_CLI 0x44
 #define PCIE_INT_CAUSE 0x3004
 #define  UNXSPLCPLERR  0x20000000U
@@ -287,6 +335,15 @@
 #define  WINDOW(x)       ((x) << WINDOW_SHIFT)
 #define PCIE_MEM_ACCESS_OFFSET 0x306c
 
+#define PCIE_FW 0x30b8
+#define  PCIE_FW_ERR		0x80000000U
+#define  PCIE_FW_INIT		0x40000000U
+#define  PCIE_FW_HALT		0x20000000U
+#define  PCIE_FW_MASTER_VLD	0x00008000U
+#define  PCIE_FW_MASTER(x)	((x) << 12)
+#define  PCIE_FW_MASTER_MASK	0x7
+#define  PCIE_FW_MASTER_GET(x)	(((x) >> 12) & PCIE_FW_MASTER_MASK)
+
 #define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908
 #define  RNPP 0x80000000U
 #define  RPCP 0x20000000U
@@ -384,6 +441,8 @@
 #define EDC_1_BASE_ADDR 0x7980
 
 #define CIM_BOOT_CFG 0x7b00
+#define  UPCRST		0x00000001U
+
 #define  BOOTADDR_MASK 0xffffff00U
 
 #define CIM_PF_MAILBOX_DATA 0x240
@@ -395,6 +454,9 @@
 #define  MBOWNER(x)     ((x) << MBOWNER_SHIFT)
 #define  MBOWNER_GET(x) (((x) & MBOWNER_MASK) >> MBOWNER_SHIFT)
 
+#define CIM_PF_HOST_INT_ENABLE 0x288
+#define  MBMSGRDYINTEN(x) ((x) << 19)
+
 #define CIM_PF_HOST_INT_CAUSE 0x28c
 #define  MBMSGRDYINT 0x00080000U
 
@@ -825,7 +887,7 @@
 
 #define SF_DATA 0x193f8
 #define SF_OP 0x193fc
-#define  BUSY          0x80000000U
+#define  SF_BUSY       0x80000000U
 #define  SF_LOCK       0x00000010U
 #define  SF_CONT       0x00000008U
 #define  BYTECNT_MASK  0x00000006U
@@ -884,6 +946,7 @@
 #define  I2CM       0x00000002U
 #define  CIM        0x00000001U
 
+#define PL_INT_ENABLE 0x19410
 #define PL_INT_MAP0 0x19414
 #define PL_RST 0x19428
 #define  PIORST     0x00000002U
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index ad53f79..034ca39 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -68,6 +68,7 @@ struct fw_wr_hdr {
 };
 
 #define FW_WR_OP(x)	 ((x) << 24)
+#define FW_WR_OP_GET(x)	 (((x) >> 24) & 0xff)
 #define FW_WR_ATOMIC(x)	 ((x) << 23)
 #define FW_WR_FLUSH(x)   ((x) << 22)
 #define FW_WR_COMPL(x)   ((x) << 21)
@@ -155,6 +156,9 @@ struct fw_eth_tx_pkt_vm_wr {
 
 #define FW_CMD_MAX_TIMEOUT 3000
 
+#define FW_CMD_HELLO_TIMEOUT (3 * FW_CMD_MAX_TIMEOUT)
+#define FW_CMD_HELLO_RETRIES 3
+
 enum fw_cmd_opcodes {
 	FW_LDST_CMD                    = 0x01,
 	FW_RESET_CMD                   = 0x03,
@@ -209,6 +213,7 @@ struct fw_cmd_hdr {
 #define FW_CMD_OP(x)		((x) << 24)
 #define FW_CMD_OP_GET(x)        (((x) >> 24) & 0xff)
 #define FW_CMD_REQUEST          (1U << 23)
+#define FW_CMD_REQUEST_GET(x)   (((x) >> 23) & 0x1)
 #define FW_CMD_READ		(1U << 22)
 #define FW_CMD_WRITE		(1U << 21)
 #define FW_CMD_EXEC		(1U << 20)
@@ -216,6 +221,7 @@ struct fw_cmd_hdr {
 #define FW_CMD_RETVAL(x)	((x) << 8)
 #define FW_CMD_RETVAL_GET(x)	(((x) >> 8) & 0xff)
 #define FW_CMD_LEN16(x)         ((x) << 0)
+#define FW_LEN16(fw_struct)	FW_CMD_LEN16(sizeof(fw_struct) / 16)
 
 enum fw_ldst_addrspc {
 	FW_LDST_ADDRSPC_FIRMWARE  = 0x0001,
@@ -228,7 +234,8 @@ enum fw_ldst_addrspc {
 	FW_LDST_ADDRSPC_TP_MIB    = 0x0012,
 	FW_LDST_ADDRSPC_MDIO      = 0x0018,
 	FW_LDST_ADDRSPC_MPS       = 0x0020,
-	FW_LDST_ADDRSPC_FUNC      = 0x0028
+	FW_LDST_ADDRSPC_FUNC      = 0x0028,
+	FW_LDST_ADDRSPC_FUNC_PCIE = 0x0029,
 };
 
 enum fw_ldst_mps_fid {
@@ -290,6 +297,16 @@ struct fw_ldst_cmd {
 			__be64 data0;
 			__be64 data1;
 		} func;
+		struct fw_ldst_pcie {
+			u8 ctrl_to_fn;
+			u8 bnum;
+			u8 r;
+			u8 ext_r;
+			u8 select_naccess;
+			u8 pcie_fn;
+			__be16 nset_pkd;
+			__be32 data[12];
+		} pcie;
 	} u;
 };
 
@@ -299,24 +316,42 @@ struct fw_ldst_cmd {
 #define FW_LDST_CMD_FID(x)	((x) << 15)
 #define FW_LDST_CMD_CTL(x)	((x) << 0)
 #define FW_LDST_CMD_RPLCPF(x)	((x) << 0)
+#define FW_LDST_CMD_LC		(1U << 4)
+#define FW_LDST_CMD_NACCESS(x)	((x) << 0)
+#define FW_LDST_CMD_FN(x)	((x) << 0)
 
 struct fw_reset_cmd {
 	__be32 op_to_write;
 	__be32 retval_len16;
 	__be32 val;
-	__be32 r3;
+	__be32 halt_pkd;
+};
+
+#define FW_RESET_CMD_HALT	(1U << 31)
+
+enum {
+	FW_HELLO_CMD_STAGE_OS		= 0,
+	FW_HELLO_CMD_STAGE_PREOS0	= 1,
+	FW_HELLO_CMD_STAGE_PREOS1	= 2,
+	FW_HELLO_CMD_STAGE_POSTOS	= 3,
 };
 
 struct fw_hello_cmd {
 	__be32 op_to_write;
 	__be32 retval_len16;
-	__be32 err_to_mbasyncnot;
-#define FW_HELLO_CMD_ERR	    (1U << 31)
-#define FW_HELLO_CMD_INIT	    (1U << 30)
-#define FW_HELLO_CMD_MASTERDIS(x)   ((x) << 29)
-#define FW_HELLO_CMD_MASTERFORCE(x) ((x) << 28)
-#define FW_HELLO_CMD_MBMASTER(x)    ((x) << 24)
-#define FW_HELLO_CMD_MBASYNCNOT(x)  ((x) << 20)
+	__be32 err_to_clearinit;
+#define FW_HELLO_CMD_ERR	        (1U << 31)
+#define FW_HELLO_CMD_INIT	        (1U << 30)
+#define FW_HELLO_CMD_MASTERDIS(x)	((x) << 29)
+#define FW_HELLO_CMD_MASTERFORCE(x)	((x) << 28)
+#define FW_HELLO_CMD_MBMASTER_MASK	0xf
+#define FW_HELLO_CMD_MBMASTER(x)	((x) << 24)
+#define FW_HELLO_CMD_MBMASTER_GET(x)	\
+		(((x) >> 24) & FW_HELLO_CMD_MBMASTER_MASK)
+#define FW_HELLO_CMD_MBASYNCNOTINT(x)	((x) << 23)
+#define FW_HELLO_CMD_MBASYNCNOT(x)	((x) << 20)
+#define FW_HELLO_CMD_STAGE(x)		((x) << 17)
+#define FW_HELLO_CMD_CLEARINIT		(1U << 16)
 	__be32 fwrev;
 };
 
@@ -399,11 +434,20 @@ enum fw_caps_config_iscsi {
 enum fw_caps_config_fcoe {
 	FW_CAPS_CONFIG_FCOE_INITIATOR	= 0x00000001,
 	FW_CAPS_CONFIG_FCOE_TARGET	= 0x00000002,
+	FW_CAPS_CONFIG_FCOE_CTRL_OFLD	= 0x00000004,
+};
+
+enum fw_memtype_cf {
+	FW_MEMTYPE_CF_EDC0		= 0x0,
+	FW_MEMTYPE_CF_EDC1		= 0x1,
+	FW_MEMTYPE_CF_EXTMEM		= 0x2,
+	FW_MEMTYPE_CF_FLASH		= 0x4,
+	FW_MEMTYPE_CF_INTERNAL		= 0x5,
 };
 
 struct fw_caps_config_cmd {
 	__be32 op_to_write;
-	__be32 retval_len16;
+	__be32 cfvalid_to_len16;
 	__be32 r2;
 	__be32 hwmbitmap;
 	__be16 nbmcaps;
@@ -416,10 +460,15 @@ struct fw_caps_config_cmd {
 	__be16 r4;
 	__be16 iscsicaps;
 	__be16 fcoecaps;
-	__be32 r5;
-	__be64 r6;
+	__be32 cfcsum;
+	__be32 finiver;
+	__be32 finicsum;
 };
 
+#define FW_CAPS_CONFIG_CMD_CFVALID (1U << 27)
+#define FW_CAPS_CONFIG_CMD_MEMTYPE_CF(x) ((x) << 24)
+#define FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(x) ((x) << 16)
+
 /*
  * params command mnemonics
  */
@@ -451,6 +500,7 @@ enum fw_params_param_dev {
 	FW_PARAMS_PARAM_DEV_INTVER_FCOE = 0x0A,
 	FW_PARAMS_PARAM_DEV_FWREV = 0x0B,
 	FW_PARAMS_PARAM_DEV_TPREV = 0x0C,
+	FW_PARAMS_PARAM_DEV_CF = 0x0D,
 };
 
 /*
@@ -511,6 +561,9 @@ enum fw_params_param_dmaq {
 #define FW_PARAMS_PARAM_Z(x)   ((x) << 0)
 #define FW_PARAMS_PARAM_XYZ(x) ((x) << 0)
 #define FW_PARAMS_PARAM_YZ(x)  ((x) << 0)
+#define FW_PARAMS_PARAM_X_GET(x) (((x) >> 16) & 0xff)
+#define FW_PARAMS_PARAM_Y_GET(x) (((x) >> 8) & 0xff)
+#define FW_PARAMS_PARAM_Z_GET(x) (((x) >> 0) & 0xff)
 
 struct fw_params_cmd {
 	__be32 op_to_vfn;
@@ -648,8 +701,8 @@ struct fw_iq_cmd {
 #define FW_IQ_CMD_FL0FETCHRO(x) ((x) << 6)
 #define FW_IQ_CMD_FL0HOSTFCMODE(x) ((x) << 4)
 #define FW_IQ_CMD_FL0CPRIO(x) ((x) << 3)
-#define FW_IQ_CMD_FL0PADEN (1U << 2)
-#define FW_IQ_CMD_FL0PACKEN (1U << 1)
+#define FW_IQ_CMD_FL0PADEN(x) ((x) << 2)
+#define FW_IQ_CMD_FL0PACKEN(x) ((x) << 1)
 #define FW_IQ_CMD_FL0CONGEN (1U << 0)
 
 #define FW_IQ_CMD_FL0DCAEN(x) ((x) << 15)
@@ -1137,6 +1190,14 @@ enum fw_port_dcb_cfg_rc {
 	FW_PORT_DCB_CFG_ERROR	= 0x1
 };
 
+enum fw_port_dcb_type {
+	FW_PORT_DCB_TYPE_PGID		= 0x00,
+	FW_PORT_DCB_TYPE_PGRATE		= 0x01,
+	FW_PORT_DCB_TYPE_PRIORATE	= 0x02,
+	FW_PORT_DCB_TYPE_PFC		= 0x03,
+	FW_PORT_DCB_TYPE_APP_ID		= 0x04,
+};
+
 struct fw_port_cmd {
 	__be32 op_to_portid;
 	__be32 action_to_len16;
@@ -1204,6 +1265,7 @@ struct fw_port_cmd {
 #define FW_PORT_CMD_TXIPG(x) ((x) << 19)
 
 #define FW_PORT_CMD_LSTATUS (1U << 31)
+#define FW_PORT_CMD_LSTATUS_GET(x) (((x) >> 31) & 0x1)
 #define FW_PORT_CMD_LSPEED(x) ((x) << 24)
 #define FW_PORT_CMD_LSPEED_GET(x) (((x) >> 24) & 0x3f)
 #define FW_PORT_CMD_TXPAUSE (1U << 23)
@@ -1252,6 +1314,9 @@ enum fw_port_module_type {
 	FW_PORT_MOD_TYPE_TWINAX_PASSIVE,
 	FW_PORT_MOD_TYPE_TWINAX_ACTIVE,
 	FW_PORT_MOD_TYPE_LRM,
+	FW_PORT_MOD_TYPE_ERROR		= FW_PORT_CMD_MODTYPE_MASK - 3,
+	FW_PORT_MOD_TYPE_UNKNOWN	= FW_PORT_CMD_MODTYPE_MASK - 2,
+	FW_PORT_MOD_TYPE_NOTSUPPORTED	= FW_PORT_CMD_MODTYPE_MASK - 1,
 
 	FW_PORT_MOD_TYPE_NONE = FW_PORT_CMD_MODTYPE_MASK
 };
@@ -1613,7 +1678,11 @@ struct fw_hdr {
 	u8 intfver_iscsi;
 	u8 intfver_fcoe;
 	u8 reserved2;
-	__be32  reserved3[27];
+	__u32   reserved3;
+	__u32   reserved4;
+	__u32   reserved5;
+	__be32  flags;
+	__be32  reserved6[23];
 };
 
 #define FW_HDR_FW_VER_MAJOR_GET(x) (((x) >> 24) & 0xff)
@@ -1621,6 +1690,11 @@ struct fw_hdr {
 #define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff)
 #define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff)
 
+enum fw_hdr_flags {
+	FW_HDR_FLAGS_RESET_HALT	= 0x00000001,
+};
+
+
 #define S_FW_CMD_OP 24
 #define V_FW_CMD_OP(x) ((x) << S_FW_CMD_OP)
 
-- 
1.7.1


^ permalink raw reply related

* [V3 PATCH 7/9] csiostor: Chelsio FCoE offload driver submission (headers part 2).
From: Naresh Kumar Inna @ 2012-09-11 14:39 UTC (permalink / raw)
  To: JBottomley, linux-scsi, dm, leedom; +Cc: netdev, naresh, chethan
In-Reply-To: <1347374347-3852-1-git-send-email-naresh@chelsio.com>

This patch contains the second set of the header files for csiostor driver.

Signed-off-by: Naresh Kumar Inna <naresh@chelsio.com>
---
 drivers/scsi/csiostor/csio_lnode.h |  255 ++++++++++++++++++
 drivers/scsi/csiostor/csio_mb.h    |  278 +++++++++++++++++++
 drivers/scsi/csiostor/csio_rnode.h |  141 ++++++++++
 drivers/scsi/csiostor/csio_scsi.h  |  342 ++++++++++++++++++++++++
 drivers/scsi/csiostor/csio_wr.h    |  512 ++++++++++++++++++++++++++++++++++++
 5 files changed, 1528 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/csiostor/csio_lnode.h
 create mode 100644 drivers/scsi/csiostor/csio_mb.h
 create mode 100644 drivers/scsi/csiostor/csio_rnode.h
 create mode 100644 drivers/scsi/csiostor/csio_scsi.h
 create mode 100644 drivers/scsi/csiostor/csio_wr.h

diff --git a/drivers/scsi/csiostor/csio_lnode.h b/drivers/scsi/csiostor/csio_lnode.h
new file mode 100644
index 0000000..8d84988
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_lnode.h
@@ -0,0 +1,255 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_LNODE_H__
+#define __CSIO_LNODE_H__
+
+#include <linux/kref.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <scsi/fc/fc_els.h>
+
+
+#include "csio_defs.h"
+#include "csio_hw.h"
+
+#define CSIO_FCOE_MAX_NPIV	128
+#define CSIO_FCOE_MAX_RNODES	2048
+
+/* FDMI port attribute unknown speed */
+#define CSIO_HBA_PORTSPEED_UNKNOWN	0x8000
+
+extern int csio_fcoe_rnodes;
+extern int csio_fdmi_enable;
+
+/* State machine evets */
+enum csio_ln_ev {
+	CSIO_LNE_NONE = (uint32_t)0,
+	CSIO_LNE_LINKUP,
+	CSIO_LNE_FAB_INIT_DONE,
+	CSIO_LNE_LINK_DOWN,
+	CSIO_LNE_DOWN_LINK,
+	CSIO_LNE_LOGO,
+	CSIO_LNE_CLOSE,
+	CSIO_LNE_MAX_EVENT,
+};
+
+
+struct csio_fcf_info {
+	struct list_head	list;
+	uint8_t			priority;
+	uint8_t			mac[6];
+	uint8_t			name_id[8];
+	uint8_t			fabric[8];
+	uint16_t		vf_id;
+	uint8_t			vlan_id;
+	uint16_t		max_fcoe_size;
+	uint8_t			fc_map[3];
+	uint32_t		fka_adv;
+	uint32_t		fcfi;
+	uint8_t			get_next:1;
+	uint8_t			link_aff:1;
+	uint8_t			fpma:1;
+	uint8_t			spma:1;
+	uint8_t			login:1;
+	uint8_t			portid;
+	uint8_t			spma_mac[6];
+	struct kref		kref;
+};
+
+/* Defines for flags */
+#define	CSIO_LNF_FIPSUPP		0x00000001	/* Fip Supported */
+#define	CSIO_LNF_NPIVSUPP		0x00000002	/* NPIV supported */
+#define CSIO_LNF_LINK_ENABLE		0x00000004	/* Link enabled */
+#define	CSIO_LNF_FDMI_ENABLE		0x00000008	/* FDMI support */
+
+/* Transport events */
+enum csio_ln_fc_evt {
+	CSIO_LN_FC_LINKUP = 1,
+	CSIO_LN_FC_LINKDOWN,
+	CSIO_LN_FC_RSCN,
+	CSIO_LN_FC_ATTRIB_UPDATE,
+};
+
+/* Lnode stats */
+struct csio_lnode_stats {
+	uint32_t	n_link_up;	/* Link down */
+	uint32_t	n_link_down;	/* Link up */
+	uint32_t	n_err;		/* error */
+	uint32_t	n_err_nomem;	/* memory not available */
+	uint32_t	n_inval_parm;   /* Invalid parameters */
+	uint32_t	n_evt_unexp;	/* unexpected event */
+	uint32_t	n_evt_drop;	/* dropped event */
+	uint32_t	n_rnode_match;  /* matched rnode */
+	uint32_t	n_dev_loss_tmo; /* Device loss timeout */
+	uint32_t	n_fdmi_err;	/* fdmi err */
+	uint32_t	n_evt_fw[RSCN_DEV_LOST];	/* fw events */
+	enum csio_ln_ev	n_evt_sm[CSIO_LNE_MAX_EVENT];	/* State m/c events */
+	uint32_t	n_rnode_alloc;	/* rnode allocated */
+	uint32_t	n_rnode_free;	/* rnode freed */
+	uint32_t	n_rnode_nomem;	/* rnode alloc failure */
+	uint32_t        n_input_requests; /* Input Requests */
+	uint32_t        n_output_requests; /* Output Requests */
+	uint32_t        n_control_requests; /* Control Requests */
+	uint32_t        n_input_bytes; /* Input Bytes */
+	uint32_t        n_output_bytes; /* Output Bytes */
+	uint32_t	rsvd1;
+};
+
+/* Common Lnode params */
+struct csio_lnode_params {
+	uint32_t	ra_tov;
+	uint32_t	fcfi;
+	uint32_t	log_level;	/* Module level for debugging */
+};
+
+struct csio_service_parms {
+	struct fc_els_csp	csp;		/* Common service parms */
+	uint8_t			wwpn[8];	/* WWPN */
+	uint8_t			wwnn[8];	/* WWNN */
+	struct fc_els_cssp	clsp[4];	/* Class service params */
+	uint8_t			vvl[16];	/* Vendor version level */
+};
+
+/* Lnode */
+struct csio_lnode {
+	struct csio_sm		sm;		/* State machine + sibling
+						 * lnode list.
+						 */
+	struct csio_hw		*hwp;		/* Pointer to the HW module */
+	uint8_t			portid;		/* Port ID */
+	uint8_t			rsvd1;
+	uint16_t		rsvd2;
+	uint32_t		dev_num;	/* Device number */
+	uint32_t		flags;		/* Flags */
+	struct list_head	fcf_lsthead;	/* FCF entries */
+	struct csio_fcf_info	*fcfinfo;	/* FCF in use */
+	struct csio_ioreq	*mgmt_req;	/* MGMT request */
+
+	/* FCoE identifiers */
+	uint8_t			mac[6];
+	uint32_t		nport_id;
+	struct csio_service_parms ln_sparm;	/* Service parms */
+
+	/* Firmware identifiers */
+	uint32_t		fcf_flowid;	/*fcf flowid */
+	uint32_t		vnp_flowid;
+	uint16_t		ssn_cnt;	/* Registered Session */
+	uint8_t			cur_evt;	/* Current event */
+	uint8_t			prev_evt;	/* Previous event */
+
+	/* Children */
+	struct list_head	cln_head;	/* Head of the children lnode
+						 * list.
+						 */
+	uint32_t		num_vports;	/* Total NPIV/children LNodes*/
+	struct csio_lnode	*pln;		/* Parent lnode of child
+						 * lnodes.
+						 */
+	struct list_head	cmpl_q;		/* Pending I/Os on this lnode */
+
+	/* Remote node information */
+	struct list_head	rnhead;		/* Head of rnode list */
+	uint32_t		num_reg_rnodes;	/* Number of rnodes registered
+						 * with the host.
+						 */
+	uint32_t		n_scsi_tgts;	/* Number of scsi targets
+						 * found
+						 */
+	uint32_t		last_scan_ntgts;/* Number of scsi targets
+						 * found per last scan.
+						 */
+	uint32_t		tgt_scan_tick;	/* timer started after
+						 * new tgt found
+						 */
+	/* FC transport data */
+	struct fc_vport		*fc_vport;
+	struct fc_host_statistics fch_stats;
+
+	struct csio_lnode_stats stats;		/* Common lnode stats */
+	struct csio_lnode_params params;	/* Common lnode params */
+};
+
+#define	csio_lnode_to_hw(ln)	((ln)->hwp)
+#define csio_root_lnode(ln)	(csio_lnode_to_hw((ln))->rln)
+#define csio_parent_lnode(ln)	((ln)->pln)
+#define	csio_ln_flowid(ln)	((ln)->vnp_flowid)
+#define csio_ln_wwpn(ln)	((ln)->ln_sparm.wwpn)
+#define csio_ln_wwnn(ln)	((ln)->ln_sparm.wwnn)
+
+#define csio_is_root_ln(ln)	(((ln) == csio_root_lnode((ln))) ? 1 : 0)
+#define csio_is_phys_ln(ln)	(((ln)->pln == NULL) ? 1 : 0)
+#define csio_is_npiv_ln(ln)	(((ln)->pln != NULL) ? 1 : 0)
+
+
+#define csio_ln_dbg(_ln, _fmt, ...)	\
+	csio_dbg(_ln->hwp, "%x:%x "_fmt, CSIO_DEVID_HI(_ln), \
+		 CSIO_DEVID_LO(_ln), ##__VA_ARGS__);
+
+#define csio_ln_err(_ln, _fmt, ...)	\
+	csio_err(_ln->hwp, "%x:%x "_fmt, CSIO_DEVID_HI(_ln), \
+		 CSIO_DEVID_LO(_ln), ##__VA_ARGS__);
+
+#define csio_ln_warn(_ln, _fmt, ...)	\
+	csio_warn(_ln->hwp, "%x:%x "_fmt, CSIO_DEVID_HI(_ln), \
+		 CSIO_DEVID_LO(_ln), ##__VA_ARGS__);
+
+/* HW->Lnode notifications */
+enum csio_ln_notify {
+	CSIO_LN_NOTIFY_HWREADY = 1,
+	CSIO_LN_NOTIFY_HWSTOP,
+	CSIO_LN_NOTIFY_HWREMOVE,
+	CSIO_LN_NOTIFY_HWRESET,
+};
+
+void csio_fcoe_fwevt_handler(struct csio_hw *,  __u8 cpl_op, __be64 *);
+int csio_is_lnode_ready(struct csio_lnode *);
+void csio_lnode_state_to_str(struct csio_lnode *ln, int8_t *str);
+struct csio_lnode *csio_lnode_lookup_by_wwpn(struct csio_hw *, uint8_t *);
+int csio_get_phy_port_stats(struct csio_hw *, uint8_t ,
+				      struct fw_fcoe_port_stats *);
+int csio_scan_done(struct csio_lnode *, unsigned long, unsigned long,
+		   unsigned long, unsigned long);
+void csio_notify_lnodes(struct csio_hw *, enum csio_ln_notify);
+void csio_disable_lnodes(struct csio_hw *, uint8_t, bool);
+void csio_lnode_async_event(struct csio_lnode *, enum csio_ln_fc_evt);
+int csio_ln_fdmi_start(struct csio_lnode *, void *);
+int csio_lnode_start(struct csio_lnode *);
+void csio_lnode_stop(struct csio_lnode *);
+void csio_lnode_close(struct csio_lnode *);
+int csio_lnode_init(struct csio_lnode *, struct csio_hw *,
+			      struct csio_lnode *);
+void csio_lnode_exit(struct csio_lnode *);
+
+#endif /* ifndef __CSIO_LNODE_H__ */
diff --git a/drivers/scsi/csiostor/csio_mb.h b/drivers/scsi/csiostor/csio_mb.h
new file mode 100644
index 0000000..1788ea5
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_mb.h
@@ -0,0 +1,278 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_MB_H__
+#define __CSIO_MB_H__
+
+#include <linux/timer.h>
+#include <linux/completion.h>
+
+#include "t4fw_api.h"
+#include "t4fw_api_stor.h"
+#include "csio_defs.h"
+
+#define CSIO_STATS_OFFSET (2)
+#define CSIO_NUM_STATS_PER_MB (6)
+
+struct fw_fcoe_port_cmd_params {
+	uint8_t		portid;
+	uint8_t		idx;
+	uint8_t		nstats;
+};
+
+#define CSIO_DUMP_MB(__hw, __num, __mb)					\
+	csio_dbg(__hw, "\t%llx %llx %llx %llx %llx %llx %llx %llx\n",	\
+		(unsigned long long)csio_rd_reg64(__hw, __mb),		\
+		(unsigned long long)csio_rd_reg64(__hw, __mb + 8),	\
+		(unsigned long long)csio_rd_reg64(__hw, __mb + 16),	\
+		(unsigned long long)csio_rd_reg64(__hw, __mb + 24),	\
+		(unsigned long long)csio_rd_reg64(__hw, __mb + 32),	\
+		(unsigned long long)csio_rd_reg64(__hw, __mb + 40),	\
+		(unsigned long long)csio_rd_reg64(__hw, __mb + 48),	\
+		(unsigned long long)csio_rd_reg64(__hw, __mb + 56))
+
+#define CSIO_MB_MAX_REGS	8
+#define CSIO_MAX_MB_SIZE	64
+#define CSIO_MB_POLL_FREQ	5		/*  5 ms */
+#define CSIO_MB_DEFAULT_TMO	FW_CMD_MAX_TIMEOUT
+
+/* Device master in HELLO command */
+enum csio_dev_master { CSIO_MASTER_CANT, CSIO_MASTER_MAY, CSIO_MASTER_MUST };
+
+enum csio_mb_owner { CSIO_MBOWNER_NONE, CSIO_MBOWNER_FW, CSIO_MBOWNER_PL };
+
+enum csio_dev_state {
+	CSIO_DEV_STATE_UNINIT,
+	CSIO_DEV_STATE_INIT,
+	CSIO_DEV_STATE_ERR
+};
+
+#define FW_PARAM_DEV(param) \
+	(FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
+	 FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
+
+#define FW_PARAM_PFVF(param) \
+	(FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
+	 FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)|  \
+	 FW_PARAMS_PARAM_Y(0) | \
+	 FW_PARAMS_PARAM_Z(0))
+
+enum {
+	PAUSE_RX      = 1 << 0,
+	PAUSE_TX      = 1 << 1,
+	PAUSE_AUTONEG = 1 << 2
+};
+
+#define CSIO_INIT_MBP(__mbp, __cp,  __tmo, __priv, __fn, __clear)	\
+do {									\
+	if (__clear)							\
+		memset((__cp), 0,					\
+			    CSIO_MB_MAX_REGS * sizeof(__be64));		\
+	INIT_LIST_HEAD(&(__mbp)->list);					\
+	(__mbp)->tmo		= (__tmo);				\
+	(__mbp)->priv		= (void *)(__priv);			\
+	(__mbp)->mb_cbfn	= (__fn);				\
+	(__mbp)->mb_size	= sizeof(*(__cp));			\
+} while (0)
+
+struct csio_mbm_stats {
+	uint32_t	n_req;		/* number of mbox req */
+	uint32_t	n_rsp;		/* number of mbox rsp */
+	uint32_t	n_activeq;	/* number of mbox req active Q */
+	uint32_t	n_cbfnq;	/* number of mbox req cbfn Q */
+	uint32_t	n_tmo;		/* number of mbox timeout */
+	uint32_t	n_cancel;	/* number of mbox cancel */
+	uint32_t	n_err;		/* number of mbox error */
+};
+
+/* Driver version of Mailbox */
+struct csio_mb {
+	struct list_head	list;			/* for req/resp */
+							/* queue in driver */
+	__be64			mb[CSIO_MB_MAX_REGS];	/* MB in HW format */
+	int			mb_size;		/* Size of this
+							 * mailbox.
+							 */
+	uint32_t		tmo;			/* Timeout */
+	struct completion	cmplobj;		/* MB Completion
+							 * object
+							 */
+	void			(*mb_cbfn) (struct csio_hw *, struct csio_mb *);
+							/* Callback fn */
+	void			*priv;			/* Owner private ptr */
+};
+
+struct csio_mbm {
+	uint32_t		a_mbox;			/* Async mbox num */
+	uint32_t		intr_idx;		/* Interrupt index */
+	struct timer_list	timer;			/* Mbox timer */
+	struct list_head	req_q;			/* Mbox request queue */
+	struct list_head	cbfn_q;			/* Mbox completion q */
+	struct csio_mb		*mcurrent;		/* Current mailbox */
+	uint32_t		req_q_cnt;		/* Outstanding mbox
+							 * cmds
+							 */
+	struct csio_mbm_stats	stats;			/* Statistics */
+};
+
+#define csio_set_mb_intr_idx(_m, _i)	((_m)->intr_idx = (_i))
+#define csio_get_mb_intr_idx(_m)	((_m)->intr_idx)
+
+struct csio_iq_params;
+struct csio_eq_params;
+
+enum fw_retval csio_mb_fw_retval(struct csio_mb *);
+
+/* MB helpers */
+void csio_mb_hello(struct csio_hw *, struct csio_mb *, uint32_t,
+		   uint32_t, uint32_t, enum csio_dev_master,
+		   void (*)(struct csio_hw *, struct csio_mb *));
+
+void csio_mb_process_hello_rsp(struct csio_hw *, struct csio_mb *,
+			       enum fw_retval *, enum csio_dev_state *,
+			       uint8_t *);
+
+void csio_mb_bye(struct csio_hw *, struct csio_mb *, uint32_t,
+		 void (*)(struct csio_hw *, struct csio_mb *));
+
+void csio_mb_reset(struct csio_hw *, struct csio_mb *, uint32_t, int, int,
+		   void (*)(struct csio_hw *, struct csio_mb *));
+
+void csio_mb_params(struct csio_hw *, struct csio_mb *, uint32_t, unsigned int,
+		    unsigned int, unsigned int, const u32 *, u32 *, bool,
+		    void (*)(struct csio_hw *, struct csio_mb *));
+
+void csio_mb_process_read_params_rsp(struct csio_hw *, struct csio_mb *,
+				enum fw_retval *, unsigned int , u32 *);
+
+void csio_mb_ldst(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
+		  int reg);
+
+void csio_mb_caps_config(struct csio_hw *, struct csio_mb *, uint32_t,
+			    bool, bool, bool, bool,
+			    void (*)(struct csio_hw *, struct csio_mb *));
+
+void csio_rss_glb_config(struct csio_hw *, struct csio_mb *,
+			 uint32_t, uint8_t, unsigned int,
+			 void (*)(struct csio_hw *, struct csio_mb *));
+
+void csio_mb_pfvf(struct csio_hw *, struct csio_mb *, uint32_t,
+		  unsigned int, unsigned int, unsigned int,
+		  unsigned int, unsigned int, unsigned int,
+		  unsigned int, unsigned int, unsigned int,
+		  unsigned int, unsigned int, unsigned int,
+		  unsigned int, void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_mb_port(struct csio_hw *, struct csio_mb *, uint32_t,
+		  uint8_t, bool, uint32_t, uint16_t,
+		  void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_mb_process_read_port_rsp(struct csio_hw *, struct csio_mb *,
+				   enum fw_retval *, uint16_t *);
+
+void csio_mb_initialize(struct csio_hw *, struct csio_mb *, uint32_t,
+			void (*)(struct csio_hw *, struct csio_mb *));
+
+void csio_mb_iq_alloc_write(struct csio_hw *, struct csio_mb *, void *,
+			uint32_t, struct csio_iq_params *,
+			void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_mb_iq_alloc_write_rsp(struct csio_hw *, struct csio_mb *,
+				enum fw_retval *, struct csio_iq_params *);
+
+void csio_mb_iq_free(struct csio_hw *, struct csio_mb *, void *,
+		     uint32_t, struct csio_iq_params *,
+		     void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_mb_eq_ofld_alloc_write(struct csio_hw *, struct csio_mb *, void *,
+				 uint32_t, struct csio_eq_params *,
+				 void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_mb_eq_ofld_alloc_write_rsp(struct csio_hw *, struct csio_mb *,
+				     enum fw_retval *, struct csio_eq_params *);
+
+void csio_mb_eq_ofld_free(struct csio_hw *, struct csio_mb *, void *,
+			  uint32_t , struct csio_eq_params *,
+			  void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_fcoe_read_res_info_init_mb(struct csio_hw *, struct csio_mb *,
+			uint32_t,
+			void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_write_fcoe_link_cond_init_mb(struct csio_lnode *, struct csio_mb *,
+			uint32_t, uint8_t, uint32_t, uint8_t, bool, uint32_t,
+			void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_fcoe_vnp_alloc_init_mb(struct csio_lnode *, struct csio_mb *,
+			uint32_t, uint32_t , uint32_t , uint16_t,
+			uint8_t [8], uint8_t [8],
+			void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_fcoe_vnp_read_init_mb(struct csio_lnode *, struct csio_mb *,
+			uint32_t, uint32_t , uint32_t ,
+			void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_fcoe_vnp_free_init_mb(struct csio_lnode *, struct csio_mb *,
+			uint32_t , uint32_t, uint32_t ,
+			void (*) (struct csio_hw *, struct csio_mb *));
+
+void csio_fcoe_read_fcf_init_mb(struct csio_lnode *, struct csio_mb *,
+			uint32_t, uint32_t, uint32_t,
+			void (*cbfn) (struct csio_hw *, struct csio_mb *));
+
+void csio_fcoe_read_portparams_init_mb(struct csio_hw *hw,
+			struct csio_mb *mbp, uint32_t mb_tmo,
+			struct fw_fcoe_port_cmd_params *portparams,
+			void (*cbfn)(struct csio_hw *, struct csio_mb *));
+
+void csio_mb_process_portparams_rsp(struct csio_hw *hw, struct csio_mb *mbp,
+				enum fw_retval *retval,
+				struct fw_fcoe_port_cmd_params *portparams,
+				struct fw_fcoe_port_stats *portstats);
+
+/* MB module functions */
+int csio_mbm_init(struct csio_mbm *, struct csio_hw *,
+			    void (*)(uintptr_t));
+void csio_mbm_exit(struct csio_mbm *);
+void csio_mb_intr_enable(struct csio_hw *);
+void csio_mb_intr_disable(struct csio_hw *);
+
+int csio_mb_issue(struct csio_hw *, struct csio_mb *);
+void csio_mb_completions(struct csio_hw *, struct list_head *);
+int csio_mb_fwevt_handler(struct csio_hw *, __be64 *);
+int csio_mb_isr_handler(struct csio_hw *);
+struct csio_mb *csio_mb_tmo_handler(struct csio_hw *);
+void csio_mb_cancel_all(struct csio_hw *, struct list_head *);
+
+#endif /* ifndef __CSIO_MB_H__ */
diff --git a/drivers/scsi/csiostor/csio_rnode.h b/drivers/scsi/csiostor/csio_rnode.h
new file mode 100644
index 0000000..a3b434c
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_rnode.h
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_RNODE_H__
+#define __CSIO_RNODE_H__
+
+#include "csio_defs.h"
+
+/* State machine evets */
+enum csio_rn_ev {
+	CSIO_RNFE_NONE = (uint32_t)0,			/* None */
+	CSIO_RNFE_LOGGED_IN,				/* [N/F]Port login
+							 * complete.
+							 */
+	CSIO_RNFE_PRLI_DONE,				/* PRLI completed */
+	CSIO_RNFE_PLOGI_RECV,				/* Received PLOGI */
+	CSIO_RNFE_PRLI_RECV,				/* Received PLOGI */
+	CSIO_RNFE_LOGO_RECV,				/* Received LOGO */
+	CSIO_RNFE_PRLO_RECV,				/* Received PRLO */
+	CSIO_RNFE_DOWN,					/* Rnode is down */
+	CSIO_RNFE_CLOSE,				/* Close rnode */
+	CSIO_RNFE_NAME_MISSING,				/* Rnode name missing
+							 * in name server.
+							 */
+	CSIO_RNFE_MAX_EVENT,
+};
+
+/* rnode stats */
+struct csio_rnode_stats {
+	uint32_t	n_err;		/* error */
+	uint32_t	n_err_inval;	/* invalid parameter */
+	uint32_t	n_err_nomem;	/* error nomem */
+	uint32_t	n_evt_unexp;	/* unexpected event */
+	uint32_t	n_evt_drop;	/* unexpected event */
+	uint32_t	n_evt_fw[RSCN_DEV_LOST];	/* fw events */
+	enum csio_rn_ev	n_evt_sm[CSIO_RNFE_MAX_EVENT];	/* State m/c events */
+	uint32_t	n_lun_rst;	/* Number of resets of
+					 * of LUNs under this
+					 * target
+					 */
+	uint32_t	n_lun_rst_fail;	/* Number of LUN reset
+					 * failures.
+					 */
+	uint32_t	n_tgt_rst;	/* Number of target resets */
+	uint32_t	n_tgt_rst_fail;	/* Number of target reset
+					 * failures.
+					 */
+};
+
+/* Defines for rnode role */
+#define	CSIO_RNFR_INITIATOR	0x1
+#define	CSIO_RNFR_TARGET	0x2
+#define CSIO_RNFR_FABRIC	0x4
+#define	CSIO_RNFR_NS		0x8
+#define CSIO_RNFR_NPORT		0x10
+
+struct csio_rnode {
+	struct csio_sm		sm;			/* State machine -
+							 * should be the
+							 * 1st member
+							 */
+	struct csio_lnode	*lnp;			/* Pointer to owning
+							 * Lnode */
+	uint32_t		flowid;			/* Firmware ID */
+	struct list_head	host_cmpl_q;		/* SCSI IOs
+							 * pending to completed
+							 * to Mid-layer.
+							 */
+	/* FC identifiers for remote node */
+	uint32_t		nport_id;
+	uint16_t		fcp_flags;		/* FCP Flags */
+	uint8_t			cur_evt;		/* Current event */
+	uint8_t			prev_evt;		/* Previous event */
+	uint32_t		role;			/* Fabric/Target/
+							 * Initiator/NS
+							 */
+	struct fcoe_rdev_entry		*rdev_entry;	/* Rdev entry */
+	struct csio_service_parms	rn_sparm;
+
+	/* FC transport attributes */
+	struct fc_rport		*rport;		/* FC transport rport */
+	uint32_t		supp_classes;	/* Supported FC classes */
+	uint32_t		maxframe_size;	/* Max Frame size */
+	uint32_t		scsi_id;	/* Transport given SCSI id */
+
+	struct csio_rnode_stats	stats;		/* Common rnode stats */
+};
+
+#define csio_rn_flowid(rn)			((rn)->flowid)
+#define csio_rn_wwpn(rn)			((rn)->rn_sparm.wwpn)
+#define csio_rn_wwnn(rn)			((rn)->rn_sparm.wwnn)
+#define csio_rnode_to_lnode(rn)			((rn)->lnp)
+
+int csio_is_rnode_ready(struct csio_rnode *rn);
+void csio_rnode_state_to_str(struct csio_rnode *rn, int8_t *str);
+
+struct csio_rnode *csio_rnode_lookup_portid(struct csio_lnode *, uint32_t);
+struct csio_rnode *csio_confirm_rnode(struct csio_lnode *,
+					  uint32_t, struct fcoe_rdev_entry *);
+
+void csio_rnode_fwevt_handler(struct csio_rnode *rn, uint8_t fwevt);
+
+void csio_put_rnode(struct csio_lnode *ln, struct csio_rnode *rn);
+
+void csio_reg_rnode(struct csio_rnode *);
+void csio_unreg_rnode(struct csio_rnode *);
+
+void csio_rnode_devloss_handler(struct csio_rnode *);
+
+#endif /* ifndef __CSIO_RNODE_H__ */
diff --git a/drivers/scsi/csiostor/csio_scsi.h b/drivers/scsi/csiostor/csio_scsi.h
new file mode 100644
index 0000000..2257c3d
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_scsi.h
@@ -0,0 +1,342 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_SCSI_H__
+#define __CSIO_SCSI_H__
+
+#include <linux/spinlock_types.h>
+#include <linux/completion.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/fc/fc_fcp.h>
+
+#include "csio_defs.h"
+#include "csio_wr.h"
+
+extern struct scsi_host_template csio_fcoe_shost_template;
+extern struct scsi_host_template csio_fcoe_shost_vport_template;
+
+extern int csio_scsi_eqsize;
+extern int csio_scsi_iqlen;
+extern int csio_scsi_ioreqs;
+extern uint32_t csio_max_scan_tmo;
+extern uint32_t csio_delta_scan_tmo;
+extern int csio_lun_qdepth;
+
+/*
+ **************************** NOTE *******************************
+ * How do we calculate MAX FCoE SCSI SGEs? Here is the math:
+ * Max Egress WR size = 512 bytes
+ * One SCSI egress WR has the following fixed no of bytes:
+ *      48 (sizeof(struct fw_scsi_write[read]_wr)) - FW WR
+ *    + 32 (sizeof(struct fc_fcp_cmnd)) - Immediate FCP_CMD
+ *    ------
+ *      80
+ *    ------
+ * That leaves us with 512 - 96 = 432 bytes for data SGE. Using
+ * struct ulptx_sgl header for the SGE consumes:
+ *	- 4 bytes for cmnd_sge.
+ *	- 12 bytes for the first SGL.
+ * That leaves us with 416 bytes for the remaining SGE pairs. Which is
+ * is 416 / 24 (size(struct ulptx_sge_pair)) = 17 SGE pairs,
+ * or 34 SGEs. Adding the first SGE fetches us 35 SGEs.
+ */
+#define CSIO_SCSI_MAX_SGE		35
+#define CSIO_SCSI_ABRT_TMO_MS		60000
+#define CSIO_SCSI_LUNRST_TMO_MS		60000
+#define CSIO_SCSI_TM_POLL_MS		2000	/* should be less than
+						 * all TM timeouts.
+						 */
+#define CSIO_SCSI_IQ_WRSZ		128
+#define CSIO_SCSI_IQSIZE		(csio_scsi_iqlen * CSIO_SCSI_IQ_WRSZ)
+
+#define	CSIO_MAX_SNS_LEN		128
+#define	CSIO_SCSI_RSP_LEN	(FCP_RESP_WITH_EXT + 4 + CSIO_MAX_SNS_LEN)
+
+/* Reference to scsi_cmnd */
+#define csio_scsi_cmnd(req)		((req)->scratch1)
+
+struct csio_scsi_stats {
+	uint64_t		n_tot_success;	/* Total number of good I/Os */
+	uint32_t		n_rn_nr_error;	/* No. of remote-node-not-
+						 * ready errors
+						 */
+	uint32_t		n_hw_nr_error;	/* No. of hw-module-not-
+						 * ready errors
+						 */
+	uint32_t		n_dmamap_error;	/* No. of DMA map erros */
+	uint32_t		n_unsupp_sge_error; /* No. of too-many-SGes
+						     * errors.
+						     */
+	uint32_t		n_no_req_error;	/* No. of Out-of-ioreqs error */
+	uint32_t		n_busy_error;	/* No. of -EBUSY errors */
+	uint32_t		n_hosterror;	/* No. of FW_HOSTERROR I/O */
+	uint32_t		n_rsperror;	/* No. of response errors */
+	uint32_t		n_autosense;	/* No. of auto sense replies */
+	uint32_t		n_ovflerror;	/* No. of overflow errors */
+	uint32_t		n_unflerror;	/* No. of underflow errors */
+	uint32_t		n_rdev_nr_error;/* No. of rdev not
+						 * ready errors
+						 */
+	uint32_t		n_rdev_lost_error;/* No. of rdev lost errors */
+	uint32_t		n_rdev_logo_error;/* No. of rdev logo errors */
+	uint32_t		n_link_down_error;/* No. of link down errors */
+	uint32_t		n_no_xchg_error; /* No. no exchange error */
+	uint32_t		n_unknown_error;/* No. of unhandled errors */
+	uint32_t		n_aborted;	/* No. of aborted I/Os */
+	uint32_t		n_abrt_timedout; /* No. of abort timedouts */
+	uint32_t		n_abrt_fail;	/* No. of abort failures */
+	uint32_t		n_abrt_dups;	/* No. of duplicate aborts */
+	uint32_t		n_abrt_race_comp; /* No. of aborts that raced
+						   * with completions.
+						   */
+	uint32_t		n_abrt_busy_error;/* No. of abort failures
+						   * due to -EBUSY.
+						   */
+	uint32_t		n_closed;	/* No. of closed I/Os */
+	uint32_t		n_cls_busy_error; /* No. of close failures
+						   * due to -EBUSY.
+						   */
+	uint32_t		n_active;	/* No. of IOs in active_q */
+	uint32_t		n_tm_active;	/* No. of TMs in active_q */
+	uint32_t		n_wcbfn;	/* No. of I/Os in worker
+						 * cbfn q
+						 */
+	uint32_t		n_free_ioreq;	/* No. of freelist entries */
+	uint32_t		n_free_ddp;	/* No. of DDP freelist */
+	uint32_t		n_unaligned;	/* No. of Unaligned SGls */
+	uint32_t		n_inval_cplop;	/* No. invalid CPL op's in IQ */
+	uint32_t		n_inval_scsiop;	/* No. invalid scsi op's in IQ*/
+};
+
+struct csio_scsim {
+	struct csio_hw		*hw;		/* Pointer to HW moduel */
+	uint8_t			max_sge;	/* Max SGE */
+	uint8_t			proto_cmd_len;	/* Proto specific SCSI
+						 * cmd length
+						 */
+	uint16_t		proto_rsp_len;	/* Proto specific SCSI
+						 * response length
+						 */
+	spinlock_t		freelist_lock;	/* Lock for ioreq freelist */
+	struct list_head	active_q;	/* Outstanding SCSI I/Os */
+	struct list_head	ioreq_freelist;	/* Free list of ioreq's */
+	struct list_head	ddp_freelist;	/* DDP descriptor freelist */
+	struct csio_scsi_stats	stats;		/* This module's statistics */
+};
+
+/* State machine defines */
+enum csio_scsi_ev {
+	CSIO_SCSIE_START_IO = 1,		/* Start a regular SCSI IO */
+	CSIO_SCSIE_START_TM,			/* Start a TM IO */
+	CSIO_SCSIE_COMPLETED,			/* IO Completed */
+	CSIO_SCSIE_ABORT,			/* Abort IO */
+	CSIO_SCSIE_ABORTED,			/* IO Aborted */
+	CSIO_SCSIE_CLOSE,			/* Close exchange */
+	CSIO_SCSIE_CLOSED,			/* Exchange closed */
+	CSIO_SCSIE_DRVCLEANUP,			/* Driver wants to manually
+						 * cleanup this I/O.
+						 */
+};
+
+enum csio_scsi_lev {
+	CSIO_LEV_ALL = 1,
+	CSIO_LEV_LNODE,
+	CSIO_LEV_RNODE,
+	CSIO_LEV_LUN,
+};
+
+struct csio_scsi_level_data {
+	enum csio_scsi_lev	level;
+	struct csio_rnode	*rnode;
+	struct csio_lnode	*lnode;
+	uint64_t		oslun;
+};
+
+static inline struct csio_ioreq *
+csio_get_scsi_ioreq(struct csio_scsim *scm)
+{
+	struct csio_sm *req;
+
+	if (likely(!list_empty(&scm->ioreq_freelist))) {
+		req = list_first_entry(&scm->ioreq_freelist,
+				       struct csio_sm, sm_list);
+		list_del_init(&req->sm_list);
+		CSIO_DEC_STATS(scm, n_free_ioreq);
+		return (struct csio_ioreq *)req;
+	} else
+		return NULL;
+}
+
+static inline void
+csio_put_scsi_ioreq(struct csio_scsim *scm, struct csio_ioreq *ioreq)
+{
+	list_add_tail(&ioreq->sm.sm_list, &scm->ioreq_freelist);
+	CSIO_INC_STATS(scm, n_free_ioreq);
+}
+
+static inline void
+csio_put_scsi_ioreq_list(struct csio_scsim *scm, struct list_head *reqlist,
+			 int n)
+{
+	list_splice_init(reqlist, &scm->ioreq_freelist);
+	scm->stats.n_free_ioreq += n;
+}
+
+static inline struct csio_dma_buf *
+csio_get_scsi_ddp(struct csio_scsim *scm)
+{
+	struct csio_dma_buf *ddp;
+
+	if (likely(!list_empty(&scm->ddp_freelist))) {
+		ddp = list_first_entry(&scm->ddp_freelist,
+				       struct csio_dma_buf, list);
+		list_del_init(&ddp->list);
+		CSIO_DEC_STATS(scm, n_free_ddp);
+		return ddp;
+	} else
+		return NULL;
+}
+
+static inline void
+csio_put_scsi_ddp(struct csio_scsim *scm, struct csio_dma_buf *ddp)
+{
+	list_add_tail(&ddp->list, &scm->ddp_freelist);
+	CSIO_INC_STATS(scm, n_free_ddp);
+}
+
+static inline void
+csio_put_scsi_ddp_list(struct csio_scsim *scm, struct list_head *reqlist,
+			 int n)
+{
+	list_splice_tail_init(reqlist, &scm->ddp_freelist);
+	scm->stats.n_free_ddp += n;
+}
+
+static inline void
+csio_scsi_completed(struct csio_ioreq *ioreq, struct list_head *cbfn_q)
+{
+	csio_post_event(&ioreq->sm, CSIO_SCSIE_COMPLETED);
+	if (csio_list_deleted(&ioreq->sm.sm_list))
+		list_add_tail(&ioreq->sm.sm_list, cbfn_q);
+}
+
+static inline void
+csio_scsi_aborted(struct csio_ioreq *ioreq, struct list_head *cbfn_q)
+{
+	csio_post_event(&ioreq->sm, CSIO_SCSIE_ABORTED);
+	list_add_tail(&ioreq->sm.sm_list, cbfn_q);
+}
+
+static inline void
+csio_scsi_closed(struct csio_ioreq *ioreq, struct list_head *cbfn_q)
+{
+	csio_post_event(&ioreq->sm, CSIO_SCSIE_CLOSED);
+	list_add_tail(&ioreq->sm.sm_list, cbfn_q);
+}
+
+static inline void
+csio_scsi_drvcleanup(struct csio_ioreq *ioreq)
+{
+	csio_post_event(&ioreq->sm, CSIO_SCSIE_DRVCLEANUP);
+}
+
+/*
+ * csio_scsi_start_io - Kick starts the IO SM.
+ * @req: io request SM.
+ *
+ * needs to be called with lock held.
+ */
+static inline int
+csio_scsi_start_io(struct csio_ioreq *ioreq)
+{
+	csio_post_event(&ioreq->sm, CSIO_SCSIE_START_IO);
+	return ioreq->drv_status;
+}
+
+/*
+ * csio_scsi_start_tm - Kicks off the Task management IO SM.
+ * @req: io request SM.
+ *
+ * needs to be called with lock held.
+ */
+static inline int
+csio_scsi_start_tm(struct csio_ioreq *ioreq)
+{
+	csio_post_event(&ioreq->sm, CSIO_SCSIE_START_TM);
+	return ioreq->drv_status;
+}
+
+/*
+ * csio_scsi_abort - Abort an IO request
+ * @req: io request SM.
+ *
+ * needs to be called with lock held.
+ */
+static inline int
+csio_scsi_abort(struct csio_ioreq *ioreq)
+{
+	csio_post_event(&ioreq->sm, CSIO_SCSIE_ABORT);
+	return ioreq->drv_status;
+}
+
+/*
+ * csio_scsi_close - Close an IO request
+ * @req: io request SM.
+ *
+ * needs to be called with lock held.
+ */
+static inline int
+csio_scsi_close(struct csio_ioreq *ioreq)
+{
+	csio_post_event(&ioreq->sm, CSIO_SCSIE_CLOSE);
+	return ioreq->drv_status;
+}
+
+void csio_scsi_cleanup_io_q(struct csio_scsim *, struct list_head *);
+int csio_scsim_cleanup_io(struct csio_scsim *, bool abort);
+int csio_scsim_cleanup_io_lnode(struct csio_scsim *,
+					  struct csio_lnode *);
+struct csio_ioreq *csio_scsi_cmpl_handler(struct csio_hw *, void *, uint32_t,
+					  struct csio_fl_dma_buf *,
+					  void *, uint8_t **);
+int csio_scsi_qconfig(struct csio_hw *);
+int csio_scsim_init(struct csio_scsim *, struct csio_hw *);
+void csio_scsim_exit(struct csio_scsim *);
+
+#endif /* __CSIO_SCSI_H__ */
diff --git a/drivers/scsi/csiostor/csio_wr.h b/drivers/scsi/csiostor/csio_wr.h
new file mode 100644
index 0000000..8d30e7a
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_wr.h
@@ -0,0 +1,512 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_WR_H__
+#define __CSIO_WR_H__
+
+#include <linux/cache.h>
+
+#include "csio_defs.h"
+#include "t4fw_api.h"
+#include "t4fw_api_stor.h"
+
+/*
+ * SGE register field values.
+ */
+#define X_INGPCIEBOUNDARY_32B		0
+#define X_INGPCIEBOUNDARY_64B		1
+#define X_INGPCIEBOUNDARY_128B		2
+#define X_INGPCIEBOUNDARY_256B		3
+#define X_INGPCIEBOUNDARY_512B		4
+#define X_INGPCIEBOUNDARY_1024B		5
+#define X_INGPCIEBOUNDARY_2048B		6
+#define X_INGPCIEBOUNDARY_4096B		7
+
+/* GTS register */
+#define X_TIMERREG_COUNTER0		0
+#define X_TIMERREG_COUNTER1		1
+#define X_TIMERREG_COUNTER2		2
+#define X_TIMERREG_COUNTER3		3
+#define X_TIMERREG_COUNTER4		4
+#define X_TIMERREG_COUNTER5		5
+#define X_TIMERREG_RESTART_COUNTER	6
+#define X_TIMERREG_UPDATE_CIDX		7
+
+/*
+ * Egress Context field values
+ */
+#define X_FETCHBURSTMIN_16B		0
+#define X_FETCHBURSTMIN_32B		1
+#define X_FETCHBURSTMIN_64B		2
+#define X_FETCHBURSTMIN_128B		3
+
+#define X_FETCHBURSTMAX_64B		0
+#define X_FETCHBURSTMAX_128B		1
+#define X_FETCHBURSTMAX_256B		2
+#define X_FETCHBURSTMAX_512B		3
+
+#define X_HOSTFCMODE_NONE		0
+#define X_HOSTFCMODE_INGRESS_QUEUE	1
+#define X_HOSTFCMODE_STATUS_PAGE	2
+#define X_HOSTFCMODE_BOTH		3
+
+/*
+ * Ingress Context field values
+ */
+#define X_UPDATESCHEDULING_TIMER	0
+#define X_UPDATESCHEDULING_COUNTER_OPTTIMER	1
+
+#define X_UPDATEDELIVERY_NONE		0
+#define X_UPDATEDELIVERY_INTERRUPT	1
+#define X_UPDATEDELIVERY_STATUS_PAGE	2
+#define X_UPDATEDELIVERY_BOTH		3
+
+#define X_INTERRUPTDESTINATION_PCIE	0
+#define X_INTERRUPTDESTINATION_IQ	1
+
+#define X_RSPD_TYPE_FLBUF		0
+#define X_RSPD_TYPE_CPL			1
+#define X_RSPD_TYPE_INTR		2
+
+/* WR status is at the same position as retval in a CMD header */
+#define csio_wr_status(_wr)		\
+		(FW_CMD_RETVAL_GET(ntohl(((struct fw_cmd_hdr *)(_wr))->lo)))
+
+struct csio_hw;
+
+extern int csio_intr_coalesce_cnt;
+extern int csio_intr_coalesce_time;
+
+/* Ingress queue params */
+struct csio_iq_params {
+
+	uint8_t		iq_start:1;
+	uint8_t		iq_stop:1;
+	uint8_t		pfn:3;
+
+	uint8_t		vfn;
+
+	uint16_t	physiqid;
+	uint16_t	iqid;
+
+	uint16_t	fl0id;
+	uint16_t	fl1id;
+
+	uint8_t		viid;
+
+	uint8_t		type;
+	uint8_t		iqasynch;
+	uint8_t		reserved4;
+
+	uint8_t		iqandst;
+	uint8_t		iqanus;
+	uint8_t		iqanud;
+
+	uint16_t	iqandstindex;
+
+	uint8_t		iqdroprss;
+	uint8_t		iqpciech;
+	uint8_t		iqdcaen;
+
+	uint8_t		iqdcacpu;
+	uint8_t		iqintcntthresh;
+	uint8_t		iqo;
+
+	uint8_t		iqcprio;
+	uint8_t		iqesize;
+
+	uint16_t	iqsize;
+
+	uint64_t	iqaddr;
+
+	uint8_t		iqflintiqhsen;
+	uint8_t		reserved5;
+	uint8_t		iqflintcongen;
+	uint8_t		iqflintcngchmap;
+
+	uint32_t	reserved6;
+
+	uint8_t		fl0hostfcmode;
+	uint8_t		fl0cprio;
+	uint8_t		fl0paden;
+	uint8_t		fl0packen;
+	uint8_t		fl0congen;
+	uint8_t		fl0dcaen;
+
+	uint8_t		fl0dcacpu;
+	uint8_t		fl0fbmin;
+
+	uint8_t		fl0fbmax;
+	uint8_t		fl0cidxfthresho;
+	uint8_t		fl0cidxfthresh;
+
+	uint16_t	fl0size;
+
+	uint64_t	fl0addr;
+
+	uint64_t	reserved7;
+
+	uint8_t		fl1hostfcmode;
+	uint8_t		fl1cprio;
+	uint8_t		fl1paden;
+	uint8_t		fl1packen;
+	uint8_t		fl1congen;
+	uint8_t		fl1dcaen;
+
+	uint8_t		fl1dcacpu;
+	uint8_t		fl1fbmin;
+
+	uint8_t		fl1fbmax;
+	uint8_t		fl1cidxfthresho;
+	uint8_t		fl1cidxfthresh;
+
+	uint16_t	fl1size;
+
+	uint64_t	fl1addr;
+};
+
+/* Egress queue params */
+struct csio_eq_params {
+
+	uint8_t		pfn;
+	uint8_t		vfn;
+
+	uint8_t		eqstart:1;
+	uint8_t		eqstop:1;
+
+	uint16_t        physeqid;
+	uint32_t	eqid;
+
+	uint8_t		hostfcmode:2;
+	uint8_t		cprio:1;
+	uint8_t		pciechn:3;
+
+	uint16_t	iqid;
+
+	uint8_t		dcaen:1;
+	uint8_t		dcacpu:5;
+
+	uint8_t		fbmin:3;
+	uint8_t		fbmax:3;
+
+	uint8_t		cidxfthresho:1;
+	uint8_t		cidxfthresh:3;
+
+	uint16_t	eqsize;
+
+	uint64_t	eqaddr;
+};
+
+struct csio_dma_buf {
+	struct list_head	list;
+	void			*vaddr;		/* Virtual address */
+	dma_addr_t		paddr;		/* Physical address */
+	uint32_t		len;		/* Buffer size */
+};
+
+/* Generic I/O request structure */
+struct csio_ioreq {
+	struct csio_sm		sm;		/* SM, List
+						 * should be the first member
+						 */
+	int			iq_idx;		/* Ingress queue index */
+	int			eq_idx;		/* Egress queue index */
+	uint32_t		nsge;		/* Number of SG elements */
+	uint32_t		tmo;		/* Driver timeout */
+	uint32_t		datadir;	/* Data direction */
+	struct csio_dma_buf	dma_buf;	/* Req/resp DMA buffers */
+	uint16_t		wr_status;	/* WR completion status */
+	int16_t			drv_status;	/* Driver internal status */
+	struct csio_lnode	*lnode;		/* Owner lnode */
+	struct csio_rnode	*rnode;		/* Src/destination rnode */
+	void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *);
+						/* completion callback */
+	void			*scratch1;	/* Scratch area 1.
+						 */
+	void			*scratch2;	/* Scratch area 2. */
+	struct list_head	gen_list;	/* Any list associated with
+						 * this ioreq.
+						 */
+	uint64_t		fw_handle;	/* Unique handle passed
+						 * to FW
+						 */
+	uint8_t			dcopy;		/* Data copy required */
+	uint8_t			reserved1;
+	uint16_t		reserved2;
+	struct completion	cmplobj;	/* ioreq completion object */
+} ____cacheline_aligned_in_smp;
+
+/*
+ * Egress status page for egress cidx updates
+ */
+struct csio_qstatus_page {
+	__be32 qid;
+	__be16 cidx;
+	__be16 pidx;
+};
+
+
+enum {
+	CSIO_MAX_FLBUF_PER_IQWR = 4,
+	CSIO_QCREDIT_SZ  = 64,			/* pidx/cidx increments
+						 * in bytes
+						 */
+	CSIO_MAX_QID = 0xFFFF,
+	CSIO_MAX_IQ = 128,
+
+	CSIO_SGE_NTIMERS = 6,
+	CSIO_SGE_NCOUNTERS = 4,
+	CSIO_SGE_FL_SIZE_REGS = 16,
+};
+
+/* Defines for type */
+enum {
+	CSIO_EGRESS	= 1,
+	CSIO_INGRESS	= 2,
+	CSIO_FREELIST	= 3,
+};
+
+/*
+ * Structure for footer (last 2 flits) of Ingress Queue Entry.
+ */
+struct csio_iqwr_footer {
+	__be32			hdrbuflen_pidx;
+	__be32			pldbuflen_qid;
+	union {
+		u8		type_gen;
+		__be64		last_flit;
+	} u;
+};
+
+#define IQWRF_NEWBUF		(1 << 31)
+#define IQWRF_LEN_GET(x)	(((x) >> 0) & 0x7fffffffU)
+#define IQWRF_GEN_SHIFT		7
+#define IQWRF_TYPE_GET(x)	(((x) >> 4) & 0x3U)
+
+
+/*
+ * WR pair:
+ * ========
+ * A WR can start towards the end of a queue, and then continue at the
+ * beginning, since the queue is considered to be circular. This will
+ * require a pair of address/len to be passed back to the caller -
+ * hence the Work request pair structure.
+ */
+struct csio_wr_pair {
+	void			*addr1;
+	uint32_t		size1;
+	void			*addr2;
+	uint32_t		size2;
+};
+
+/*
+ * The following structure is used by ingress processing to return the
+ * free list buffers to consumers.
+ */
+struct csio_fl_dma_buf {
+	struct csio_dma_buf	flbufs[CSIO_MAX_FLBUF_PER_IQWR];
+						/* Freelist DMA buffers */
+	int			offset;		/* Offset within the
+						 * first FL buf.
+						 */
+	uint32_t		totlen;		/* Total length */
+	uint8_t			defer_free;	/* Free of buffer can
+						 * deferred
+						 */
+};
+
+/* Data-types */
+typedef void (*iq_handler_t)(struct csio_hw *, void *, uint32_t,
+			     struct csio_fl_dma_buf *, void *);
+
+struct csio_iq {
+	uint16_t		iqid;		/* Queue ID */
+	uint16_t		physiqid;	/* Physical Queue ID */
+	uint16_t		genbit;		/* Generation bit,
+						 * initially set to 1
+						 */
+	int			flq_idx;	/* Freelist queue index */
+	iq_handler_t		iq_intx_handler; /* IQ INTx handler routine */
+};
+
+struct csio_eq {
+	uint16_t		eqid;		/* Qid */
+	uint16_t		physeqid;	/* Physical Queue ID */
+	uint8_t			wrap[512];	/* Temp area for q-wrap around*/
+};
+
+struct csio_fl {
+	uint16_t		flid;		/* Qid */
+	uint16_t		packen;		/* Packing enabled? */
+	int			offset;		/* Offset within FL buf */
+	int			sreg;		/* Size register */
+	struct csio_dma_buf	*bufs;		/* Free list buffer ptr array
+						 * indexed using flq->cidx/pidx
+						 */
+};
+
+struct csio_qstats {
+	uint32_t	n_tot_reqs;		/* Total no. of Requests */
+	uint32_t	n_tot_rsps;		/* Total no. of responses */
+	uint32_t	n_qwrap;		/* Queue wraps */
+	uint32_t	n_eq_wr_split;		/* Number of split EQ WRs */
+	uint32_t	n_qentry;		/* Queue entry */
+	uint32_t	n_qempty;		/* Queue empty */
+	uint32_t	n_qfull;		/* Queue fulls */
+	uint32_t	n_rsp_unknown;		/* Unknown response type */
+	uint32_t	n_stray_comp;		/* Stray completion intr */
+	uint32_t	n_flq_refill;		/* Number of FL refills */
+};
+
+/* Queue metadata */
+struct csio_q {
+	uint16_t		type;		/* Type: Ingress/Egress/FL */
+	uint16_t		pidx;		/* producer index */
+	uint16_t		cidx;		/* consumer index */
+	uint16_t		inc_idx;	/* Incremental index */
+	uint32_t		wr_sz;		/* Size of all WRs in this q
+						 * if fixed
+						 */
+	void			*vstart;	/* Base virtual address
+						 * of queue
+						 */
+	void			*vwrap;		/* Virtual end address to
+						 * wrap around at
+						 */
+	uint32_t		credits;	/* Size of queue in credits */
+	void			*owner;		/* Owner */
+	union {					/* Queue contexts */
+		struct csio_iq	iq;
+		struct csio_eq	eq;
+		struct csio_fl	fl;
+	} un;
+
+	dma_addr_t		pstart;		/* Base physical address of
+						 * queue
+						 */
+	uint32_t		portid;		/* PCIE Channel */
+	uint32_t		size;		/* Size of queue in bytes */
+	struct csio_qstats	stats;		/* Statistics */
+} ____cacheline_aligned_in_smp;
+
+struct csio_sge {
+	uint32_t	csio_fl_align;		/* Calculated and cached
+						 * for fast path
+						 */
+	uint32_t	sge_control;		/* padding, boundaries,
+						 * lengths, etc.
+						 */
+	uint32_t	sge_host_page_size;	/* Host page size */
+	uint32_t	sge_fl_buf_size[CSIO_SGE_FL_SIZE_REGS];
+						/* free list buffer sizes */
+	uint16_t	timer_val[CSIO_SGE_NTIMERS];
+	uint8_t		counter_val[CSIO_SGE_NCOUNTERS];
+};
+
+/* Work request module */
+struct csio_wrm {
+	int			num_q;		/* Number of queues */
+	struct csio_q		**q_arr;	/* Array of queue pointers
+						 * allocated dynamically
+						 * based on configured values
+						 */
+	uint32_t		fw_iq_start;	/* Start ID of IQ for this fn*/
+	uint32_t		fw_eq_start;	/* Start ID of EQ for this fn*/
+	struct csio_q		*intr_map[CSIO_MAX_IQ];
+						/* IQ-id to IQ map table. */
+	int			free_qidx;	/* queue idx of free queue */
+	struct csio_sge		sge;		/* SGE params */
+};
+
+#define csio_get_q(__hw, __idx)		((__hw)->wrm.q_arr[__idx])
+#define	csio_q_type(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->type)
+#define	csio_q_pidx(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->pidx)
+#define	csio_q_cidx(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->cidx)
+#define	csio_q_inc_idx(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->inc_idx)
+#define	csio_q_vstart(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->vstart)
+#define	csio_q_pstart(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->pstart)
+#define	csio_q_size(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->size)
+#define	csio_q_credits(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->credits)
+#define	csio_q_portid(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->portid)
+#define	csio_q_wr_sz(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->wr_sz)
+#define	csio_q_iqid(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->un.iq.iqid)
+#define csio_q_physiqid(__hw, __idx)					\
+				((__hw)->wrm.q_arr[(__idx)]->un.iq.physiqid)
+#define csio_q_iq_flq_idx(__hw, __idx)					\
+				((__hw)->wrm.q_arr[(__idx)]->un.iq.flq_idx)
+#define	csio_q_eqid(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->un.eq.eqid)
+#define	csio_q_flid(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->un.fl.flid)
+
+#define csio_q_physeqid(__hw, __idx)					\
+				((__hw)->wrm.q_arr[(__idx)]->un.eq.physeqid)
+#define csio_iq_has_fl(__iq)		((__iq)->un.iq.flq_idx != -1)
+
+#define csio_q_iq_to_flid(__hw, __iq_idx)				\
+	csio_q_flid((__hw), (__hw)->wrm.q_arr[(__iq_qidx)]->un.iq.flq_idx)
+#define csio_q_set_intr_map(__hw, __iq_idx, __rel_iq_id)		\
+		(__hw)->wrm.intr_map[__rel_iq_id] = csio_get_q(__hw, __iq_idx)
+#define	csio_q_eq_wrap(__hw, __idx)	((__hw)->wrm.q_arr[(__idx)]->un.eq.wrap)
+
+struct csio_mb;
+
+int csio_wr_alloc_q(struct csio_hw *, uint32_t, uint32_t,
+		    uint16_t, void *, uint32_t, int, iq_handler_t);
+int csio_wr_iq_create(struct csio_hw *, void *, int,
+				uint32_t, uint8_t, bool,
+				void (*)(struct csio_hw *, struct csio_mb *));
+int csio_wr_eq_create(struct csio_hw *, void *, int, int, uint8_t,
+				void (*)(struct csio_hw *, struct csio_mb *));
+int csio_wr_destroy_queues(struct csio_hw *, bool cmd);
+
+
+int csio_wr_get(struct csio_hw *, int, uint32_t,
+			  struct csio_wr_pair *);
+void csio_wr_copy_to_wrp(void *, struct csio_wr_pair *, uint32_t, uint32_t);
+int csio_wr_issue(struct csio_hw *, int, bool);
+int csio_wr_process_iq(struct csio_hw *, struct csio_q *,
+				 void (*)(struct csio_hw *, void *,
+					  uint32_t, struct csio_fl_dma_buf *,
+					  void *),
+				 void *);
+int csio_wr_process_iq_idx(struct csio_hw *, int,
+				 void (*)(struct csio_hw *, void *,
+					  uint32_t, struct csio_fl_dma_buf *,
+					  void *),
+				 void *);
+
+void csio_wr_sge_init(struct csio_hw *);
+int csio_wrm_init(struct csio_wrm *, struct csio_hw *);
+void csio_wrm_exit(struct csio_wrm *, struct csio_hw *);
+
+#endif /* ifndef __CSIO_WR_H__ */
-- 
1.7.1


^ permalink raw reply related

* [V3 PATCH 6/9] csiostor: Chelsio FCoE offload driver submission (headers part 1).
From: Naresh Kumar Inna @ 2012-09-11 14:39 UTC (permalink / raw)
  To: JBottomley, linux-scsi, dm, leedom; +Cc: netdev, naresh, chethan
In-Reply-To: <1347374347-3852-1-git-send-email-naresh@chelsio.com>

This patch contains the first set of the header files for csiostor driver.

Signed-off-by: Naresh Kumar Inna <naresh@chelsio.com>
---
V2:
- Removed csio_fcoe_proto.h, using defines from include/scsi/fc instead.
- Removed driver-specific return values, using errno values instead.
- Retained CSIO_INC_STATS, since it is useful in multiple places and
  the name of the structure has been standardized to make use of this macro.
- Removed csio_deq_from_head(), replaced it inline with calls from list.h.
- Removed csio_deq_from_tail().
- Replaced state machine macros with static functions.
- Capitalizing macros with CPP keys.

V3:
- Replaced CSIO_ROUNDUP with DIV_ROUND_UP.
- Use BUG_ON in CSIO_ASSERT macro.

 drivers/scsi/csiostor/csio_defs.h     |  108 ++++++
 drivers/scsi/csiostor/csio_hw.h       |  666 +++++++++++++++++++++++++++++++++
 drivers/scsi/csiostor/csio_init.h     |  158 ++++++++
 drivers/scsi/csiostor/t4fw_api_stor.h |  578 ++++++++++++++++++++++++++++
 4 files changed, 1510 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/csiostor/csio_defs.h
 create mode 100644 drivers/scsi/csiostor/csio_hw.h
 create mode 100644 drivers/scsi/csiostor/csio_init.h
 create mode 100644 drivers/scsi/csiostor/t4fw_api_stor.h

diff --git a/drivers/scsi/csiostor/csio_defs.h b/drivers/scsi/csiostor/csio_defs.h
new file mode 100644
index 0000000..80be354
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_defs.h
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_DEFS_H__
+#define __CSIO_DEFS_H__
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/bug.h>
+#include <linux/pci.h>
+#include <linux/jiffies.h>
+
+#define CSIO_INVALID_IDX		0xFFFFFFFF
+#define CSIO_INC_STATS(elem, val)	((elem)->stats.val++)
+#define CSIO_DEC_STATS(elem, val)	((elem)->stats.val--)
+#define CSIO_VALID_WWN(__n)		((*__n >> 4) == 0x5 ? true : false)
+#define CSIO_DID_MASK			0xFFFFFF
+#define CSIO_WORD_TO_BYTE		4
+
+static inline int
+csio_list_deleted(struct list_head *list)
+{
+	return ((list->next == list) && (list->prev == list));
+}
+
+#define csio_list_next(elem)	(((struct list_head *)(elem))->next)
+#define csio_list_prev(elem)	(((struct list_head *)(elem))->prev)
+
+/* State machine */
+typedef void (*csio_sm_state_t)(void *, uint32_t);
+
+struct csio_sm {
+	struct list_head	sm_list;
+	csio_sm_state_t		sm_state;
+};
+
+static inline void
+csio_set_state(void *smp, void *state)
+{
+	((struct csio_sm *)smp)->sm_state = (csio_sm_state_t)state;
+}
+
+static inline void
+csio_init_state(struct csio_sm *smp, void *state)
+{
+	csio_set_state(smp, state);
+}
+
+static inline void
+csio_post_event(void *smp, uint32_t evt)
+{
+	((struct csio_sm *)smp)->sm_state(smp, evt);
+}
+
+static inline csio_sm_state_t
+csio_get_state(void *smp)
+{
+	return ((struct csio_sm *)smp)->sm_state;
+}
+
+static inline bool
+csio_match_state(void *smp, void *state)
+{
+	return (csio_get_state(smp) == (csio_sm_state_t)state);
+}
+
+#define	CSIO_ASSERT(cond)		BUG_ON(!(cond))
+
+#ifdef __CSIO_DEBUG__
+#define CSIO_DB_ASSERT(__c)		CSIO_ASSERT((__c))
+#else
+#define CSIO_DB_ASSERT(__c)
+#endif
+
+#endif /* ifndef __CSIO_DEFS_H__ */
diff --git a/drivers/scsi/csiostor/csio_hw.h b/drivers/scsi/csiostor/csio_hw.h
new file mode 100644
index 0000000..a58fdc9
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_hw.h
@@ -0,0 +1,666 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_HW_H__
+#define __CSIO_HW_H__
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/compiler.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/mempool.h>
+#include <linux/io.h>
+#include <linux/spinlock_types.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "csio_wr.h"
+#include "csio_mb.h"
+#include "csio_scsi.h"
+#include "csio_defs.h"
+#include "t4_regs.h"
+#include "t4_msg.h"
+
+/*
+ * An error value used by host. Should not clash with FW defined return values.
+ */
+#define	FW_HOSTERROR			255
+
+#define CSIO_FW_FNAME		"cxgb4/t4fw.bin"
+#define CSIO_CF_FNAME		"cxgb4/t4-config.txt"
+
+#define FW_VERSION_MAJOR	1
+#define FW_VERSION_MINOR	2
+#define FW_VERSION_MICRO	8
+
+#define CSIO_HW_NAME		"Chelsio FCoE Adapter"
+#define CSIO_MAX_PFN		8
+#define CSIO_MAX_PPORTS		4
+
+#define CSIO_MAX_LUN		0xFFFF
+#define CSIO_MAX_QUEUE		2048
+#define CSIO_MAX_CMD_PER_LUN	32
+#define CSIO_MAX_DDP_BUF_SIZE	(1024 * 1024)
+#define CSIO_MAX_SECTOR_SIZE	128
+
+/* Interrupts */
+#define CSIO_EXTRA_MSI_IQS	2	/* Extra iqs for INTX/MSI mode
+					 * (Forward intr iq + fw iq) */
+#define CSIO_EXTRA_VECS		2	/* non-data + FW evt */
+#define CSIO_MAX_SCSI_CPU	128
+#define CSIO_MAX_SCSI_QSETS	(CSIO_MAX_SCSI_CPU * CSIO_MAX_PPORTS)
+#define CSIO_MAX_MSIX_VECS	(CSIO_MAX_SCSI_QSETS + CSIO_EXTRA_VECS)
+
+/* Queues */
+enum {
+	CSIO_INTR_WRSIZE = 128,
+	CSIO_INTR_IQSIZE = ((CSIO_MAX_MSIX_VECS + 1) * CSIO_INTR_WRSIZE),
+	CSIO_FWEVT_WRSIZE = 128,
+	CSIO_FWEVT_IQLEN = 128,
+	CSIO_FWEVT_FLBUFS = 64,
+	CSIO_FWEVT_IQSIZE = (CSIO_FWEVT_WRSIZE * CSIO_FWEVT_IQLEN),
+	CSIO_HW_NIQ = 1,
+	CSIO_HW_NFLQ = 1,
+	CSIO_HW_NEQ = 1,
+	CSIO_HW_NINTXQ = 1,
+};
+
+struct csio_msix_entries {
+	unsigned short	vector;		/* Vector assigned by pci_enable_msix */
+	void		*dev_id;	/* Priv object associated w/ this msix*/
+	char		desc[24];	/* Description of this vector */
+};
+
+struct csio_scsi_qset {
+	int		iq_idx;		/* Ingress index */
+	int		eq_idx;		/* Egress index */
+	uint32_t	intr_idx;	/* MSIX Vector index */
+};
+
+struct csio_scsi_cpu_info {
+	int16_t	max_cpus;
+};
+
+extern int csio_dbg_level;
+extern int csio_force_master;
+extern unsigned int csio_port_mask;
+extern int csio_msi;
+
+#define CSIO_VENDOR_ID				0x1425
+#define CSIO_ASIC_DEVID_PROTO_MASK		0xFF00
+#define CSIO_ASIC_DEVID_TYPE_MASK		0x00FF
+#define CSIO_FPGA				0xA000
+#define CSIO_T4_FCOE_ASIC			0x4600
+
+#define CSIO_GLBL_INTR_MASK		(CIM | MPS | PL | PCIE | MC | EDC0 | \
+					 EDC1 | LE | TP | MA | PM_TX | PM_RX | \
+					 ULP_RX | CPL_SWITCH | SGE | \
+					 ULP_TX | SF)
+
+/*
+ * Hard parameters used to initialize the card in the absence of a
+ * configuration file.
+ */
+enum {
+	/* General */
+	CSIO_SGE_DBFIFO_INT_THRESH	= 10,
+
+	CSIO_SGE_RX_DMA_OFFSET		= 2,
+
+	CSIO_SGE_FLBUF_SIZE1		= 65536,
+	CSIO_SGE_FLBUF_SIZE2		= 1536,
+	CSIO_SGE_FLBUF_SIZE3		= 9024,
+	CSIO_SGE_FLBUF_SIZE4		= 9216,
+	CSIO_SGE_FLBUF_SIZE5		= 2048,
+	CSIO_SGE_FLBUF_SIZE6		= 128,
+	CSIO_SGE_FLBUF_SIZE7		= 8192,
+	CSIO_SGE_FLBUF_SIZE8		= 16384,
+
+	CSIO_SGE_TIMER_VAL_0		= 5,
+	CSIO_SGE_TIMER_VAL_1		= 10,
+	CSIO_SGE_TIMER_VAL_2		= 20,
+	CSIO_SGE_TIMER_VAL_3		= 50,
+	CSIO_SGE_TIMER_VAL_4		= 100,
+	CSIO_SGE_TIMER_VAL_5		= 200,
+
+	CSIO_SGE_INT_CNT_VAL_0		= 1,
+	CSIO_SGE_INT_CNT_VAL_1		= 4,
+	CSIO_SGE_INT_CNT_VAL_2		= 8,
+	CSIO_SGE_INT_CNT_VAL_3		= 16,
+
+	/* Storage specific - used by FW_PFVF_CMD */
+	CSIO_WX_CAPS			= FW_CMD_CAP_PF, /* w/x all */
+	CSIO_R_CAPS			= FW_CMD_CAP_PF, /* r all */
+	CSIO_NVI			= 4,
+	CSIO_NIQ_FLINT			= 34,
+	CSIO_NETH_CTRL			= 32,
+	CSIO_NEQ			= 66,
+	CSIO_NEXACTF			= 32,
+	CSIO_CMASK			= FW_PFVF_CMD_CMASK_MASK,
+	CSIO_PMASK			= FW_PFVF_CMD_PMASK_MASK,
+};
+
+/* Slowpath events */
+enum csio_evt {
+	CSIO_EVT_FW  = 0,	/* FW event */
+	CSIO_EVT_MBX,		/* MBX event */
+	CSIO_EVT_SCN,		/* State change notification */
+	CSIO_EVT_DEV_LOSS,	/* Device loss event */
+	CSIO_EVT_MAX,		/* Max supported event */
+};
+
+#define CSIO_EVT_MSG_SIZE	512
+#define CSIO_EVTQ_SIZE		512
+
+/* Event msg  */
+struct csio_evt_msg {
+	struct list_head	list;	/* evt queue*/
+	enum csio_evt		type;
+	uint8_t			data[CSIO_EVT_MSG_SIZE];
+};
+
+enum {
+	EEPROMVSIZE    = 32768, /* Serial EEPROM virtual address space size */
+	SERNUM_LEN     = 16,    /* Serial # length */
+	EC_LEN         = 16,    /* E/C length */
+	ID_LEN         = 16,    /* ID length */
+	TRACE_LEN      = 112,   /* length of trace data and mask */
+};
+
+enum {
+	SF_PAGE_SIZE = 256,           /* serial flash page size */
+	SF_SEC_SIZE = 64 * 1024,      /* serial flash sector size */
+	SF_SIZE = SF_SEC_SIZE * 16,   /* serial flash size */
+};
+
+enum { MEM_EDC0, MEM_EDC1, MEM_MC };
+
+enum {
+	MEMWIN0_APERTURE = 2048,
+	MEMWIN0_BASE     = 0x1b800,
+	MEMWIN1_APERTURE = 32768,
+	MEMWIN1_BASE     = 0x28000,
+	MEMWIN2_APERTURE = 65536,
+	MEMWIN2_BASE     = 0x30000,
+};
+
+/* serial flash and firmware constants */
+enum {
+	SF_ATTEMPTS = 10,             /* max retries for SF operations */
+
+	/* flash command opcodes */
+	SF_PROG_PAGE    = 2,          /* program page */
+	SF_WR_DISABLE   = 4,          /* disable writes */
+	SF_RD_STATUS    = 5,          /* read status register */
+	SF_WR_ENABLE    = 6,          /* enable writes */
+	SF_RD_DATA_FAST = 0xb,        /* read flash */
+	SF_RD_ID	= 0x9f,	      /* read ID */
+	SF_ERASE_SECTOR = 0xd8,       /* erase sector */
+
+	FW_START_SEC = 8,             /* first flash sector for FW */
+	FW_END_SEC = 15,              /* last flash sector for FW */
+	FW_IMG_START = FW_START_SEC * SF_SEC_SIZE,
+	FW_MAX_SIZE = (FW_END_SEC - FW_START_SEC + 1) * SF_SEC_SIZE,
+
+	FLASH_CFG_MAX_SIZE    = 0x10000 , /* max size of the flash config file*/
+	FLASH_CFG_OFFSET      = 0x1f0000,
+	FLASH_CFG_START_SEC   = FLASH_CFG_OFFSET / SF_SEC_SIZE,
+	FPGA_FLASH_CFG_OFFSET = 0xf0000 , /* if FPGA mode, then cfg file is
+					   * at 1MB - 64KB */
+	FPGA_FLASH_CFG_START_SEC  = FPGA_FLASH_CFG_OFFSET / SF_SEC_SIZE,
+};
+
+/*
+ * Flash layout.
+ */
+#define FLASH_START(start)	((start) * SF_SEC_SIZE)
+#define FLASH_MAX_SIZE(nsecs)	((nsecs) * SF_SEC_SIZE)
+
+enum {
+	/*
+	 * Location of firmware image in FLASH.
+	 */
+	FLASH_FW_START_SEC = 8,
+	FLASH_FW_NSECS = 8,
+	FLASH_FW_START = FLASH_START(FLASH_FW_START_SEC),
+	FLASH_FW_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FW_NSECS),
+
+};
+
+#undef FLASH_START
+#undef FLASH_MAX_SIZE
+
+/* Management module */
+enum {
+	CSIO_MGMT_EQ_WRSIZE = 512,
+	CSIO_MGMT_IQ_WRSIZE = 128,
+	CSIO_MGMT_EQLEN = 64,
+	CSIO_MGMT_IQLEN = 64,
+};
+
+#define CSIO_MGMT_EQSIZE	(CSIO_MGMT_EQLEN * CSIO_MGMT_EQ_WRSIZE)
+#define CSIO_MGMT_IQSIZE	(CSIO_MGMT_IQLEN * CSIO_MGMT_IQ_WRSIZE)
+
+/* mgmt module stats */
+struct csio_mgmtm_stats {
+	uint32_t	n_abort_req;		/* Total abort request */
+	uint32_t	n_abort_rsp;		/* Total abort response */
+	uint32_t	n_close_req;		/* Total close request */
+	uint32_t	n_close_rsp;		/* Total close response */
+	uint32_t	n_err;			/* Total Errors */
+	uint32_t	n_drop;			/* Total request dropped */
+	uint32_t	n_active;		/* Count of active_q */
+	uint32_t	n_cbfn;			/* Count of cbfn_q */
+};
+
+/* MGMT module */
+struct csio_mgmtm {
+	struct	csio_hw		*hw;		/* Pointer to HW moduel */
+	int			eq_idx;		/* Egress queue index */
+	int			iq_idx;		/* Ingress queue index */
+	int			msi_vec;	/* MSI vector */
+	struct list_head	active_q;	/* Outstanding ELS/CT */
+	struct list_head	abort_q;	/* Outstanding abort req */
+	struct list_head	cbfn_q;		/* Completion queue */
+	struct list_head	mgmt_req_freelist; /* Free poll of reqs */
+						/* ELSCT request freelist*/
+	struct timer_list	mgmt_timer;	/* MGMT timer */
+	struct csio_mgmtm_stats stats;		/* ELS/CT stats */
+};
+
+struct csio_adap_desc {
+	char model_no[16];
+	char description[32];
+};
+
+struct pci_params {
+	uint16_t   vendor_id;
+	uint16_t   device_id;
+	uint32_t   vpd_cap_addr;
+	uint16_t   speed;
+	uint8_t    width;
+};
+
+/* User configurable hw parameters */
+struct csio_hw_params {
+	uint32_t		sf_size;		/* serial flash
+							 * size in bytes
+							 */
+	uint32_t		sf_nsec;		/* # of flash sectors */
+	struct pci_params	pci;
+	uint32_t		log_level;		/* Module-level for
+							 * debug log.
+							 */
+};
+
+struct csio_vpd {
+	uint32_t cclk;
+	uint8_t ec[EC_LEN + 1];
+	uint8_t sn[SERNUM_LEN + 1];
+	uint8_t id[ID_LEN + 1];
+};
+
+struct csio_pport {
+	uint16_t	pcap;
+	uint8_t		portid;
+	uint8_t		link_status;
+	uint16_t	link_speed;
+	uint8_t		mac[6];
+	uint8_t		mod_type;
+	uint8_t		rsvd1;
+	uint8_t		rsvd2;
+	uint8_t		rsvd3;
+};
+
+/* fcoe resource information */
+struct csio_fcoe_res_info {
+	uint16_t	e_d_tov;
+	uint16_t	r_a_tov_seq;
+	uint16_t	r_a_tov_els;
+	uint16_t	r_r_tov;
+	uint32_t	max_xchgs;
+	uint32_t	max_ssns;
+	uint32_t	used_xchgs;
+	uint32_t	used_ssns;
+	uint32_t	max_fcfs;
+	uint32_t	max_vnps;
+	uint32_t	used_fcfs;
+	uint32_t	used_vnps;
+};
+
+/* HW State machine Events */
+enum csio_hw_ev {
+	CSIO_HWE_CFG = (uint32_t)1, /* Starts off the State machine */
+	CSIO_HWE_INIT,	         /* Config done, start Init      */
+	CSIO_HWE_INIT_DONE,      /* Init Mailboxes sent, HW ready */
+	CSIO_HWE_FATAL,		 /* Fatal error during initialization */
+	CSIO_HWE_PCIERR_DETECTED,/* PCI error recovery detetced */
+	CSIO_HWE_PCIERR_SLOT_RESET, /* Slot reset after PCI recoviery */
+	CSIO_HWE_PCIERR_RESUME,  /* Resume after PCI error recovery */
+	CSIO_HWE_QUIESCED,	 /* HBA quiesced */
+	CSIO_HWE_HBA_RESET,      /* HBA reset requested */
+	CSIO_HWE_HBA_RESET_DONE, /* HBA reset completed */
+	CSIO_HWE_FW_DLOAD,       /* FW download requested */
+	CSIO_HWE_PCI_REMOVE,     /* PCI de-instantiation */
+	CSIO_HWE_SUSPEND,        /* HW suspend for Online(hot) replacement */
+	CSIO_HWE_RESUME,         /* HW resume for Online(hot) replacement */
+	CSIO_HWE_MAX,		 /* Max HW event */
+};
+
+/* hw stats */
+struct csio_hw_stats {
+	uint32_t	n_evt_activeq;	/* Number of event in active Q */
+	uint32_t	n_evt_freeq;	/* Number of event in free Q */
+	uint32_t	n_evt_drop;	/* Number of event droped */
+	uint32_t	n_evt_unexp;	/* Number of unexpected events */
+	uint32_t	n_pcich_offline;/* Number of pci channel offline */
+	uint32_t	n_lnlkup_miss;  /* Number of lnode lookup miss */
+	uint32_t	n_cpl_fw6_msg;	/* Number of cpl fw6 message*/
+	uint32_t	n_cpl_fw6_pld;	/* Number of cpl fw6 payload*/
+	uint32_t	n_cpl_unexp;	/* Number of unexpected cpl */
+	uint32_t	n_mbint_unexp;	/* Number of unexpected mbox */
+					/* interrupt */
+	uint32_t	n_plint_unexp;	/* Number of unexpected PL */
+					/* interrupt */
+	uint32_t	n_plint_cnt;	/* Number of PL interrupt */
+	uint32_t	n_int_stray;	/* Number of stray interrupt */
+	uint32_t	n_err;		/* Number of hw errors */
+	uint32_t	n_err_fatal;	/* Number of fatal errors */
+	uint32_t	n_err_nomem;	/* Number of memory alloc failure */
+	uint32_t	n_err_io;	/* Number of IO failure */
+	enum csio_hw_ev	n_evt_sm[CSIO_HWE_MAX];	/* Number of sm events */
+	uint64_t	n_reset_start;  /* Start time after the reset */
+	uint32_t	rsvd1;
+};
+
+/* Defines for hw->flags */
+#define CSIO_HWF_MASTER			0x00000001	/* This is the Master
+							 * function for the
+							 * card.
+							 */
+#define	CSIO_HWF_HW_INTR_ENABLED	0x00000002	/* Are HW Interrupt
+							 * enable bit set?
+							 */
+#define	CSIO_HWF_FWEVT_PENDING		0x00000004	/* FW events pending */
+#define	CSIO_HWF_Q_MEM_ALLOCED		0x00000008	/* Queues have been
+							 * allocated memory.
+							 */
+#define	CSIO_HWF_Q_FW_ALLOCED		0x00000010	/* Queues have been
+							 * allocated in FW.
+							 */
+#define CSIO_HWF_VPD_VALID		0x00000020	/* Valid VPD copied */
+#define CSIO_HWF_DEVID_CACHED		0X00000040	/* PCI vendor & device
+							 * id cached */
+#define	CSIO_HWF_FWEVT_STOP		0x00000080	/* Stop processing
+							 * FW events
+							 */
+#define CSIO_HWF_USING_SOFT_PARAMS	0x00000100      /* Using FW config
+							 * params
+							 */
+#define	CSIO_HWF_HOST_INTR_ENABLED	0x00000200	/* Are host interrupts
+							 * enabled?
+							 */
+
+#define csio_is_hw_intr_enabled(__hw)	\
+				((__hw)->flags & CSIO_HWF_HW_INTR_ENABLED)
+#define csio_is_host_intr_enabled(__hw)	\
+				((__hw)->flags & CSIO_HWF_HOST_INTR_ENABLED)
+#define csio_is_hw_master(__hw)		((__hw)->flags & CSIO_HWF_MASTER)
+#define csio_is_valid_vpd(__hw)		((__hw)->flags & CSIO_HWF_VPD_VALID)
+#define csio_is_dev_id_cached(__hw)	((__hw)->flags & CSIO_HWF_DEVID_CACHED)
+#define csio_valid_vpd_copied(__hw)	((__hw)->flags |= CSIO_HWF_VPD_VALID)
+#define csio_dev_id_cached(__hw)	((__hw)->flags |= CSIO_HWF_DEVID_CACHED)
+
+/* Defines for intr_mode */
+enum csio_intr_mode {
+	CSIO_IM_NONE = 0,
+	CSIO_IM_INTX = 1,
+	CSIO_IM_MSI  = 2,
+	CSIO_IM_MSIX = 3,
+};
+
+/* Master HW structure: One per function */
+struct csio_hw {
+	struct csio_sm		sm;			/* State machine: should
+							 * be the 1st member.
+							 */
+	spinlock_t		lock;			/* Lock for hw */
+
+	struct csio_scsim	scsim;			/* SCSI module*/
+	struct csio_wrm		wrm;			/* Work request module*/
+	struct pci_dev		*pdev;			/* PCI device */
+
+	void __iomem		*regstart;		/* Virtual address of
+							 * register map
+							 */
+	/* SCSI queue sets */
+	uint32_t		num_sqsets;		/* Number of SCSI
+							 * queue sets */
+	uint32_t		num_scsi_msix_cpus;	/* Number of CPUs that
+							 * will be used
+							 * for ingress
+							 * processing.
+							 */
+
+	struct csio_scsi_qset	sqset[CSIO_MAX_PPORTS][CSIO_MAX_SCSI_CPU];
+	struct csio_scsi_cpu_info scsi_cpu_info[CSIO_MAX_PPORTS];
+
+	uint32_t		evtflag;		/* Event flag  */
+	uint32_t		flags;			/* HW flags */
+
+	struct csio_mgmtm	mgmtm;			/* management module */
+	struct csio_mbm		mbm;			/* Mailbox module */
+
+	/* Lnodes */
+	uint32_t		num_lns;		/* Number of lnodes */
+	struct csio_lnode	*rln;			/* Root lnode */
+	struct list_head	sln_head;		/* Sibling node list
+							 * list
+							 */
+	int			intr_iq_idx;		/* Forward interrupt
+							 * queue.
+							 */
+	int			fwevt_iq_idx;		/* FW evt queue */
+	struct work_struct	evtq_work;		/* Worker thread for
+							 * HW events.
+							 */
+	struct list_head	evt_free_q;		/* freelist of evt
+							 * elements
+							 */
+	struct list_head	evt_active_q;		/* active evt queue*/
+
+	/* board related info */
+	char			name[32];
+	char			hw_ver[16];
+	char			model_desc[32];
+	char			drv_version[32];
+	char			fwrev_str[32];
+	uint32_t		optrom_ver;
+	uint32_t		fwrev;
+	uint32_t		tp_vers;
+	char			chip_ver;
+	uint32_t		cfg_finiver;
+	uint32_t		cfg_finicsum;
+	uint32_t		cfg_cfcsum;
+	uint8_t			cfg_csum_status;
+	uint8_t			cfg_store;
+	enum csio_dev_state	fw_state;
+	struct csio_vpd		vpd;
+
+	uint8_t			pfn;			/* Physical Function
+							 * number
+							 */
+	uint32_t		port_vec;		/* Port vector */
+	uint8_t			num_pports;		/* Number of physical
+							 * ports.
+							 */
+	uint8_t			rst_retries;		/* Reset retries */
+	uint8_t			cur_evt;		/* current s/m evt */
+	uint8_t			prev_evt;		/* Previous s/m evt */
+	uint32_t		dev_num;		/* device number */
+	struct csio_pport	pport[CSIO_MAX_PPORTS];	/* Ports (XGMACs) */
+	struct csio_hw_params	params;			/* Hw parameters */
+
+	struct pci_pool		*scsi_pci_pool;		/* PCI pool for SCSI */
+	mempool_t		*mb_mempool;		/* Mailbox memory pool*/
+	mempool_t		*rnode_mempool;		/* rnode memory pool */
+
+	/* Interrupt */
+	enum csio_intr_mode	intr_mode;		/* INTx, MSI, MSIX */
+	uint32_t		fwevt_intr_idx;		/* FW evt MSIX/interrupt
+							 * index
+							 */
+	uint32_t		nondata_intr_idx;	/* nondata MSIX/intr
+							 * idx
+							 */
+
+	uint8_t			cfg_neq;		/* FW configured no of
+							 * egress queues
+							 */
+	uint8_t			cfg_niq;		/* FW configured no of
+							 * iq queues.
+							 */
+
+	struct csio_fcoe_res_info  fres_info;		/* Fcoe resource info */
+
+	/* MSIX vectors */
+	struct csio_msix_entries msix_entries[CSIO_MAX_MSIX_VECS];
+
+	struct dentry		*debugfs_root;		/* Debug FS */
+	struct csio_hw_stats	stats;			/* Hw statistics */
+};
+
+/* Register access macros */
+#define csio_reg(_b, _r)		((_b) + (_r))
+
+#define	csio_rd_reg8(_h, _r)		readb(csio_reg((_h)->regstart, (_r)))
+#define	csio_rd_reg16(_h, _r)		readw(csio_reg((_h)->regstart, (_r)))
+#define	csio_rd_reg32(_h, _r)		readl(csio_reg((_h)->regstart, (_r)))
+#define	csio_rd_reg64(_h, _r)		readq(csio_reg((_h)->regstart, (_r)))
+
+#define	csio_wr_reg8(_h, _v, _r)	writeb((_v), \
+						csio_reg((_h)->regstart, (_r)))
+#define	csio_wr_reg16(_h, _v, _r)	writew((_v), \
+						csio_reg((_h)->regstart, (_r)))
+#define	csio_wr_reg32(_h, _v, _r)	writel((_v), \
+						csio_reg((_h)->regstart, (_r)))
+#define	csio_wr_reg64(_h, _v, _r)	writeq((_v), \
+						csio_reg((_h)->regstart, (_r)))
+
+void csio_set_reg_field(struct csio_hw *, uint32_t, uint32_t, uint32_t);
+
+/* Core clocks <==> uSecs */
+static inline uint32_t
+csio_core_ticks_to_us(struct csio_hw *hw, uint32_t ticks)
+{
+	/* add Core Clock / 2 to round ticks to nearest uS */
+	return (ticks * 1000 + hw->vpd.cclk/2) / hw->vpd.cclk;
+}
+
+static inline uint32_t
+csio_us_to_core_ticks(struct csio_hw *hw, uint32_t us)
+{
+	return (us * hw->vpd.cclk) / 1000;
+}
+
+/* Easy access macros */
+#define csio_hw_to_wrm(hw)		((struct csio_wrm *)(&(hw)->wrm))
+#define csio_hw_to_mbm(hw)		((struct csio_mbm *)(&(hw)->mbm))
+#define csio_hw_to_scsim(hw)		((struct csio_scsim *)(&(hw)->scsim))
+#define csio_hw_to_mgmtm(hw)		((struct csio_mgmtm *)(&(hw)->mgmtm))
+
+#define CSIO_PCI_BUS(hw)		((hw)->pdev->bus->number)
+#define CSIO_PCI_DEV(hw)		(PCI_SLOT((hw)->pdev->devfn))
+#define CSIO_PCI_FUNC(hw)		(PCI_FUNC((hw)->pdev->devfn))
+
+#define csio_set_fwevt_intr_idx(_h, _i)		((_h)->fwevt_intr_idx = (_i))
+#define csio_get_fwevt_intr_idx(_h)		((_h)->fwevt_intr_idx)
+#define csio_set_nondata_intr_idx(_h, _i)	((_h)->nondata_intr_idx = (_i))
+#define csio_get_nondata_intr_idx(_h)		((_h)->nondata_intr_idx)
+
+/* Printing/logging */
+#define CSIO_DEVID(__dev)		((__dev)->dev_num)
+#define CSIO_DEVID_LO(__dev)		(CSIO_DEVID((__dev)) & 0xFFFF)
+#define CSIO_DEVID_HI(__dev)		((CSIO_DEVID((__dev)) >> 16) & 0xFFFF)
+
+#define csio_info(__hw, __fmt, ...)					\
+			dev_info(&(__hw)->pdev->dev, __fmt, ##__VA_ARGS__)
+
+#define csio_fatal(__hw, __fmt, ...)					\
+			dev_crit(&(__hw)->pdev->dev, __fmt, ##__VA_ARGS__)
+
+#define csio_err(__hw, __fmt, ...)					\
+			dev_err(&(__hw)->pdev->dev, __fmt, ##__VA_ARGS__)
+
+#define csio_warn(__hw, __fmt, ...)					\
+			dev_warn(&(__hw)->pdev->dev, __fmt, ##__VA_ARGS__)
+
+#ifdef __CSIO_DEBUG__
+#define csio_dbg(__hw, __fmt, ...)					\
+			csio_info((__hw), __fmt, ##__VA_ARGS__);
+#else
+#define csio_dbg(__hw, __fmt, ...)
+#endif
+
+int csio_mgmt_req_lookup(struct csio_mgmtm *, struct csio_ioreq *);
+void csio_hw_intr_disable(struct csio_hw *);
+int csio_hw_slow_intr_handler(struct csio_hw *hw);
+int csio_hw_start(struct csio_hw *);
+int csio_hw_stop(struct csio_hw *);
+int csio_hw_reset(struct csio_hw *);
+int csio_is_hw_ready(struct csio_hw *);
+int csio_is_hw_removing(struct csio_hw *);
+
+int csio_fwevtq_handler(struct csio_hw *);
+void csio_evtq_worker(struct work_struct *);
+int csio_enqueue_evt(struct csio_hw *hw, enum csio_evt type,
+				void *evt_msg, uint16_t len);
+void csio_evtq_flush(struct csio_hw *hw);
+
+int csio_request_irqs(struct csio_hw *);
+void csio_intr_enable(struct csio_hw *);
+void csio_intr_disable(struct csio_hw *, bool);
+
+struct csio_lnode *csio_lnode_alloc(struct csio_hw *);
+int csio_config_queues(struct csio_hw *);
+
+int csio_hw_mc_read(struct csio_hw *, uint32_t,
+			      uint32_t *, uint64_t *);
+int csio_hw_edc_read(struct csio_hw *, int, uint32_t, uint32_t *,
+			       uint64_t *);
+int csio_hw_init(struct csio_hw *);
+void csio_hw_exit(struct csio_hw *);
+#endif /* ifndef __CSIO_HW_H__ */
diff --git a/drivers/scsi/csiostor/csio_init.h b/drivers/scsi/csiostor/csio_init.h
new file mode 100644
index 0000000..0838fd7
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_init.h
@@ -0,0 +1,158 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_INIT_H__
+#define __CSIO_INIT_H__
+
+#include <linux/pci.h>
+#include <linux/if_ether.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "csio_scsi.h"
+#include "csio_lnode.h"
+#include "csio_rnode.h"
+#include "csio_hw.h"
+
+#define CSIO_DRV_AUTHOR			"Chelsio Communications"
+#define CSIO_DRV_LICENSE		"Dual BSD/GPL"
+#define CSIO_DRV_DESC			"Chelsio FCoE driver"
+#define CSIO_DRV_VERSION		"1.0.0"
+
+#define CSIO_DEVICE(devid, idx)					\
+{ PCI_VENDOR_ID_CHELSIO, (devid), PCI_ANY_ID, PCI_ANY_ID, 0, 0, (idx) }
+
+#define CSIO_IS_T4_FPGA(_dev)		(((_dev) == CSIO_DEVID_PE10K) ||\
+					 ((_dev) == CSIO_DEVID_PE10K_PF1))
+
+/* FCoE device IDs */
+#define CSIO_DEVID_PE10K		0xA000
+#define CSIO_DEVID_PE10K_PF1		0xA001
+#define CSIO_DEVID_T440DBG_FCOE		0x4600
+#define CSIO_DEVID_T420CR_FCOE		0x4601
+#define CSIO_DEVID_T422CR_FCOE		0x4602
+#define CSIO_DEVID_T440CR_FCOE		0x4603
+#define CSIO_DEVID_T420BCH_FCOE		0x4604
+#define CSIO_DEVID_T440BCH_FCOE		0x4605
+#define CSIO_DEVID_T440CH_FCOE		0x4606
+#define CSIO_DEVID_T420SO_FCOE		0x4607
+#define CSIO_DEVID_T420CX_FCOE		0x4608
+#define CSIO_DEVID_T420BT_FCOE		0x4609
+#define CSIO_DEVID_T404BT_FCOE		0x460A
+#define CSIO_DEVID_B420_FCOE		0x460B
+#define CSIO_DEVID_B404_FCOE		0x460C
+#define CSIO_DEVID_T480CR_FCOE		0x460D
+#define CSIO_DEVID_T440LPCR_FCOE	0x460E
+
+extern struct fc_function_template csio_fc_transport_funcs;
+extern struct fc_function_template csio_fc_transport_vport_funcs;
+
+void csio_fchost_attr_init(struct csio_lnode *);
+
+/* INTx handlers */
+void csio_scsi_intx_handler(struct csio_hw *, void *, uint32_t,
+			       struct csio_fl_dma_buf *, void *);
+
+void csio_fwevt_intx_handler(struct csio_hw *, void *, uint32_t,
+				struct csio_fl_dma_buf *, void *);
+
+/* Common os lnode APIs */
+void csio_lnodes_block_request(struct csio_hw *);
+void csio_lnodes_unblock_request(struct csio_hw *);
+void csio_lnodes_block_by_port(struct csio_hw *, uint8_t);
+void csio_lnodes_unblock_by_port(struct csio_hw *, uint8_t);
+
+struct csio_lnode *csio_shost_init(struct csio_hw *, struct device *, bool,
+					struct csio_lnode *);
+void csio_shost_exit(struct csio_lnode *);
+void csio_lnodes_exit(struct csio_hw *, bool);
+
+static inline struct Scsi_Host *
+csio_ln_to_shost(struct csio_lnode *ln)
+{
+	return container_of((void *)ln, struct Scsi_Host, hostdata[0]);
+}
+
+/* SCSI -- locking version of get/put ioreqs  */
+static inline struct csio_ioreq *
+csio_get_scsi_ioreq_lock(struct csio_hw *hw, struct csio_scsim *scsim)
+{
+	struct csio_ioreq *ioreq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scsim->freelist_lock, flags);
+	ioreq = csio_get_scsi_ioreq(scsim);
+	spin_unlock_irqrestore(&scsim->freelist_lock, flags);
+
+	return ioreq;
+}
+
+static inline void
+csio_put_scsi_ioreq_lock(struct csio_hw *hw, struct csio_scsim *scsim,
+			 struct csio_ioreq *ioreq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&scsim->freelist_lock, flags);
+	csio_put_scsi_ioreq(scsim, ioreq);
+	spin_unlock_irqrestore(&scsim->freelist_lock, flags);
+}
+
+/* Called in interrupt context */
+static inline void
+csio_put_scsi_ioreq_list_lock(struct csio_hw *hw, struct csio_scsim *scsim,
+			      struct list_head *reqlist, int n)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&scsim->freelist_lock, flags);
+	csio_put_scsi_ioreq_list(scsim, reqlist, n);
+	spin_unlock_irqrestore(&scsim->freelist_lock, flags);
+}
+
+/* Called in interrupt context */
+static inline void
+csio_put_scsi_ddp_list_lock(struct csio_hw *hw, struct csio_scsim *scsim,
+			      struct list_head *reqlist, int n)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hw->lock, flags);
+	csio_put_scsi_ddp_list(scsim, reqlist, n);
+	spin_unlock_irqrestore(&hw->lock, flags);
+}
+
+#endif /* ifndef __CSIO_INIT_H__ */
diff --git a/drivers/scsi/csiostor/t4fw_api_stor.h b/drivers/scsi/csiostor/t4fw_api_stor.h
new file mode 100644
index 0000000..b96903a
--- /dev/null
+++ b/drivers/scsi/csiostor/t4fw_api_stor.h
@@ -0,0 +1,578 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _T4FW_API_STOR_H_
+#define _T4FW_API_STOR_H_
+
+
+/******************************************************************************
+ *   R E T U R N   V A L U E S
+ ********************************/
+
+enum fw_retval {
+	FW_SUCCESS		= 0,	/* completed sucessfully */
+	FW_EPERM		= 1,	/* operation not permitted */
+	FW_ENOENT		= 2,	/* no such file or directory */
+	FW_EIO			= 5,	/* input/output error; hw bad */
+	FW_ENOEXEC		= 8,	/* exec format error; inv microcode */
+	FW_EAGAIN		= 11,	/* try again */
+	FW_ENOMEM		= 12,	/* out of memory */
+	FW_EFAULT		= 14,	/* bad address; fw bad */
+	FW_EBUSY		= 16,	/* resource busy */
+	FW_EEXIST		= 17,	/* file exists */
+	FW_EINVAL		= 22,	/* invalid argument */
+	FW_ENOSPC		= 28,	/* no space left on device */
+	FW_ENOSYS		= 38,	/* functionality not implemented */
+	FW_EPROTO		= 71,	/* protocol error */
+	FW_EADDRINUSE		= 98,	/* address already in use */
+	FW_EADDRNOTAVAIL	= 99,	/* cannot assigned requested address */
+	FW_ENETDOWN		= 100,	/* network is down */
+	FW_ENETUNREACH		= 101,	/* network is unreachable */
+	FW_ENOBUFS		= 105,	/* no buffer space available */
+	FW_ETIMEDOUT		= 110,	/* timeout */
+	FW_EINPROGRESS		= 115,	/* fw internal */
+	FW_SCSI_ABORT_REQUESTED	= 128,	/* */
+	FW_SCSI_ABORT_TIMEDOUT	= 129,	/* */
+	FW_SCSI_ABORTED		= 130,	/* */
+	FW_SCSI_CLOSE_REQUESTED	= 131,	/* */
+	FW_ERR_LINK_DOWN	= 132,	/* */
+	FW_RDEV_NOT_READY	= 133,	/* */
+	FW_ERR_RDEV_LOST	= 134,	/* */
+	FW_ERR_RDEV_LOGO	= 135,	/* */
+	FW_FCOE_NO_XCHG		= 136,	/* */
+	FW_SCSI_RSP_ERR		= 137,	/* */
+	FW_ERR_RDEV_IMPL_LOGO	= 138,	/* */
+	FW_SCSI_UNDER_FLOW_ERR  = 139,	/* */
+	FW_SCSI_OVER_FLOW_ERR   = 140,	/* */
+	FW_SCSI_DDP_ERR		= 141,	/* DDP error*/
+	FW_SCSI_TASK_ERR	= 142,	/* No SCSI tasks available */
+};
+
+enum fw_fcoe_link_sub_op {
+	FCOE_LINK_DOWN	= 0x0,
+	FCOE_LINK_UP	= 0x1,
+	FCOE_LINK_COND	= 0x2,
+};
+
+enum fw_fcoe_link_status {
+	FCOE_LINKDOWN	= 0x0,
+	FCOE_LINKUP	= 0x1,
+};
+
+enum fw_ofld_prot {
+	PROT_FCOE	= 0x1,
+	PROT_ISCSI	= 0x2,
+};
+
+enum rport_type_fcoe {
+	FLOGI_VFPORT	= 0x1,		/* 0xfffffe */
+	FDISC_VFPORT	= 0x2,		/* 0xfffffe */
+	NS_VNPORT	= 0x3,		/* 0xfffffc */
+	REG_FC4_VNPORT	= 0x4,		/* any FC4 type VN_PORT */
+	REG_VNPORT	= 0x5,		/* 0xfffxxx - non FC4 port in switch */
+	FDMI_VNPORT	= 0x6,		/* 0xfffffa */
+	FAB_CTLR_VNPORT	= 0x7,		/* 0xfffffd */
+};
+
+enum event_cause_fcoe {
+	PLOGI_ACC_RCVD		= 0x01,
+	PLOGI_RJT_RCVD		= 0x02,
+	PLOGI_RCVD		= 0x03,
+	PLOGO_RCVD		= 0x04,
+	PRLI_ACC_RCVD		= 0x05,
+	PRLI_RJT_RCVD		= 0x06,
+	PRLI_RCVD		= 0x07,
+	PRLO_RCVD		= 0x08,
+	NPORT_ID_CHGD		= 0x09,
+	FLOGO_RCVD		= 0x0a,
+	CLR_VIRT_LNK_RCVD	= 0x0b,
+	FLOGI_ACC_RCVD		= 0x0c,
+	FLOGI_RJT_RCVD		= 0x0d,
+	FDISC_ACC_RCVD		= 0x0e,
+	FDISC_RJT_RCVD		= 0x0f,
+	FLOGI_TMO_MAX_RETRY	= 0x10,
+	IMPL_LOGO_ADISC_ACC	= 0x11,
+	IMPL_LOGO_ADISC_RJT	= 0x12,
+	IMPL_LOGO_ADISC_CNFLT	= 0x13,
+	PRLI_TMO		= 0x14,
+	ADISC_TMO		= 0x15,
+	RSCN_DEV_LOST		= 0x16,
+	SCR_ACC_RCVD		= 0x17,
+	ADISC_RJT_RCVD		= 0x18,
+	LOGO_SNT		= 0x19,
+	PROTO_ERR_IMPL_LOGO	= 0x1a,
+};
+
+enum fcoe_cmn_type {
+	FCOE_ELS,
+	FCOE_CT,
+	FCOE_SCSI_CMD,
+	FCOE_UNSOL_ELS,
+};
+
+enum fw_wr_stor_opcodes {
+	FW_RDEV_WR                     = 0x38,
+	FW_FCOE_ELS_CT_WR              = 0x30,
+	FW_SCSI_WRITE_WR               = 0x31,
+	FW_SCSI_READ_WR                = 0x32,
+	FW_SCSI_CMD_WR                 = 0x33,
+	FW_SCSI_ABRT_CLS_WR            = 0x34,
+};
+
+struct fw_rdev_wr {
+	__be32 op_to_immdlen;
+	__be32 alloc_to_len16;
+	__be64 cookie;
+	u8     protocol;
+	u8     event_cause;
+	u8     cur_state;
+	u8     prev_state;
+	__be32 flags_to_assoc_flowid;
+	union rdev_entry {
+		struct fcoe_rdev_entry {
+			__be32 flowid;
+			u8     protocol;
+			u8     event_cause;
+			u8     flags;
+			u8     rjt_reason;
+			u8     cur_login_st;
+			u8     prev_login_st;
+			__be16 rcv_fr_sz;
+			u8     rd_xfer_rdy_to_rport_type;
+			u8     vft_to_qos;
+			u8     org_proc_assoc_to_acc_rsp_code;
+			u8     enh_disc_to_tgt;
+			u8     wwnn[8];
+			u8     wwpn[8];
+			__be16 iqid;
+			u8     fc_oui[3];
+			u8     r_id[3];
+		} fcoe_rdev;
+		struct iscsi_rdev_entry {
+			__be32 flowid;
+			u8     protocol;
+			u8     event_cause;
+			u8     flags;
+			u8     r3;
+			__be16 iscsi_opts;
+			__be16 tcp_opts;
+			__be16 ip_opts;
+			__be16 max_rcv_len;
+			__be16 max_snd_len;
+			__be16 first_brst_len;
+			__be16 max_brst_len;
+			__be16 r4;
+			__be16 def_time2wait;
+			__be16 def_time2ret;
+			__be16 nop_out_intrvl;
+			__be16 non_scsi_to;
+			__be16 isid;
+			__be16 tsid;
+			__be16 port;
+			__be16 tpgt;
+			u8     r5[6];
+			__be16 iqid;
+		} iscsi_rdev;
+	} u;
+};
+
+#define FW_RDEV_WR_FLOWID_GET(x)	(((x) >> 8) & 0xfffff)
+#define FW_RDEV_WR_ASSOC_FLOWID_GET(x)	(((x) >> 0) & 0xfffff)
+#define FW_RDEV_WR_RPORT_TYPE_GET(x)	(((x) >> 0) & 0x1f)
+#define FW_RDEV_WR_NPIV_GET(x)		(((x) >> 6) & 0x1)
+#define FW_RDEV_WR_CLASS_GET(x)		(((x) >> 4) & 0x3)
+#define FW_RDEV_WR_TASK_RETRY_ID_GET(x)	(((x) >> 5) & 0x1)
+#define FW_RDEV_WR_RETRY_GET(x)		(((x) >> 4) & 0x1)
+#define FW_RDEV_WR_CONF_CMPL_GET(x)	(((x) >> 3) & 0x1)
+#define FW_RDEV_WR_INI_GET(x)		(((x) >> 1) & 0x1)
+#define FW_RDEV_WR_TGT_GET(x)		(((x) >> 0) & 0x1)
+
+struct fw_fcoe_els_ct_wr {
+	__be32 op_immdlen;
+	__be32 flowid_len16;
+	__be64 cookie;
+	__be16 iqid;
+	u8     tmo_val;
+	u8     els_ct_type;
+	u8     ctl_pri;
+	u8     cp_en_class;
+	__be16 xfer_cnt;
+	u8     fl_to_sp;
+	u8     l_id[3];
+	u8     r5;
+	u8     r_id[3];
+	__be64 rsp_dmaaddr;
+	__be32 rsp_dmalen;
+	__be32 r6;
+};
+
+#define FW_FCOE_ELS_CT_WR_OPCODE(x)		((x) << 24)
+#define FW_FCOE_ELS_CT_WR_OPCODE_GET(x)		(((x) >> 24) & 0xff)
+#define FW_FCOE_ELS_CT_WR_IMMDLEN(x)		((x) << 0)
+#define FW_FCOE_ELS_CT_WR_IMMDLEN_GET(x)	(((x) >> 0) & 0xff)
+#define FW_FCOE_ELS_CT_WR_SP(x)			((x) << 0)
+
+struct fw_scsi_write_wr {
+	__be32 op_immdlen;
+	__be32 flowid_len16;
+	__be64 cookie;
+	__be16 iqid;
+	u8     tmo_val;
+	u8     use_xfer_cnt;
+	union fw_scsi_write_priv {
+		struct fcoe_write_priv {
+			u8   ctl_pri;
+			u8   cp_en_class;
+			u8   r3_lo[2];
+		} fcoe;
+		struct iscsi_write_priv {
+			u8   r3[4];
+		} iscsi;
+	} u;
+	__be32 xfer_cnt;
+	__be32 ini_xfer_cnt;
+	__be64 rsp_dmaaddr;
+	__be32 rsp_dmalen;
+	__be32 r4;
+};
+
+#define FW_SCSI_WRITE_WR_IMMDLEN(x)	((x) << 0)
+
+struct fw_scsi_read_wr {
+	__be32 op_immdlen;
+	__be32 flowid_len16;
+	__be64 cookie;
+	__be16 iqid;
+	u8     tmo_val;
+	u8     use_xfer_cnt;
+	union fw_scsi_read_priv {
+		struct fcoe_read_priv {
+			u8   ctl_pri;
+			u8   cp_en_class;
+			u8   r3_lo[2];
+		} fcoe;
+		struct iscsi_read_priv {
+			u8   r3[4];
+		} iscsi;
+	} u;
+	__be32 xfer_cnt;
+	__be32 ini_xfer_cnt;
+	__be64 rsp_dmaaddr;
+	__be32 rsp_dmalen;
+	__be32 r4;
+};
+
+#define FW_SCSI_READ_WR_IMMDLEN(x)	((x) << 0)
+
+struct fw_scsi_cmd_wr {
+	__be32 op_immdlen;
+	__be32 flowid_len16;
+	__be64 cookie;
+	__be16 iqid;
+	u8     tmo_val;
+	u8     r3;
+	union fw_scsi_cmd_priv {
+		struct fcoe_cmd_priv {
+			u8   ctl_pri;
+			u8   cp_en_class;
+			u8   r4_lo[2];
+		} fcoe;
+		struct iscsi_cmd_priv {
+			u8   r4[4];
+		} iscsi;
+	} u;
+	u8     r5[8];
+	__be64 rsp_dmaaddr;
+	__be32 rsp_dmalen;
+	__be32 r6;
+};
+
+#define FW_SCSI_CMD_WR_IMMDLEN(x)	((x) << 0)
+
+#define SCSI_ABORT 0
+#define SCSI_CLOSE 1
+
+struct fw_scsi_abrt_cls_wr {
+	__be32 op_immdlen;
+	__be32 flowid_len16;
+	__be64 cookie;
+	__be16 iqid;
+	u8     tmo_val;
+	u8     sub_opcode_to_chk_all_io;
+	u8     r3[4];
+	__be64 t_cookie;
+};
+
+#define FW_SCSI_ABRT_CLS_WR_SUB_OPCODE(x)	((x) << 2)
+#define FW_SCSI_ABRT_CLS_WR_SUB_OPCODE_GET(x)	(((x) >> 2) & 0x3f)
+#define FW_SCSI_ABRT_CLS_WR_CHK_ALL_IO(x)	((x) << 0)
+
+enum fw_cmd_stor_opcodes {
+	FW_FCOE_RES_INFO_CMD           = 0x31,
+	FW_FCOE_LINK_CMD               = 0x32,
+	FW_FCOE_VNP_CMD                = 0x33,
+	FW_FCOE_SPARAMS_CMD            = 0x35,
+	FW_FCOE_STATS_CMD              = 0x37,
+	FW_FCOE_FCF_CMD                = 0x38,
+};
+
+struct fw_fcoe_res_info_cmd {
+	__be32 op_to_read;
+	__be32 retval_len16;
+	__be16 e_d_tov;
+	__be16 r_a_tov_seq;
+	__be16 r_a_tov_els;
+	__be16 r_r_tov;
+	__be32 max_xchgs;
+	__be32 max_ssns;
+	__be32 used_xchgs;
+	__be32 used_ssns;
+	__be32 max_fcfs;
+	__be32 max_vnps;
+	__be32 used_fcfs;
+	__be32 used_vnps;
+};
+
+struct fw_fcoe_link_cmd {
+	__be32 op_to_portid;
+	__be32 retval_len16;
+	__be32 sub_opcode_fcfi;
+	u8     r3;
+	u8     lstatus;
+	__be16 flags;
+	u8     r4;
+	u8     set_vlan;
+	__be16 vlan_id;
+	__be32 vnpi_pkd;
+	__be16 r6;
+	u8     phy_mac[6];
+	u8     vnport_wwnn[8];
+	u8     vnport_wwpn[8];
+};
+
+#define FW_FCOE_LINK_CMD_PORTID(x)	((x) << 0)
+#define FW_FCOE_LINK_CMD_PORTID_GET(x)	(((x) >> 0) & 0xf)
+#define FW_FCOE_LINK_CMD_SUB_OPCODE(x)  ((x) << 24U)
+#define FW_FCOE_LINK_CMD_FCFI(x)	((x) << 0)
+#define FW_FCOE_LINK_CMD_FCFI_GET(x)	(((x) >> 0) & 0xffffff)
+#define FW_FCOE_LINK_CMD_VNPI_GET(x)	(((x) >> 0) & 0xfffff)
+
+struct fw_fcoe_vnp_cmd {
+	__be32 op_to_fcfi;
+	__be32 alloc_to_len16;
+	__be32 gen_wwn_to_vnpi;
+	__be32 vf_id;
+	__be16 iqid;
+	u8   vnport_mac[6];
+	u8   vnport_wwnn[8];
+	u8   vnport_wwpn[8];
+	u8   cmn_srv_parms[16];
+	u8   clsp_word_0_1[8];
+};
+
+#define FW_FCOE_VNP_CMD_FCFI(x)		((x) << 0)
+#define FW_FCOE_VNP_CMD_ALLOC		(1U << 31)
+#define FW_FCOE_VNP_CMD_FREE		(1U << 30)
+#define FW_FCOE_VNP_CMD_MODIFY		(1U << 29)
+#define FW_FCOE_VNP_CMD_GEN_WWN		(1U << 22)
+#define FW_FCOE_VNP_CMD_VFID_EN		(1U << 20)
+#define FW_FCOE_VNP_CMD_VNPI(x)		((x) << 0)
+#define FW_FCOE_VNP_CMD_VNPI_GET(x)	(((x) >> 0) & 0xfffff)
+
+struct fw_fcoe_sparams_cmd {
+	__be32 op_to_portid;
+	__be32 retval_len16;
+	u8     r3[7];
+	u8     cos;
+	u8     lport_wwnn[8];
+	u8     lport_wwpn[8];
+	u8     cmn_srv_parms[16];
+	u8     cls_srv_parms[16];
+};
+
+#define FW_FCOE_SPARAMS_CMD_PORTID(x)	((x) << 0)
+
+struct fw_fcoe_stats_cmd {
+	__be32 op_to_flowid;
+	__be32 free_to_len16;
+	union fw_fcoe_stats {
+		struct fw_fcoe_stats_ctl {
+			u8   nstats_port;
+			u8   port_valid_ix;
+			__be16 r6;
+			__be32 r7;
+			__be64 stat0;
+			__be64 stat1;
+			__be64 stat2;
+			__be64 stat3;
+			__be64 stat4;
+			__be64 stat5;
+		} ctl;
+		struct fw_fcoe_port_stats {
+			__be64 tx_bcast_bytes;
+			__be64 tx_bcast_frames;
+			__be64 tx_mcast_bytes;
+			__be64 tx_mcast_frames;
+			__be64 tx_ucast_bytes;
+			__be64 tx_ucast_frames;
+			__be64 tx_drop_frames;
+			__be64 tx_offload_bytes;
+			__be64 tx_offload_frames;
+			__be64 rx_bcast_bytes;
+			__be64 rx_bcast_frames;
+			__be64 rx_mcast_bytes;
+			__be64 rx_mcast_frames;
+			__be64 rx_ucast_bytes;
+			__be64 rx_ucast_frames;
+			__be64 rx_err_frames;
+		} port_stats;
+		struct fw_fcoe_fcf_stats {
+			__be32 fip_tx_bytes;
+			__be32 fip_tx_fr;
+			__be64 fcf_ka;
+			__be64 mcast_adv_rcvd;
+			__be16 ucast_adv_rcvd;
+			__be16 sol_sent;
+			__be16 vlan_req;
+			__be16 vlan_rpl;
+			__be16 clr_vlink;
+			__be16 link_down;
+			__be16 link_up;
+			__be16 logo;
+			__be16 flogi_req;
+			__be16 flogi_rpl;
+			__be16 fdisc_req;
+			__be16 fdisc_rpl;
+			__be16 fka_prd_chg;
+			__be16 fc_map_chg;
+			__be16 vfid_chg;
+			u8   no_fka_req;
+			u8   no_vnp;
+		} fcf_stats;
+		struct fw_fcoe_pcb_stats {
+			__be64 tx_bytes;
+			__be64 tx_frames;
+			__be64 rx_bytes;
+			__be64 rx_frames;
+			__be32 vnp_ka;
+			__be32 unsol_els_rcvd;
+			__be64 unsol_cmd_rcvd;
+			__be16 implicit_logo;
+			__be16 flogi_inv_sparm;
+			__be16 fdisc_inv_sparm;
+			__be16 flogi_rjt;
+			__be16 fdisc_rjt;
+			__be16 no_ssn;
+			__be16 mac_flt_fail;
+			__be16 inv_fr_rcvd;
+		} pcb_stats;
+		struct fw_fcoe_scb_stats {
+			__be64 tx_bytes;
+			__be64 tx_frames;
+			__be64 rx_bytes;
+			__be64 rx_frames;
+			__be32 host_abrt_req;
+			__be32 adap_auto_abrt;
+			__be32 adap_abrt_rsp;
+			__be32 host_ios_req;
+			__be16 ssn_offl_ios;
+			__be16 ssn_not_rdy_ios;
+			u8   rx_data_ddp_err;
+			u8   ddp_flt_set_err;
+			__be16 rx_data_fr_err;
+			u8   bad_st_abrt_req;
+			u8   no_io_abrt_req;
+			u8   abort_tmo;
+			u8   abort_tmo_2;
+			__be32 abort_req;
+			u8   no_ppod_res_tmo;
+			u8   bp_tmo;
+			u8   adap_auto_cls;
+			u8   no_io_cls_req;
+			__be32 host_cls_req;
+			__be64 unsol_cmd_rcvd;
+			__be32 plogi_req_rcvd;
+			__be32 prli_req_rcvd;
+			__be16 logo_req_rcvd;
+			__be16 prlo_req_rcvd;
+			__be16 plogi_rjt_rcvd;
+			__be16 prli_rjt_rcvd;
+			__be32 adisc_req_rcvd;
+			__be32 rscn_rcvd;
+			__be32 rrq_req_rcvd;
+			__be32 unsol_els_rcvd;
+			u8   adisc_rjt_rcvd;
+			u8   scr_rjt;
+			u8   ct_rjt;
+			u8   inval_bls_rcvd;
+			__be32 ba_rjt_rcvd;
+		} scb_stats;
+	} u;
+};
+
+#define FW_FCOE_STATS_CMD_FLOWID(x)	((x) << 0)
+#define FW_FCOE_STATS_CMD_FREE		(1U << 30)
+#define FW_FCOE_STATS_CMD_NSTATS(x)	((x) << 4)
+#define FW_FCOE_STATS_CMD_PORT(x)	((x) << 0)
+#define FW_FCOE_STATS_CMD_PORT_VALID	(1U << 7)
+#define FW_FCOE_STATS_CMD_IX(x)		((x) << 0)
+
+struct fw_fcoe_fcf_cmd {
+	__be32 op_to_fcfi;
+	__be32 retval_len16;
+	__be16 priority_pkd;
+	u8     mac[6];
+	u8     name_id[8];
+	u8     fabric[8];
+	__be16 vf_id;
+	__be16 max_fcoe_size;
+	u8     vlan_id;
+	u8     fc_map[3];
+	__be32 fka_adv;
+	__be32 r6;
+	u8     r7_hi;
+	u8     fpma_to_portid;
+	u8     spma_mac[6];
+	__be64 r8;
+};
+
+#define FW_FCOE_FCF_CMD_FCFI(x)		((x) << 0)
+#define FW_FCOE_FCF_CMD_FCFI_GET(x)	(((x) >> 0) & 0xfffff)
+#define FW_FCOE_FCF_CMD_PRIORITY_GET(x)	(((x) >> 0) & 0xff)
+#define FW_FCOE_FCF_CMD_FPMA_GET(x)	(((x) >> 6) & 0x1)
+#define FW_FCOE_FCF_CMD_SPMA_GET(x)	(((x) >> 5) & 0x1)
+#define FW_FCOE_FCF_CMD_LOGIN_GET(x)	(((x) >> 4) & 0x1)
+#define FW_FCOE_FCF_CMD_PORTID_GET(x)	(((x) >> 0) & 0xf)
+
+#endif /* _T4FW_API_STOR_H_ */
-- 
1.7.1


^ permalink raw reply related

* [V3 PATCH 5/9] csiostor: Chelsio FCoE offload driver submission (sources part 5).
From: Naresh Kumar Inna @ 2012-09-11 14:39 UTC (permalink / raw)
  To: JBottomley, linux-scsi, dm, leedom; +Cc: netdev, naresh, chethan
In-Reply-To: <1347374347-3852-1-git-send-email-naresh@chelsio.com>

This patch contains code to implement the interrupt handling and the fast
path I/O functionality. The interrupt handling includes allocation of
MSIX vectors, registering and implemeting the interrupt service routines.
The fast path I/O functionality includes posting the I/O request to firmware
via Work Requests, tracking/completing them, and handling task management
requests. SCSI midlayer host template implementation is also covered by
this patch.

Signed-off-by: Naresh Kumar Inna <naresh@chelsio.com>
---
V2:
- Inlined code instead of macro in csio_isr.c
- Use true/false instead if CSIO_TRUE/CSIO_FALSE.                               - Use DMA_ defines instead of CSIO_IOREQF_DMA_ defines.
- Replaced large local stack buffer with pre-allocated memory.
- Replaced fast path macros with static functions.
- Removed extra empty lines, needless comment.

 drivers/scsi/csiostor/csio_isr.c  |  624 +++++++++
 drivers/scsi/csiostor/csio_scsi.c | 2561 +++++++++++++++++++++++++++++++++++++
 2 files changed, 3185 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/csiostor/csio_isr.c
 create mode 100644 drivers/scsi/csiostor/csio_scsi.c

diff --git a/drivers/scsi/csiostor/csio_isr.c b/drivers/scsi/csiostor/csio_isr.c
new file mode 100644
index 0000000..7ee9777
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_isr.c
@@ -0,0 +1,624 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/cpumask.h>
+#include <linux/string.h>
+
+#include "csio_init.h"
+#include "csio_hw.h"
+
+static irqreturn_t
+csio_nondata_isr(int irq, void *dev_id)
+{
+	struct csio_hw *hw = (struct csio_hw *) dev_id;
+	int rv;
+	unsigned long flags;
+
+	if (unlikely(!hw))
+		return IRQ_NONE;
+
+	if (unlikely(pci_channel_offline(hw->pdev))) {
+		CSIO_INC_STATS(hw, n_pcich_offline);
+		return IRQ_NONE;
+	}
+
+	spin_lock_irqsave(&hw->lock, flags);
+	csio_hw_slow_intr_handler(hw);
+	rv = csio_mb_isr_handler(hw);
+
+	if (rv == 0 && !(hw->flags & CSIO_HWF_FWEVT_PENDING)) {
+		hw->flags |= CSIO_HWF_FWEVT_PENDING;
+		spin_unlock_irqrestore(&hw->lock, flags);
+		schedule_work(&hw->evtq_work);
+		return IRQ_HANDLED;
+	}
+	spin_unlock_irqrestore(&hw->lock, flags);
+	return IRQ_HANDLED;
+}
+
+/*
+ * csio_fwevt_handler - Common FW event handler routine.
+ * @hw: HW module.
+ *
+ * This is the ISR for FW events. It is shared b/w MSIX
+ * and INTx handlers.
+ */
+static void
+csio_fwevt_handler(struct csio_hw *hw)
+{
+	int rv;
+	unsigned long flags;
+
+	rv = csio_fwevtq_handler(hw);
+
+	spin_lock_irqsave(&hw->lock, flags);
+	if (rv == 0 && !(hw->flags & CSIO_HWF_FWEVT_PENDING)) {
+		hw->flags |= CSIO_HWF_FWEVT_PENDING;
+		spin_unlock_irqrestore(&hw->lock, flags);
+		schedule_work(&hw->evtq_work);
+		return;
+	}
+	spin_unlock_irqrestore(&hw->lock, flags);
+
+} /* csio_fwevt_handler */
+
+/*
+ * csio_fwevt_isr() - FW events MSIX ISR
+ * @irq:
+ * @dev_id:
+ *
+ * Process WRs on the FW event queue.
+ *
+ */
+static irqreturn_t
+csio_fwevt_isr(int irq, void *dev_id)
+{
+	struct csio_hw *hw = (struct csio_hw *) dev_id;
+
+	if (unlikely(!hw))
+		return IRQ_NONE;
+
+	if (unlikely(pci_channel_offline(hw->pdev))) {
+		CSIO_INC_STATS(hw, n_pcich_offline);
+		return IRQ_NONE;
+	}
+
+	csio_fwevt_handler(hw);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * csio_fwevt_isr() - INTx wrapper for handling FW events.
+ * @irq:
+ * @dev_id:
+ */
+void
+csio_fwevt_intx_handler(struct csio_hw *hw, void *wr, uint32_t len,
+			   struct csio_fl_dma_buf *flb, void *priv)
+{
+	csio_fwevt_handler(hw);
+} /* csio_fwevt_intx_handler */
+
+/*
+ * csio_process_scsi_cmpl - Process a SCSI WR completion.
+ * @hw: HW module.
+ * @wr: The completed WR from the ingress queue.
+ * @len: Length of the WR.
+ * @flb: Freelist buffer array.
+ *
+ */
+static void
+csio_process_scsi_cmpl(struct csio_hw *hw, void *wr, uint32_t len,
+			struct csio_fl_dma_buf *flb, void *cbfn_q)
+{
+	struct csio_ioreq *ioreq;
+	uint8_t *scsiwr;
+	uint8_t subop;
+	void *cmnd;
+	unsigned long flags;
+
+	ioreq = csio_scsi_cmpl_handler(hw, wr, len, flb, NULL, &scsiwr);
+	if (likely(ioreq)) {
+		if (unlikely(*scsiwr == FW_SCSI_ABRT_CLS_WR)) {
+			subop = FW_SCSI_ABRT_CLS_WR_SUB_OPCODE_GET(
+					((struct fw_scsi_abrt_cls_wr *)
+					    scsiwr)->sub_opcode_to_chk_all_io);
+
+			csio_dbg(hw, "%s cmpl recvd ioreq:%p status:%d\n",
+				    subop ? "Close" : "Abort",
+				    ioreq, ioreq->wr_status);
+
+			spin_lock_irqsave(&hw->lock, flags);
+			if (subop)
+				csio_scsi_closed(ioreq,
+						 (struct list_head *)cbfn_q);
+			else
+				csio_scsi_aborted(ioreq,
+						  (struct list_head *)cbfn_q);
+			/*
+			 * We call scsi_done for I/Os that driver thinks aborts
+			 * have timed out. If there is a race caused by FW
+			 * completing abort at the exact same time that the
+			 * driver has deteced the abort timeout, the following
+			 * check prevents calling of scsi_done twice for the
+			 * same command: once from the eh_abort_handler, another
+			 * from csio_scsi_isr_handler(). This also avoids the
+			 * need to check if csio_scsi_cmnd(req) is NULL in the
+			 * fast path.
+			 */
+			cmnd = csio_scsi_cmnd(ioreq);
+			if (unlikely(cmnd == NULL))
+				list_del_init(&ioreq->sm.sm_list);
+
+			spin_unlock_irqrestore(&hw->lock, flags);
+
+			if (unlikely(cmnd == NULL))
+				csio_put_scsi_ioreq_lock(hw,
+						csio_hw_to_scsim(hw), ioreq);
+		} else {
+			spin_lock_irqsave(&hw->lock, flags);
+			csio_scsi_completed(ioreq, (struct list_head *)cbfn_q);
+			spin_unlock_irqrestore(&hw->lock, flags);
+		}
+	}
+}
+
+/*
+ * csio_scsi_isr_handler() - Common SCSI ISR handler.
+ * @iq: Ingress queue pointer.
+ *
+ * Processes SCSI completions on the SCSI IQ indicated by scm->iq_idx
+ * by calling csio_wr_process_iq_idx. If there are completions on the
+ * isr_cbfn_q, yank them out into a local queue and call their io_cbfns.
+ * Once done, add these completions onto the freelist.
+ * This routine is shared b/w MSIX and INTx.
+ */
+static inline irqreturn_t
+csio_scsi_isr_handler(struct csio_q *iq)
+{
+	struct csio_hw *hw = (struct csio_hw *)iq->owner;
+	LIST_HEAD(cbfn_q);
+	struct list_head *tmp;
+	struct csio_scsim *scm;
+	struct csio_ioreq *ioreq;
+	int isr_completions = 0;
+
+	scm = csio_hw_to_scsim(hw);
+
+	if (unlikely(csio_wr_process_iq(hw, iq, csio_process_scsi_cmpl,
+					&cbfn_q) != 0))
+		return IRQ_NONE;
+
+	/* Call back the completion routines */
+	list_for_each(tmp, &cbfn_q) {
+		ioreq = (struct csio_ioreq *)tmp;
+		isr_completions++;
+		ioreq->io_cbfn(hw, ioreq);
+		/* Release ddp buffer if used for this req */
+		if (unlikely(ioreq->dcopy))
+			csio_put_scsi_ddp_list_lock(hw, scm, &ioreq->gen_list,
+						    ioreq->nsge);
+	}
+
+	if (isr_completions) {
+		/* Return the ioreqs back to ioreq->freelist */
+		csio_put_scsi_ioreq_list_lock(hw, scm, &cbfn_q,
+					      isr_completions);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * csio_scsi_isr() - SCSI MSIX handler
+ * @irq:
+ * @dev_id:
+ *
+ * This is the top level SCSI MSIX handler. Calls csio_scsi_isr_handler()
+ * for handling SCSI completions.
+ */
+static irqreturn_t
+csio_scsi_isr(int irq, void *dev_id)
+{
+	struct csio_q *iq = (struct csio_q *) dev_id;
+	struct csio_hw *hw;
+
+	if (unlikely(!iq))
+		return IRQ_NONE;
+
+	hw = (struct csio_hw *)iq->owner;
+
+	if (unlikely(pci_channel_offline(hw->pdev))) {
+		CSIO_INC_STATS(hw, n_pcich_offline);
+		return IRQ_NONE;
+	}
+
+	csio_scsi_isr_handler(iq);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * csio_scsi_intx_handler() - SCSI INTx handler
+ * @irq:
+ * @dev_id:
+ *
+ * This is the top level SCSI INTx handler. Calls csio_scsi_isr_handler()
+ * for handling SCSI completions.
+ */
+void
+csio_scsi_intx_handler(struct csio_hw *hw, void *wr, uint32_t len,
+			struct csio_fl_dma_buf *flb, void *priv)
+{
+	struct csio_q *iq = priv;
+
+	csio_scsi_isr_handler(iq);
+
+} /* csio_scsi_intx_handler */
+
+/*
+ * csio_fcoe_isr() - INTx/MSI interrupt service routine for FCoE.
+ * @irq:
+ * @dev_id:
+ *
+ *
+ */
+static irqreturn_t
+csio_fcoe_isr(int irq, void *dev_id)
+{
+	struct csio_hw *hw = (struct csio_hw *) dev_id;
+	struct csio_q *intx_q = NULL;
+	int rv;
+	irqreturn_t ret = IRQ_NONE;
+	unsigned long flags;
+
+	if (unlikely(!hw))
+		return IRQ_NONE;
+
+	if (unlikely(pci_channel_offline(hw->pdev))) {
+		CSIO_INC_STATS(hw, n_pcich_offline);
+		return IRQ_NONE;
+	}
+
+	/* Disable the interrupt for this PCI function. */
+	if (hw->intr_mode == CSIO_IM_INTX)
+		csio_wr_reg32(hw, 0, MYPF_REG(PCIE_PF_CLI));
+
+	/*
+	 * The read in the following function will flush the
+	 * above write.
+	 */
+	if (csio_hw_slow_intr_handler(hw))
+		ret = IRQ_HANDLED;
+
+	/* Get the INTx Forward interrupt IQ. */
+	intx_q = csio_get_q(hw, hw->intr_iq_idx);
+
+	CSIO_DB_ASSERT(intx_q);
+
+	/* IQ handler is not possible for intx_q, hence pass in NULL */
+	if (likely(csio_wr_process_iq(hw, intx_q, NULL, NULL) == 0))
+		ret = IRQ_HANDLED;
+
+	spin_lock_irqsave(&hw->lock, flags);
+	rv = csio_mb_isr_handler(hw);
+	if (rv == 0 && !(hw->flags & CSIO_HWF_FWEVT_PENDING)) {
+		hw->flags |= CSIO_HWF_FWEVT_PENDING;
+		spin_unlock_irqrestore(&hw->lock, flags);
+		schedule_work(&hw->evtq_work);
+		return IRQ_HANDLED;
+	}
+	spin_unlock_irqrestore(&hw->lock, flags);
+
+	return ret;
+}
+
+static void
+csio_add_msix_desc(struct csio_hw *hw)
+{
+	int i;
+	struct csio_msix_entries *entryp = &hw->msix_entries[0];
+	int k = CSIO_EXTRA_VECS;
+	int len = sizeof(entryp->desc) - 1;
+	int cnt = hw->num_sqsets + k;
+
+	/* Non-data vector */
+	memset(entryp->desc, 0, len + 1);
+	snprintf(entryp->desc, len, "csio-%02x:%02x:%x-nondata",
+		 CSIO_PCI_BUS(hw), CSIO_PCI_DEV(hw), CSIO_PCI_FUNC(hw));
+
+	entryp++;
+	memset(entryp->desc, 0, len + 1);
+	snprintf(entryp->desc, len, "csio-%02x:%02x:%x-fwevt",
+		 CSIO_PCI_BUS(hw), CSIO_PCI_DEV(hw), CSIO_PCI_FUNC(hw));
+	entryp++;
+
+	/* Name SCSI vecs */
+	for (i = k; i < cnt; i++, entryp++) {
+		memset(entryp->desc, 0, len + 1);
+		snprintf(entryp->desc, len, "csio-%02x:%02x:%x-scsi%d",
+			 CSIO_PCI_BUS(hw), CSIO_PCI_DEV(hw),
+			 CSIO_PCI_FUNC(hw), i - CSIO_EXTRA_VECS);
+	}
+}
+
+int
+csio_request_irqs(struct csio_hw *hw)
+{
+	int rv, i, j, k = 0;
+	struct csio_msix_entries *entryp = &hw->msix_entries[0];
+	struct csio_scsi_cpu_info *info;
+
+	if (hw->intr_mode != CSIO_IM_MSIX) {
+		rv = request_irq(hw->pdev->irq, csio_fcoe_isr,
+					(hw->intr_mode == CSIO_IM_MSI) ?
+							0 : IRQF_SHARED,
+					KBUILD_MODNAME, hw);
+		if (rv) {
+			if (hw->intr_mode == CSIO_IM_MSI)
+				pci_disable_msi(hw->pdev);
+			csio_err(hw, "Failed to allocate interrupt line.\n");
+			return -EINVAL;
+		}
+
+		goto out;
+	}
+
+	/* Add the MSIX vector descriptions */
+	csio_add_msix_desc(hw);
+
+	rv = request_irq(entryp[k].vector, csio_nondata_isr, 0,
+			 entryp[k].desc, hw);
+	if (rv) {
+		csio_err(hw, "IRQ request failed for vec %d err:%d\n",
+			 entryp[k].vector, rv);
+		goto err;
+	}
+
+	entryp[k++].dev_id = (void *)hw;
+
+	rv = request_irq(entryp[k].vector, csio_fwevt_isr, 0,
+			 entryp[k].desc, hw);
+	if (rv) {
+		csio_err(hw, "IRQ request failed for vec %d err:%d\n",
+			 entryp[k].vector, rv);
+		goto err;
+	}
+
+	entryp[k++].dev_id = (void *)hw;
+
+	/* Allocate IRQs for SCSI */
+	for (i = 0; i < hw->num_pports; i++) {
+		info = &hw->scsi_cpu_info[i];
+		for (j = 0; j < info->max_cpus; j++, k++) {
+			struct csio_scsi_qset *sqset = &hw->sqset[i][j];
+			struct csio_q *q = hw->wrm.q_arr[sqset->iq_idx];
+
+			rv = request_irq(entryp[k].vector, csio_scsi_isr, 0,
+					 entryp[k].desc, q);
+			if (rv) {
+				csio_err(hw,
+				       "IRQ request failed for vec %d err:%d\n",
+				       entryp[k].vector, rv);
+				goto err;
+			}
+
+			entryp[k].dev_id = (void *)q;
+
+		} /* for all scsi cpus */
+	} /* for all ports */
+
+out:
+	hw->flags |= CSIO_HWF_HOST_INTR_ENABLED;
+
+	return 0;
+
+err:
+	for (i = 0; i < k; i++) {
+		entryp = &hw->msix_entries[i];
+		free_irq(entryp->vector, entryp->dev_id);
+	}
+	pci_disable_msix(hw->pdev);
+
+	return -EINVAL;
+}
+
+static void
+csio_disable_msix(struct csio_hw *hw, bool free)
+{
+	int i;
+	struct csio_msix_entries *entryp;
+	int cnt = hw->num_sqsets + CSIO_EXTRA_VECS;
+
+	if (free) {
+		for (i = 0; i < cnt; i++) {
+			entryp = &hw->msix_entries[i];
+			free_irq(entryp->vector, entryp->dev_id);
+		}
+	}
+	pci_disable_msix(hw->pdev);
+}
+
+/* Reduce per-port max possible CPUs */
+static void
+csio_reduce_sqsets(struct csio_hw *hw, int cnt)
+{
+	int i;
+	struct csio_scsi_cpu_info *info;
+
+	while (cnt < hw->num_sqsets) {
+		for (i = 0; i < hw->num_pports; i++) {
+			info = &hw->scsi_cpu_info[i];
+			if (info->max_cpus > 1) {
+				info->max_cpus--;
+				hw->num_sqsets--;
+				if (hw->num_sqsets <= cnt)
+					break;
+			}
+		}
+	}
+
+	csio_dbg(hw, "Reduced sqsets to %d\n", hw->num_sqsets);
+}
+
+static int
+csio_enable_msix(struct csio_hw *hw)
+{
+	int rv, i, j, k, n, min, cnt;
+	struct csio_msix_entries *entryp;
+	struct msix_entry *entries;
+	int extra = CSIO_EXTRA_VECS;
+	struct csio_scsi_cpu_info *info;
+
+	min = hw->num_pports + extra;
+	cnt = hw->num_sqsets + extra;
+
+	/* Max vectors required based on #niqs configured in fw */
+	if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS || !csio_is_hw_master(hw))
+		cnt = min_t(uint8_t, hw->cfg_niq, cnt);
+
+	entries = kzalloc(sizeof(struct msix_entry) * cnt, GFP_KERNEL);
+	if (!entries)
+		return -ENOMEM;
+
+	for (i = 0; i < cnt; i++)
+		entries[i].entry = (uint16_t)i;
+
+	csio_dbg(hw, "FW supp #niq:%d, trying %d msix's\n", hw->cfg_niq, cnt);
+
+	while ((rv = pci_enable_msix(hw->pdev, entries, cnt)) >= min)
+		cnt = rv;
+	if (!rv) {
+		if (cnt < (hw->num_sqsets + extra)) {
+			csio_dbg(hw, "Reducing sqsets to %d\n", cnt - extra);
+			csio_reduce_sqsets(hw, cnt - extra);
+		}
+	} else {
+		if (rv > 0) {
+			pci_disable_msix(hw->pdev);
+			csio_info(hw, "Not using MSI-X, remainder:%d\n", rv);
+		}
+
+		kfree(entries);
+		return -ENOMEM;
+	}
+
+	/* Save off vectors */
+	for (i = 0; i < cnt; i++) {
+		entryp = &hw->msix_entries[i];
+		entryp->vector = entries[i].vector;
+	}
+
+	/* Distribute vectors */
+	k = 0;
+	csio_set_nondata_intr_idx(hw, entries[k].entry);
+	csio_set_mb_intr_idx(csio_hw_to_mbm(hw), entries[k++].entry);
+	csio_set_fwevt_intr_idx(hw, entries[k++].entry);
+
+	for (i = 0; i < hw->num_pports; i++) {
+		info = &hw->scsi_cpu_info[i];
+
+		for (j = 0; j < hw->num_scsi_msix_cpus; j++) {
+			n = (j % info->max_cpus) +  k;
+			hw->sqset[i][j].intr_idx = entries[n].entry;
+		}
+
+		k += info->max_cpus;
+	}
+
+	kfree(entries);
+	return 0;
+}
+
+void
+csio_intr_enable(struct csio_hw *hw)
+{
+	hw->intr_mode = CSIO_IM_NONE;
+	hw->flags &= ~CSIO_HWF_HOST_INTR_ENABLED;
+
+	/* Try MSIX, then MSI or fall back to INTx */
+	if ((csio_msi == 2) && !csio_enable_msix(hw))
+		hw->intr_mode = CSIO_IM_MSIX;
+	else {
+		/* Max iqs required based on #niqs configured in fw */
+		if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS ||
+			!csio_is_hw_master(hw)) {
+			int extra = CSIO_EXTRA_MSI_IQS;
+
+			if (hw->cfg_niq < (hw->num_sqsets + extra)) {
+				csio_dbg(hw, "Reducing sqsets to %d\n",
+					 hw->cfg_niq - extra);
+				csio_reduce_sqsets(hw, hw->cfg_niq - extra);
+			}
+		}
+
+		if ((csio_msi == 1) && !pci_enable_msi(hw->pdev))
+			hw->intr_mode = CSIO_IM_MSI;
+		else
+			hw->intr_mode = CSIO_IM_INTX;
+	}
+
+	csio_dbg(hw, "Using %s interrupt mode.\n",
+		(hw->intr_mode == CSIO_IM_MSIX) ? "MSIX" :
+		((hw->intr_mode == CSIO_IM_MSI) ? "MSI" : "INTx"));
+}
+
+void
+csio_intr_disable(struct csio_hw *hw, bool free)
+{
+	csio_hw_intr_disable(hw);
+
+	switch (hw->intr_mode) {
+	case CSIO_IM_MSIX:
+		csio_disable_msix(hw, free);
+		break;
+	case CSIO_IM_MSI:
+		if (free)
+			free_irq(hw->pdev->irq, hw);
+		pci_disable_msi(hw->pdev);
+		break;
+	case CSIO_IM_INTX:
+		if (free)
+			free_irq(hw->pdev->irq, hw);
+		break;
+	default:
+		break;
+	}
+	hw->intr_mode = CSIO_IM_NONE;
+	hw->flags &= ~CSIO_HWF_HOST_INTR_ENABLED;
+}
diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c
new file mode 100644
index 0000000..a7ce747
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_scsi.c
@@ -0,0 +1,2561 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/compiler.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+#include <asm/page.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "csio_hw.h"
+#include "csio_lnode.h"
+#include "csio_rnode.h"
+#include "csio_scsi.h"
+#include "csio_init.h"
+
+int csio_scsi_eqsize = 65536;
+int csio_scsi_iqlen = 128;
+int csio_scsi_ioreqs = 2048;
+uint32_t csio_max_scan_tmo;
+uint32_t csio_delta_scan_tmo = 5;
+int csio_lun_qdepth = 32;
+
+static int csio_ddp_descs = 128;
+
+static int csio_do_abrt_cls(struct csio_hw *,
+				      struct csio_ioreq *, bool);
+
+static void csio_scsis_uninit(struct csio_ioreq *, enum csio_scsi_ev);
+static void csio_scsis_io_active(struct csio_ioreq *, enum csio_scsi_ev);
+static void csio_scsis_tm_active(struct csio_ioreq *, enum csio_scsi_ev);
+static void csio_scsis_aborting(struct csio_ioreq *, enum csio_scsi_ev);
+static void csio_scsis_closing(struct csio_ioreq *, enum csio_scsi_ev);
+static void csio_scsis_shost_cmpl_await(struct csio_ioreq *, enum csio_scsi_ev);
+
+/*
+ * csio_scsi_match_io - Match an ioreq with the given SCSI level data.
+ * @ioreq: The I/O request
+ * @sld: Level information
+ *
+ * Should be called with lock held.
+ *
+ */
+static bool
+csio_scsi_match_io(struct csio_ioreq *ioreq, struct csio_scsi_level_data *sld)
+{
+	struct scsi_cmnd *scmnd = csio_scsi_cmnd(ioreq);
+
+	switch (sld->level) {
+	case CSIO_LEV_LUN:
+		if (scmnd == NULL)
+			return false;
+
+		return ((ioreq->lnode == sld->lnode) &&
+			(ioreq->rnode == sld->rnode) &&
+			((uint64_t)scmnd->device->lun == sld->oslun));
+
+	case CSIO_LEV_RNODE:
+		return ((ioreq->lnode == sld->lnode) &&
+				(ioreq->rnode == sld->rnode));
+	case CSIO_LEV_LNODE:
+		return (ioreq->lnode == sld->lnode);
+	case CSIO_LEV_ALL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/*
+ * csio_scsi_gather_active_ios - Gather active I/Os based on level
+ * @scm: SCSI module
+ * @sld: Level information
+ * @dest: The queue where these I/Os have to be gathered.
+ *
+ * Should be called with lock held.
+ */
+static void
+csio_scsi_gather_active_ios(struct csio_scsim *scm,
+			    struct csio_scsi_level_data *sld,
+			    struct list_head *dest)
+{
+	struct list_head *tmp, *next;
+
+	if (list_empty(&scm->active_q))
+		return;
+
+	/* Just splice the entire active_q into dest */
+	if (sld->level == CSIO_LEV_ALL) {
+		list_splice_tail_init(&scm->active_q, dest);
+		return;
+	}
+
+	list_for_each_safe(tmp, next, &scm->active_q) {
+		if (csio_scsi_match_io((struct csio_ioreq *)tmp, sld)) {
+			list_del_init(tmp);
+			list_add_tail(tmp, dest);
+		}
+	}
+}
+
+static inline bool
+csio_scsi_itnexus_loss_error(uint16_t error)
+{
+	switch (error) {
+	case FW_ERR_LINK_DOWN:
+	case FW_RDEV_NOT_READY:
+	case FW_ERR_RDEV_LOST:
+	case FW_ERR_RDEV_LOGO:
+	case FW_ERR_RDEV_IMPL_LOGO:
+		return 1;
+	}
+	return 0;
+}
+
+static inline void
+csio_scsi_tag(struct scsi_cmnd *scmnd, uint8_t *tag, uint8_t hq,
+	      uint8_t oq, uint8_t sq)
+{
+	char stag[2];
+
+	if (scsi_populate_tag_msg(scmnd, stag)) {
+		switch (stag[0]) {
+		case HEAD_OF_QUEUE_TAG:
+			*tag = hq;
+			break;
+		case ORDERED_QUEUE_TAG:
+			*tag = oq;
+			break;
+		default:
+			*tag = sq;
+			break;
+		}
+	} else
+		*tag = 0;
+}
+
+/*
+ * csio_scsi_fcp_cmnd - Frame the SCSI FCP command paylod.
+ * @req: IO req structure.
+ * @addr: DMA location to place the payload.
+ *
+ * This routine is shared between FCP_WRITE, FCP_READ and FCP_CMD requests.
+ */
+static inline void
+csio_scsi_fcp_cmnd(struct csio_ioreq *req, void *addr)
+{
+	struct fcp_cmnd *fcp_cmnd = (struct fcp_cmnd *)addr;
+	struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
+
+	/* Check for Task Management */
+	if (likely(scmnd->SCp.Message == 0)) {
+		int_to_scsilun(scmnd->device->lun, &fcp_cmnd->fc_lun);
+		fcp_cmnd->fc_tm_flags = 0;
+		fcp_cmnd->fc_cmdref = 0;
+		fcp_cmnd->fc_pri_ta = 0;
+
+		memcpy(fcp_cmnd->fc_cdb, scmnd->cmnd, 16);
+		csio_scsi_tag(scmnd, &fcp_cmnd->fc_pri_ta,
+			      FCP_PTA_HEADQ, FCP_PTA_ORDERED, FCP_PTA_SIMPLE);
+		fcp_cmnd->fc_dl = cpu_to_be32(scsi_bufflen(scmnd));
+
+		if (req->nsge)
+			if (req->datadir == DMA_TO_DEVICE)
+				fcp_cmnd->fc_flags = FCP_CFL_WRDATA;
+			else
+				fcp_cmnd->fc_flags = FCP_CFL_RDDATA;
+		else
+			fcp_cmnd->fc_flags = 0;
+	} else {
+		memset(fcp_cmnd, 0, sizeof(*fcp_cmnd));
+		int_to_scsilun(scmnd->device->lun, &fcp_cmnd->fc_lun);
+		fcp_cmnd->fc_tm_flags = (uint8_t)scmnd->SCp.Message;
+	}
+}
+
+/*
+ * csio_scsi_init_cmd_wr - Initialize the SCSI CMD WR.
+ * @req: IO req structure.
+ * @addr: DMA location to place the payload.
+ * @size: Size of WR (including FW WR + immed data + rsp SG entry
+ *
+ * Wrapper for populating fw_scsi_cmd_wr.
+ */
+static inline void
+csio_scsi_init_cmd_wr(struct csio_ioreq *req, void *addr, uint32_t size)
+{
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_rnode *rn = req->rnode;
+	struct fw_scsi_cmd_wr *wr = (struct fw_scsi_cmd_wr *)addr;
+	struct csio_dma_buf *dma_buf;
+	uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len;
+
+	wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_CMD_WR) |
+					  FW_SCSI_CMD_WR_IMMDLEN(imm));
+	wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
+					    FW_WR_LEN16(
+						DIV_ROUND_UP(size, 16)));
+
+	wr->cookie = (uintptr_t) req;
+	wr->iqid = (uint16_t)cpu_to_be16(csio_q_physiqid(hw, req->iq_idx));
+	wr->tmo_val = (uint8_t) req->tmo;
+	wr->r3 = 0;
+	memset(&wr->r5, 0, 8);
+
+	/* Get RSP DMA buffer */
+	dma_buf = &req->dma_buf;
+
+	/* Prepare RSP SGL */
+	wr->rsp_dmalen = cpu_to_be32(dma_buf->len);
+	wr->rsp_dmaaddr = cpu_to_be64(dma_buf->paddr);
+
+	wr->r6 = 0;
+
+	wr->u.fcoe.ctl_pri = 0;
+	wr->u.fcoe.cp_en_class = 0;
+	wr->u.fcoe.r4_lo[0] = 0;
+	wr->u.fcoe.r4_lo[1] = 0;
+
+	/* Frame a FCP command */
+	csio_scsi_fcp_cmnd(req, (void *)((uintptr_t)addr +
+				    sizeof(struct fw_scsi_cmd_wr)));
+}
+
+#define CSIO_SCSI_CMD_WR_SZ(_imm)					\
+	(sizeof(struct fw_scsi_cmd_wr) +		/* WR size */	\
+	 ALIGN((_imm), 16))				/* Immed data */
+
+#define CSIO_SCSI_CMD_WR_SZ_16(_imm)					\
+			(ALIGN(CSIO_SCSI_CMD_WR_SZ((_imm)), 16))
+
+/*
+ * csio_scsi_cmd - Create a SCSI CMD WR.
+ * @req: IO req structure.
+ *
+ * Gets a WR slot in the ingress queue and initializes it with SCSI CMD WR.
+ *
+ */
+static inline void
+csio_scsi_cmd(struct csio_ioreq *req)
+{
+	struct csio_wr_pair wrp;
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_scsim *scsim = csio_hw_to_scsim(hw);
+	uint32_t size = CSIO_SCSI_CMD_WR_SZ_16(scsim->proto_cmd_len);
+
+	req->drv_status = csio_wr_get(hw, req->eq_idx, size, &wrp);
+	if (unlikely(req->drv_status != 0))
+		return;
+
+	if (wrp.size1 >= size) {
+		/* Initialize WR in one shot */
+		csio_scsi_init_cmd_wr(req, wrp.addr1, size);
+	} else {
+		uint8_t *tmpwr = csio_q_eq_wrap(hw, req->eq_idx);
+
+		/*
+		 * Make a temporary copy of the WR and write back
+		 * the copy into the WR pair.
+		 */
+		csio_scsi_init_cmd_wr(req, (void *)tmpwr, size);
+		memcpy(wrp.addr1, tmpwr, wrp.size1);
+		memcpy(wrp.addr2, tmpwr + wrp.size1, size - wrp.size1);
+	}
+}
+
+/*
+ * csio_scsi_init_ulptx_dsgl - Fill in a ULP_TX_SC_DSGL
+ * @hw: HW module
+ * @req: IO request
+ * @sgl: ULP TX SGL pointer.
+ *
+ */
+static inline void
+csio_scsi_init_ultptx_dsgl(struct csio_hw *hw, struct csio_ioreq *req,
+			   struct ulptx_sgl *sgl)
+{
+	struct ulptx_sge_pair *sge_pair = NULL;
+	struct scatterlist *sgel;
+	uint32_t i = 0;
+	uint32_t xfer_len;
+	struct list_head *tmp;
+	struct csio_dma_buf *dma_buf;
+	struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
+
+	sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) | ULPTX_MORE |
+				     ULPTX_NSGE(req->nsge));
+	/* Now add the data SGLs */
+	if (likely(!req->dcopy)) {
+		scsi_for_each_sg(scmnd, sgel, req->nsge, i) {
+			if (i == 0) {
+				sgl->addr0 = cpu_to_be64(sg_dma_address(sgel));
+				sgl->len0 = cpu_to_be32(sg_dma_len(sgel));
+				sge_pair = (struct ulptx_sge_pair *)(sgl + 1);
+				continue;
+			}
+			if ((i - 1) & 0x1) {
+				sge_pair->addr[1] = cpu_to_be64(
+							sg_dma_address(sgel));
+				sge_pair->len[1] = cpu_to_be32(
+							sg_dma_len(sgel));
+				sge_pair++;
+			} else {
+				sge_pair->addr[0] = cpu_to_be64(
+							sg_dma_address(sgel));
+				sge_pair->len[0] = cpu_to_be32(
+							sg_dma_len(sgel));
+			}
+		}
+	} else {
+		/* Program sg elements with driver's DDP buffer */
+		xfer_len = scsi_bufflen(scmnd);
+		list_for_each(tmp, &req->gen_list) {
+			dma_buf = (struct csio_dma_buf *)tmp;
+			if (i == 0) {
+				sgl->addr0 = cpu_to_be64(dma_buf->paddr);
+				sgl->len0 = cpu_to_be32(
+						min(xfer_len, dma_buf->len));
+				sge_pair = (struct ulptx_sge_pair *)(sgl + 1);
+			} else if ((i - 1) & 0x1) {
+				sge_pair->addr[1] = cpu_to_be64(dma_buf->paddr);
+				sge_pair->len[1] = cpu_to_be32(
+						min(xfer_len, dma_buf->len));
+				sge_pair++;
+			} else {
+				sge_pair->addr[0] = cpu_to_be64(dma_buf->paddr);
+				sge_pair->len[0] = cpu_to_be32(
+						min(xfer_len, dma_buf->len));
+			}
+			xfer_len -= min(xfer_len, dma_buf->len);
+			i++;
+		}
+	}
+}
+
+/*
+ * csio_scsi_init_read_wr - Initialize the READ SCSI WR.
+ * @req: IO req structure.
+ * @wrp: DMA location to place the payload.
+ * @size: Size of WR (including FW WR + immed data + rsp SG entry + data SGL
+ *
+ * Wrapper for populating fw_scsi_read_wr.
+ */
+static inline void
+csio_scsi_init_read_wr(struct csio_ioreq *req, void *wrp, uint32_t size)
+{
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_rnode *rn = req->rnode;
+	struct fw_scsi_read_wr *wr = (struct fw_scsi_read_wr *)wrp;
+	struct ulptx_sgl *sgl;
+	struct csio_dma_buf *dma_buf;
+	uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len;
+	struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
+
+	wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_READ_WR) |
+				     FW_SCSI_READ_WR_IMMDLEN(imm));
+	wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
+				       FW_WR_LEN16(DIV_ROUND_UP(size, 16)));
+	wr->cookie = (uintptr_t)req;
+	wr->iqid = (uint16_t)cpu_to_be16(csio_q_physiqid(hw, req->iq_idx));
+	wr->tmo_val = (uint8_t)(req->tmo);
+	wr->use_xfer_cnt = 1;
+	wr->xfer_cnt = cpu_to_be32(scsi_bufflen(scmnd));
+	wr->ini_xfer_cnt = cpu_to_be32(scsi_bufflen(scmnd));
+	/* Get RSP DMA buffer */
+	dma_buf = &req->dma_buf;
+
+	/* Prepare RSP SGL */
+	wr->rsp_dmalen = cpu_to_be32(dma_buf->len);
+	wr->rsp_dmaaddr = cpu_to_be64(dma_buf->paddr);
+
+	wr->r4 = 0;
+
+	wr->u.fcoe.ctl_pri = 0;
+	wr->u.fcoe.cp_en_class = 0;
+	wr->u.fcoe.r3_lo[0] = 0;
+	wr->u.fcoe.r3_lo[1] = 0;
+	csio_scsi_fcp_cmnd(req, (void *)((uintptr_t)wrp +
+					sizeof(struct fw_scsi_read_wr)));
+
+	/* Move WR pointer past command and immediate data */
+	sgl = (struct ulptx_sgl *)((uintptr_t)wrp +
+			      sizeof(struct fw_scsi_read_wr) + ALIGN(imm, 16));
+
+	/* Fill in the DSGL */
+	csio_scsi_init_ultptx_dsgl(hw, req, sgl);
+}
+
+/*
+ * csio_scsi_init_write_wr - Initialize the WRITE SCSI WR.
+ * @req: IO req structure.
+ * @wrp: DMA location to place the payload.
+ * @size: Size of WR (including FW WR + immed data + rsp SG entry + data SGL
+ *
+ * Wrapper for populating fw_scsi_write_wr.
+ */
+static inline void
+csio_scsi_init_write_wr(struct csio_ioreq *req, void *wrp, uint32_t size)
+{
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_rnode *rn = req->rnode;
+	struct fw_scsi_write_wr *wr = (struct fw_scsi_write_wr *)wrp;
+	struct ulptx_sgl *sgl;
+	struct csio_dma_buf *dma_buf;
+	uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len;
+	struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
+
+	wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_WRITE_WR) |
+				     FW_SCSI_WRITE_WR_IMMDLEN(imm));
+	wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
+				       FW_WR_LEN16(DIV_ROUND_UP(size, 16)));
+	wr->cookie = (uintptr_t)req;
+	wr->iqid = (uint16_t)cpu_to_be16(csio_q_physiqid(hw, req->iq_idx));
+	wr->tmo_val = (uint8_t)(req->tmo);
+	wr->use_xfer_cnt = 1;
+	wr->xfer_cnt = cpu_to_be32(scsi_bufflen(scmnd));
+	wr->ini_xfer_cnt = cpu_to_be32(scsi_bufflen(scmnd));
+	/* Get RSP DMA buffer */
+	dma_buf = &req->dma_buf;
+
+	/* Prepare RSP SGL */
+	wr->rsp_dmalen = cpu_to_be32(dma_buf->len);
+	wr->rsp_dmaaddr = cpu_to_be64(dma_buf->paddr);
+
+	wr->r4 = 0;
+
+	wr->u.fcoe.ctl_pri = 0;
+	wr->u.fcoe.cp_en_class = 0;
+	wr->u.fcoe.r3_lo[0] = 0;
+	wr->u.fcoe.r3_lo[1] = 0;
+	csio_scsi_fcp_cmnd(req, (void *)((uintptr_t)wrp +
+					sizeof(struct fw_scsi_write_wr)));
+
+	/* Move WR pointer past command and immediate data */
+	sgl = (struct ulptx_sgl *)((uintptr_t)wrp +
+			      sizeof(struct fw_scsi_write_wr) + ALIGN(imm, 16));
+
+	/* Fill in the DSGL */
+	csio_scsi_init_ultptx_dsgl(hw, req, sgl);
+}
+
+/* Calculate WR size needed for fw_scsi_read_wr/fw_scsi_write_wr */
+#define CSIO_SCSI_DATA_WRSZ(req, oper, sz, imm)				       \
+do {									       \
+	(sz) = sizeof(struct fw_scsi_##oper##_wr) +	/* WR size */          \
+	       ALIGN((imm), 16) +			/* Immed data */       \
+	       sizeof(struct ulptx_sgl);		/* ulptx_sgl */	       \
+									       \
+	if (unlikely((req)->nsge > 1))				               \
+		(sz) += (sizeof(struct ulptx_sge_pair) *		       \
+				(ALIGN(((req)->nsge - 1), 2) / 2));            \
+							/* Data SGE */	       \
+} while (0)
+
+/*
+ * csio_scsi_read - Create a SCSI READ WR.
+ * @req: IO req structure.
+ *
+ * Gets a WR slot in the ingress queue and initializes it with
+ * SCSI READ WR.
+ *
+ */
+static inline void
+csio_scsi_read(struct csio_ioreq *req)
+{
+	struct csio_wr_pair wrp;
+	uint32_t size;
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_scsim *scsim = csio_hw_to_scsim(hw);
+
+	CSIO_SCSI_DATA_WRSZ(req, read, size, scsim->proto_cmd_len);
+	size = ALIGN(size, 16);
+
+	req->drv_status = csio_wr_get(hw, req->eq_idx, size, &wrp);
+	if (likely(req->drv_status == 0)) {
+		if (likely(wrp.size1 >= size)) {
+			/* Initialize WR in one shot */
+			csio_scsi_init_read_wr(req, wrp.addr1, size);
+		} else {
+			uint8_t *tmpwr = csio_q_eq_wrap(hw, req->eq_idx);
+			/*
+			 * Make a temporary copy of the WR and write back
+			 * the copy into the WR pair.
+			 */
+			csio_scsi_init_read_wr(req, (void *)tmpwr, size);
+			memcpy(wrp.addr1, tmpwr, wrp.size1);
+			memcpy(wrp.addr2, tmpwr + wrp.size1, size - wrp.size1);
+		}
+	}
+}
+
+/*
+ * csio_scsi_write - Create a SCSI WRITE WR.
+ * @req: IO req structure.
+ *
+ * Gets a WR slot in the ingress queue and initializes it with
+ * SCSI WRITE WR.
+ *
+ */
+static inline void
+csio_scsi_write(struct csio_ioreq *req)
+{
+	struct csio_wr_pair wrp;
+	uint32_t size;
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_scsim *scsim = csio_hw_to_scsim(hw);
+
+	CSIO_SCSI_DATA_WRSZ(req, write, size, scsim->proto_cmd_len);
+	size = ALIGN(size, 16);
+
+	req->drv_status = csio_wr_get(hw, req->eq_idx, size, &wrp);
+	if (likely(req->drv_status == 0)) {
+		if (likely(wrp.size1 >= size)) {
+			/* Initialize WR in one shot */
+			csio_scsi_init_write_wr(req, wrp.addr1, size);
+		} else {
+			uint8_t *tmpwr = csio_q_eq_wrap(hw, req->eq_idx);
+			/*
+			 * Make a temporary copy of the WR and write back
+			 * the copy into the WR pair.
+			 */
+			csio_scsi_init_write_wr(req, (void *)tmpwr, size);
+			memcpy(wrp.addr1, tmpwr, wrp.size1);
+			memcpy(wrp.addr2, tmpwr + wrp.size1, size - wrp.size1);
+		}
+	}
+}
+
+/*
+ * csio_setup_ddp - Setup DDP buffers for Read request.
+ * @req: IO req structure.
+ *
+ * Checks SGLs/Data buffers are virtually contiguous required for DDP.
+ * If contiguous,driver posts SGLs in the WR otherwise post internal
+ * buffers for such request for DDP.
+ */
+static inline void
+csio_setup_ddp(struct csio_scsim *scsim, struct csio_ioreq *req)
+{
+#ifdef __CSIO_DEBUG__
+	struct csio_hw *hw = req->lnode->hwp;
+#endif
+	struct scatterlist *sgel = NULL;
+	struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
+	uint64_t sg_addr = 0;
+	uint32_t ddp_pagesz = 4096;
+	uint32_t buf_off;
+	struct csio_dma_buf *dma_buf = NULL;
+	uint32_t alloc_len = 0;
+	uint32_t xfer_len = 0;
+	uint32_t sg_len = 0;
+	uint32_t i;
+
+	scsi_for_each_sg(scmnd, sgel, req->nsge, i) {
+		sg_addr = sg_dma_address(sgel);
+		sg_len	= sg_dma_len(sgel);
+
+		buf_off = sg_addr & (ddp_pagesz - 1);
+
+		/* Except 1st buffer,all buffer addr have to be Page aligned */
+		if (i != 0 && buf_off) {
+			csio_dbg(hw, "SGL addr not DDP aligned (%llx:%d)\n",
+				 sg_addr, sg_len);
+			goto unaligned;
+		}
+
+		/* Except last buffer,all buffer must end on page boundary */
+		if ((i != (req->nsge - 1)) &&
+			((buf_off + sg_len) & (ddp_pagesz - 1))) {
+			csio_dbg(hw,
+				 "SGL addr not ending on page boundary"
+				 "(%llx:%d)\n", sg_addr, sg_len);
+			goto unaligned;
+		}
+	}
+
+	/* SGL's are virtually contiguous. HW will DDP to SGLs */
+	req->dcopy = 0;
+	csio_scsi_read(req);
+
+	return;
+
+unaligned:
+	CSIO_INC_STATS(scsim, n_unaligned);
+	/*
+	 * For unaligned SGLs, driver will allocate internal DDP buffer.
+	 * Once command is completed data from DDP buffer copied to SGLs
+	 */
+	req->dcopy = 1;
+
+	/* Use gen_list to store the DDP buffers */
+	INIT_LIST_HEAD(&req->gen_list);
+	xfer_len = scsi_bufflen(scmnd);
+
+	i = 0;
+	/* Allocate ddp buffers for this request */
+	while (alloc_len < xfer_len) {
+		dma_buf = csio_get_scsi_ddp(scsim);
+		if (dma_buf == NULL || i > scsim->max_sge) {
+			req->drv_status = -EBUSY;
+			break;
+		}
+		alloc_len += dma_buf->len;
+		/* Added to IO req */
+		list_add_tail(&dma_buf->list, &req->gen_list);
+		i++;
+	}
+
+	if (!req->drv_status) {
+		/* set number of ddp bufs used */
+		req->nsge = i;
+		csio_scsi_read(req);
+		return;
+	}
+
+	 /* release dma descs */
+	if (i > 0)
+		csio_put_scsi_ddp_list(scsim, &req->gen_list, i);
+}
+
+/*
+ * csio_scsi_init_abrt_cls_wr - Initialize an ABORT/CLOSE WR.
+ * @req: IO req structure.
+ * @addr: DMA location to place the payload.
+ * @size: Size of WR
+ * @abort: abort OR close
+ *
+ * Wrapper for populating fw_scsi_cmd_wr.
+ */
+static inline void
+csio_scsi_init_abrt_cls_wr(struct csio_ioreq *req, void *addr, uint32_t size,
+			   bool abort)
+{
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_rnode *rn = req->rnode;
+	struct fw_scsi_abrt_cls_wr *wr = (struct fw_scsi_abrt_cls_wr *)addr;
+
+	wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_ABRT_CLS_WR));
+	wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
+					    FW_WR_LEN16(
+						DIV_ROUND_UP(size, 16)));
+
+	wr->cookie = (uintptr_t) req;
+	wr->iqid = (uint16_t)cpu_to_be16(csio_q_physiqid(hw, req->iq_idx));
+	wr->tmo_val = (uint8_t) req->tmo;
+	/* 0 for CHK_ALL_IO tells FW to look up t_cookie */
+	wr->sub_opcode_to_chk_all_io =
+				(FW_SCSI_ABRT_CLS_WR_SUB_OPCODE(abort) |
+				 FW_SCSI_ABRT_CLS_WR_CHK_ALL_IO(0));
+	wr->r3[0] = 0;
+	wr->r3[1] = 0;
+	wr->r3[2] = 0;
+	wr->r3[3] = 0;
+	/* Since we re-use the same ioreq for abort as well */
+	wr->t_cookie = (uintptr_t) req;
+}
+
+static inline void
+csio_scsi_abrt_cls(struct csio_ioreq *req, bool abort)
+{
+	struct csio_wr_pair wrp;
+	struct csio_hw *hw = req->lnode->hwp;
+	uint32_t size = ALIGN(sizeof(struct fw_scsi_abrt_cls_wr), 16);
+
+	req->drv_status = csio_wr_get(hw, req->eq_idx, size, &wrp);
+	if (req->drv_status != 0)
+		return;
+
+	if (wrp.size1 >= size) {
+		/* Initialize WR in one shot */
+		csio_scsi_init_abrt_cls_wr(req, wrp.addr1, size, abort);
+	} else {
+		uint8_t *tmpwr = csio_q_eq_wrap(hw, req->eq_idx);
+		/*
+		 * Make a temporary copy of the WR and write back
+		 * the copy into the WR pair.
+		 */
+		csio_scsi_init_abrt_cls_wr(req, (void *)tmpwr, size, abort);
+		memcpy(wrp.addr1, tmpwr, wrp.size1);
+		memcpy(wrp.addr2, tmpwr + wrp.size1, size - wrp.size1);
+	}
+}
+
+/*****************************************************************************/
+/* START: SCSI SM                                                            */
+/*****************************************************************************/
+static void
+csio_scsis_uninit(struct csio_ioreq *req, enum csio_scsi_ev evt)
+{
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_scsim *scsim = csio_hw_to_scsim(hw);
+
+	switch (evt) {
+	case CSIO_SCSIE_START_IO:
+
+		if (req->nsge) {
+			if (req->datadir == DMA_TO_DEVICE) {
+				req->dcopy = 0;
+				csio_scsi_write(req);
+			} else
+				csio_setup_ddp(scsim, req);
+		} else {
+			csio_scsi_cmd(req);
+		}
+
+		if (likely(req->drv_status == 0)) {
+			/* change state and enqueue on active_q */
+			csio_set_state(&req->sm, csio_scsis_io_active);
+			list_add_tail(&req->sm.sm_list, &scsim->active_q);
+			csio_wr_issue(hw, req->eq_idx, false);
+			CSIO_INC_STATS(scsim, n_active);
+
+			return;
+		}
+		break;
+
+	case CSIO_SCSIE_START_TM:
+		csio_scsi_cmd(req);
+		if (req->drv_status == 0) {
+			/*
+			 * NOTE: We collect the affected I/Os prior to issuing
+			 * LUN reset, and not after it. This is to prevent
+			 * aborting I/Os that get issued after the LUN reset,
+			 * but prior to LUN reset completion (in the event that
+			 * the host stack has not blocked I/Os to a LUN that is
+			 * being reset.
+			 */
+			csio_set_state(&req->sm, csio_scsis_tm_active);
+			list_add_tail(&req->sm.sm_list, &scsim->active_q);
+			csio_wr_issue(hw, req->eq_idx, false);
+			CSIO_INC_STATS(scsim, n_tm_active);
+		}
+		return;
+
+	case CSIO_SCSIE_ABORT:
+	case CSIO_SCSIE_CLOSE:
+		/*
+		 * NOTE:
+		 * We could get here due to  :
+		 * - a window in the cleanup path of the SCSI module
+		 *   (csio_scsi_abort_io()). Please see NOTE in this function.
+		 * - a window in the time we tried to issue an abort/close
+		 *   of a request to FW, and the FW completed the request
+		 *   itself.
+		 *   Print a message for now, and return INVAL either way.
+		 */
+		req->drv_status = -EINVAL;
+		csio_warn(hw, "Trying to abort/close completed IO:%p!\n", req);
+		break;
+
+	default:
+		csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req);
+		CSIO_DB_ASSERT(0);
+	}
+}
+
+static void
+csio_scsis_io_active(struct csio_ioreq *req, enum csio_scsi_ev evt)
+{
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_scsim *scm = csio_hw_to_scsim(hw);
+	struct csio_rnode *rn;
+
+	switch (evt) {
+	case CSIO_SCSIE_COMPLETED:
+		CSIO_DEC_STATS(scm, n_active);
+		list_del_init(&req->sm.sm_list);
+		csio_set_state(&req->sm, csio_scsis_uninit);
+		/*
+		 * In MSIX mode, with multiple queues, the SCSI compeltions
+		 * could reach us sooner than the FW events sent to indicate
+		 * I-T nexus loss (link down, remote device logo etc). We
+		 * dont want to be returning such I/Os to the upper layer
+		 * immediately, since we wouldnt have reported the I-T nexus
+		 * loss itself. This forces us to serialize such completions
+		 * with the reporting of the I-T nexus loss. Therefore, we
+		 * internally queue up such up such completions in the rnode.
+		 * The reporting of I-T nexus loss to the upper layer is then
+		 * followed by the returning of I/Os in this internal queue.
+		 * Having another state alongwith another queue helps us take
+		 * actions for events such as ABORT received while we are
+		 * in this rnode queue.
+		 */
+		if (unlikely(req->wr_status != FW_SUCCESS)) {
+			rn = req->rnode;
+			/*
+			 * FW says remote device is lost, but rnode
+			 * doesnt reflect it.
+			 */
+			if (csio_scsi_itnexus_loss_error(req->wr_status) &&
+						csio_is_rnode_ready(rn)) {
+				csio_set_state(&req->sm,
+						csio_scsis_shost_cmpl_await);
+				list_add_tail(&req->sm.sm_list,
+					      &rn->host_cmpl_q);
+			}
+		}
+
+		break;
+
+	case CSIO_SCSIE_ABORT:
+		csio_scsi_abrt_cls(req, SCSI_ABORT);
+		if (req->drv_status == 0) {
+			csio_wr_issue(hw, req->eq_idx, false);
+			csio_set_state(&req->sm, csio_scsis_aborting);
+		}
+		break;
+
+	case CSIO_SCSIE_CLOSE:
+		csio_scsi_abrt_cls(req, SCSI_CLOSE);
+		if (req->drv_status == 0) {
+			csio_wr_issue(hw, req->eq_idx, false);
+			csio_set_state(&req->sm, csio_scsis_closing);
+		}
+		break;
+
+	case CSIO_SCSIE_DRVCLEANUP:
+		req->wr_status = FW_HOSTERROR;
+		CSIO_DEC_STATS(scm, n_active);
+		csio_set_state(&req->sm, csio_scsis_uninit);
+		break;
+
+	default:
+		csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req);
+		CSIO_DB_ASSERT(0);
+	}
+}
+
+static void
+csio_scsis_tm_active(struct csio_ioreq *req, enum csio_scsi_ev evt)
+{
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_scsim *scm = csio_hw_to_scsim(hw);
+
+	switch (evt) {
+	case CSIO_SCSIE_COMPLETED:
+		CSIO_DEC_STATS(scm, n_tm_active);
+		list_del_init(&req->sm.sm_list);
+		csio_set_state(&req->sm, csio_scsis_uninit);
+
+		break;
+
+	case CSIO_SCSIE_ABORT:
+		csio_scsi_abrt_cls(req, SCSI_ABORT);
+		if (req->drv_status == 0) {
+			csio_wr_issue(hw, req->eq_idx, false);
+			csio_set_state(&req->sm, csio_scsis_aborting);
+		}
+		break;
+
+
+	case CSIO_SCSIE_CLOSE:
+		csio_scsi_abrt_cls(req, SCSI_CLOSE);
+		if (req->drv_status == 0) {
+			csio_wr_issue(hw, req->eq_idx, false);
+			csio_set_state(&req->sm, csio_scsis_closing);
+		}
+		break;
+
+	case CSIO_SCSIE_DRVCLEANUP:
+		req->wr_status = FW_HOSTERROR;
+		CSIO_DEC_STATS(scm, n_tm_active);
+		csio_set_state(&req->sm, csio_scsis_uninit);
+		break;
+
+	default:
+		csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req);
+		CSIO_DB_ASSERT(0);
+	}
+}
+
+static void
+csio_scsis_aborting(struct csio_ioreq *req, enum csio_scsi_ev evt)
+{
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_scsim *scm = csio_hw_to_scsim(hw);
+
+	switch (evt) {
+	case CSIO_SCSIE_COMPLETED:
+		csio_dbg(hw,
+			 "ioreq %p recvd cmpltd (wr_status:%d) "
+			 "in aborting st\n", req, req->wr_status);
+		/*
+		 * Use -ECANCELED to explicitly tell the ABORTED event that
+		 * the original I/O was returned to driver by FW.
+		 * We dont really care if the I/O was returned with success by
+		 * FW (because the ABORT and completion of the I/O crossed each
+		 * other), or any other return value. Once we are in aborting
+		 * state, the success or failure of the I/O is unimportant to
+		 * us.
+		 */
+		req->drv_status = -ECANCELED;
+		break;
+
+	case CSIO_SCSIE_ABORT:
+		CSIO_INC_STATS(scm, n_abrt_dups);
+		break;
+
+	case CSIO_SCSIE_ABORTED:
+
+		csio_dbg(hw, "abort of %p return status:0x%x drv_status:%x\n",
+			 req, req->wr_status, req->drv_status);
+		/*
+		 * Check if original I/O WR completed before the Abort
+		 * completion.
+		 */
+		if (req->drv_status != -ECANCELED) {
+			csio_warn(hw,
+				  "Abort completed before original I/O,"
+				   " req:%p\n", req);
+			CSIO_DB_ASSERT(0);
+		}
+
+		/*
+		 * There are the following possible scenarios:
+		 * 1. The abort completed successfully, FW returned FW_SUCCESS.
+		 * 2. The completion of an I/O and the receipt of
+		 *    abort for that I/O by the FW crossed each other.
+		 *    The FW returned FW_EINVAL. The original I/O would have
+		 *    returned with FW_SUCCESS or any other SCSI error.
+		 * 3. The FW couldnt sent the abort out on the wire, as there
+		 *    was an I-T nexus loss (link down, remote device logged
+		 *    out etc). FW sent back an appropriate IT nexus loss status
+		 *    for the abort.
+		 * 4. FW sent an abort, but abort timed out (remote device
+		 *    didnt respond). FW replied back with
+		 *    FW_SCSI_ABORT_TIMEDOUT.
+		 * 5. FW couldnt genuinely abort the request for some reason,
+		 *    and sent us an error.
+		 *
+		 * The first 3 scenarios are treated as  succesful abort
+		 * operations by the host, while the last 2 are failed attempts
+		 * to abort. Manipulate the return value of the request
+		 * appropriately, so that host can convey these results
+		 * back to the upper layer.
+		 */
+		if ((req->wr_status == FW_SUCCESS) ||
+		    (req->wr_status == FW_EINVAL) ||
+		    csio_scsi_itnexus_loss_error(req->wr_status))
+			req->wr_status = FW_SCSI_ABORT_REQUESTED;
+
+		CSIO_DEC_STATS(scm, n_active);
+		list_del_init(&req->sm.sm_list);
+		csio_set_state(&req->sm, csio_scsis_uninit);
+		break;
+
+	case CSIO_SCSIE_DRVCLEANUP:
+		req->wr_status = FW_HOSTERROR;
+		CSIO_DEC_STATS(scm, n_active);
+		csio_set_state(&req->sm, csio_scsis_uninit);
+		break;
+
+	case CSIO_SCSIE_CLOSE:
+		/*
+		 * We can receive this event from the module
+		 * cleanup paths, if the FW forgot to reply to the ABORT WR
+		 * and left this ioreq in this state. For now, just ignore
+		 * the event. The CLOSE event is sent to this state, as
+		 * the LINK may have already gone down.
+		 */
+		break;
+
+	default:
+		csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req);
+		CSIO_DB_ASSERT(0);
+	}
+}
+
+static void
+csio_scsis_closing(struct csio_ioreq *req, enum csio_scsi_ev evt)
+{
+	struct csio_hw *hw = req->lnode->hwp;
+	struct csio_scsim *scm = csio_hw_to_scsim(hw);
+
+	switch (evt) {
+	case CSIO_SCSIE_COMPLETED:
+		csio_dbg(hw,
+			 "ioreq %p recvd cmpltd (wr_status:%d) "
+			 "in closing st\n", req, req->wr_status);
+		/*
+		 * Use -ECANCELED to explicitly tell the CLOSED event that
+		 * the original I/O was returned to driver by FW.
+		 * We dont really care if the I/O was returned with success by
+		 * FW (because the CLOSE and completion of the I/O crossed each
+		 * other), or any other return value. Once we are in aborting
+		 * state, the success or failure of the I/O is unimportant to
+		 * us.
+		 */
+		req->drv_status = -ECANCELED;
+		break;
+
+	case CSIO_SCSIE_CLOSED:
+		/*
+		 * Check if original I/O WR completed before the Close
+		 * completion.
+		 */
+		if (req->drv_status != -ECANCELED) {
+			csio_fatal(hw,
+				   "Close completed before original I/O,"
+				   " req:%p\n", req);
+			CSIO_DB_ASSERT(0);
+		}
+
+		/*
+		 * Either close succeeded, or we issued close to FW at the
+		 * same time FW compelted it to us. Either way, the I/O
+		 * is closed.
+		 */
+		CSIO_DB_ASSERT((req->wr_status == FW_SUCCESS) ||
+					(req->wr_status == FW_EINVAL));
+		req->wr_status = FW_SCSI_CLOSE_REQUESTED;
+
+		CSIO_DEC_STATS(scm, n_active);
+		list_del_init(&req->sm.sm_list);
+		csio_set_state(&req->sm, csio_scsis_uninit);
+		break;
+
+	case CSIO_SCSIE_CLOSE:
+		break;
+
+	case CSIO_SCSIE_DRVCLEANUP:
+		req->wr_status = FW_HOSTERROR;
+		CSIO_DEC_STATS(scm, n_active);
+		csio_set_state(&req->sm, csio_scsis_uninit);
+		break;
+
+	default:
+		csio_dbg(hw, "Unhandled event:%d sent to req:%p\n", evt, req);
+		CSIO_DB_ASSERT(0);
+	}
+}
+
+static void
+csio_scsis_shost_cmpl_await(struct csio_ioreq *req, enum csio_scsi_ev evt)
+{
+	switch (evt) {
+	case CSIO_SCSIE_ABORT:
+	case CSIO_SCSIE_CLOSE:
+		/*
+		 * Just succeed the abort request, and hope that
+		 * the remote device unregister path will cleanup
+		 * this I/O to the upper layer within a sane
+		 * amount of time.
+		 */
+		/*
+		 * A close can come in during a LINK DOWN. The FW would have
+		 * returned us the I/O back, but not the remote device lost
+		 * FW event. In this interval, if the I/O times out at the upper
+		 * layer, a close can come in. Take the same action as abort:
+		 * return success, and hope that the remote device unregister
+		 * path will cleanup this I/O. If the FW still doesnt send
+		 * the msg, the close times out, and the upper layer resorts
+		 * to the next level of error recovery.
+		 */
+		req->drv_status = 0;
+		break;
+	case CSIO_SCSIE_DRVCLEANUP:
+		csio_set_state(&req->sm, csio_scsis_uninit);
+		break;
+	default:
+		csio_dbg(req->lnode->hwp, "Unhandled event:%d sent to req:%p\n",
+			 evt, req);
+		CSIO_DB_ASSERT(0);
+	}
+}
+
+/*
+ * csio_scsi_cmpl_handler - WR completion handler for SCSI.
+ * @hw: HW module.
+ * @wr: The completed WR from the ingress queue.
+ * @len: Length of the WR.
+ * @flb: Freelist buffer array.
+ * @priv: Private object
+ * @scsiwr: Pointer to SCSI WR.
+ *
+ * This is the WR completion handler called per completion from the
+ * ISR. It is called with lock held. It walks past the RSS and CPL message
+ * header where the actual WR is present.
+ * It then gets the status, WR handle (ioreq pointer) and the len of
+ * the WR, based on WR opcode. Only on a non-good status is the entire
+ * WR copied into the WR cache (ioreq->fw_wr).
+ * The ioreq corresponding to the WR is returned to the caller.
+ * NOTE: The SCSI queue doesnt allocate a freelist today, hence
+ * no freelist buffer is expected.
+ */
+struct csio_ioreq *
+csio_scsi_cmpl_handler(struct csio_hw *hw, void *wr, uint32_t len,
+		     struct csio_fl_dma_buf *flb, void *priv, uint8_t **scsiwr)
+{
+	struct csio_ioreq *ioreq = NULL;
+	struct cpl_fw6_msg *cpl;
+	uint8_t *tempwr;
+	uint8_t	status;
+	struct csio_scsim *scm = csio_hw_to_scsim(hw);
+
+	/* skip RSS header */
+	cpl = (struct cpl_fw6_msg *)((uintptr_t)wr + sizeof(__be64));
+
+	if (unlikely(cpl->opcode != CPL_FW6_MSG)) {
+		csio_warn(hw, "Error: Invalid CPL msg %x recvd on SCSI q\n",
+			  cpl->opcode);
+		CSIO_INC_STATS(scm, n_inval_cplop);
+		return NULL;
+	}
+
+	tempwr = (uint8_t *)(cpl->data);
+	status = csio_wr_status(tempwr);
+	*scsiwr = tempwr;
+
+	if (likely((*tempwr == FW_SCSI_READ_WR) ||
+			(*tempwr == FW_SCSI_WRITE_WR) ||
+			(*tempwr == FW_SCSI_CMD_WR))) {
+		ioreq = (struct csio_ioreq *)((uintptr_t)
+				 (((struct fw_scsi_read_wr *)tempwr)->cookie));
+		CSIO_DB_ASSERT(virt_addr_valid(ioreq));
+
+		ioreq->wr_status = status;
+
+		return ioreq;
+	}
+
+	if (*tempwr == FW_SCSI_ABRT_CLS_WR) {
+		ioreq = (struct csio_ioreq *)((uintptr_t)
+			 (((struct fw_scsi_abrt_cls_wr *)tempwr)->cookie));
+		CSIO_DB_ASSERT(virt_addr_valid(ioreq));
+
+		ioreq->wr_status = status;
+		return ioreq;
+	}
+
+	csio_warn(hw, "WR with invalid opcode in SCSI IQ: %x\n", *tempwr);
+	CSIO_INC_STATS(scm, n_inval_scsiop);
+	return NULL;
+}
+
+/*
+ * csio_scsi_cleanup_io_q - Cleanup the given queue.
+ * @scm: SCSI module.
+ * @q: Queue to be cleaned up.
+ *
+ * Called with lock held. Has to exit with lock held.
+ */
+void
+csio_scsi_cleanup_io_q(struct csio_scsim *scm, struct list_head *q)
+{
+	struct csio_hw *hw = scm->hw;
+	struct csio_ioreq *ioreq;
+	struct list_head *tmp, *next;
+	struct scsi_cmnd *scmnd;
+
+	/* Call back the completion routines of the active_q */
+	list_for_each_safe(tmp, next, q) {
+		ioreq = (struct csio_ioreq *)tmp;
+		csio_scsi_drvcleanup(ioreq);
+		list_del_init(&ioreq->sm.sm_list);
+		scmnd = csio_scsi_cmnd(ioreq);
+		spin_unlock_irq(&hw->lock);
+
+		/*
+		 * Upper layers may have cleared this command, hence this
+		 * check to avoid accessing stale references.
+		 */
+		if (scmnd != NULL)
+			ioreq->io_cbfn(hw, ioreq);
+
+		spin_lock_irq(&scm->freelist_lock);
+		csio_put_scsi_ioreq(scm, ioreq);
+		spin_unlock_irq(&scm->freelist_lock);
+
+		spin_lock_irq(&hw->lock);
+	}
+}
+
+#define CSIO_SCSI_ABORT_Q_POLL_MS		2000
+
+static void
+csio_abrt_cls(struct csio_ioreq *ioreq, struct scsi_cmnd *scmnd)
+{
+	struct csio_lnode *ln = ioreq->lnode;
+	struct csio_hw *hw = ln->hwp;
+	int ready = 0;
+	struct csio_scsim *scsim = csio_hw_to_scsim(hw);
+	int rv;
+
+	if (csio_scsi_cmnd(ioreq) != scmnd) {
+		CSIO_INC_STATS(scsim, n_abrt_race_comp);
+		return;
+	}
+
+	ready = csio_is_lnode_ready(ln);
+
+	rv = csio_do_abrt_cls(hw, ioreq, (ready ? SCSI_ABORT : SCSI_CLOSE));
+	if (rv != 0) {
+		if (ready)
+			CSIO_INC_STATS(scsim, n_abrt_busy_error);
+		else
+			CSIO_INC_STATS(scsim, n_cls_busy_error);
+	}
+}
+
+/*
+ * csio_scsi_abort_io_q - Abort all I/Os on given queue
+ * @scm: SCSI module.
+ * @q: Queue to abort.
+ * @tmo: Timeout in ms
+ *
+ * Attempt to abort all I/Os on given queue, and wait for a max
+ * of tmo milliseconds for them to complete. Returns success
+ * if all I/Os are aborted. Else returns -ETIMEDOUT.
+ * Should be entered with lock held. Exits with lock held.
+ * NOTE:
+ * Lock has to be held across the loop that aborts I/Os, since dropping the lock
+ * in between can cause the list to be corrupted. As a result, the caller
+ * of this function has to ensure that the number of I/os to be aborted
+ * is finite enough to not cause lock-held-for-too-long issues.
+ */
+static int
+csio_scsi_abort_io_q(struct csio_scsim *scm, struct list_head *q, uint32_t tmo)
+{
+	struct csio_hw *hw = scm->hw;
+	struct list_head *tmp, *next;
+	int count = DIV_ROUND_UP(tmo, CSIO_SCSI_ABORT_Q_POLL_MS);
+	struct scsi_cmnd *scmnd;
+
+	if (list_empty(q))
+		return 0;
+
+	csio_dbg(hw, "Aborting SCSI I/Os\n");
+
+	/* Now abort/close I/Os in the queue passed */
+	list_for_each_safe(tmp, next, q) {
+		scmnd = csio_scsi_cmnd((struct csio_ioreq *)tmp);
+		csio_abrt_cls((struct csio_ioreq *)tmp, scmnd);
+	}
+
+	/* Wait till all active I/Os are completed/aborted/closed */
+	while (!list_empty(q) && count--) {
+		spin_unlock_irq(&hw->lock);
+		msleep(CSIO_SCSI_ABORT_Q_POLL_MS);
+		spin_lock_irq(&hw->lock);
+	}
+
+	/* all aborts completed */
+	if (list_empty(q))
+		return 0;
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * csio_scsim_cleanup_io - Cleanup all I/Os in SCSI module.
+ * @scm: SCSI module.
+ * @abort: abort required.
+ * Called with lock held, should exit with lock held.
+ * Can sleep when waiting for I/Os to complete.
+ */
+int
+csio_scsim_cleanup_io(struct csio_scsim *scm, bool abort)
+{
+	struct csio_hw *hw = scm->hw;
+	int rv = 0;
+	int count = DIV_ROUND_UP(60 * 1000, CSIO_SCSI_ABORT_Q_POLL_MS);
+
+	/* No I/Os pending */
+	if (list_empty(&scm->active_q))
+		return 0;
+
+	/* Wait until all active I/Os are completed */
+	while (!list_empty(&scm->active_q) && count--) {
+		spin_unlock_irq(&hw->lock);
+		msleep(CSIO_SCSI_ABORT_Q_POLL_MS);
+		spin_lock_irq(&hw->lock);
+	}
+
+	/* all I/Os completed */
+	if (list_empty(&scm->active_q))
+		return 0;
+
+	/* Else abort */
+	if (abort) {
+		rv = csio_scsi_abort_io_q(scm, &scm->active_q, 30000);
+		if (rv == 0)
+			return rv;
+		csio_dbg(hw, "Some I/O aborts timed out, cleaning up..\n");
+	}
+
+	csio_scsi_cleanup_io_q(scm, &scm->active_q);
+
+	CSIO_DB_ASSERT(list_empty(&scm->active_q));
+
+	return rv;
+}
+
+/*
+ * csio_scsim_cleanup_io_lnode - Cleanup all I/Os of given lnode.
+ * @scm: SCSI module.
+ * @lnode: lnode
+ *
+ * Called with lock held, should exit with lock held.
+ * Can sleep (with dropped lock) when waiting for I/Os to complete.
+ */
+int
+csio_scsim_cleanup_io_lnode(struct csio_scsim *scm, struct csio_lnode *ln)
+{
+	struct csio_hw *hw = scm->hw;
+	struct csio_scsi_level_data sld;
+	int rv;
+	int count = DIV_ROUND_UP(60 * 1000, CSIO_SCSI_ABORT_Q_POLL_MS);
+
+	csio_dbg(hw, "Gathering all SCSI I/Os on lnode %p\n", ln);
+
+	sld.level = CSIO_LEV_LNODE;
+	sld.lnode = ln;
+	INIT_LIST_HEAD(&ln->cmpl_q);
+	csio_scsi_gather_active_ios(scm, &sld, &ln->cmpl_q);
+
+	/* No I/Os pending on this lnode  */
+	if (list_empty(&ln->cmpl_q))
+		return 0;
+
+	/* Wait until all active I/Os on this lnode are completed */
+	while (!list_empty(&ln->cmpl_q) && count--) {
+		spin_unlock_irq(&hw->lock);
+		msleep(CSIO_SCSI_ABORT_Q_POLL_MS);
+		spin_lock_irq(&hw->lock);
+	}
+
+	/* all I/Os completed */
+	if (list_empty(&ln->cmpl_q))
+		return 0;
+
+	csio_dbg(hw, "Some I/Os pending on ln:%p, aborting them..\n", ln);
+
+	/* I/Os are pending, abort them */
+	rv = csio_scsi_abort_io_q(scm, &ln->cmpl_q, 30000);
+	if (rv != 0) {
+		csio_dbg(hw, "Some I/O aborts timed out, cleaning up..\n");
+		csio_scsi_cleanup_io_q(scm, &ln->cmpl_q);
+	}
+
+	CSIO_DB_ASSERT(list_empty(&ln->cmpl_q));
+
+	return rv;
+}
+
+static ssize_t
+csio_show_hw_state(struct device *dev,
+		   struct device_attribute *attr, char *buf)
+{
+	struct csio_lnode *ln = shost_priv(class_to_shost(dev));
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+	if (csio_is_hw_ready(hw))
+		return snprintf(buf, PAGE_SIZE, "ready\n");
+	else
+		return snprintf(buf, PAGE_SIZE, "not ready\n");
+}
+
+/* Device reset */
+static ssize_t
+csio_device_reset(struct device *dev,
+		   struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct csio_lnode *ln = shost_priv(class_to_shost(dev));
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+	if (*buf != '1')
+		return -EINVAL;
+
+	/* Delete NPIV lnodes */
+	 csio_lnodes_exit(hw, 1);
+
+	/* Block upper IOs */
+	csio_lnodes_block_request(hw);
+
+	spin_lock_irq(&hw->lock);
+	csio_hw_reset(hw);
+	spin_unlock_irq(&hw->lock);
+
+	/* Unblock upper IOs */
+	csio_lnodes_unblock_request(hw);
+	return count;
+}
+
+/* disable port */
+static ssize_t
+csio_disable_port(struct device *dev,
+		   struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct csio_lnode *ln = shost_priv(class_to_shost(dev));
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+	bool disable;
+
+	if (*buf == '1' || *buf == '0')
+		disable = (*buf == '1') ? true : false;
+	else
+		return -EINVAL;
+
+	/* Block upper IOs */
+	csio_lnodes_block_by_port(hw, ln->portid);
+
+	spin_lock_irq(&hw->lock);
+	csio_disable_lnodes(hw, ln->portid, disable);
+	spin_unlock_irq(&hw->lock);
+
+	/* Unblock upper IOs */
+	csio_lnodes_unblock_by_port(hw, ln->portid);
+	return count;
+}
+
+/* Show debug level */
+static ssize_t
+csio_show_dbg_level(struct device *dev,
+		   struct device_attribute *attr, char *buf)
+{
+	struct csio_lnode *ln = shost_priv(class_to_shost(dev));
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ln->params.log_level);
+}
+
+/* Store debug level */
+static ssize_t
+csio_store_dbg_level(struct device *dev,
+		   struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct csio_lnode *ln = shost_priv(class_to_shost(dev));
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+	uint32_t dbg_level = 0;
+
+	if (!isdigit(buf[0]))
+		return -EINVAL;
+
+	if (sscanf(buf, "%i", &dbg_level))
+		return -EINVAL;
+
+	ln->params.log_level = dbg_level;
+	hw->params.log_level = dbg_level;
+
+	return 0;
+}
+
+static DEVICE_ATTR(hw_state, S_IRUGO, csio_show_hw_state, NULL);
+static DEVICE_ATTR(device_reset, S_IRUGO | S_IWUSR, NULL, csio_device_reset);
+static DEVICE_ATTR(disable_port, S_IRUGO | S_IWUSR, NULL, csio_disable_port);
+static DEVICE_ATTR(dbg_level, S_IRUGO | S_IWUSR, csio_show_dbg_level,
+		  csio_store_dbg_level);
+
+static struct device_attribute *csio_fcoe_lport_attrs[] = {
+	&dev_attr_hw_state,
+	&dev_attr_device_reset,
+	&dev_attr_disable_port,
+	&dev_attr_dbg_level,
+	NULL,
+};
+
+static ssize_t
+csio_show_num_reg_rnodes(struct device *dev,
+		     struct device_attribute *attr, char *buf)
+{
+	struct csio_lnode *ln = shost_priv(class_to_shost(dev));
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", ln->num_reg_rnodes);
+}
+
+static DEVICE_ATTR(num_reg_rnodes, S_IRUGO, csio_show_num_reg_rnodes, NULL);
+
+static struct device_attribute *csio_fcoe_vport_attrs[] = {
+	&dev_attr_num_reg_rnodes,
+	&dev_attr_dbg_level,
+	NULL,
+};
+
+static inline uint32_t
+csio_scsi_copy_to_sgl(struct csio_hw *hw, struct csio_ioreq *req)
+{
+	struct scsi_cmnd *scmnd  = (struct scsi_cmnd *)csio_scsi_cmnd(req);
+	struct scatterlist *sg;
+	uint32_t bytes_left;
+	uint32_t bytes_copy;
+	uint32_t buf_off = 0;
+	uint32_t start_off = 0;
+	uint32_t sg_off = 0;
+	void *sg_addr;
+	void *buf_addr;
+	struct csio_dma_buf *dma_buf;
+
+	bytes_left = scsi_bufflen(scmnd);
+	sg = scsi_sglist(scmnd);
+	dma_buf = (struct csio_dma_buf *)csio_list_next(&req->gen_list);
+
+	/* Copy data from driver buffer to SGs of SCSI CMD */
+	while (bytes_left > 0 && sg && dma_buf) {
+		if (buf_off >= dma_buf->len) {
+			buf_off = 0;
+			dma_buf = (struct csio_dma_buf *)
+					csio_list_next(dma_buf);
+			continue;
+		}
+
+		if (start_off >= sg->length) {
+			start_off -= sg->length;
+			sg = sg_next(sg);
+			continue;
+		}
+
+		buf_addr = dma_buf->vaddr + buf_off;
+		sg_off = sg->offset + start_off;
+		bytes_copy = min((dma_buf->len - buf_off),
+				sg->length - start_off);
+		bytes_copy = min((uint32_t)(PAGE_SIZE - (sg_off & ~PAGE_MASK)),
+				 bytes_copy);
+
+		sg_addr = kmap_atomic(sg_page(sg) + (sg_off >> PAGE_SHIFT));
+		if (!sg_addr) {
+			csio_err(hw, "failed to kmap sg:%p of ioreq:%p\n",
+				sg, req);
+			break;
+		}
+
+		csio_dbg(hw, "copy_to_sgl:sg_addr %p sg_off %d buf %p len %d\n",
+				sg_addr, sg_off, buf_addr, bytes_copy);
+		memcpy(sg_addr + (sg_off & ~PAGE_MASK), buf_addr, bytes_copy);
+		kunmap_atomic(sg_addr);
+
+		start_off +=  bytes_copy;
+		buf_off += bytes_copy;
+		bytes_left -= bytes_copy;
+	}
+
+	if (bytes_left > 0)
+		return DID_ERROR;
+	else
+		return DID_OK;
+}
+
+/*
+ * csio_scsi_err_handler - SCSI error handler.
+ * @hw: HW module.
+ * @req: IO request.
+ *
+ */
+static inline void
+csio_scsi_err_handler(struct csio_hw *hw, struct csio_ioreq *req)
+{
+	struct scsi_cmnd *cmnd  = (struct scsi_cmnd *)csio_scsi_cmnd(req);
+	struct csio_scsim *scm = csio_hw_to_scsim(hw);
+	struct fcp_resp_with_ext *fcp_resp;
+	struct fcp_resp_rsp_info *rsp_info;
+	struct csio_dma_buf *dma_buf;
+	uint8_t flags, scsi_status = 0;
+	uint32_t host_status = DID_OK;
+	uint32_t rsp_len = 0, sns_len = 0;
+	struct csio_rnode *rn = (struct csio_rnode *)(cmnd->device->hostdata);
+
+
+	switch (req->wr_status) {
+	case FW_HOSTERROR:
+		if (unlikely(!csio_is_hw_ready(hw)))
+			return;
+
+		host_status = DID_ERROR;
+		CSIO_INC_STATS(scm, n_hosterror);
+
+		break;
+	case FW_SCSI_RSP_ERR:
+		dma_buf = &req->dma_buf;
+		fcp_resp = (struct fcp_resp_with_ext *)dma_buf->vaddr;
+		rsp_info = (struct fcp_resp_rsp_info *)(fcp_resp + 1);
+		flags = fcp_resp->resp.fr_flags;
+		scsi_status = fcp_resp->resp.fr_status;
+
+		if (flags & FCP_RSP_LEN_VAL) {
+			rsp_len = be32_to_cpu(fcp_resp->ext.fr_rsp_len);
+			if ((rsp_len != 0 && rsp_len != 4 && rsp_len != 8) ||
+				(rsp_info->rsp_code != FCP_TMF_CMPL)) {
+				host_status = DID_ERROR;
+				goto out;
+			}
+		}
+
+		if ((flags & FCP_SNS_LEN_VAL) && fcp_resp->ext.fr_sns_len) {
+			sns_len = be32_to_cpu(fcp_resp->ext.fr_sns_len);
+			if (sns_len > SCSI_SENSE_BUFFERSIZE)
+				sns_len = SCSI_SENSE_BUFFERSIZE;
+
+			memcpy(cmnd->sense_buffer,
+			       &rsp_info->_fr_resvd[0] + rsp_len, sns_len);
+			CSIO_INC_STATS(scm, n_autosense);
+		}
+
+		scsi_set_resid(cmnd, 0);
+
+		/* Under run */
+		if (flags & FCP_RESID_UNDER) {
+			scsi_set_resid(cmnd,
+				       be32_to_cpu(fcp_resp->ext.fr_resid));
+
+			if (!(flags & FCP_SNS_LEN_VAL) &&
+			    (scsi_status == SAM_STAT_GOOD) &&
+			    ((scsi_bufflen(cmnd) - scsi_get_resid(cmnd))
+							< cmnd->underflow))
+				host_status = DID_ERROR;
+		} else if (flags & FCP_RESID_OVER)
+			host_status = DID_ERROR;
+
+		CSIO_INC_STATS(scm, n_rsperror);
+		break;
+
+	case FW_SCSI_OVER_FLOW_ERR:
+		csio_warn(hw,
+			  "Over-flow error,cmnd:0x%x expected len:0x%x"
+			  " resid:0x%x\n", cmnd->cmnd[0],
+			  scsi_bufflen(cmnd), scsi_get_resid(cmnd));
+		host_status = DID_ERROR;
+		CSIO_INC_STATS(scm, n_ovflerror);
+		break;
+
+	case FW_SCSI_UNDER_FLOW_ERR:
+		csio_warn(hw,
+			  "Under-flow error,cmnd:0x%x expected"
+			  " len:0x%x resid:0x%x lun:0x%x ssn:0x%x\n",
+			  cmnd->cmnd[0], scsi_bufflen(cmnd),
+			  scsi_get_resid(cmnd), cmnd->device->lun,
+			  rn->flowid);
+		host_status = DID_ERROR;
+		CSIO_INC_STATS(scm, n_unflerror);
+		break;
+
+	case FW_SCSI_ABORT_REQUESTED:
+	case FW_SCSI_ABORTED:
+	case FW_SCSI_CLOSE_REQUESTED:
+		csio_dbg(hw, "Req %p cmd:%p op:%x %s\n", req, cmnd,
+			     cmnd->cmnd[0],
+			    (req->wr_status == FW_SCSI_CLOSE_REQUESTED) ?
+			    "closed" : "aborted");
+		/*
+		 * csio_eh_abort_handler checks this value to
+		 * succeed or fail the abort request.
+		 */
+		host_status = DID_REQUEUE;
+		if (req->wr_status == FW_SCSI_CLOSE_REQUESTED)
+			CSIO_INC_STATS(scm, n_closed);
+		else
+			CSIO_INC_STATS(scm, n_aborted);
+		break;
+
+	case FW_SCSI_ABORT_TIMEDOUT:
+		/* FW timed out the abort itself */
+		csio_dbg(hw, "FW timed out abort req:%p cmnd:%p status:%x\n",
+			 req, cmnd, req->wr_status);
+		host_status = DID_ERROR;
+		CSIO_INC_STATS(scm, n_abrt_timedout);
+		break;
+
+	case FW_RDEV_NOT_READY:
+		/*
+		 * In firmware, a RDEV can get into this state
+		 * temporarily, before moving into dissapeared/lost
+		 * state. So, the driver should complete the request equivalent
+		 * to device-disappeared!
+		 */
+		CSIO_INC_STATS(scm, n_rdev_nr_error);
+		host_status = DID_ERROR;
+		break;
+
+	case FW_ERR_RDEV_LOST:
+		CSIO_INC_STATS(scm, n_rdev_lost_error);
+		host_status = DID_ERROR;
+		break;
+
+	case FW_ERR_RDEV_LOGO:
+		CSIO_INC_STATS(scm, n_rdev_logo_error);
+		host_status = DID_ERROR;
+		break;
+
+	case FW_ERR_RDEV_IMPL_LOGO:
+		host_status = DID_ERROR;
+		break;
+
+	case FW_ERR_LINK_DOWN:
+		CSIO_INC_STATS(scm, n_link_down_error);
+		host_status = DID_ERROR;
+		break;
+
+	case FW_FCOE_NO_XCHG:
+		CSIO_INC_STATS(scm, n_no_xchg_error);
+		host_status = DID_ERROR;
+		break;
+
+	default:
+		csio_err(hw, "Unknown SCSI FW WR status:%d req:%p cmnd:%p\n",
+			    req->wr_status, req, cmnd);
+		CSIO_DB_ASSERT(0);
+
+		CSIO_INC_STATS(scm, n_unknown_error);
+		host_status = DID_ERROR;
+		break;
+	}
+
+out:
+	if (req->nsge > 0)
+		scsi_dma_unmap(cmnd);
+
+	cmnd->result = (((host_status) << 16) | scsi_status);
+	cmnd->scsi_done(cmnd);
+
+	/* Wake up waiting threads */
+	csio_scsi_cmnd(req) = NULL;
+	complete_all(&req->cmplobj);
+}
+
+/*
+ * csio_scsi_cbfn - SCSI callback function.
+ * @hw: HW module.
+ * @req: IO request.
+ *
+ */
+static void
+csio_scsi_cbfn(struct csio_hw *hw, struct csio_ioreq *req)
+{
+	struct scsi_cmnd *cmnd  = (struct scsi_cmnd *)csio_scsi_cmnd(req);
+	uint8_t scsi_status = SAM_STAT_GOOD;
+	uint32_t host_status = DID_OK;
+
+	if (likely(req->wr_status == FW_SUCCESS)) {
+		if (req->nsge > 0) {
+			scsi_dma_unmap(cmnd);
+			if (req->dcopy)
+				host_status = csio_scsi_copy_to_sgl(hw, req);
+		}
+
+		cmnd->result = (((host_status) << 16) | scsi_status);
+		cmnd->scsi_done(cmnd);
+		csio_scsi_cmnd(req) = NULL;
+		CSIO_INC_STATS(csio_hw_to_scsim(hw), n_tot_success);
+	} else {
+		/* Error handling */
+		csio_scsi_err_handler(hw, req);
+	}
+}
+
+/**
+ * csio_queuecommand_lck - Entry point to kickstart an I/O request.
+ * @cmnd:	The I/O request from ML.
+ * @done:	The ML callback routine.
+ *
+ * This routine does the following:
+ *	- Checks for HW and Rnode module readiness.
+ *	- Gets a free ioreq structure (which is already initialized
+ *	  to uninit during its allocation).
+ *	- Maps SG elements.
+ *	- Initializes ioreq members.
+ *	- Kicks off the SCSI state machine for this IO.
+ *	- Returns busy status on error.
+ */
+static int
+csio_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done)(struct scsi_cmnd *))
+{
+	struct csio_lnode *ln = shost_priv(cmnd->device->host);
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+	struct csio_scsim *scsim = csio_hw_to_scsim(hw);
+	struct csio_rnode *rn = (struct csio_rnode *)(cmnd->device->hostdata);
+	struct csio_ioreq *ioreq = NULL;
+	unsigned long flags;
+	int nsge = 0;
+	int rv = SCSI_MLQUEUE_HOST_BUSY, nr;
+	int retval;
+	int cpu;
+	struct csio_scsi_qset *sqset;
+	struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
+
+	if (!blk_rq_cpu_valid(cmnd->request))
+		cpu = smp_processor_id();
+	else
+		cpu = cmnd->request->cpu;
+
+	sqset = &hw->sqset[ln->portid][cpu];
+
+	nr = fc_remote_port_chkready(rport);
+	if (nr) {
+		cmnd->result = nr;
+		CSIO_INC_STATS(scsim, n_rn_nr_error);
+		goto err_done;
+	}
+
+	if (unlikely(!csio_is_hw_ready(hw))) {
+		cmnd->result = (DID_REQUEUE << 16);
+		CSIO_INC_STATS(scsim, n_hw_nr_error);
+		goto err_done;
+	}
+
+	/* Get req->nsge, if there are SG elements to be mapped  */
+	nsge = scsi_dma_map(cmnd);
+	if (unlikely(nsge < 0)) {
+		CSIO_INC_STATS(scsim, n_dmamap_error);
+		goto err;
+	}
+
+	/* Do we support so many mappings? */
+	if (unlikely(nsge > scsim->max_sge)) {
+		csio_warn(hw,
+			  "More SGEs than can be supported."
+			  " SGEs: %d, Max SGEs: %d\n", nsge, scsim->max_sge);
+		CSIO_INC_STATS(scsim, n_unsupp_sge_error);
+		goto err_dma_unmap;
+	}
+
+	/* Get a free ioreq structure - SM is already set to uninit */
+	ioreq = csio_get_scsi_ioreq_lock(hw, scsim);
+	if (!ioreq) {
+		csio_err(hw, "Out of I/O request elements. Active #:%d\n",
+			 scsim->stats.n_active);
+		CSIO_INC_STATS(scsim, n_no_req_error);
+		goto err_dma_unmap;
+	}
+
+	ioreq->nsge		= nsge;
+	ioreq->lnode		= ln;
+	ioreq->rnode		= rn;
+	ioreq->iq_idx		= sqset->iq_idx;
+	ioreq->eq_idx		= sqset->eq_idx;
+	ioreq->wr_status	= 0;
+	ioreq->drv_status	= 0;
+	csio_scsi_cmnd(ioreq)	= (void *)cmnd;
+	ioreq->tmo		= 0;
+	ioreq->datadir		= cmnd->sc_data_direction;
+
+	if (cmnd->sc_data_direction == DMA_TO_DEVICE) {
+		CSIO_INC_STATS(ln, n_output_requests);
+		ln->stats.n_output_bytes += scsi_bufflen(cmnd);
+	} else if (cmnd->sc_data_direction == DMA_FROM_DEVICE) {
+		CSIO_INC_STATS(ln, n_input_requests);
+		ln->stats.n_input_bytes += scsi_bufflen(cmnd);
+	} else
+		CSIO_INC_STATS(ln, n_control_requests);
+
+	/* Set cbfn */
+	ioreq->io_cbfn = csio_scsi_cbfn;
+
+	/* Needed during abort */
+	cmnd->host_scribble = (unsigned char *)ioreq;
+	cmnd->scsi_done = done;
+	cmnd->SCp.Message = 0;
+
+	/* Kick off SCSI IO SM on the ioreq */
+	spin_lock_irqsave(&hw->lock, flags);
+	retval = csio_scsi_start_io(ioreq);
+	spin_unlock_irqrestore(&hw->lock, flags);
+
+	if (retval != 0) {
+		csio_err(hw, "ioreq: %p couldnt be started, status:%d\n",
+			 ioreq, retval);
+		CSIO_INC_STATS(scsim, n_busy_error);
+		goto err_put_req;
+	}
+
+	return 0;
+
+err_put_req:
+	csio_put_scsi_ioreq_lock(hw, scsim, ioreq);
+err_dma_unmap:
+	if (nsge > 0)
+		scsi_dma_unmap(cmnd);
+err:
+	return rv;
+
+err_done:
+	done(cmnd);
+	return 0;
+}
+
+static DEF_SCSI_QCMD(csio_queuecommand);
+
+static int
+csio_do_abrt_cls(struct csio_hw *hw, struct csio_ioreq *ioreq, bool abort)
+{
+	int rv;
+	int cpu = smp_processor_id();
+	struct csio_lnode *ln = ioreq->lnode;
+	struct csio_scsi_qset *sqset = &hw->sqset[ln->portid][cpu];
+
+	ioreq->tmo = CSIO_SCSI_ABRT_TMO_MS;
+	/*
+	 * Use current processor queue for posting the abort/close, but retain
+	 * the ingress queue ID of the original I/O being aborted/closed - we
+	 * need the abort/close completion to be received on the same queue
+	 * as the original I/O.
+	 */
+	ioreq->eq_idx = sqset->eq_idx;
+
+	if (abort == SCSI_ABORT)
+		rv = csio_scsi_abort(ioreq);
+	else
+		rv = csio_scsi_close(ioreq);
+
+	return rv;
+}
+
+static int
+csio_eh_abort_handler(struct scsi_cmnd *cmnd)
+{
+	struct csio_ioreq *ioreq;
+	struct csio_lnode *ln = shost_priv(cmnd->device->host);
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+	struct csio_scsim *scsim = csio_hw_to_scsim(hw);
+	int ready = 0, ret;
+	unsigned long tmo = 0;
+	int rv;
+	struct csio_rnode *rn = (struct csio_rnode *)(cmnd->device->hostdata);
+
+	ret = fc_block_scsi_eh(cmnd);
+	if (ret)
+		return ret;
+
+	ioreq = (struct csio_ioreq *)cmnd->host_scribble;
+	if (!ioreq)
+		return SUCCESS;
+
+	if (!rn)
+		return FAILED;
+
+	csio_dbg(hw,
+		 "Request to abort ioreq:%p cmd:%p cdb:%08llx"
+		 " ssni:0x%x lun:%d iq:0x%x\n",
+		ioreq, cmnd, *((uint64_t *)cmnd->cmnd), rn->flowid,
+		cmnd->device->lun, csio_q_physiqid(hw, ioreq->iq_idx));
+
+	if (((struct scsi_cmnd *)csio_scsi_cmnd(ioreq)) != cmnd) {
+		CSIO_INC_STATS(scsim, n_abrt_race_comp);
+		return SUCCESS;
+	}
+
+	ready = csio_is_lnode_ready(ln);
+	tmo = CSIO_SCSI_ABRT_TMO_MS;
+
+	spin_lock_irq(&hw->lock);
+	rv = csio_do_abrt_cls(hw, ioreq, (ready ? SCSI_ABORT : SCSI_CLOSE));
+	spin_unlock_irq(&hw->lock);
+
+	if (rv != 0) {
+		if (rv == -EINVAL) {
+			/* Return success, if abort/close request issued on
+			 * already completed IO
+			 */
+			return SUCCESS;
+		}
+		if (ready)
+			CSIO_INC_STATS(scsim, n_abrt_busy_error);
+		else
+			CSIO_INC_STATS(scsim, n_cls_busy_error);
+
+		goto inval_scmnd;
+	}
+
+	/* Wait for completion */
+	init_completion(&ioreq->cmplobj);
+	wait_for_completion_timeout(&ioreq->cmplobj, msecs_to_jiffies(tmo));
+
+	/* FW didnt respond to abort within our timeout */
+	if (((struct scsi_cmnd *)csio_scsi_cmnd(ioreq)) == cmnd) {
+
+		csio_err(hw, "Abort timed out -- req: %p\n", ioreq);
+		CSIO_INC_STATS(scsim, n_abrt_timedout);
+
+inval_scmnd:
+		if (ioreq->nsge > 0)
+			scsi_dma_unmap(cmnd);
+
+		spin_lock_irq(&hw->lock);
+		csio_scsi_cmnd(ioreq) = NULL;
+		spin_unlock_irq(&hw->lock);
+
+		cmnd->result = (DID_ERROR << 16);
+		cmnd->scsi_done(cmnd);
+
+		return FAILED;
+	}
+
+	/* FW successfully aborted the request */
+	if (host_byte(cmnd->result) == DID_REQUEUE) {
+		csio_info(hw,
+			"Aborted SCSI command to (%d:%d) serial#:0x%lx\n",
+			cmnd->device->id, cmnd->device->lun,
+			cmnd->serial_number);
+		return SUCCESS;
+	} else {
+		csio_info(hw,
+			"Failed to abort SCSI command, (%d:%d) serial#:0x%lx\n",
+			cmnd->device->id, cmnd->device->lun,
+			cmnd->serial_number);
+		return FAILED;
+	}
+}
+
+/*
+ * csio_tm_cbfn - TM callback function.
+ * @hw: HW module.
+ * @req: IO request.
+ *
+ * Cache the result in 'cmnd', since ioreq will be freed soon
+ * after we return from here, and the waiting thread shouldnt trust
+ * the ioreq contents.
+ */
+static void
+csio_tm_cbfn(struct csio_hw *hw, struct csio_ioreq *req)
+{
+	struct scsi_cmnd *cmnd  = (struct scsi_cmnd *)csio_scsi_cmnd(req);
+	struct csio_dma_buf *dma_buf;
+	uint8_t flags = 0;
+	struct fcp_resp_with_ext *fcp_resp;
+	struct fcp_resp_rsp_info *rsp_info;
+
+	csio_dbg(hw, "req: %p in csio_tm_cbfn status: %d\n",
+		      req, req->wr_status);
+
+	/* Cache FW return status */
+	cmnd->SCp.Status = req->wr_status;
+
+	/* Special handling based on FCP response */
+
+	/*
+	 * FW returns us this error, if flags were set. FCP4 says
+	 * FCP_RSP_LEN_VAL in flags shall be set for TM completions.
+	 * So if a target were to set this bit, we expect that the
+	 * rsp_code is set to FCP_TMF_CMPL for a successful TM
+	 * completion. Any other rsp_code means TM operation failed.
+	 * If a target were to just ignore setting flags, we treat
+	 * the TM operation as success, and FW returns FW_SUCCESS.
+	 */
+	if (req->wr_status == FW_SCSI_RSP_ERR) {
+		dma_buf = &req->dma_buf;
+		fcp_resp = (struct fcp_resp_with_ext *)dma_buf->vaddr;
+		rsp_info = (struct fcp_resp_rsp_info *)(fcp_resp + 1);
+
+		flags = fcp_resp->resp.fr_flags;
+
+		/* Modify return status if flags indicate success */
+		if (flags & FCP_RSP_LEN_VAL)
+			if (rsp_info->rsp_code == FCP_TMF_CMPL)
+				cmnd->SCp.Status = FW_SUCCESS;
+
+		csio_dbg(hw, "TM FCP rsp code: %d\n", rsp_info->rsp_code);
+	}
+
+	/* Wake up the TM handler thread */
+	csio_scsi_cmnd(req) = NULL;
+}
+
+static int
+csio_eh_lun_reset_handler(struct scsi_cmnd *cmnd)
+{
+	struct csio_lnode *ln = shost_priv(cmnd->device->host);
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+	struct csio_scsim *scsim = csio_hw_to_scsim(hw);
+	struct csio_rnode *rn = (struct csio_rnode *)(cmnd->device->hostdata);
+	struct csio_ioreq *ioreq = NULL;
+	struct csio_scsi_qset *sqset;
+	unsigned long flags;
+	int retval;
+	int count, ret;
+	LIST_HEAD(local_q);
+	struct csio_scsi_level_data sld;
+
+	if (!rn)
+		goto fail;
+
+	csio_dbg(hw, "Request to reset LUN:%d (ssni:0x%x tgtid:%d)\n",
+		      cmnd->device->lun, rn->flowid, rn->scsi_id);
+
+	if (!csio_is_lnode_ready(ln)) {
+		csio_err(hw,
+			 "LUN reset cannot be issued on non-ready"
+			 " local node vnpi:0x%x (LUN:%d)\n",
+			 ln->vnp_flowid, cmnd->device->lun);
+		goto fail;
+	}
+
+	/* Lnode is ready, now wait on rport node readiness */
+	ret = fc_block_scsi_eh(cmnd);
+	if (ret)
+		return ret;
+
+	/*
+	 * If we have blocked in the previous call, at this point, either the
+	 * remote node has come back online, or device loss timer has fired
+	 * and the remote node is destroyed. Allow the LUN reset only for
+	 * the former case, since LUN reset is a TMF I/O on the wire, and we
+	 * need a valid session to issue it.
+	 */
+	if (fc_remote_port_chkready(rn->rport)) {
+		csio_err(hw,
+			 "LUN reset cannot be issued on non-ready"
+			 " remote node ssni:0x%x (LUN:%d)\n",
+			 rn->flowid, cmnd->device->lun);
+		goto fail;
+	}
+
+	/* Get a free ioreq structure - SM is already set to uninit */
+	ioreq = csio_get_scsi_ioreq_lock(hw, scsim);
+
+	if (!ioreq) {
+		csio_err(hw, "Out of IO request elements. Active # :%d\n",
+			 scsim->stats.n_active);
+		goto fail;
+	}
+
+	sqset			= &hw->sqset[ln->portid][smp_processor_id()];
+	ioreq->nsge		= 0;
+	ioreq->lnode		= ln;
+	ioreq->rnode		= rn;
+	ioreq->iq_idx		= sqset->iq_idx;
+	ioreq->eq_idx		= sqset->eq_idx;
+
+	csio_scsi_cmnd(ioreq)	= cmnd;
+	cmnd->host_scribble	= (unsigned char *)ioreq;
+	cmnd->SCp.Status	= 0;
+
+	cmnd->SCp.Message	= FCP_TMF_LUN_RESET;
+	ioreq->tmo		= CSIO_SCSI_LUNRST_TMO_MS / 1000;
+
+	/*
+	 * FW times the LUN reset for ioreq->tmo, so we got to wait a little
+	 * longer (10s for now) than that to allow FW to return the timed
+	 * out command.
+	 */
+	count = DIV_ROUND_UP((ioreq->tmo + 10) * 1000, CSIO_SCSI_TM_POLL_MS);
+
+	/* Set cbfn */
+	ioreq->io_cbfn = csio_tm_cbfn;
+
+	/* Save of the ioreq info for later use */
+	sld.level = CSIO_LEV_LUN;
+	sld.lnode = ioreq->lnode;
+	sld.rnode = ioreq->rnode;
+	sld.oslun = (uint64_t)cmnd->device->lun;
+
+	spin_lock_irqsave(&hw->lock, flags);
+	/* Kick off TM SM on the ioreq */
+	retval = csio_scsi_start_tm(ioreq);
+	spin_unlock_irqrestore(&hw->lock, flags);
+
+	if (retval != 0) {
+		csio_err(hw, "Failed to issue LUN reset, req:%p, status:%d\n",
+			    ioreq, retval);
+		goto fail_ret_ioreq;
+	}
+
+	csio_dbg(hw, "Waiting max %d secs for LUN reset completion\n",
+		    count * (CSIO_SCSI_TM_POLL_MS / 1000));
+	/* Wait for completion */
+	while ((((struct scsi_cmnd *)csio_scsi_cmnd(ioreq)) == cmnd)
+								&& count--)
+		msleep(CSIO_SCSI_TM_POLL_MS);
+
+	/* LUN reset timed-out */
+	if (((struct scsi_cmnd *)csio_scsi_cmnd(ioreq)) == cmnd) {
+		csio_err(hw, "LUN reset (%d:%d) timed out\n",
+			 cmnd->device->id, cmnd->device->lun);
+
+		spin_lock_irq(&hw->lock);
+		csio_scsi_drvcleanup(ioreq);
+		list_del_init(&ioreq->sm.sm_list);
+		spin_unlock_irq(&hw->lock);
+
+		goto fail_ret_ioreq;
+	}
+
+	/* LUN reset returned, check cached status */
+	if (cmnd->SCp.Status != FW_SUCCESS) {
+		csio_err(hw, "LUN reset failed (%d:%d), status: %d\n",
+			 cmnd->device->id, cmnd->device->lun, cmnd->SCp.Status);
+		goto fail;
+	}
+
+	/* LUN reset succeeded, Start aborting affected I/Os */
+	/*
+	 * Since the host guarantees during LUN reset that there
+	 * will not be any more I/Os to that LUN, until the LUN reset
+	 * completes, we gather pending I/Os after the LUN reset.
+	 */
+	spin_lock_irq(&hw->lock);
+	csio_scsi_gather_active_ios(scsim, &sld, &local_q);
+
+	retval = csio_scsi_abort_io_q(scsim, &local_q, 30000);
+	spin_unlock_irq(&hw->lock);
+
+	/* Aborts may have timed out */
+	if (retval != 0) {
+		csio_err(hw,
+			 "Attempt to abort I/Os during LUN reset of %d"
+			 " returned %d\n", cmnd->device->lun, retval);
+		/* Return I/Os back to active_q */
+		spin_lock_irq(&hw->lock);
+		list_splice_tail_init(&local_q, &scsim->active_q);
+		spin_unlock_irq(&hw->lock);
+		goto fail;
+	}
+
+	CSIO_INC_STATS(rn, n_lun_rst);
+
+	csio_info(hw, "LUN reset occurred (%d:%d)\n",
+		  cmnd->device->id, cmnd->device->lun);
+
+	return SUCCESS;
+
+fail_ret_ioreq:
+	csio_put_scsi_ioreq_lock(hw, scsim, ioreq);
+fail:
+	CSIO_INC_STATS(rn, n_lun_rst_fail);
+	return FAILED;
+}
+
+static int
+csio_slave_alloc(struct scsi_device *sdev)
+{
+	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+
+	if (!rport || fc_remote_port_chkready(rport))
+		return -ENXIO;
+
+	sdev->hostdata = *((struct csio_lnode **)(rport->dd_data));
+
+	return 0;
+}
+
+static int
+csio_slave_configure(struct scsi_device *sdev)
+{
+	if (sdev->tagged_supported)
+		scsi_activate_tcq(sdev, csio_lun_qdepth);
+	else
+		scsi_deactivate_tcq(sdev, csio_lun_qdepth);
+
+	return 0;
+}
+
+static void
+csio_slave_destroy(struct scsi_device *sdev)
+{
+	sdev->hostdata = NULL;
+}
+
+static int
+csio_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+	struct csio_lnode *ln = shost_priv(shost);
+	int rv = 0;
+
+	spin_lock_irq(shost->host_lock);
+	if (!ln->hwp || csio_list_deleted(&ln->sm.sm_list)) {
+		spin_unlock_irq(shost->host_lock);
+		return 1;
+	}
+
+	rv = csio_scan_done(ln, jiffies, time, csio_max_scan_tmo * HZ,
+			    csio_delta_scan_tmo * HZ);
+
+	spin_unlock_irq(shost->host_lock);
+
+	return rv;
+}
+
+struct scsi_host_template csio_fcoe_shost_template = {
+	.module			= THIS_MODULE,
+	.name			= CSIO_DRV_DESC,
+	.proc_name		= KBUILD_MODNAME,
+	.queuecommand		= csio_queuecommand,
+	.eh_abort_handler	= csio_eh_abort_handler,
+	.eh_device_reset_handler = csio_eh_lun_reset_handler,
+	.slave_alloc		= csio_slave_alloc,
+	.slave_configure	= csio_slave_configure,
+	.slave_destroy		= csio_slave_destroy,
+	.scan_finished		= csio_scan_finished,
+	.this_id		= -1,
+	.sg_tablesize		= CSIO_SCSI_MAX_SGE,
+	.cmd_per_lun		= CSIO_MAX_CMD_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= csio_fcoe_lport_attrs,
+	.max_sectors		= CSIO_MAX_SECTOR_SIZE,
+};
+
+struct scsi_host_template csio_fcoe_shost_vport_template = {
+	.module			= THIS_MODULE,
+	.name			= CSIO_DRV_DESC,
+	.proc_name		= KBUILD_MODNAME,
+	.queuecommand		= csio_queuecommand,
+	.eh_abort_handler	= csio_eh_abort_handler,
+	.eh_device_reset_handler = csio_eh_lun_reset_handler,
+	.slave_alloc		= csio_slave_alloc,
+	.slave_configure	= csio_slave_configure,
+	.slave_destroy		= csio_slave_destroy,
+	.scan_finished		= csio_scan_finished,
+	.this_id		= -1,
+	.sg_tablesize		= CSIO_SCSI_MAX_SGE,
+	.cmd_per_lun		= CSIO_MAX_CMD_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= csio_fcoe_vport_attrs,
+	.max_sectors		= CSIO_MAX_SECTOR_SIZE,
+};
+
+/*
+ * csio_scsi_alloc_ddp_bufs - Allocate buffers for DDP of unaligned SGLs.
+ * @scm: SCSI Module
+ * @hw: HW device.
+ * @buf_size: buffer size
+ * @num_buf : Number of buffers.
+ *
+ * This routine allocates DMA buffers required for SCSI Data xfer, if
+ * each SGL buffer for a SCSI Read request posted by SCSI midlayer are
+ * not virtually contiguous.
+ */
+static int
+csio_scsi_alloc_ddp_bufs(struct csio_scsim *scm, struct csio_hw *hw,
+			 int buf_size, int num_buf)
+{
+	int n = 0;
+	struct list_head *tmp;
+	struct csio_dma_buf *ddp_desc = NULL;
+	uint32_t unit_size = 0;
+
+	if (!num_buf)
+		return 0;
+
+	if (!buf_size)
+		return -EINVAL;
+
+	INIT_LIST_HEAD(&scm->ddp_freelist);
+
+	/* Align buf size to page size */
+	buf_size = (buf_size + PAGE_SIZE - 1) & PAGE_MASK;
+	/* Initialize dma descriptors */
+	for (n = 0; n < num_buf; n++) {
+		/* Set unit size to request size */
+		unit_size = buf_size;
+		ddp_desc = kzalloc(sizeof(struct csio_dma_buf), GFP_KERNEL);
+		if (!ddp_desc) {
+			csio_err(hw,
+				 "Failed to allocate ddp descriptors,"
+				 " Num allocated = %d.\n",
+				 scm->stats.n_free_ddp);
+			goto no_mem;
+		}
+
+		/* Allocate Dma buffers for DDP */
+		ddp_desc->vaddr = pci_alloc_consistent(hw->pdev, unit_size,
+							&ddp_desc->paddr);
+		if (!ddp_desc->vaddr) {
+			csio_err(hw,
+				 "SCSI response DMA buffer (ddp) allocation"
+				 " failed!\n");
+			kfree(ddp_desc);
+			goto no_mem;
+		}
+
+		ddp_desc->len = unit_size;
+
+		/* Added it to scsi ddp freelist */
+		list_add_tail(&ddp_desc->list, &scm->ddp_freelist);
+		CSIO_INC_STATS(scm, n_free_ddp);
+	}
+
+	return 0;
+no_mem:
+	/* release dma descs back to freelist and free dma memory */
+	list_for_each(tmp, &scm->ddp_freelist) {
+		ddp_desc = (struct csio_dma_buf *) tmp;
+		tmp = csio_list_prev(tmp);
+		pci_free_consistent(hw->pdev, ddp_desc->len, ddp_desc->vaddr,
+				    ddp_desc->paddr);
+		list_del_init(&ddp_desc->list);
+		kfree(ddp_desc);
+	}
+	scm->stats.n_free_ddp = 0;
+
+	return -ENOMEM;
+}
+
+/*
+ * csio_scsi_free_ddp_bufs - free DDP buffers of unaligned SGLs.
+ * @scm: SCSI Module
+ * @hw: HW device.
+ *
+ * This routine frees ddp buffers.
+ */
+static void
+csio_scsi_free_ddp_bufs(struct csio_scsim *scm, struct csio_hw *hw)
+{
+	struct list_head *tmp;
+	struct csio_dma_buf *ddp_desc;
+
+	/* release dma descs back to freelist and free dma memory */
+	list_for_each(tmp, &scm->ddp_freelist) {
+		ddp_desc = (struct csio_dma_buf *) tmp;
+		tmp = csio_list_prev(tmp);
+		pci_free_consistent(hw->pdev, ddp_desc->len, ddp_desc->vaddr,
+				    ddp_desc->paddr);
+		list_del_init(&ddp_desc->list);
+		kfree(ddp_desc);
+	}
+	scm->stats.n_free_ddp = 0;
+}
+
+/**
+ * csio_scsim_init - Initialize SCSI Module
+ * @scm:	SCSI Module
+ * @hw:		HW module
+ *
+ */
+int
+csio_scsim_init(struct csio_scsim *scm, struct csio_hw *hw)
+{
+	int i;
+	struct csio_ioreq *ioreq;
+	struct csio_dma_buf *dma_buf;
+
+	INIT_LIST_HEAD(&scm->active_q);
+	scm->hw = hw;
+
+	scm->proto_cmd_len = sizeof(struct fcp_cmnd);
+	scm->proto_rsp_len = CSIO_SCSI_RSP_LEN;
+	scm->max_sge = CSIO_SCSI_MAX_SGE;
+
+	spin_lock_init(&scm->freelist_lock);
+
+	/* Pre-allocate ioreqs and initialize them */
+	INIT_LIST_HEAD(&scm->ioreq_freelist);
+	for (i = 0; i < csio_scsi_ioreqs; i++) {
+
+		ioreq = kzalloc(sizeof(struct csio_ioreq), GFP_KERNEL);
+		if (!ioreq) {
+			csio_err(hw,
+				 "I/O request element allocation failed, "
+				 " Num allocated = %d.\n",
+				 scm->stats.n_free_ioreq);
+
+			goto free_ioreq;
+		}
+
+		/* Allocate Dma buffers for Response Payload */
+		dma_buf = &ioreq->dma_buf;
+		dma_buf->vaddr = pci_pool_alloc(hw->scsi_pci_pool, GFP_KERNEL,
+						&dma_buf->paddr);
+		if (!dma_buf->vaddr) {
+			csio_err(hw,
+				 "SCSI response DMA buffer allocation"
+				 " failed!\n");
+			kfree(ioreq);
+			goto free_ioreq;
+		}
+
+		dma_buf->len = scm->proto_rsp_len;
+
+		/* Set state to uninit */
+		csio_init_state(&ioreq->sm, csio_scsis_uninit);
+		INIT_LIST_HEAD(&ioreq->gen_list);
+		init_completion(&ioreq->cmplobj);
+
+		list_add_tail(&ioreq->sm.sm_list, &scm->ioreq_freelist);
+		CSIO_INC_STATS(scm, n_free_ioreq);
+	}
+
+	if (csio_scsi_alloc_ddp_bufs(scm, hw, PAGE_SIZE, csio_ddp_descs))
+		goto free_ioreq;
+
+	return 0;
+
+free_ioreq:
+	/*
+	 * Free up existing allocations, since an error
+	 * from here means we are returning for good
+	 */
+	while (!list_empty(&scm->ioreq_freelist)) {
+		struct csio_sm *tmp;
+
+		tmp = list_first_entry(&scm->ioreq_freelist,
+				       struct csio_sm, sm_list);
+		list_del_init(&tmp->sm_list);
+		ioreq = (struct csio_ioreq *)tmp;
+
+		dma_buf = &ioreq->dma_buf;
+		pci_pool_free(hw->scsi_pci_pool, dma_buf->vaddr,
+			      dma_buf->paddr);
+
+		kfree(ioreq);
+	}
+
+	scm->stats.n_free_ioreq = 0;
+
+	return -ENOMEM;
+}
+
+/**
+ * csio_scsim_exit: Uninitialize SCSI Module
+ * @scm: SCSI Module
+ *
+ */
+void
+csio_scsim_exit(struct csio_scsim *scm)
+{
+	struct csio_ioreq *ioreq;
+	struct csio_dma_buf *dma_buf;
+
+	while (!list_empty(&scm->ioreq_freelist)) {
+		struct csio_sm *tmp;
+
+		tmp = list_first_entry(&scm->ioreq_freelist,
+				       struct csio_sm, sm_list);
+		list_del_init(&tmp->sm_list);
+		ioreq = (struct csio_ioreq *)tmp;
+
+		dma_buf = &ioreq->dma_buf;
+		pci_pool_free(scm->hw->scsi_pci_pool, dma_buf->vaddr,
+			      dma_buf->paddr);
+
+		kfree(ioreq);
+	}
+
+	scm->stats.n_free_ioreq = 0;
+
+	csio_scsi_free_ddp_bufs(scm, scm->hw);
+}
-- 
1.7.1


^ permalink raw reply related

* [V3 PATCH 4/9] csiostor: Chelsio FCoE offload driver submission (sources part 4).
From: Naresh Kumar Inna @ 2012-09-11 14:39 UTC (permalink / raw)
  To: JBottomley, linux-scsi, dm, leedom; +Cc: netdev, naresh, chethan
In-Reply-To: <1347374347-3852-1-git-send-email-naresh@chelsio.com>

This patch contains code to implement the local and remote node port
functionality. It includes tracking the firmware events for changes to
the states of these ports.

Signed-off-by: Naresh Kumar Inna <naresh@chelsio.com>
---
 drivers/scsi/csiostor/csio_lnode.c | 2148 ++++++++++++++++++++++++++++++++++++
 drivers/scsi/csiostor/csio_rnode.c |  889 +++++++++++++++
 2 files changed, 3037 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/csiostor/csio_lnode.c
 create mode 100644 drivers/scsi/csiostor/csio_rnode.c

diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c
new file mode 100644
index 0000000..24f38a2
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_lnode.c
@@ -0,0 +1,2148 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/utsname.h>
+#include <scsi/scsi_transport_fc.h>
+#include <asm/unaligned.h>
+#include <scsi/fc/fc_els.h>
+#include <scsi/fc/fc_fs.h>
+#include <scsi/fc/fc_gs.h>
+#include <scsi/fc/fc_ms.h>
+
+#include "csio_hw.h"
+#include "csio_mb.h"
+#include "csio_lnode.h"
+#include "csio_rnode.h"
+
+int csio_fcoe_rnodes = 512;
+int csio_fdmi_enable = 1;
+
+#define PORT_ID_PTR(_x)         ((uint8_t *)(&_x) + 1)
+
+/* Lnode SM declarations */
+static void csio_lns_uninit(struct csio_lnode *, enum csio_ln_ev);
+static void csio_lns_online(struct csio_lnode *, enum csio_ln_ev);
+static void csio_lns_ready(struct csio_lnode *, enum csio_ln_ev);
+static void csio_lns_offline(struct csio_lnode *, enum csio_ln_ev);
+
+static int csio_ln_mgmt_submit_req(struct csio_ioreq *,
+		void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *),
+		enum fcoe_cmn_type, struct csio_dma_buf *, uint32_t);
+
+/* LN event mapping */
+static enum csio_ln_ev fwevt_to_lnevt[] = {
+	CSIO_LNE_NONE,		/* None */
+	CSIO_LNE_NONE,		/* PLOGI_ACC_RCVD  */
+	CSIO_LNE_NONE,		/* PLOGI_RJT_RCVD  */
+	CSIO_LNE_NONE,		/* PLOGI_RCVD	   */
+	CSIO_LNE_NONE,		/* PLOGO_RCVD	   */
+	CSIO_LNE_NONE,		/* PRLI_ACC_RCVD   */
+	CSIO_LNE_NONE,		/* PRLI_RJT_RCVD   */
+	CSIO_LNE_NONE,		/* PRLI_RCVD	   */
+	CSIO_LNE_NONE,		/* PRLO_RCVD	   */
+	CSIO_LNE_NONE,		/* NPORT_ID_CHGD   */
+	CSIO_LNE_LOGO,		/* FLOGO_RCVD	   */
+	CSIO_LNE_LOGO,		/* CLR_VIRT_LNK_RCVD */
+	CSIO_LNE_FAB_INIT_DONE,/* FLOGI_ACC_RCVD   */
+	CSIO_LNE_NONE,		/* FLOGI_RJT_RCVD   */
+	CSIO_LNE_FAB_INIT_DONE,/* FDISC_ACC_RCVD   */
+	CSIO_LNE_NONE,		/* FDISC_RJT_RCVD   */
+	CSIO_LNE_NONE,		/* FLOGI_TMO_MAX_RETRY */
+	CSIO_LNE_NONE,		/* IMPL_LOGO_ADISC_ACC */
+	CSIO_LNE_NONE,		/* IMPL_LOGO_ADISC_RJT */
+	CSIO_LNE_NONE,		/* IMPL_LOGO_ADISC_CNFLT */
+	CSIO_LNE_NONE,		/* PRLI_TMO		*/
+	CSIO_LNE_NONE,		/* ADISC_TMO		*/
+	CSIO_LNE_NONE,		/* RSCN_DEV_LOST */
+	CSIO_LNE_NONE,		/* SCR_ACC_RCVD */
+	CSIO_LNE_NONE,		/* ADISC_RJT_RCVD */
+	CSIO_LNE_NONE,		/* LOGO_SNT */
+	CSIO_LNE_NONE,		/* PROTO_ERR_IMPL_LOGO */
+};
+
+#define CSIO_FWE_TO_LNE(_evt)	((_evt > PROTO_ERR_IMPL_LOGO) ?		\
+						CSIO_LNE_NONE :	\
+						fwevt_to_lnevt[_evt])
+
+#define csio_ct_rsp(cp)		(((struct fc_ct_hdr *)cp)->ct_cmd)
+#define csio_ct_reason(cp)	(((struct fc_ct_hdr *)cp)->ct_reason)
+#define csio_ct_expl(cp)	(((struct fc_ct_hdr *)cp)->ct_explan)
+#define csio_ct_get_pld(cp)	((void *)(((uint8_t *)cp) + FC_CT_HDR_LEN))
+
+/*
+ * csio_ln_match_by_portid - lookup lnode using given portid.
+ * @hw: HW module
+ * @portid: port-id.
+ *
+ * If found, returns lnode matching given portid otherwise returns NULL.
+ */
+static struct csio_lnode *
+csio_ln_lookup_by_portid(struct csio_hw *hw, uint8_t portid)
+{
+	struct csio_lnode *ln = hw->rln;
+	struct list_head *tmp;
+
+	/* Match siblings lnode with portid */
+	list_for_each(tmp, &hw->sln_head) {
+		ln = (struct csio_lnode *) tmp;
+		if (ln->portid == portid)
+			return ln;
+	}
+
+	return NULL;
+}
+
+/*
+ * csio_ln_lookup_by_vnpi - Lookup lnode using given vnp id.
+ * @hw - HW module
+ * @vnpi - vnp index.
+ * Returns - If found, returns lnode matching given vnp id
+ * otherwise returns NULL.
+ */
+static struct csio_lnode *
+csio_ln_lookup_by_vnpi(struct csio_hw *hw, uint32_t vnp_id)
+{
+	struct list_head *tmp1, *tmp2;
+	struct csio_lnode *sln = NULL, *cln = NULL;
+
+	if (list_empty(&hw->sln_head)) {
+		CSIO_INC_STATS(hw, n_lnlkup_miss);
+		return NULL;
+	}
+	/* Traverse sibling lnodes */
+	list_for_each(tmp1, &hw->sln_head) {
+		sln = (struct csio_lnode *) tmp1;
+
+		/* Match sibling lnode */
+		if (sln->vnp_flowid == vnp_id)
+			return sln;
+
+		if (list_empty(&sln->cln_head))
+			continue;
+
+		/* Traverse children lnodes */
+		list_for_each(tmp2, &sln->cln_head) {
+			cln = (struct csio_lnode *) tmp2;
+
+			if (cln->vnp_flowid == vnp_id)
+				return cln;
+		}
+	}
+	CSIO_INC_STATS(hw, n_lnlkup_miss);
+	return NULL;
+}
+
+/**
+ * csio_lnode_lookup_by_wwpn - Lookup lnode using given wwpn.
+ * @hw:		HW module.
+ * @wwpn:	WWPN.
+ *
+ * If found, returns lnode matching given wwpn, returns NULL otherwise.
+ */
+struct csio_lnode *
+csio_lnode_lookup_by_wwpn(struct csio_hw *hw, uint8_t *wwpn)
+{
+	struct list_head *tmp1, *tmp2;
+	struct csio_lnode *sln = NULL, *cln = NULL;
+
+	if (list_empty(&hw->sln_head)) {
+		CSIO_INC_STATS(hw, n_lnlkup_miss);
+		return NULL;
+	}
+	/* Traverse sibling lnodes */
+	list_for_each(tmp1, &hw->sln_head) {
+		sln = (struct csio_lnode *) tmp1;
+
+		/* Match sibling lnode */
+		if (!memcmp(csio_ln_wwpn(sln), wwpn, 8))
+			return sln;
+
+		if (list_empty(&sln->cln_head))
+			continue;
+
+		/* Traverse children lnodes */
+		list_for_each(tmp2, &sln->cln_head) {
+			cln = (struct csio_lnode *) tmp2;
+
+			if (!memcmp(csio_ln_wwpn(cln), wwpn, 8))
+				return cln;
+		}
+	}
+	return NULL;
+}
+
+/* FDMI */
+static void
+csio_fill_ct_iu(void *buf, uint8_t type, uint8_t sub_type, uint16_t op)
+{
+	struct fc_ct_hdr *cmd = (struct fc_ct_hdr *)buf;
+	cmd->ct_rev = FC_CT_REV;
+	cmd->ct_fs_type = type;
+	cmd->ct_fs_subtype = sub_type;
+	cmd->ct_cmd = op;
+}
+
+static int
+csio_hostname(uint8_t *buf, size_t buf_len)
+{
+	if (sprintf(buf, "%s", init_utsname()->nodename))
+		return 0;
+	return -1;
+}
+
+static int
+csio_osname(uint8_t *buf, size_t buf_len)
+{
+	uint8_t *ptr = buf;
+
+	strcpy(ptr, init_utsname()->sysname);
+	ptr += strlen(init_utsname()->sysname);
+	*ptr = ' '; /* SPACE */
+	strcpy(ptr, init_utsname()->release);
+	ptr += strlen(init_utsname()->release);
+	*ptr = ' '; /* SPACE */
+	strcpy(ptr, init_utsname()->version);
+	ptr += strlen(init_utsname()->version);
+	*ptr = '\0';
+	return 0;
+}
+
+static inline void
+csio_append_attrib(uint8_t **ptr, uint16_t type, uint8_t *val, uint16_t len)
+{
+	struct fc_fdmi_attr_entry *ae = (struct fc_fdmi_attr_entry *)*ptr;
+	ae->type = htons(type);
+	len += 4;		/* includes attribute type and length */
+	len = (len + 3) & ~3;	/* should be multiple of 4 bytes */
+	ae->len = htons(len);
+	memset(ae->value, 0, len - 4);
+	memcpy(ae->value, val, len);
+	*ptr += len;
+}
+
+/*
+ * csio_ln_fdmi_done - FDMI registeration completion
+ * @hw: HW context
+ * @fdmi_req: fdmi request
+ */
+static void
+csio_ln_fdmi_done(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
+{
+	void *cmd;
+	struct csio_lnode *ln = fdmi_req->lnode;
+
+	if (fdmi_req->wr_status != FW_SUCCESS) {
+		csio_ln_err(ln, "WR error:%x in processing fdmi rpa cmd\n",
+			    fdmi_req->wr_status);
+		CSIO_INC_STATS(ln, n_fdmi_err);
+	}
+
+	cmd = fdmi_req->dma_buf.vaddr;
+	if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) {
+		csio_ln_dbg(ln, "fdmi rpa cmd rejected reason %x expl %x\n",
+			    csio_ct_reason(cmd), csio_ct_expl(cmd));
+	}
+}
+
+/*
+ * csio_ln_fdmi_rhba_cbfn - RHBA completion
+ * @hw: HW context
+ * @fdmi_req: fdmi request
+ */
+static void
+csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
+{
+	void *cmd;
+	uint8_t *pld;
+	uint32_t len = 0;
+	struct csio_lnode *ln = fdmi_req->lnode;
+	struct fs_fdmi_attrs *attrib_blk;
+	struct fc_fdmi_port_name *port_name;
+	uint8_t buf[64];
+	uint32_t val;
+	uint8_t *fc4_type;
+
+	if (fdmi_req->wr_status != FW_SUCCESS) {
+		csio_ln_err(ln, "WR error:%x in processing fdmi rhba cmd\n",
+			    fdmi_req->wr_status);
+		CSIO_INC_STATS(ln, n_fdmi_err);
+	}
+
+	cmd = fdmi_req->dma_buf.vaddr;
+	if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) {
+		csio_ln_dbg(ln, "fdmi rhba cmd rejected reason %x expl %x\n",
+			    csio_ct_reason(cmd), csio_ct_expl(cmd));
+	}
+
+	if (!csio_is_rnode_ready(fdmi_req->rnode)) {
+		CSIO_INC_STATS(ln, n_fdmi_err);
+		return;
+	}
+
+	/* Prepare CT hdr for RPA cmd */
+	memset(cmd, 0, FC_CT_HDR_LEN);
+	csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, htons(FC_FDMI_RPA));
+
+	/* Prepare RPA payload */
+	pld = (uint8_t *)csio_ct_get_pld(cmd);
+	port_name = (struct fc_fdmi_port_name *)pld;
+	memcpy(&port_name->portname, csio_ln_wwpn(ln), 8);
+	pld += sizeof(*port_name);
+
+	/* Start appending Port attributes */
+	attrib_blk = (struct fs_fdmi_attrs *)pld;
+	attrib_blk->numattrs = 0;
+	len += sizeof(attrib_blk->numattrs);
+	pld += sizeof(attrib_blk->numattrs);
+
+	fc4_type = &buf[0];
+	memset(fc4_type, 0, FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
+	fc4_type[2] = 1;
+	fc4_type[7] = 1;
+	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_FC4TYPES,
+			   fc4_type, FC_FDMI_PORT_ATTR_FC4TYPES_LEN);
+	attrib_blk->numattrs++;
+	val = htonl(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
+	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_SUPPORTEDSPEED,
+			   (uint8_t *)&val,
+			   FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN);
+	attrib_blk->numattrs++;
+
+	if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_1G)
+		val = htonl(FC_PORTSPEED_1GBIT);
+	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_10G)
+		val = htonl(FC_PORTSPEED_10GBIT);
+	else
+		val = htonl(CSIO_HBA_PORTSPEED_UNKNOWN);
+	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,
+			   (uint8_t *)&val,
+			   FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN);
+	attrib_blk->numattrs++;
+
+	val = htonl(ln->ln_sparm.csp.sp_bb_data);
+	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_MAXFRAMESIZE,
+			   (uint8_t *)&val, FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN);
+	attrib_blk->numattrs++;
+
+	strcpy(buf, "csiostor");
+	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_OSDEVICENAME, buf,
+			   (uint16_t)strlen(buf));
+	attrib_blk->numattrs++;
+
+	if (!csio_hostname(buf, sizeof(buf))) {
+		csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_HOSTNAME,
+				   buf, (uint16_t)strlen(buf));
+		attrib_blk->numattrs++;
+	}
+	attrib_blk->numattrs = ntohl(attrib_blk->numattrs);
+	len = (uint32_t)(pld - (uint8_t *)cmd);
+
+	/* Submit FDMI RPA request */
+	spin_lock_irq(&hw->lock);
+	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_done,
+				FCOE_CT, &fdmi_req->dma_buf, len)) {
+		CSIO_INC_STATS(ln, n_fdmi_err);
+		csio_ln_err(ln, "Failed to issue fdmi rpa req\n");
+	}
+	spin_unlock_irq(&hw->lock);
+}
+
+/*
+ * csio_ln_fdmi_dprt_cbfn - DPRT completion
+ * @hw: HW context
+ * @fdmi_req: fdmi request
+ */
+static void
+csio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
+{
+	void *cmd;
+	uint8_t *pld;
+	uint32_t len = 0;
+	uint32_t maxpayload = htonl(65536);
+	struct fc_fdmi_hba_identifier *hbaid;
+	struct csio_lnode *ln = fdmi_req->lnode;
+	struct fc_fdmi_rpl *reg_pl;
+	struct fs_fdmi_attrs *attrib_blk;
+	uint8_t buf[64];
+
+	if (fdmi_req->wr_status != FW_SUCCESS) {
+		csio_ln_err(ln, "WR error:%x in processing fdmi dprt cmd\n",
+			    fdmi_req->wr_status);
+		CSIO_INC_STATS(ln, n_fdmi_err);
+	}
+
+	if (!csio_is_rnode_ready(fdmi_req->rnode)) {
+		CSIO_INC_STATS(ln, n_fdmi_err);
+		return;
+	}
+	cmd = fdmi_req->dma_buf.vaddr;
+	if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) {
+		csio_ln_dbg(ln, "fdmi dprt cmd rejected reason %x expl %x\n",
+			    csio_ct_reason(cmd), csio_ct_expl(cmd));
+	}
+
+	/* Prepare CT hdr for RHBA cmd */
+	memset(cmd, 0, FC_CT_HDR_LEN);
+	csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, htons(FC_FDMI_RHBA));
+	len = FC_CT_HDR_LEN;
+
+	/* Prepare RHBA payload */
+	pld = (uint8_t *)csio_ct_get_pld(cmd);
+	hbaid = (struct fc_fdmi_hba_identifier *)pld;
+	memcpy(&hbaid->id, csio_ln_wwpn(ln), 8); /* HBA identifer */
+	pld += sizeof(*hbaid);
+
+	/* Register one port per hba */
+	reg_pl = (struct fc_fdmi_rpl *)pld;
+	reg_pl->numport = ntohl(1);
+	memcpy(&reg_pl->port[0].portname, csio_ln_wwpn(ln), 8);
+	pld += sizeof(*reg_pl);
+
+	/* Start appending HBA attributes hba */
+	attrib_blk = (struct fs_fdmi_attrs *)pld;
+	attrib_blk->numattrs = 0;
+	len += sizeof(attrib_blk->numattrs);
+	pld += sizeof(attrib_blk->numattrs);
+
+	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_NODENAME, csio_ln_wwnn(ln),
+			   FC_FDMI_HBA_ATTR_NODENAME_LEN);
+	attrib_blk->numattrs++;
+
+	memset(buf, 0, sizeof(buf));
+
+	strcpy(buf, "Chelsio Communications");
+	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MANUFACTURER, buf,
+			   (uint16_t)strlen(buf));
+	attrib_blk->numattrs++;
+	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_SERIALNUMBER,
+			   hw->vpd.sn, (uint16_t)sizeof(hw->vpd.sn));
+	attrib_blk->numattrs++;
+	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODEL, hw->vpd.id,
+			   (uint16_t)sizeof(hw->vpd.id));
+	attrib_blk->numattrs++;
+	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODELDESCRIPTION,
+			   hw->model_desc, (uint16_t)strlen(hw->model_desc));
+	attrib_blk->numattrs++;
+	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_HARDWAREVERSION,
+			   hw->hw_ver, (uint16_t)sizeof(hw->hw_ver));
+	attrib_blk->numattrs++;
+	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_FIRMWAREVERSION,
+			   hw->fwrev_str, (uint16_t)strlen(hw->fwrev_str));
+	attrib_blk->numattrs++;
+
+	if (!csio_osname(buf, sizeof(buf))) {
+		csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_OSNAMEVERSION,
+				   buf, (uint16_t)strlen(buf));
+		attrib_blk->numattrs++;
+	}
+
+	csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MAXCTPAYLOAD,
+			   (uint8_t *)&maxpayload,
+			   FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN);
+	len = (uint32_t)(pld - (uint8_t *)cmd);
+	attrib_blk->numattrs++;
+	attrib_blk->numattrs = ntohl(attrib_blk->numattrs);
+
+	/* Submit FDMI RHBA request */
+	spin_lock_irq(&hw->lock);
+	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_rhba_cbfn,
+				FCOE_CT, &fdmi_req->dma_buf, len)) {
+		CSIO_INC_STATS(ln, n_fdmi_err);
+		csio_ln_err(ln, "Failed to issue fdmi rhba req\n");
+	}
+	spin_unlock_irq(&hw->lock);
+}
+
+/*
+ * csio_ln_fdmi_dhba_cbfn - DHBA completion
+ * @hw: HW context
+ * @fdmi_req: fdmi request
+ */
+static void
+csio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
+{
+	struct csio_lnode *ln = fdmi_req->lnode;
+	void *cmd;
+	struct fc_fdmi_port_name *port_name;
+	uint32_t len;
+
+	if (fdmi_req->wr_status != FW_SUCCESS) {
+		csio_ln_err(ln, "WR error:%x in processing fdmi dhba cmd\n",
+			    fdmi_req->wr_status);
+		CSIO_INC_STATS(ln, n_fdmi_err);
+	}
+
+	if (!csio_is_rnode_ready(fdmi_req->rnode)) {
+		CSIO_INC_STATS(ln, n_fdmi_err);
+		return;
+	}
+	cmd = fdmi_req->dma_buf.vaddr;
+	if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) {
+		csio_ln_dbg(ln, "fdmi dhba cmd rejected reason %x expl %x\n",
+			    csio_ct_reason(cmd), csio_ct_expl(cmd));
+	}
+
+	/* Send FDMI cmd to de-register any Port attributes if registered
+	 * before
+	 */
+
+	/* Prepare FDMI DPRT cmd */
+	memset(cmd, 0, FC_CT_HDR_LEN);
+	csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, htons(FC_FDMI_DPRT));
+	len = FC_CT_HDR_LEN;
+	port_name = (struct fc_fdmi_port_name *)csio_ct_get_pld(cmd);
+	memcpy(&port_name->portname, csio_ln_wwpn(ln), 8);
+	len += sizeof(*port_name);
+
+	/* Submit FDMI request */
+	spin_lock_irq(&hw->lock);
+	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dprt_cbfn,
+				FCOE_CT, &fdmi_req->dma_buf, len)) {
+		CSIO_INC_STATS(ln, n_fdmi_err);
+		csio_ln_err(ln, "Failed to issue fdmi dprt req\n");
+	}
+	spin_unlock_irq(&hw->lock);
+}
+
+/**
+ * csio_ln_fdmi_start - Start an FDMI request.
+ * @ln:		lnode
+ * @context:	session context
+ *
+ * Issued with lock held.
+ */
+int
+csio_ln_fdmi_start(struct csio_lnode *ln, void *context)
+{
+	struct csio_ioreq *fdmi_req;
+	struct csio_rnode *fdmi_rn = (struct csio_rnode *)context;
+	void *cmd;
+	struct fc_fdmi_hba_identifier *hbaid;
+	uint32_t len;
+
+	if (!(ln->flags & CSIO_LNF_FDMI_ENABLE))
+		return -EPROTONOSUPPORT;
+
+	if (!csio_is_rnode_ready(fdmi_rn))
+		CSIO_INC_STATS(ln, n_fdmi_err);
+
+	/* Send FDMI cmd to de-register any HBA attributes if registered
+	 * before
+	 */
+
+	fdmi_req = ln->mgmt_req;
+	fdmi_req->lnode = ln;
+	fdmi_req->rnode = fdmi_rn;
+
+	/* Prepare FDMI DHBA cmd */
+	cmd = fdmi_req->dma_buf.vaddr;
+	memset(cmd, 0, FC_CT_HDR_LEN);
+	csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, htons(FC_FDMI_DHBA));
+	len = FC_CT_HDR_LEN;
+
+	hbaid = (struct fc_fdmi_hba_identifier *)csio_ct_get_pld(cmd);
+	memcpy(&hbaid->id, csio_ln_wwpn(ln), 8);
+	len += sizeof(*hbaid);
+
+	/* Submit FDMI request */
+	if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dhba_cbfn,
+					FCOE_CT, &fdmi_req->dma_buf, len)) {
+		CSIO_INC_STATS(ln, n_fdmi_err);
+		csio_ln_err(ln, "Failed to issue fdmi dhba req\n");
+	}
+
+	return 0;
+}
+
+/*
+ * csio_ln_vnp_read_cbfn - vnp read completion handler.
+ * @hw: HW lnode
+ * @cbfn: Completion handler.
+ *
+ * Reads vnp response and updates ln parameters.
+ */
+static void
+csio_ln_vnp_read_cbfn(struct csio_hw *hw, struct csio_mb *mbp)
+{
+	struct csio_lnode *ln = ((struct csio_lnode *)mbp->priv);
+	struct fw_fcoe_vnp_cmd *rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
+	struct fc_els_csp *csp;
+	struct fc_els_cssp *clsp;
+	enum fw_retval retval;
+
+	spin_lock_irq(&hw->lock);
+
+	retval = FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16));
+	if (retval != FW_SUCCESS) {
+		csio_err(hw, "FCOE VNP read cmd returned error:0x%x\n", retval);
+		spin_unlock_irq(&hw->lock);
+		mempool_free(mbp, hw->mb_mempool);
+		return;
+	}
+
+	memcpy(ln->mac, rsp->vnport_mac, sizeof(ln->mac));
+	memcpy(&ln->nport_id, &rsp->vnport_mac[3],
+			sizeof(uint8_t)*3);
+	ln->nport_id = ntohl(ln->nport_id);
+	ln->nport_id = ln->nport_id>>8;
+
+	/* Update WWNs */
+	/*
+	 * This may look like a duplication of what csio_fcoe_enable_link()
+	 * does, but is absolutely necessary if the vnpi changes between
+	 * a FCOE LINK UP and FCOE LINK DOWN.
+	 */
+	memcpy(csio_ln_wwnn(ln), rsp->vnport_wwnn, 8);
+	memcpy(csio_ln_wwpn(ln), rsp->vnport_wwpn, 8);
+
+	/* Copy common sparam */
+	csp = (struct fc_els_csp *)rsp->cmn_srv_parms;
+	ln->ln_sparm.csp.sp_hi_ver = csp->sp_hi_ver;
+	ln->ln_sparm.csp.sp_lo_ver = csp->sp_lo_ver;
+	ln->ln_sparm.csp.sp_bb_cred = ntohs(csp->sp_bb_cred);
+	ln->ln_sparm.csp.sp_features = ntohs(csp->sp_features);
+	ln->ln_sparm.csp.sp_bb_data = ntohs(csp->sp_bb_data);
+	ln->ln_sparm.csp.sp_r_a_tov = ntohl(csp->sp_r_a_tov);
+	ln->ln_sparm.csp.sp_e_d_tov = ntohl(csp->sp_e_d_tov);
+
+	/* Copy word 0 & word 1 of class sparam */
+	clsp = (struct fc_els_cssp *)rsp->clsp_word_0_1;
+	ln->ln_sparm.clsp[2].cp_class = ntohs(clsp->cp_class);
+	ln->ln_sparm.clsp[2].cp_init = ntohs(clsp->cp_init);
+	ln->ln_sparm.clsp[2].cp_recip = ntohs(clsp->cp_recip);
+	ln->ln_sparm.clsp[2].cp_rdfs = ntohs(clsp->cp_rdfs);
+
+	spin_unlock_irq(&hw->lock);
+
+	mempool_free(mbp, hw->mb_mempool);
+
+	/* Send an event to update local attribs */
+	csio_lnode_async_event(ln, CSIO_LN_FC_ATTRIB_UPDATE);
+}
+
+/*
+ * csio_ln_vnp_read - Read vnp params.
+ * @ln: lnode
+ * @cbfn: Completion handler.
+ *
+ * Issued with lock held.
+ */
+static int
+csio_ln_vnp_read(struct csio_lnode *ln,
+		void (*cbfn) (struct csio_hw *, struct csio_mb *))
+{
+	struct csio_hw *hw = ln->hwp;
+	struct csio_mb  *mbp;
+
+	/* Allocate Mbox request */
+	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+	if (!mbp) {
+		CSIO_INC_STATS(hw, n_err_nomem);
+		return -ENOMEM;
+	}
+
+	/* Prepare VNP Command */
+	csio_fcoe_vnp_read_init_mb(ln, mbp,
+				    CSIO_MB_DEFAULT_TMO,
+				    ln->fcf_flowid,
+				    ln->vnp_flowid,
+				    cbfn);
+
+	/* Issue MBOX cmd */
+	if (csio_mb_issue(hw, mbp)) {
+		csio_err(hw, "Failed to issue mbox FCoE VNP command\n");
+		mempool_free(mbp, hw->mb_mempool);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * csio_fcoe_enable_link - Enable fcoe link.
+ * @ln: lnode
+ * @enable: enable/disable
+ * Issued with lock held.
+ * Issues mbox cmd to bring up FCOE link on port associated with given ln.
+ */
+static int
+csio_fcoe_enable_link(struct csio_lnode *ln, bool enable)
+{
+	struct csio_hw *hw = ln->hwp;
+	struct csio_mb  *mbp;
+	enum fw_retval retval;
+	uint8_t portid;
+	uint8_t sub_op;
+	struct fw_fcoe_link_cmd *lcmd;
+	int i;
+
+	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+	if (!mbp) {
+		CSIO_INC_STATS(hw, n_err_nomem);
+		return -ENOMEM;
+	}
+
+	portid = ln->portid;
+	sub_op = enable ? FCOE_LINK_UP : FCOE_LINK_DOWN;
+
+	csio_dbg(hw, "bringing FCOE LINK %s on Port:%d\n",
+		 sub_op ? "UP" : "DOWN", portid);
+
+	csio_write_fcoe_link_cond_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
+					  portid, sub_op, 0, 0, 0, NULL);
+
+	if (csio_mb_issue(hw, mbp)) {
+		csio_err(hw, "failed to issue FCOE LINK cmd on port[%d]\n",
+			portid);
+		mempool_free(mbp, hw->mb_mempool);
+		return -EINVAL;
+	}
+
+	retval = csio_mb_fw_retval(mbp);
+	if (retval != FW_SUCCESS) {
+		csio_err(hw,
+			 "FCOE LINK %s cmd on port[%d] failed with "
+			 "ret:x%x\n", sub_op ? "UP" : "DOWN", portid, retval);
+		mempool_free(mbp, hw->mb_mempool);
+		return -EINVAL;
+	}
+
+	if (!enable)
+		goto out;
+
+	lcmd = (struct fw_fcoe_link_cmd *)mbp->mb;
+
+	memcpy(csio_ln_wwnn(ln), lcmd->vnport_wwnn, 8);
+	memcpy(csio_ln_wwpn(ln), lcmd->vnport_wwpn, 8);
+
+	for (i = 0; i < CSIO_MAX_PPORTS; i++)
+		if (hw->pport[i].portid == portid)
+			memcpy(hw->pport[i].mac, lcmd->phy_mac, 6);
+
+out:
+	mempool_free(mbp, hw->mb_mempool);
+	return 0;
+}
+
+/*
+ * csio_ln_read_fcf_cbfn - Read fcf parameters
+ * @ln: lnode
+ *
+ * read fcf response and Update ln fcf information.
+ */
+static void
+csio_ln_read_fcf_cbfn(struct csio_hw *hw, struct csio_mb *mbp)
+{
+	struct csio_lnode *ln = (struct csio_lnode *)mbp->priv;
+	struct csio_fcf_info	*fcf_info;
+	struct fw_fcoe_fcf_cmd *rsp =
+				(struct fw_fcoe_fcf_cmd *)(mbp->mb);
+	enum fw_retval retval;
+
+	spin_lock_irq(&hw->lock);
+
+	retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
+	if (retval != FW_SUCCESS) {
+		csio_ln_err(ln, "FCOE FCF cmd failed with ret x%x\n",
+				retval);
+		mempool_free(mbp, hw->mb_mempool);
+		spin_unlock_irq(&hw->lock);
+		return;
+	}
+
+	fcf_info = ln->fcfinfo;
+	fcf_info->priority = FW_FCOE_FCF_CMD_PRIORITY_GET(
+					ntohs(rsp->priority_pkd));
+	fcf_info->vf_id = ntohs(rsp->vf_id);
+	fcf_info->vlan_id = rsp->vlan_id;
+	fcf_info->max_fcoe_size = ntohs(rsp->max_fcoe_size);
+	fcf_info->fka_adv = be32_to_cpu(rsp->fka_adv);
+	fcf_info->fcfi = FW_FCOE_FCF_CMD_FCFI_GET(ntohl(rsp->op_to_fcfi));
+	fcf_info->fpma = FW_FCOE_FCF_CMD_FPMA_GET(rsp->fpma_to_portid);
+	fcf_info->spma = FW_FCOE_FCF_CMD_SPMA_GET(rsp->fpma_to_portid);
+	fcf_info->login = FW_FCOE_FCF_CMD_LOGIN_GET(rsp->fpma_to_portid);
+	fcf_info->portid = FW_FCOE_FCF_CMD_PORTID_GET(rsp->fpma_to_portid);
+	memcpy(fcf_info->fc_map, rsp->fc_map, sizeof(fcf_info->fc_map));
+	memcpy(fcf_info->mac, rsp->mac, sizeof(fcf_info->mac));
+	memcpy(fcf_info->name_id, rsp->name_id, sizeof(fcf_info->name_id));
+	memcpy(fcf_info->fabric, rsp->fabric, sizeof(fcf_info->fabric));
+	memcpy(fcf_info->spma_mac, rsp->spma_mac, sizeof(fcf_info->spma_mac));
+
+	spin_unlock_irq(&hw->lock);
+	mempool_free(mbp, hw->mb_mempool);
+
+}
+
+/*
+ * csio_ln_read_fcf_entry - Read fcf entry.
+ * @ln: lnode
+ * @cbfn: Completion handler.
+ *
+ * Issued with lock held.
+ */
+static int
+csio_ln_read_fcf_entry(struct csio_lnode *ln,
+			void (*cbfn) (struct csio_hw *, struct csio_mb *))
+{
+	struct csio_hw *hw = ln->hwp;
+	struct csio_mb  *mbp;
+
+	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+	if (!mbp) {
+		CSIO_INC_STATS(hw, n_err_nomem);
+		return -ENOMEM;
+	}
+
+	/* Get FCoE FCF information */
+	csio_fcoe_read_fcf_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
+				      ln->portid, ln->fcf_flowid, cbfn);
+
+	if (csio_mb_issue(hw, mbp)) {
+		csio_err(hw, "failed to issue FCOE FCF cmd\n");
+		mempool_free(mbp, hw->mb_mempool);
+		return -EINVAL;
+	}
+
+	if (cbfn == NULL) {
+		spin_unlock_irq(&hw->lock);
+		csio_ln_read_fcf_cbfn(hw, mbp);
+		spin_lock_irq(&hw->lock);
+	}
+
+	return 0;
+}
+
+/*
+ * csio_handle_link_up - Logical Linkup event.
+ * @hw - HW module.
+ * @portid - Physical port number
+ * @fcfi - FCF index.
+ * @vnpi - VNP index.
+ * Returns - none.
+ *
+ * This event is received from FW, when virtual link is established between
+ * Physical port[ENode] and FCF. If its new vnpi, then local node object is
+ * created on this FCF and set to [ONLINE] state.
+ * Lnode waits for FW_RDEV_CMD event to be received indicating that
+ * Fabric login is completed and lnode moves to [READY] state.
+ *
+ * This called with hw lock held
+ */
+static void
+csio_handle_link_up(struct csio_hw *hw, uint8_t portid, uint32_t fcfi,
+		    uint32_t vnpi)
+{
+	struct csio_lnode *ln = NULL;
+
+	/* Lookup lnode based on vnpi */
+	ln = csio_ln_lookup_by_vnpi(hw, vnpi);
+	if (!ln) {
+		/* Pick lnode based on portid */
+		ln = csio_ln_lookup_by_portid(hw, portid);
+		if (!ln) {
+			csio_err(hw, "failed to lookup fcoe lnode on port:%d\n",
+				portid);
+			CSIO_DB_ASSERT(0);
+			return;
+		}
+
+		/* Check if lnode has valid vnp flowid */
+		if (ln->vnp_flowid != CSIO_INVALID_IDX) {
+			/* New VN-Port */
+			spin_unlock_irq(&hw->lock);
+			csio_lnode_alloc(hw);
+			spin_lock_irq(&hw->lock);
+			if (!ln) {
+				csio_err(hw,
+					 "failed to allocate fcoe lnode"
+					 "for port:%d vnpi:x%x\n",
+					 portid, vnpi);
+				CSIO_DB_ASSERT(0);
+				return;
+			}
+			ln->portid = portid;
+		}
+		ln->vnp_flowid = vnpi;
+		ln->dev_num &= ~0xFFFF;
+		ln->dev_num |= vnpi;
+	}
+
+	/*Initialize fcfi */
+	ln->fcf_flowid = fcfi;
+
+	csio_info(hw, "Port:%d - FCOE LINK UP\n", portid);
+
+	CSIO_INC_STATS(ln, n_link_up);
+
+	/* Send LINKUP event to SM */
+	csio_post_event(&ln->sm, CSIO_LNE_LINKUP);
+}
+
+/*
+ * csio_post_event_rns
+ * @ln - FCOE lnode
+ * @evt - Given rnode event
+ * Returns - none
+ *
+ * Posts given rnode event to all FCOE rnodes connected with given Lnode.
+ * This routine is invoked when lnode receives LINK_DOWN/DOWN_LINK/CLOSE
+ * event.
+ *
+ * This called with hw lock held
+ */
+static void
+csio_post_event_rns(struct csio_lnode *ln, enum csio_rn_ev evt)
+{
+	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
+	struct list_head *tmp, *next;
+	struct csio_rnode *rn;
+
+	list_for_each_safe(tmp, next, &rnhead->sm.sm_list) {
+		rn = (struct csio_rnode *) tmp;
+		csio_post_event(&rn->sm, evt);
+	}
+}
+
+/*
+ * csio_cleanup_rns
+ * @ln - FCOE lnode
+ * Returns - none
+ *
+ * Frees all FCOE rnodes connected with given Lnode.
+ *
+ * This called with hw lock held
+ */
+static void
+csio_cleanup_rns(struct csio_lnode *ln)
+{
+	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
+	struct list_head *tmp, *next_rn;
+	struct csio_rnode *rn;
+
+	list_for_each_safe(tmp, next_rn, &rnhead->sm.sm_list) {
+		rn = (struct csio_rnode *) tmp;
+		csio_put_rnode(ln, rn);
+	}
+
+}
+
+/*
+ * csio_post_event_lns
+ * @ln - FCOE lnode
+ * @evt - Given lnode event
+ * Returns - none
+ *
+ * Posts given lnode event to all FCOE lnodes connected with given Lnode.
+ * This routine is invoked when lnode receives LINK_DOWN/DOWN_LINK/CLOSE
+ * event.
+ *
+ * This called with hw lock held
+ */
+static void
+csio_post_event_lns(struct csio_lnode *ln, enum csio_ln_ev evt)
+{
+	struct list_head *tmp;
+	struct csio_lnode *cln, *sln;
+
+	/* If NPIV lnode, send evt only to that and return */
+	if (csio_is_npiv_ln(ln)) {
+		csio_post_event(&ln->sm, evt);
+		return;
+	}
+
+	sln = ln;
+	/* Traverse children lnodes list and send evt */
+	list_for_each(tmp, &sln->cln_head) {
+		cln = (struct csio_lnode *) tmp;
+		csio_post_event(&cln->sm, evt);
+	}
+
+	/* Send evt to parent lnode */
+	csio_post_event(&ln->sm, evt);
+}
+
+/*
+ * csio_ln_down - Lcoal nport is down
+ * @ln - FCOE Lnode
+ * Returns - none
+ *
+ * Sends LINK_DOWN events to Lnode and its associated NPIVs lnodes.
+ *
+ * This called with hw lock held
+ */
+static void
+csio_ln_down(struct csio_lnode *ln)
+{
+	csio_post_event_lns(ln, CSIO_LNE_LINK_DOWN);
+}
+
+/*
+ * csio_handle_link_down - Logical Linkdown event.
+ * @hw - HW module.
+ * @portid - Physical port number
+ * @fcfi - FCF index.
+ * @vnpi - VNP index.
+ * Returns - none
+ *
+ * This event is received from FW, when virtual link goes down between
+ * Physical port[ENode] and FCF. Lnode and its associated NPIVs lnode hosted on
+ * this vnpi[VN-Port] will be de-instantiated.
+ *
+ * This called with hw lock held
+ */
+static void
+csio_handle_link_down(struct csio_hw *hw, uint8_t portid, uint32_t fcfi,
+		      uint32_t vnpi)
+{
+	struct csio_fcf_info *fp;
+	struct csio_lnode *ln;
+
+	/* Lookup lnode based on vnpi */
+	ln = csio_ln_lookup_by_vnpi(hw, vnpi);
+	if (ln) {
+		fp = ln->fcfinfo;
+		CSIO_INC_STATS(ln, n_link_down);
+
+		/*Warn if linkdown received if lnode is not in ready state */
+		if (!csio_is_lnode_ready(ln)) {
+			csio_ln_warn(ln,
+				"warn: FCOE link is already in offline "
+				"Ignoring Fcoe linkdown event on portid %d\n",
+				 portid);
+			CSIO_INC_STATS(ln, n_evt_drop);
+			return;
+		}
+
+		/* Verify portid */
+		if (fp->portid != portid) {
+			csio_ln_warn(ln,
+				"warn: FCOE linkdown recv with "
+				"invalid port %d\n", portid);
+			CSIO_INC_STATS(ln, n_evt_drop);
+			return;
+		}
+
+		/* verify fcfi */
+		if (ln->fcf_flowid != fcfi) {
+			csio_ln_warn(ln,
+				"warn: FCOE linkdown recv with "
+				"invalid fcfi x%x\n", fcfi);
+			CSIO_INC_STATS(ln, n_evt_drop);
+			return;
+		}
+
+		csio_info(hw, "Port:%d - FCOE LINK DOWN\n", portid);
+
+		/* Send LINK_DOWN event to lnode s/m */
+		csio_ln_down(ln);
+
+		return;
+	} else {
+		csio_warn(hw,
+			  "warn: FCOE linkdown recv with invalid vnpi x%x\n",
+			  vnpi);
+		CSIO_INC_STATS(hw, n_evt_drop);
+	}
+}
+
+/*
+ * csio_is_lnode_ready - Checks FCOE lnode is in ready state.
+ * @ln: Lnode module
+ *
+ * Returns True if FCOE lnode is in ready state.
+ */
+int
+csio_is_lnode_ready(struct csio_lnode *ln)
+{
+	return (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready));
+}
+
+/*****************************************************************************/
+/* START: Lnode SM                                                           */
+/*****************************************************************************/
+/*
+ * csio_lns_uninit - The request in uninit state.
+ * @ln - FCOE lnode.
+ * @evt - Event to be processed.
+ *
+ * Process the given lnode event which is currently in "uninit" state.
+ * Invoked with HW lock held.
+ * Return - none.
+ */
+static void
+csio_lns_uninit(struct csio_lnode *ln, enum csio_ln_ev evt)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+	struct csio_lnode *rln = hw->rln;
+	int rv;
+
+	CSIO_INC_STATS(ln, n_evt_sm[evt]);
+	switch (evt) {
+	case CSIO_LNE_LINKUP:
+		csio_set_state(&ln->sm, csio_lns_online);
+		/* Read FCF only for physical lnode */
+		if (csio_is_phys_ln(ln)) {
+			rv = csio_ln_read_fcf_entry(ln,
+					csio_ln_read_fcf_cbfn);
+			if (rv != 0) {
+				/* TODO: Send HW RESET event */
+				CSIO_INC_STATS(ln, n_err);
+				break;
+			}
+
+			/* Add FCF record */
+			list_add_tail(&ln->fcfinfo->list, &rln->fcf_lsthead);
+		}
+
+		rv = csio_ln_vnp_read(ln, csio_ln_vnp_read_cbfn);
+		if (rv != 0) {
+			/* TODO: Send HW RESET event */
+			CSIO_INC_STATS(ln, n_err);
+		}
+		break;
+
+	case CSIO_LNE_DOWN_LINK:
+		break;
+
+	default:
+		csio_ln_dbg(ln,
+			    "unexp ln event %d recv from did:x%x in "
+			    "ln state[uninit].\n", evt, ln->nport_id);
+		CSIO_INC_STATS(ln, n_evt_unexp);
+		break;
+	} /* switch event */
+}
+
+/*
+ * csio_lns_online - The request in online state.
+ * @ln - FCOE lnode.
+ * @evt - Event to be processed.
+ *
+ * Process the given lnode event which is currently in "online" state.
+ * Invoked with HW lock held.
+ * Return - none.
+ */
+static void
+csio_lns_online(struct csio_lnode *ln, enum csio_ln_ev evt)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+	CSIO_INC_STATS(ln, n_evt_sm[evt]);
+	switch (evt) {
+	case CSIO_LNE_LINKUP:
+		csio_ln_warn(ln,
+			     "warn: FCOE link is up already "
+			     "Ignoring linkup on port:%d\n", ln->portid);
+		CSIO_INC_STATS(ln, n_evt_drop);
+		break;
+
+	case CSIO_LNE_FAB_INIT_DONE:
+		csio_set_state(&ln->sm, csio_lns_ready);
+
+		spin_unlock_irq(&hw->lock);
+		csio_lnode_async_event(ln, CSIO_LN_FC_LINKUP);
+		spin_lock_irq(&hw->lock);
+
+		break;
+
+	case CSIO_LNE_LINK_DOWN:
+		/* Fall through */
+	case CSIO_LNE_DOWN_LINK:
+		csio_set_state(&ln->sm, csio_lns_uninit);
+		if (csio_is_phys_ln(ln)) {
+			/* Remove FCF entry */
+			list_del_init(&ln->fcfinfo->list);
+		}
+		break;
+
+	default:
+		csio_ln_dbg(ln,
+			    "unexp ln event %d recv from did:x%x in "
+			    "ln state[uninit].\n", evt, ln->nport_id);
+		CSIO_INC_STATS(ln, n_evt_unexp);
+
+		break;
+	} /* switch event */
+}
+
+/*
+ * csio_lns_ready - The request in ready state.
+ * @ln - FCOE lnode.
+ * @evt - Event to be processed.
+ *
+ * Process the given lnode event which is currently in "ready" state.
+ * Invoked with HW lock held.
+ * Return - none.
+ */
+static void
+csio_lns_ready(struct csio_lnode *ln, enum csio_ln_ev evt)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+	CSIO_INC_STATS(ln, n_evt_sm[evt]);
+	switch (evt) {
+	case CSIO_LNE_FAB_INIT_DONE:
+		csio_ln_err(ln,
+			    "ignoring event %d recv from did x%x"
+			    "in ln state[ready].\n", evt, ln->nport_id);
+		CSIO_INC_STATS(ln, n_evt_drop);
+		break;
+
+	case CSIO_LNE_LINK_DOWN:
+		csio_set_state(&ln->sm, csio_lns_offline);
+		csio_post_event_rns(ln, CSIO_RNFE_DOWN);
+
+		spin_unlock_irq(&hw->lock);
+		csio_lnode_async_event(ln, CSIO_LN_FC_LINKDOWN);
+		spin_lock_irq(&hw->lock);
+
+		if (csio_is_phys_ln(ln)) {
+			/* Remove FCF entry */
+			list_del_init(&ln->fcfinfo->list);
+		}
+		break;
+
+	case CSIO_LNE_DOWN_LINK:
+		csio_set_state(&ln->sm, csio_lns_offline);
+		csio_post_event_rns(ln, CSIO_RNFE_DOWN);
+
+		/* Host need to issue aborts in case if FW has not returned
+		 * WRs with status "ABORTED"
+		 */
+		spin_unlock_irq(&hw->lock);
+		csio_lnode_async_event(ln, CSIO_LN_FC_LINKDOWN);
+		spin_lock_irq(&hw->lock);
+
+		if (csio_is_phys_ln(ln)) {
+			/* Remove FCF entry */
+			list_del_init(&ln->fcfinfo->list);
+		}
+		break;
+
+	case CSIO_LNE_CLOSE:
+		csio_set_state(&ln->sm, csio_lns_uninit);
+		csio_post_event_rns(ln, CSIO_RNFE_CLOSE);
+		break;
+
+	case CSIO_LNE_LOGO:
+		csio_set_state(&ln->sm, csio_lns_offline);
+		csio_post_event_rns(ln, CSIO_RNFE_DOWN);
+		break;
+
+	default:
+		csio_ln_dbg(ln,
+			    "unexp ln event %d recv from did:x%x in "
+			    "ln state[uninit].\n", evt, ln->nport_id);
+		CSIO_INC_STATS(ln, n_evt_unexp);
+		CSIO_DB_ASSERT(0);
+		break;
+	} /* switch event */
+}
+
+/*
+ * csio_lns_offline - The request in offline state.
+ * @ln - FCOE lnode.
+ * @evt - Event to be processed.
+ *
+ * Process the given lnode event which is currently in "offline" state.
+ * Invoked with HW lock held.
+ * Return - none.
+ */
+static void
+csio_lns_offline(struct csio_lnode *ln, enum csio_ln_ev evt)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+	struct csio_lnode *rln = hw->rln;
+	int rv;
+
+	CSIO_INC_STATS(ln, n_evt_sm[evt]);
+	switch (evt) {
+	case CSIO_LNE_LINKUP:
+		csio_set_state(&ln->sm, csio_lns_online);
+		/* Read FCF only for physical lnode */
+		if (csio_is_phys_ln(ln)) {
+			rv = csio_ln_read_fcf_entry(ln,
+					csio_ln_read_fcf_cbfn);
+			if (rv != 0) {
+				/* TODO: Send HW RESET event */
+				CSIO_INC_STATS(ln, n_err);
+				break;
+			}
+
+			/* Add FCF record */
+			list_add_tail(&ln->fcfinfo->list, &rln->fcf_lsthead);
+		}
+
+		rv = csio_ln_vnp_read(ln, csio_ln_vnp_read_cbfn);
+		if (rv != 0) {
+			/* TODO: Send HW RESET event */
+			CSIO_INC_STATS(ln, n_err);
+		}
+		break;
+
+	case CSIO_LNE_LINK_DOWN:
+	case CSIO_LNE_DOWN_LINK:
+	case CSIO_LNE_LOGO:
+		csio_ln_err(ln,
+			    "ignoring event %d recv from did x%x"
+			    "in ln state[offline].\n", evt, ln->nport_id);
+		CSIO_INC_STATS(ln, n_evt_drop);
+		break;
+
+	case CSIO_LNE_CLOSE:
+		csio_set_state(&ln->sm, csio_lns_uninit);
+		csio_post_event_rns(ln, CSIO_RNFE_CLOSE);
+		break;
+
+	default:
+		csio_ln_dbg(ln,
+			    "unexp ln event %d recv from did:x%x in "
+			    "ln state[offline]\n", evt, ln->nport_id);
+		CSIO_INC_STATS(ln, n_evt_unexp);
+		CSIO_DB_ASSERT(0);
+		break;
+	} /* switch event */
+}
+
+/*****************************************************************************/
+/* END: Lnode SM                                                             */
+/*****************************************************************************/
+
+static void
+csio_free_fcfinfo(struct kref *kref)
+{
+	struct csio_fcf_info *fcfinfo = container_of(kref,
+						struct csio_fcf_info, kref);
+	kfree(fcfinfo);
+}
+
+/* Helper routines for attributes  */
+/*
+ * csio_lnode_state_to_str - Get current state of FCOE lnode.
+ * @ln - lnode
+ * @str - state of lnode.
+ *
+ */
+void
+csio_lnode_state_to_str(struct csio_lnode *ln, int8_t *str)
+{
+	if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_uninit)) {
+		strcpy(str, "UNINIT");
+		return;
+	}
+	if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)) {
+		strcpy(str, "READY");
+		return;
+	}
+	if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_offline)) {
+		strcpy(str, "OFFLINE");
+		return;
+	}
+	strcpy(str, "UNKNOWN");
+} /* csio_lnode_state_to_str */
+
+
+int
+csio_get_phy_port_stats(struct csio_hw *hw, uint8_t portid,
+			struct fw_fcoe_port_stats *port_stats)
+{
+	struct csio_mb  *mbp;
+	struct fw_fcoe_port_cmd_params portparams;
+	enum fw_retval retval;
+	int idx;
+
+	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+	if (!mbp) {
+		csio_err(hw, "FCoE FCF PARAMS command out of memory!\n");
+		return -EINVAL;
+	}
+	portparams.portid = portid;
+
+	for (idx = 1; idx <= 3; idx++) {
+		portparams.idx = (idx-1)*6 + 1;
+		portparams.nstats = 6;
+		if (idx == 3)
+			portparams.nstats = 4;
+		csio_fcoe_read_portparams_init_mb(hw, mbp, CSIO_MB_DEFAULT_TMO,
+							&portparams, NULL);
+		if (csio_mb_issue(hw, mbp)) {
+			csio_err(hw, "Issue of FCoE port params failed!\n");
+			mempool_free(mbp, hw->mb_mempool);
+			return -EINVAL;
+		}
+		csio_mb_process_portparams_rsp(hw, mbp, &retval,
+						&portparams, port_stats);
+	}
+
+	mempool_free(mbp, hw->mb_mempool);
+	return 0;
+}
+
+/*
+ * csio_ln_mgmt_wr_handler -Mgmt Work Request handler.
+ * @wr - WR.
+ * @len - WR len.
+ * This handler is invoked when an outstanding mgmt WR is completed.
+ * Its invoked in the context of FW event worker thread for every
+ * mgmt event received.
+ * Return - none.
+ */
+
+static void
+csio_ln_mgmt_wr_handler(struct csio_hw *hw, void *wr, uint32_t len)
+{
+	struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw);
+	struct csio_ioreq *io_req = NULL;
+	struct fw_fcoe_els_ct_wr *wr_cmd;
+
+
+	wr_cmd = (struct fw_fcoe_els_ct_wr *) wr;
+
+	if (len < sizeof(struct fw_fcoe_els_ct_wr)) {
+		csio_err(mgmtm->hw,
+			 "Invalid ELS CT WR length recvd, len:%x\n", len);
+		mgmtm->stats.n_err++;
+		return;
+	}
+
+	io_req = (struct csio_ioreq *) ((uintptr_t) wr_cmd->cookie);
+	io_req->wr_status = csio_wr_status(wr_cmd);
+
+	/* lookup ioreq exists in our active Q */
+	spin_lock_irq(&hw->lock);
+	if (csio_mgmt_req_lookup(mgmtm, io_req) != 0) {
+		csio_err(mgmtm->hw,
+			"Error- Invalid IO handle recv in WR. handle: %p\n",
+			io_req);
+		mgmtm->stats.n_err++;
+		spin_unlock_irq(&hw->lock);
+		return;
+	}
+
+	mgmtm = csio_hw_to_mgmtm(hw);
+
+	/* Dequeue from active queue */
+	list_del_init(&io_req->sm.sm_list);
+	mgmtm->stats.n_active--;
+	spin_unlock_irq(&hw->lock);
+
+	/* io_req will be freed by completion handler */
+	if (io_req->io_cbfn)
+		io_req->io_cbfn(hw, io_req);
+}
+
+/**
+ * csio_fcoe_fwevt_handler - Event handler for Firmware FCoE events.
+ * @hw:		HW module
+ * @cpl_op:	CPL opcode
+ * @cmd:	FW cmd/WR.
+ *
+ * Process received FCoE cmd/WR event from FW.
+ */
+void
+csio_fcoe_fwevt_handler(struct csio_hw *hw, __u8 cpl_op, __be64 *cmd)
+{
+	struct csio_lnode *ln;
+	struct csio_rnode *rn;
+	uint8_t portid, opcode = *(uint8_t *)cmd;
+	struct fw_fcoe_link_cmd *lcmd;
+	struct fw_wr_hdr *wr;
+	struct fw_rdev_wr *rdev_wr;
+	enum fw_fcoe_link_status lstatus;
+	uint32_t fcfi, rdev_flowid, vnpi;
+	enum csio_ln_ev evt;
+
+	if (cpl_op == CPL_FW6_MSG && opcode == FW_FCOE_LINK_CMD) {
+
+		lcmd = (struct fw_fcoe_link_cmd *)cmd;
+		lstatus = lcmd->lstatus;
+		portid = FW_FCOE_LINK_CMD_PORTID_GET(
+					ntohl(lcmd->op_to_portid));
+		fcfi = FW_FCOE_LINK_CMD_FCFI_GET(ntohl(lcmd->sub_opcode_fcfi));
+		vnpi = FW_FCOE_LINK_CMD_VNPI_GET(ntohl(lcmd->vnpi_pkd));
+
+		if (lstatus == FCOE_LINKUP) {
+
+			/* HW lock here */
+			spin_lock_irq(&hw->lock);
+			csio_handle_link_up(hw, portid, fcfi, vnpi);
+			spin_unlock_irq(&hw->lock);
+			/* HW un lock here */
+
+		} else if (lstatus == FCOE_LINKDOWN) {
+
+			/* HW lock here */
+			spin_lock_irq(&hw->lock);
+			csio_handle_link_down(hw, portid, fcfi, vnpi);
+			spin_unlock_irq(&hw->lock);
+			/* HW un lock here */
+		} else {
+			csio_warn(hw, "Unexpected FCOE LINK status:0x%x\n",
+				    ntohl(lcmd->lstatus));
+			CSIO_INC_STATS(hw, n_cpl_unexp);
+		}
+	} else if (cpl_op == CPL_FW6_PLD) {
+		wr = (struct fw_wr_hdr *) (cmd + 4);
+		if (FW_WR_OP_GET(be32_to_cpu(wr->hi))
+			== FW_RDEV_WR) {
+
+			rdev_wr = (struct fw_rdev_wr *) (cmd + 4);
+
+			rdev_flowid = FW_RDEV_WR_FLOWID_GET(
+					ntohl(rdev_wr->alloc_to_len16));
+			vnpi = FW_RDEV_WR_ASSOC_FLOWID_GET(
+				    ntohl(rdev_wr->flags_to_assoc_flowid));
+
+			csio_dbg(hw,
+				"FW_RDEV_WR: flowid:x%x ev_cause:x%x "
+				"vnpi:0x%x\n", rdev_flowid,
+				rdev_wr->event_cause, vnpi);
+
+			if (rdev_wr->protocol != PROT_FCOE) {
+				csio_err(hw,
+					"FW_RDEV_WR: invalid proto:x%x "
+					"received with flowid:x%x\n",
+					rdev_wr->protocol,
+					rdev_flowid);
+				CSIO_INC_STATS(hw, n_evt_drop);
+				return;
+			}
+
+			/* HW lock here */
+			spin_lock_irq(&hw->lock);
+			ln = csio_ln_lookup_by_vnpi(hw, vnpi);
+			if (!ln) {
+				csio_err(hw,
+					"FW_DEV_WR: invalid vnpi:x%x received "
+					"with flowid:x%x\n", vnpi, rdev_flowid);
+				CSIO_INC_STATS(hw, n_evt_drop);
+				spin_unlock_irq(&hw->lock);
+				return;
+			}
+
+			rn = csio_confirm_rnode(ln, rdev_flowid,
+					&rdev_wr->u.fcoe_rdev);
+			if (!rn) {
+				csio_ln_dbg(ln,
+					"Failed to confirm rnode "
+					"for flowid:x%x\n", rdev_flowid);
+				CSIO_INC_STATS(hw, n_evt_drop);
+				spin_unlock_irq(&hw->lock);
+				return;
+			}
+
+			/* save previous event for debugging */
+			ln->prev_evt = ln->cur_evt;
+			ln->cur_evt = rdev_wr->event_cause;
+			CSIO_INC_STATS(ln, n_evt_fw[rdev_wr->event_cause]);
+
+			/* Translate all the fabric events to lnode SM events */
+			evt = CSIO_FWE_TO_LNE(rdev_wr->event_cause);
+			if (evt) {
+				csio_ln_dbg(ln,
+					"Posting event to lnode event:%d "
+					"cause:%d flowid:x%x\n", evt,
+					rdev_wr->event_cause, rdev_flowid);
+				csio_post_event(&ln->sm, evt);
+			}
+
+			/* Handover event to rn SM here. */
+			csio_rnode_fwevt_handler(rn, rdev_wr->event_cause);
+
+			spin_unlock_irq(&hw->lock);
+		} else {
+			csio_warn(hw, "unexpected WR op(0x%x) recv\n",
+				FW_WR_OP_GET(be32_to_cpu((wr->hi))));
+			CSIO_INC_STATS(hw, n_cpl_unexp);
+		}
+	} else if (cpl_op == CPL_FW6_MSG) {
+		wr = (struct fw_wr_hdr *) (cmd);
+		if (FW_WR_OP_GET(be32_to_cpu(wr->hi)) == FW_FCOE_ELS_CT_WR) {
+			csio_ln_mgmt_wr_handler(hw, wr,
+					sizeof(struct fw_fcoe_els_ct_wr));
+		} else {
+			csio_warn(hw, "unexpected WR op(0x%x) recv\n",
+				FW_WR_OP_GET(be32_to_cpu((wr->hi))));
+			CSIO_INC_STATS(hw, n_cpl_unexp);
+		}
+	} else {
+		csio_warn(hw, "unexpected CPL op(0x%x) recv\n", opcode);
+		CSIO_INC_STATS(hw, n_cpl_unexp);
+	}
+}
+
+/**
+ * csio_lnode_start - Kickstart lnode discovery.
+ * @ln:		lnode
+ *
+ * This routine kickstarts the discovery by issuing an FCOE_LINK (up) command.
+ */
+int
+csio_lnode_start(struct csio_lnode *ln)
+{
+	int rv = 0;
+	if (csio_is_phys_ln(ln) && !(ln->flags & CSIO_LNF_LINK_ENABLE)) {
+		rv = csio_fcoe_enable_link(ln, 1);
+		ln->flags |= CSIO_LNF_LINK_ENABLE;
+	}
+
+	return rv;
+}
+
+/**
+ * csio_lnode_stop - Stop the lnode.
+ * @ln:		lnode
+ *
+ * This routine is invoked by HW module to stop lnode and its associated NPIV
+ * lnodes.
+ */
+void
+csio_lnode_stop(struct csio_lnode *ln)
+{
+	csio_post_event_lns(ln, CSIO_LNE_DOWN_LINK);
+	if (csio_is_phys_ln(ln) && (ln->flags & CSIO_LNF_LINK_ENABLE)) {
+		csio_fcoe_enable_link(ln, 0);
+		ln->flags &= ~CSIO_LNF_LINK_ENABLE;
+	}
+	csio_ln_dbg(ln, "stopping ln :%p\n", ln);
+}
+
+/**
+ * csio_lnode_close - Close an lnode.
+ * @ln:		lnode
+ *
+ * This routine is invoked by HW module to close an lnode and its
+ * associated NPIV lnodes. Lnode and its associated NPIV lnodes are
+ * set to uninitialized state.
+ */
+void
+csio_lnode_close(struct csio_lnode *ln)
+{
+	csio_post_event_lns(ln, CSIO_LNE_CLOSE);
+	if (csio_is_phys_ln(ln))
+		ln->vnp_flowid = CSIO_INVALID_IDX;
+
+	csio_ln_dbg(ln, "closed ln :%p\n", ln);
+}
+
+/*
+ * csio_ln_prep_ecwr - Prepare ELS/CT WR.
+ * @io_req - IO request.
+ * @wr_len - WR len
+ * @immd_len - WR immediate data
+ * @sub_op - Sub opcode
+ * @sid - source portid.
+ * @did - destination portid
+ * @flow_id - flowid
+ * @fw_wr - ELS/CT WR to be prepared.
+ * Returns: 0 - on success
+ */
+static int
+csio_ln_prep_ecwr(struct csio_ioreq *io_req, uint32_t wr_len,
+		      uint32_t immd_len, uint8_t sub_op, uint32_t sid,
+		      uint32_t did, uint32_t flow_id, uint8_t *fw_wr)
+{
+	struct fw_fcoe_els_ct_wr *wr;
+	uint32_t port_id;
+
+	wr  = (struct fw_fcoe_els_ct_wr *)fw_wr;
+	wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_FCOE_ELS_CT_WR) |
+				     FW_FCOE_ELS_CT_WR_IMMDLEN(immd_len));
+
+	wr_len =  DIV_ROUND_UP(wr_len, 16);
+	wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(flow_id) |
+					  FW_WR_LEN16(wr_len));
+	wr->els_ct_type = sub_op;
+	wr->ctl_pri = 0;
+	wr->cp_en_class = 0;
+	wr->cookie = io_req->fw_handle;
+	wr->iqid = (uint16_t)cpu_to_be16(csio_q_physiqid(
+			io_req->lnode->hwp, io_req->iq_idx));
+	wr->fl_to_sp =  FW_FCOE_ELS_CT_WR_SP(1);
+	wr->tmo_val = (uint8_t) io_req->tmo;
+	port_id = htonl(sid);
+	memcpy(wr->l_id, PORT_ID_PTR(port_id), 3);
+	port_id = htonl(did);
+	memcpy(wr->r_id, PORT_ID_PTR(port_id), 3);
+
+	/* Prepare RSP SGL */
+	wr->rsp_dmalen = cpu_to_be32(io_req->dma_buf.len);
+	wr->rsp_dmaaddr = cpu_to_be64(io_req->dma_buf.paddr);
+	return 0;
+}
+
+/*
+ * csio_ln_mgmt_submit_wr - Post elsct work request.
+ * @mgmtm - mgmtm
+ * @io_req - io request.
+ * @sub_op - ELS or CT request type
+ * @pld - Dma Payload buffer
+ * @pld_len - Payload len
+ * Prepares ELSCT Work request and sents it to FW.
+ * Returns: 0 - on success
+ */
+static int
+csio_ln_mgmt_submit_wr(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req,
+		uint8_t sub_op, struct csio_dma_buf *pld,
+		uint32_t pld_len)
+{
+	struct csio_wr_pair wrp;
+	struct csio_lnode *ln = io_req->lnode;
+	struct csio_rnode *rn = io_req->rnode;
+	struct	csio_hw	*hw = mgmtm->hw;
+	uint8_t fw_wr[64];
+	struct ulptx_sgl dsgl;
+	uint32_t wr_size = 0;
+	uint8_t im_len = 0;
+	uint32_t wr_off = 0;
+
+	int ret = 0;
+
+	/* Calculate WR Size for this ELS REQ */
+	wr_size = sizeof(struct fw_fcoe_els_ct_wr);
+
+	/* Send as immediate data if pld < 256 */
+	if (pld_len < 256) {
+		wr_size += ALIGN(pld_len, 8);
+		im_len = (uint8_t)pld_len;
+	} else
+		wr_size += sizeof(struct ulptx_sgl);
+
+	/* Roundup WR size in units of 16 bytes */
+	wr_size = ALIGN(wr_size, 16);
+
+	/* Get WR to send ELS REQ */
+	ret = csio_wr_get(hw, mgmtm->eq_idx, wr_size, &wrp);
+	if (ret != 0) {
+		csio_err(hw, "Failed to get WR for ec_req %p ret:%d\n",
+			io_req, ret);
+		return ret;
+	}
+
+	/* Prepare Generic WR used by all ELS/CT cmd */
+	csio_ln_prep_ecwr(io_req, wr_size, im_len, sub_op,
+				ln->nport_id, rn->nport_id,
+				csio_rn_flowid(rn),
+				&fw_wr[0]);
+
+	/* Copy ELS/CT WR CMD */
+	csio_wr_copy_to_wrp(&fw_wr[0], &wrp, wr_off,
+			sizeof(struct fw_fcoe_els_ct_wr));
+	wr_off += sizeof(struct fw_fcoe_els_ct_wr);
+
+	/* Copy payload to Immediate section of WR */
+	if (im_len)
+		csio_wr_copy_to_wrp(pld->vaddr, &wrp, wr_off, im_len);
+	else {
+		/* Program DSGL to dma payload */
+		dsgl.cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) |
+					ULPTX_MORE | ULPTX_NSGE(1));
+		dsgl.len0 = cpu_to_be32(pld_len);
+		dsgl.addr0 = cpu_to_be64(pld->paddr);
+		csio_wr_copy_to_wrp(&dsgl, &wrp, ALIGN(wr_off, 8),
+				   sizeof(struct ulptx_sgl));
+	}
+
+	/* Issue work request to xmit ELS/CT req to FW */
+	csio_wr_issue(mgmtm->hw, mgmtm->eq_idx, false);
+	return ret;
+}
+
+/*
+ * csio_ln_mgmt_submit_req - Submit FCOE Mgmt request.
+ * @io_req - IO Request
+ * @io_cbfn - Completion handler.
+ * @req_type - ELS or CT request type
+ * @pld - Dma Payload buffer
+ * @pld_len - Payload len
+ *
+ *
+ * This API used submit managment ELS/CT request.
+ * This called with hw lock held
+ * Returns: 0 - on success
+ *	    -ENOMEM	- on error.
+ */
+static int
+csio_ln_mgmt_submit_req(struct csio_ioreq *io_req,
+		void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *),
+		enum fcoe_cmn_type req_type, struct csio_dma_buf *pld,
+		uint32_t pld_len)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(io_req->lnode);
+	struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw);
+	int rv;
+
+	io_req->io_cbfn = io_cbfn;	/* Upper layer callback handler */
+	io_req->fw_handle = (uintptr_t) (io_req);
+	io_req->eq_idx = mgmtm->eq_idx;
+	io_req->iq_idx = mgmtm->iq_idx;
+
+	rv = csio_ln_mgmt_submit_wr(mgmtm, io_req, req_type, pld, pld_len);
+	if (rv == 0) {
+		list_add_tail(&io_req->sm.sm_list, &mgmtm->active_q);
+		mgmtm->stats.n_active++;
+	}
+	return rv;
+}
+
+/*
+ * csio_ln_fdmi_init - FDMI Init entry point.
+ * @ln: lnode
+ */
+static int
+csio_ln_fdmi_init(struct csio_lnode *ln)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+	struct csio_dma_buf	*dma_buf;
+
+	/* Allocate MGMT request required for FDMI */
+	ln->mgmt_req = kzalloc(sizeof(struct csio_ioreq), GFP_KERNEL);
+	if (!ln->mgmt_req) {
+		csio_ln_err(ln, "Failed to alloc ioreq for FDMI\n");
+		CSIO_INC_STATS(hw, n_err_nomem);
+		return -ENOMEM;
+	}
+
+	/* Allocate Dma buffers for FDMI response Payload */
+	dma_buf = &ln->mgmt_req->dma_buf;
+	dma_buf->len = 2048;
+	dma_buf->vaddr = pci_alloc_consistent(hw->pdev, dma_buf->len,
+						&dma_buf->paddr);
+	if (!dma_buf->vaddr) {
+		csio_err(hw, "Failed to alloc DMA buffer for FDMI!\n");
+		kfree(ln->mgmt_req);
+		ln->mgmt_req = NULL;
+		return -ENOMEM;
+	}
+
+	ln->flags |= CSIO_LNF_FDMI_ENABLE;
+	return 0;
+}
+
+/*
+ * csio_ln_fdmi_exit - FDMI exit entry point.
+ * @ln: lnode
+ */
+static int
+csio_ln_fdmi_exit(struct csio_lnode *ln)
+{
+	struct csio_dma_buf *dma_buf;
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+	if (!ln->mgmt_req)
+		return 0;
+
+	dma_buf = &ln->mgmt_req->dma_buf;
+	if (dma_buf->vaddr)
+		pci_free_consistent(hw->pdev, dma_buf->len, dma_buf->vaddr,
+				    dma_buf->paddr);
+
+	kfree(ln->mgmt_req);
+	return 0;
+}
+
+int
+csio_scan_done(struct csio_lnode *ln, unsigned long ticks,
+		unsigned long time, unsigned long max_scan_ticks,
+		unsigned long delta_scan_ticks)
+{
+	int rv = 0;
+
+	if (time >= max_scan_ticks)
+		return 1;
+
+	if (!ln->tgt_scan_tick)
+		ln->tgt_scan_tick = ticks;
+
+	if (((ticks - ln->tgt_scan_tick) >= delta_scan_ticks)) {
+		if (!ln->last_scan_ntgts)
+			ln->last_scan_ntgts = ln->n_scsi_tgts;
+		else {
+			if (ln->last_scan_ntgts == ln->n_scsi_tgts)
+				return 1;
+
+			ln->last_scan_ntgts = ln->n_scsi_tgts;
+		}
+		ln->tgt_scan_tick = ticks;
+	}
+	return rv;
+}
+
+/*
+ * csio_notify_lnodes:
+ * @hw: HW module
+ * @note: Notification
+ *
+ * Called from the HW SM to fan out notifications to the
+ * Lnode SM. Since the HW SM is entered with lock held,
+ * there is no need to hold locks here.
+ *
+ */
+void
+csio_notify_lnodes(struct csio_hw *hw, enum csio_ln_notify note)
+{
+	struct list_head *tmp;
+	struct csio_lnode *ln;
+
+	csio_dbg(hw, "Notifying all nodes of event %d\n", note);
+
+	/* Traverse children lnodes list and send evt */
+	list_for_each(tmp, &hw->sln_head) {
+		ln = (struct csio_lnode *) tmp;
+
+		switch (note) {
+		case CSIO_LN_NOTIFY_HWREADY:
+			csio_lnode_start(ln);
+			break;
+
+		case CSIO_LN_NOTIFY_HWRESET:
+		case CSIO_LN_NOTIFY_HWREMOVE:
+			csio_lnode_close(ln);
+			break;
+
+		case CSIO_LN_NOTIFY_HWSTOP:
+			csio_lnode_stop(ln);
+			break;
+
+		default:
+			break;
+
+		}
+	}
+}
+
+/*
+ * csio_disable_lnodes:
+ * @hw: HW module
+ * @portid:port id
+ * @disable: disable/enable flag.
+ * If disable=1, disables all lnode hosted on given physical port.
+ * otherwise enables all the lnodes on given phsysical port.
+ * This routine need to called with hw lock held.
+ */
+void
+csio_disable_lnodes(struct csio_hw *hw, uint8_t portid, bool disable)
+{
+	struct list_head *tmp;
+	struct csio_lnode *ln;
+
+	csio_dbg(hw, "Notifying event to all nodes of port:%d\n", portid);
+
+	/* Traverse sibling lnodes list and send evt */
+	list_for_each(tmp, &hw->sln_head) {
+		ln = (struct csio_lnode *) tmp;
+		if (ln->portid != portid)
+			continue;
+
+		if (disable)
+			csio_lnode_stop(ln);
+		else
+			csio_lnode_start(ln);
+	}
+}
+
+/*
+ * csio_ln_init - Initialize an lnode.
+ * @ln:		lnode
+ *
+ */
+static int
+csio_ln_init(struct csio_lnode *ln)
+{
+	int rv = -EINVAL;
+	struct csio_lnode *rln, *pln;
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+	csio_init_state(&ln->sm, csio_lns_uninit);
+	ln->vnp_flowid = CSIO_INVALID_IDX;
+	ln->fcf_flowid = CSIO_INVALID_IDX;
+
+	if (csio_is_root_ln(ln)) {
+
+		/* This is the lnode used during initialization */
+
+		ln->fcfinfo = kzalloc(sizeof(struct csio_fcf_info), GFP_KERNEL);
+		if (!ln->fcfinfo) {
+			csio_ln_err(ln, "Failed to alloc FCF record\n");
+			CSIO_INC_STATS(hw, n_err_nomem);
+			goto err;
+		}
+
+		INIT_LIST_HEAD(&ln->fcf_lsthead);
+		kref_init(&ln->fcfinfo->kref);
+
+		if (csio_fdmi_enable && csio_ln_fdmi_init(ln))
+			goto err;
+
+	} else { /* Either a non-root physical or a virtual lnode */
+
+		/*
+		 * THe rest is common for non-root physical and NPIV lnodes.
+		 * Just get references to all other modules
+		 */
+		rln = csio_root_lnode(ln);
+
+		if (csio_is_npiv_ln(ln)) {
+			/* NPIV */
+			pln = csio_parent_lnode(ln);
+			kref_get(&pln->fcfinfo->kref);
+			ln->fcfinfo = pln->fcfinfo;
+		} else {
+			/* Another non-root physical lnode (FCF) */
+			ln->fcfinfo = kzalloc(sizeof(struct csio_fcf_info),
+								GFP_KERNEL);
+			if (!ln->fcfinfo) {
+				csio_ln_err(ln,
+					"Failed to alloc FCF info\n");
+				CSIO_INC_STATS(hw, n_err_nomem);
+				goto err;
+			}
+
+			kref_init(&ln->fcfinfo->kref);
+
+			if (csio_fdmi_enable && csio_ln_fdmi_init(ln))
+				goto err;
+		}
+
+	} /* if (!csio_is_root_ln(ln)) */
+
+	return 0;
+err:
+	return rv;
+}
+
+static void
+csio_ln_exit(struct csio_lnode *ln)
+{
+	struct csio_lnode *pln;
+
+	csio_cleanup_rns(ln);
+	if (csio_is_npiv_ln(ln)) {
+		pln = csio_parent_lnode(ln);
+		kref_put(&pln->fcfinfo->kref, csio_free_fcfinfo);
+	} else {
+		kref_put(&ln->fcfinfo->kref, csio_free_fcfinfo);
+		if (csio_fdmi_enable)
+			csio_ln_fdmi_exit(ln);
+	}
+	ln->fcfinfo = NULL;
+}
+
+/**
+ * csio_lnode_init - Initialize the members of an lnode.
+ * @ln:		lnode
+ *
+ */
+int
+csio_lnode_init(struct csio_lnode *ln, struct csio_hw *hw,
+		struct csio_lnode *pln)
+{
+	int rv = -EINVAL;
+
+	/* Link this lnode to hw */
+	csio_lnode_to_hw(ln)	= hw;
+
+	/* Link child to parent if child lnode */
+	if (pln)
+		ln->pln = pln;
+	else
+		ln->pln = NULL;
+
+	/* Initialize scsi_tgt and timers to zero */
+	ln->n_scsi_tgts = 0;
+	ln->last_scan_ntgts = 0;
+	ln->tgt_scan_tick = 0;
+
+	/* Initialize rnode list */
+	INIT_LIST_HEAD(&ln->rnhead);
+	INIT_LIST_HEAD(&ln->cln_head);
+
+	/* Initialize log level for debug */
+	ln->params.log_level	= hw->params.log_level;
+
+	if (csio_ln_init(ln))
+		goto err;
+
+	/* Add lnode to list of sibling or children lnodes */
+	spin_lock_irq(&hw->lock);
+	list_add_tail(&ln->sm.sm_list, pln ? &pln->cln_head : &hw->sln_head);
+	if (pln)
+		pln->num_vports++;
+	spin_unlock_irq(&hw->lock);
+
+	hw->num_lns++;
+
+	return 0;
+err:
+	csio_lnode_to_hw(ln) = NULL;
+	return rv;
+}
+
+/**
+ * csio_lnode_exit - De-instantiate an lnode.
+ * @ln:		lnode
+ *
+ */
+void
+csio_lnode_exit(struct csio_lnode *ln)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+	csio_ln_exit(ln);
+
+	/* Remove this lnode from hw->sln_head */
+	spin_lock_irq(&hw->lock);
+
+	list_del_init(&ln->sm.sm_list);
+
+	/* If it is children lnode, decrement the
+	 * counter in its parent lnode
+	 */
+	if (ln->pln)
+		ln->pln->num_vports--;
+
+	/* Update root lnode pointer */
+	if (list_empty(&hw->sln_head))
+		hw->rln = NULL;
+	else
+		hw->rln = (struct csio_lnode *)csio_list_next(&hw->sln_head);
+
+	spin_unlock_irq(&hw->lock);
+
+	csio_lnode_to_hw(ln)	= NULL;
+	hw->num_lns--;
+}
diff --git a/drivers/scsi/csiostor/csio_rnode.c b/drivers/scsi/csiostor/csio_rnode.c
new file mode 100644
index 0000000..5e224a0
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_rnode.c
@@ -0,0 +1,889 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/string.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/fc/fc_els.h>
+#include <scsi/fc/fc_fs.h>
+
+#include "csio_hw.h"
+#include "csio_lnode.h"
+#include "csio_rnode.h"
+
+static int csio_rnode_init(struct csio_rnode *, struct csio_lnode *);
+static void csio_rnode_exit(struct csio_rnode *);
+
+/* Static machine forward declarations */
+static void csio_rns_uninit(struct csio_rnode *, enum csio_rn_ev);
+static void csio_rns_ready(struct csio_rnode *, enum csio_rn_ev);
+static void csio_rns_offline(struct csio_rnode *, enum csio_rn_ev);
+static void csio_rns_disappeared(struct csio_rnode *, enum csio_rn_ev);
+
+/* RNF event mapping */
+static enum csio_rn_ev fwevt_to_rnevt[] = {
+	CSIO_RNFE_NONE,		/* None */
+	CSIO_RNFE_LOGGED_IN,	/* PLOGI_ACC_RCVD  */
+	CSIO_RNFE_NONE,		/* PLOGI_RJT_RCVD  */
+	CSIO_RNFE_PLOGI_RECV,	/* PLOGI_RCVD	   */
+	CSIO_RNFE_LOGO_RECV,	/* PLOGO_RCVD	   */
+	CSIO_RNFE_PRLI_DONE,	/* PRLI_ACC_RCVD   */
+	CSIO_RNFE_NONE,		/* PRLI_RJT_RCVD   */
+	CSIO_RNFE_PRLI_RECV,	/* PRLI_RCVD	   */
+	CSIO_RNFE_PRLO_RECV,	/* PRLO_RCVD	   */
+	CSIO_RNFE_NONE,		/* NPORT_ID_CHGD   */
+	CSIO_RNFE_LOGO_RECV,	/* FLOGO_RCVD	   */
+	CSIO_RNFE_NONE,		/* CLR_VIRT_LNK_RCVD */
+	CSIO_RNFE_LOGGED_IN,	/* FLOGI_ACC_RCVD   */
+	CSIO_RNFE_NONE,		/* FLOGI_RJT_RCVD   */
+	CSIO_RNFE_LOGGED_IN,	/* FDISC_ACC_RCVD   */
+	CSIO_RNFE_NONE,		/* FDISC_RJT_RCVD   */
+	CSIO_RNFE_NONE,		/* FLOGI_TMO_MAX_RETRY */
+	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_ACC */
+	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_RJT */
+	CSIO_RNFE_NONE,		/* IMPL_LOGO_ADISC_CNFLT */
+	CSIO_RNFE_NONE,		/* PRLI_TMO		*/
+	CSIO_RNFE_NONE,		/* ADISC_TMO		*/
+	CSIO_RNFE_NAME_MISSING,	/* RSCN_DEV_LOST  */
+	CSIO_RNFE_NONE,		/* SCR_ACC_RCVD	*/
+	CSIO_RNFE_NONE,		/* ADISC_RJT_RCVD */
+	CSIO_RNFE_NONE,		/* LOGO_SNT */
+	CSIO_RNFE_LOGO_RECV,	/* PROTO_ERR_IMPL_LOGO */
+};
+
+#define CSIO_FWE_TO_RNFE(_evt)	((_evt > PROTO_ERR_IMPL_LOGO) ?		\
+						CSIO_RNFE_NONE :	\
+						fwevt_to_rnevt[_evt])
+int
+csio_is_rnode_ready(struct csio_rnode *rn)
+{
+	return csio_match_state(rn, csio_rns_ready);
+}
+
+static int
+csio_is_rnode_uninit(struct csio_rnode *rn)
+{
+	return csio_match_state(rn, csio_rns_uninit);
+}
+
+/*
+ * csio_rn_lookup - Finds the rnode with the given flowid
+ * @ln - lnode
+ * @flowid - flowid.
+ *
+ * Does the rnode lookup on the given lnode and flowid.If no matching entry
+ * found, NULL is returned.
+ */
+static struct csio_rnode *
+csio_rn_lookup(struct csio_lnode *ln, uint32_t flowid)
+{
+	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
+	struct list_head *tmp;
+	struct csio_rnode *rn;
+
+	list_for_each(tmp, &rnhead->sm.sm_list) {
+		rn = (struct csio_rnode *) tmp;
+		if (rn->flowid == flowid)
+			return rn;
+	}
+
+	return NULL;
+}
+
+/*
+ * csio_rn_lookup_wwpn - Finds the rnode with the given wwpn
+ * @ln: lnode
+ * @wwpn: wwpn
+ *
+ * Does the rnode lookup on the given lnode and wwpn. If no matching entry
+ * found, NULL is returned.
+ */
+static struct csio_rnode *
+csio_rn_lookup_wwpn(struct csio_lnode *ln, uint8_t *wwpn)
+{
+	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
+	struct list_head *tmp;
+	struct csio_rnode *rn;
+
+	list_for_each(tmp, &rnhead->sm.sm_list) {
+		rn = (struct csio_rnode *) tmp;
+		if (!memcmp(csio_rn_wwpn(rn), wwpn, 8))
+			return rn;
+	}
+
+	return NULL;
+}
+
+/**
+ * csio_rnode_lookup_portid - Finds the rnode with the given portid
+ * @ln:		lnode
+ * @portid:	port id
+ *
+ * Lookup the rnode list for a given portid. If no matching entry
+ * found, NULL is returned.
+ */
+struct csio_rnode *
+csio_rnode_lookup_portid(struct csio_lnode *ln, uint32_t portid)
+{
+	struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
+	struct list_head *tmp;
+	struct csio_rnode *rn;
+
+	list_for_each(tmp, &rnhead->sm.sm_list) {
+		rn = (struct csio_rnode *) tmp;
+		if (rn->nport_id == portid)
+			return rn;
+	}
+
+	return NULL;
+}
+
+static int
+csio_rn_dup_flowid(struct csio_lnode *ln, uint32_t rdev_flowid,
+		    uint32_t *vnp_flowid)
+{
+	struct csio_rnode *rnhead;
+	struct list_head *tmp, *tmp1;
+	struct csio_rnode *rn;
+	struct csio_lnode *ln_tmp;
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+	list_for_each(tmp1, &hw->sln_head) {
+		ln_tmp = (struct csio_lnode *) tmp1;
+		if (ln_tmp == ln)
+			continue;
+
+		rnhead = (struct csio_rnode *)&ln_tmp->rnhead;
+		list_for_each(tmp, &rnhead->sm.sm_list) {
+
+			rn = (struct csio_rnode *) tmp;
+			if (csio_is_rnode_ready(rn)) {
+				if (rn->flowid == rdev_flowid) {
+					*vnp_flowid = csio_ln_flowid(ln_tmp);
+					return 1;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static struct csio_rnode *
+csio_alloc_rnode(struct csio_lnode *ln)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+	struct csio_rnode *rn = mempool_alloc(hw->rnode_mempool, GFP_ATOMIC);
+	if (!rn)
+		goto err;
+
+	memset(rn, 0, sizeof(struct csio_rnode));
+	if (csio_rnode_init(rn, ln))
+		goto err_free;
+
+	CSIO_INC_STATS(ln, n_rnode_alloc);
+
+	return rn;
+
+err_free:
+	mempool_free(rn, hw->rnode_mempool);
+err:
+	CSIO_INC_STATS(ln, n_rnode_nomem);
+	return NULL;
+}
+
+static void
+csio_free_rnode(struct csio_rnode *rn)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn));
+
+	csio_rnode_exit(rn);
+	CSIO_INC_STATS(rn->lnp, n_rnode_free);
+	mempool_free(rn, hw->rnode_mempool);
+}
+
+/*
+ * csio_get_rnode - Gets rnode with the given flowid
+ * @ln - lnode
+ * @flowid - flow id.
+ *
+ * Does the rnode lookup on the given lnode and flowid. If no matching
+ * rnode found, then new rnode with given npid is allocated and returned.
+ */
+static struct csio_rnode *
+csio_get_rnode(struct csio_lnode *ln, uint32_t flowid)
+{
+	struct csio_rnode *rn;
+
+	rn = csio_rn_lookup(ln, flowid);
+	if (!rn) {
+		rn = csio_alloc_rnode(ln);
+		if (!rn)
+			return NULL;
+
+		rn->flowid = flowid;
+	}
+
+	return rn;
+}
+
+/*
+ * csio_put_rnode - Frees the given rnode
+ * @ln - lnode
+ * @flowid - flow id.
+ *
+ * Does the rnode lookup on the given lnode and flowid. If no matching
+ * rnode found, then new rnode with given npid is allocated and returned.
+ */
+void
+csio_put_rnode(struct csio_lnode *ln, struct csio_rnode *rn)
+{
+	CSIO_DB_ASSERT(csio_is_rnode_uninit(rn) != 0);
+	csio_free_rnode(rn);
+}
+
+/*
+ * csio_confirm_rnode - confirms rnode based on wwpn.
+ * @ln: lnode
+ * @rdev_flowid: remote device flowid
+ * @rdevp: remote device params
+ * This routines searches other rnode in list having same wwpn of new rnode.
+ * If there is a match, then matched rnode is returned and otherwise new rnode
+ * is returned.
+ * returns rnode.
+ */
+struct csio_rnode *
+csio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
+		   struct fcoe_rdev_entry *rdevp)
+{
+	uint8_t rport_type;
+	struct csio_rnode *rn, *match_rn;
+	uint32_t vnp_flowid;
+
+	rport_type =
+		FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
+	/* Drop rdev event for cntrl port */
+	if (rport_type == FAB_CTLR_VNPORT) {
+		csio_ln_dbg(ln,
+			    "Unhandled rport_type:%d recv in rdev evt "
+			    "ssni:x%x\n", rport_type, rdev_flowid);
+		return NULL;
+	}
+
+	/* Lookup on flowid */
+	rn = csio_rn_lookup(ln, rdev_flowid);
+	if (!rn) {
+
+		/* Drop events with duplicate flowid */
+		if (csio_rn_dup_flowid(ln, rdev_flowid, &vnp_flowid)) {
+			csio_ln_warn(ln,
+				     "ssni:%x already active on vnpi:%x",
+				     rdev_flowid, vnp_flowid);
+			return NULL;
+		}
+
+		/* skip wwpn lookup for fabric ports, cntrl port */
+		if (rport_type == FLOGI_VFPORT || rport_type == FDISC_VFPORT
+		    || rport_type == FAB_CTLR_VNPORT) {
+			goto alloc_rnode;
+		}
+
+		/* Lookup on wwpn for NPORTs */
+		rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
+		if (!rn)
+			goto alloc_rnode;
+
+		/* found rn */
+		goto found_rnode;
+	} else {
+		/* verify rnode found for fabric ports, cntrl port */
+		if (rport_type == FLOGI_VFPORT || rport_type == FDISC_VFPORT
+		    || rport_type == FAB_CTLR_VNPORT) {
+
+			/* Rnode role mismatch. Allocate new rnode */
+			if (rn->role == CSIO_RNFR_NS ||
+			    rn->role == CSIO_RNFR_NPORT) {
+				csio_ln_dbg(ln,
+					"rnode role mismatch found ssni:x%x "
+					"role:%d new_type:%d\n",
+					rdev_flowid, rn->role, rport_type);
+				if (csio_is_rnode_ready(rn)) {
+					csio_ln_warn(ln,
+						     "rnode is already"
+						     "active ssni:x%x\n",
+						     rdev_flowid);
+					CSIO_DB_ASSERT(0);
+				}
+				csio_rn_flowid(rn) = CSIO_INVALID_IDX;
+				goto alloc_rnode;
+			} else
+				goto found_rnode;
+		}
+
+		/* wwpn match */
+		if (!memcmp(csio_rn_wwpn(rn), rdevp->wwpn, 8)) {
+			/* Update rn */
+			goto found_rnode;
+		}
+
+		/* Search for rnode that have same wwpn */
+		match_rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
+		if (match_rn != NULL) {
+			csio_ln_dbg(ln,
+				"ssni:x%x changed for rport name(wwpn):%llx "
+				"did:x%x\n", rdev_flowid,
+				wwn_to_u64(rdevp->wwpn),
+				match_rn->nport_id);
+			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
+			rn = match_rn;
+			CSIO_INC_STATS(ln, n_rnode_match);
+		} else {
+			csio_ln_dbg(ln,
+				"rnode wwpn mismatch found ssni:x%x "
+				"name(wwpn):%llx\n",
+				rdev_flowid,
+				wwn_to_u64(csio_rn_wwpn(rn)));
+			if (csio_is_rnode_ready(rn)) {
+				csio_ln_warn(ln,
+					     "rnode is already active "
+					     "wwpn:%llx ssni:x%x\n",
+					     wwn_to_u64(csio_rn_wwpn(rn)),
+					     rdev_flowid);
+				CSIO_DB_ASSERT(0);
+			}
+			csio_rn_flowid(rn) = CSIO_INVALID_IDX;
+			goto alloc_rnode;
+		}
+	}
+
+found_rnode:
+	csio_ln_dbg(ln, "found rnode:%p ssni:x%x name(wwpn):%llx\n",
+		rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
+
+	/* Update flowid */
+	csio_rn_flowid(rn) = rdev_flowid;
+
+	/* update rdev entry */
+	rn->rdev_entry = rdevp;
+	return rn;
+
+alloc_rnode:
+	rn = csio_get_rnode(ln, rdev_flowid);
+	if (!rn)
+		return NULL;
+
+	csio_ln_dbg(ln, "alloc rnode:%p ssni:x%x name(wwpn):%llx\n",
+		rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
+
+	/* update rdev entry */
+	rn->rdev_entry = rdevp;
+	return rn;
+}
+
+/*
+ * csio_rn_verify_rparams - verify rparams.
+ * @ln: lnode
+ * @rn: rnode
+ * @rdevp: remote device params
+ * returns success if rparams are verified.
+ */
+static int
+csio_rn_verify_rparams(struct csio_lnode *ln, struct csio_rnode *rn,
+			struct fcoe_rdev_entry *rdevp)
+{
+	uint8_t null[8];
+	uint8_t rport_type;
+	uint8_t fc_class;
+	uint32_t *did;
+
+	did = (uint32_t *) &rdevp->r_id[0];
+	rport_type =
+		FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
+	switch (rport_type) {
+	case FLOGI_VFPORT:
+		rn->role = CSIO_RNFR_FABRIC;
+		if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_FLOGI) {
+			csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
+				csio_rn_flowid(rn));
+			return -EINVAL;
+		}
+		/* NPIV support */
+		if (FW_RDEV_WR_NPIV_GET(rdevp->vft_to_qos))
+			ln->flags |= CSIO_LNF_NPIVSUPP;
+
+		break;
+
+	case NS_VNPORT:
+		rn->role = CSIO_RNFR_NS;
+		if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_DIR_SERV) {
+			csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
+				csio_rn_flowid(rn));
+			return -EINVAL;
+		}
+		break;
+
+	case REG_FC4_VNPORT:
+	case REG_VNPORT:
+		rn->role = CSIO_RNFR_NPORT;
+		if (rdevp->event_cause == PRLI_ACC_RCVD ||
+			rdevp->event_cause == PRLI_RCVD) {
+			if (FW_RDEV_WR_TASK_RETRY_ID_GET(
+							rdevp->enh_disc_to_tgt))
+				rn->fcp_flags |= FCP_SPPF_OVLY_ALLOW;
+
+			if (FW_RDEV_WR_RETRY_GET(rdevp->enh_disc_to_tgt))
+				rn->fcp_flags |= FCP_SPPF_RETRY;
+
+			if (FW_RDEV_WR_CONF_CMPL_GET(rdevp->enh_disc_to_tgt))
+				rn->fcp_flags |= FCP_SPPF_CONF_COMPL;
+
+			if (FW_RDEV_WR_TGT_GET(rdevp->enh_disc_to_tgt))
+				rn->role |= CSIO_RNFR_TARGET;
+
+			if (FW_RDEV_WR_INI_GET(rdevp->enh_disc_to_tgt))
+				rn->role |= CSIO_RNFR_INITIATOR;
+		}
+
+		break;
+
+	case FDMI_VNPORT:
+	case FAB_CTLR_VNPORT:
+		rn->role = 0;
+		break;
+
+	default:
+		csio_ln_err(ln, "ssni:x%x invalid rport type recv x%x\n",
+			csio_rn_flowid(rn), rport_type);
+		return -EINVAL;
+	}
+
+	/* validate wwpn/wwnn for Name server/remote port */
+	if (rport_type == REG_VNPORT || rport_type == NS_VNPORT) {
+		memset(null, 0, 8);
+		if (!memcmp(rdevp->wwnn, null, 8)) {
+			csio_ln_err(ln,
+				    "ssni:x%x invalid wwnn received from"
+				    " rport did:x%x\n",
+				    csio_rn_flowid(rn),
+				    (ntohl(*did) & CSIO_DID_MASK));
+			return -EINVAL;
+		}
+
+		if (!memcmp(rdevp->wwpn, null, 8)) {
+			csio_ln_err(ln,
+				    "ssni:x%x invalid wwpn received from"
+				    " rport did:x%x\n",
+				    csio_rn_flowid(rn),
+				    (ntohl(*did) & CSIO_DID_MASK));
+			return -EINVAL;
+		}
+
+	}
+
+	/* Copy wwnn, wwpn and nport id */
+	rn->nport_id = (ntohl(*did) >> 8) & CSIO_DID_MASK;
+	memcpy(csio_rn_wwnn(rn), rdevp->wwnn, 8);
+	memcpy(csio_rn_wwpn(rn), rdevp->wwpn, 8);
+	rn->rn_sparm.csp.sp_bb_data = ntohs(rdevp->rcv_fr_sz);
+	fc_class = FW_RDEV_WR_CLASS_GET(rdevp->vft_to_qos);
+	rn->rn_sparm.clsp[fc_class - 1].cp_class = htons(FC_CPC_VALID);
+	return 0;
+}
+
+static void
+__csio_reg_rnode(struct csio_rnode *rn)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn));
+	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
+
+	spin_unlock_irq(&hw->lock);
+	csio_reg_rnode(rn);
+	spin_lock_irq(&hw->lock);
+
+	if (rn->nport_id == FC_FID_MGMT_SERV)
+		csio_ln_fdmi_start(ln, (void *) rn);
+}
+
+static void
+__csio_unreg_rnode(struct csio_rnode *rn)
+{
+	struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn));
+	LIST_HEAD(tmp_q);
+	int cmpl = 0;
+
+	if (!list_empty(&rn->host_cmpl_q)) {
+		csio_dbg(hw, "Returning completion queue I/Os\n");
+		list_splice_tail_init(&rn->host_cmpl_q, &tmp_q);
+		cmpl = 1;
+	}
+
+	spin_unlock_irq(&hw->lock);
+	csio_unreg_rnode(rn);
+	spin_lock_irq(&hw->lock);
+
+	/* Cleanup I/Os that were waiting for rnode to unregister */
+	if (cmpl)
+		csio_scsi_cleanup_io_q(csio_hw_to_scsim(hw), &tmp_q);
+
+}
+
+/*****************************************************************************/
+/* START: Rnode SM                                                           */
+/*****************************************************************************/
+
+/*
+ * csio_rns_uninit -
+ * @rn - rnode
+ * @evt - SM event.
+ *
+ */
+static void
+csio_rns_uninit(struct csio_rnode *rn, enum csio_rn_ev evt)
+{
+	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
+	int ret = 0;
+
+	CSIO_INC_STATS(rn, n_evt_sm[evt]);
+
+	switch (evt) {
+	case CSIO_RNFE_LOGGED_IN:
+	case CSIO_RNFE_PLOGI_RECV:
+		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
+		if (!ret) {
+			csio_set_state(&rn->sm, csio_rns_ready);
+			__csio_reg_rnode(rn);
+		} else {
+			CSIO_INC_STATS(rn, n_err_inval);
+		}
+		break;
+	case CSIO_RNFE_LOGO_RECV:
+		csio_ln_dbg(ln,
+			    "ssni:x%x Ignoring event %d recv "
+			    "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
+		CSIO_INC_STATS(rn, n_evt_drop);
+		break;
+	default:
+		csio_ln_dbg(ln,
+			    "ssni:x%x unexp event %d recv "
+			    "in rn state[uninit]\n", csio_rn_flowid(rn), evt);
+		CSIO_INC_STATS(rn, n_evt_unexp);
+		break;
+	}
+}
+
+/*
+ * csio_rns_ready -
+ * @rn - rnode
+ * @evt - SM event.
+ *
+ */
+static void
+csio_rns_ready(struct csio_rnode *rn, enum csio_rn_ev evt)
+{
+	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
+	int ret = 0;
+
+	CSIO_INC_STATS(rn, n_evt_sm[evt]);
+
+	switch (evt) {
+	case CSIO_RNFE_LOGGED_IN:
+	case CSIO_RNFE_PLOGI_RECV:
+		csio_ln_dbg(ln,
+			"ssni:x%x Ignoring event %d recv from did:x%x "
+			"in rn state[ready]\n", csio_rn_flowid(rn), evt,
+			rn->nport_id);
+		CSIO_INC_STATS(rn, n_evt_drop);
+		break;
+
+	case CSIO_RNFE_PRLI_DONE:
+	case CSIO_RNFE_PRLI_RECV:
+		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
+		if (!ret)
+			__csio_reg_rnode(rn);
+		else
+			CSIO_INC_STATS(rn, n_err_inval);
+
+		break;
+	case CSIO_RNFE_DOWN:
+		csio_set_state(&rn->sm, csio_rns_offline);
+		__csio_unreg_rnode(rn);
+
+		/* FW expected to internally aborted outstanding SCSI WRs
+		 * and return all SCSI WRs to host with status "ABORTED".
+		 */
+		break;
+
+	case CSIO_RNFE_LOGO_RECV:
+		csio_set_state(&rn->sm, csio_rns_offline);
+
+		__csio_unreg_rnode(rn);
+
+		/* FW expected to internally aborted outstanding SCSI WRs
+		 * and return all SCSI WRs to host with status "ABORTED".
+		 */
+		break;
+
+	case CSIO_RNFE_CLOSE:
+		/*
+		 * Each rnode receives CLOSE event when driver is removed or
+		 * device is reset
+		 * Note: All outstanding IOs on remote port need to returned
+		 * to uppper layer with appropriate error before sending
+		 * CLOSE event
+		 */
+		csio_set_state(&rn->sm, csio_rns_uninit);
+		__csio_unreg_rnode(rn);
+		break;
+
+	case CSIO_RNFE_NAME_MISSING:
+		csio_set_state(&rn->sm, csio_rns_disappeared);
+		__csio_unreg_rnode(rn);
+
+		/*
+		 * FW expected to internally aborted outstanding SCSI WRs
+		 * and return all SCSI WRs to host with status "ABORTED".
+		 */
+
+		break;
+
+	default:
+		csio_ln_dbg(ln,
+			"ssni:x%x unexp event %d recv from did:x%x "
+			"in rn state[uninit]\n", csio_rn_flowid(rn), evt,
+			rn->nport_id);
+		CSIO_INC_STATS(rn, n_evt_unexp);
+		break;
+	}
+}
+
+/*
+ * csio_rns_offline -
+ * @rn - rnode
+ * @evt - SM event.
+ *
+ */
+static void
+csio_rns_offline(struct csio_rnode *rn, enum csio_rn_ev evt)
+{
+	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
+	int ret = 0;
+
+	CSIO_INC_STATS(rn, n_evt_sm[evt]);
+
+	switch (evt) {
+	case CSIO_RNFE_LOGGED_IN:
+	case CSIO_RNFE_PLOGI_RECV:
+		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
+		if (!ret) {
+			csio_set_state(&rn->sm, csio_rns_ready);
+			__csio_reg_rnode(rn);
+		} else {
+			CSIO_INC_STATS(rn, n_err_inval);
+			csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
+		}
+		break;
+
+	case CSIO_RNFE_DOWN:
+		csio_ln_dbg(ln,
+			"ssni:x%x Ignoring event %d recv from did:x%x "
+			"in rn state[offline]\n", csio_rn_flowid(rn), evt,
+			rn->nport_id);
+		CSIO_INC_STATS(rn, n_evt_drop);
+		break;
+
+	case CSIO_RNFE_CLOSE:
+		/* Each rnode receives CLOSE event when driver is removed or
+		 * device is reset
+		 * Note: All outstanding IOs on remote port need to returned
+		 * to uppper layer with appropriate error before sending
+		 * CLOSE event
+		 */
+		csio_set_state(&rn->sm, csio_rns_uninit);
+		break;
+
+	case CSIO_RNFE_NAME_MISSING:
+		csio_set_state(&rn->sm, csio_rns_disappeared);
+		break;
+
+	default:
+		csio_ln_dbg(ln,
+			"ssni:x%x unexp event %d recv from did:x%x "
+			"in rn state[offline]\n", csio_rn_flowid(rn), evt,
+			rn->nport_id);
+		CSIO_INC_STATS(rn, n_evt_unexp);
+		break;
+	}
+}
+
+/*
+ * csio_rns_disappeared -
+ * @rn - rnode
+ * @evt - SM event.
+ *
+ */
+static void
+csio_rns_disappeared(struct csio_rnode *rn, enum csio_rn_ev evt)
+{
+	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
+	int ret = 0;
+
+	CSIO_INC_STATS(rn, n_evt_sm[evt]);
+
+	switch (evt) {
+	case CSIO_RNFE_LOGGED_IN:
+	case CSIO_RNFE_PLOGI_RECV:
+		ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
+		if (!ret) {
+			csio_set_state(&rn->sm, csio_rns_ready);
+			__csio_reg_rnode(rn);
+		} else {
+			CSIO_INC_STATS(rn, n_err_inval);
+			csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
+		}
+		break;
+
+	case CSIO_RNFE_CLOSE:
+		/* Each rnode receives CLOSE event when driver is removed or
+		 * device is reset.
+		 * Note: All outstanding IOs on remote port need to returned
+		 * to uppper layer with appropriate error before sending
+		 * CLOSE event
+		 */
+		csio_set_state(&rn->sm, csio_rns_uninit);
+		break;
+
+	case CSIO_RNFE_DOWN:
+	case CSIO_RNFE_NAME_MISSING:
+		csio_ln_dbg(ln,
+			"ssni:x%x Ignoring event %d recv from did x%x"
+			"in rn state[disappeared]\n", csio_rn_flowid(rn),
+			evt, rn->nport_id);
+		break;
+
+	default:
+		csio_ln_dbg(ln,
+			"ssni:x%x unexp event %d recv from did x%x"
+			"in rn state[disappeared]\n", csio_rn_flowid(rn),
+			evt, rn->nport_id);
+		CSIO_INC_STATS(rn, n_evt_unexp);
+		break;
+	}
+}
+
+/*****************************************************************************/
+/* END: Rnode SM                                                             */
+/*****************************************************************************/
+
+/*
+ * csio_rnode_devloss_handler - Device loss event handler
+ * @rn: rnode
+ *
+ * Post event to close rnode SM and free rnode.
+ */
+void
+csio_rnode_devloss_handler(struct csio_rnode *rn)
+{
+	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
+
+	/* ignore if same rnode came back as online */
+	if (csio_is_rnode_ready(rn))
+		return;
+
+	csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
+
+	/* Free rn if in uninit state */
+	if (csio_is_rnode_uninit(rn))
+		csio_put_rnode(ln, rn);
+}
+
+/**
+ * csio_rnode_fwevt_handler - Event handler for firmware rnode events.
+ * @rn:		rnode
+ *
+ */
+void
+csio_rnode_fwevt_handler(struct csio_rnode *rn, uint8_t fwevt)
+{
+	struct csio_lnode *ln = csio_rnode_to_lnode(rn);
+	enum csio_rn_ev evt;
+
+	evt = CSIO_FWE_TO_RNFE(fwevt);
+	if (!evt) {
+		csio_ln_err(ln, "ssni:x%x Unhandled FW Rdev event: %d\n",
+			    csio_rn_flowid(rn), fwevt);
+		CSIO_INC_STATS(rn, n_evt_unexp);
+		return;
+	}
+	CSIO_INC_STATS(rn, n_evt_fw[fwevt]);
+
+	/* Track previous & current events for debugging */
+	rn->prev_evt = rn->cur_evt;
+	rn->cur_evt = fwevt;
+
+	/* Post event to rnode SM */
+	csio_post_event(&rn->sm, evt);
+
+	/* Free rn if in uninit state */
+	if (csio_is_rnode_uninit(rn))
+		csio_put_rnode(ln, rn);
+}
+
+/*
+ * csio_rnode_init - Initialize rnode.
+ * @rn: RNode
+ * @ln: Associated lnode
+ *
+ * Caller is responsible for holding the lock. The lock is required
+ * to be held for inserting the rnode in ln->rnhead list.
+ */
+static int
+csio_rnode_init(struct csio_rnode *rn, struct csio_lnode *ln)
+{
+	csio_rnode_to_lnode(rn) = ln;
+	csio_init_state(&rn->sm, csio_rns_uninit);
+	INIT_LIST_HEAD(&rn->host_cmpl_q);
+	csio_rn_flowid(rn) = CSIO_INVALID_IDX;
+
+	/* Add rnode to list of lnodes->rnhead */
+	list_add_tail(&rn->sm.sm_list, &ln->rnhead);
+
+	return 0;
+}
+
+static void
+csio_rnode_exit(struct csio_rnode *rn)
+{
+	list_del_init(&rn->sm.sm_list);
+	CSIO_DB_ASSERT(list_empty(&rn->host_cmpl_q));
+}
-- 
1.7.1


^ permalink raw reply related

* Regarding ethernet dir
From: byungho an @ 2012-09-11 14:37 UTC (permalink / raw)
  To: netdev

Hi all,

I have one suggestion for ethernet dir.
Currently It is well-defined and good for management.

But if IP vendor is different from SoC vender, It is a bit confusing
to guess dir name.
For example, stmmac is using Synopsys dwmac.
In this case, if another SoC vendors try to use Synopsys IP, they
sould make their own dir under the their name?

If there is common dir of IP vendor, It would be more clear like below.

What do you think about it?
I want to exchange opinion and find a resonable and rational way.

Thank you.
Andy.

^ permalink raw reply

* GRO aggregation
From: Shlomo Pongartz @ 2012-09-11 13:45 UTC (permalink / raw)
  To: netdev

Hi,

I’m checking GRO aggregation with kernel 3.6.0-rc1+ using Intel ixgbe 
driver.
The mtu is 1500 and GRO is on and so are SG and RX checksum.
I ran iperf with default setting and monitor the receiver with tcpdump.
The tcpdump shows that the maximal aggregation is 32120 which is 21 * 1500.
In the transmitter side tcpdump shows that TSO works better (~64K).
I did a capture without GRO enabled to see if there was a difference 
between any flag
of any two consecutive packets that forced flushing but didn't find 
anything.
Is the GRO aggregation can be tuned.



Shlomo Pongratz

^ permalink raw reply

* Re: [PATCH 06/16] ARM: netx: move platform_data definitions
From: Sascha Hauer @ 2012-09-11 13:35 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Russell King, netdev, linux-kernel,
	David S. Miller
In-Reply-To: <1347368390-31252-6-git-send-email-arnd@arndb.de>

On Tue, Sep 11, 2012 at 02:59:40PM +0200, Arnd Bergmann wrote:
> Platform data for device drivers should be defined in
> include/linux/platform_data/*.h, not in the architecture
> and platform specific directories.
> 
> This moves such data out of the netx include directories
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: netdev@vger.kernel.org
> Cc: Sascha Hauer <s.hauer@pengutronix.de>

Acked-by: Sascha Hauer <s.hauer@pengutronix.de>

> ---
>  arch/arm/mach-netx/nxdb500.c                                         |    2 +-
>  arch/arm/mach-netx/nxdkn.c                                           |    2 +-
>  arch/arm/mach-netx/nxeb500hmi.c                                      |    2 +-
>  drivers/net/ethernet/netx-eth.c                                      |    2 +-
>  .../include/mach/eth.h => include/linux/platform_data/eth-netx.h     |    0
>  5 files changed, 4 insertions(+), 4 deletions(-)
>  rename arch/arm/mach-netx/include/mach/eth.h => include/linux/platform_data/eth-netx.h (100%)
> 
> diff --git a/arch/arm/mach-netx/nxdb500.c b/arch/arm/mach-netx/nxdb500.c
> index 180ea89..8b781ff 100644
> --- a/arch/arm/mach-netx/nxdb500.c
> +++ b/arch/arm/mach-netx/nxdb500.c
> @@ -30,7 +30,7 @@
>  #include <asm/mach/arch.h>
>  #include <asm/hardware/vic.h>
>  #include <mach/netx-regs.h>
> -#include <mach/eth.h>
> +#include <linux/platform_data/eth-netx.h>
>  
>  #include "generic.h"
>  #include "fb.h"
> diff --git a/arch/arm/mach-netx/nxdkn.c b/arch/arm/mach-netx/nxdkn.c
> index 58009e2..b26dbce 100644
> --- a/arch/arm/mach-netx/nxdkn.c
> +++ b/arch/arm/mach-netx/nxdkn.c
> @@ -30,7 +30,7 @@
>  #include <asm/mach/arch.h>
>  #include <asm/hardware/vic.h>
>  #include <mach/netx-regs.h>
> -#include <mach/eth.h>
> +#include <linux/platform_data/eth-netx.h>
>  
>  #include "generic.h"
>  
> diff --git a/arch/arm/mach-netx/nxeb500hmi.c b/arch/arm/mach-netx/nxeb500hmi.c
> index 122e998..257382e 100644
> --- a/arch/arm/mach-netx/nxeb500hmi.c
> +++ b/arch/arm/mach-netx/nxeb500hmi.c
> @@ -30,7 +30,7 @@
>  #include <asm/mach/arch.h>
>  #include <asm/hardware/vic.h>
>  #include <mach/netx-regs.h>
> -#include <mach/eth.h>
> +#include <linux/platform_data/eth-netx.h>
>  
>  #include "generic.h"
>  #include "fb.h"
> diff --git a/drivers/net/ethernet/netx-eth.c b/drivers/net/ethernet/netx-eth.c
> index 9d11ab7..63e7af4 100644
> --- a/drivers/net/ethernet/netx-eth.c
> +++ b/drivers/net/ethernet/netx-eth.c
> @@ -34,7 +34,7 @@
>  #include <mach/netx-regs.h>
>  #include <mach/pfifo.h>
>  #include <mach/xc.h>
> -#include <mach/eth.h>
> +#include <linux/platform_data/eth-netx.h>
>  
>  /* XC Fifo Offsets */
>  #define EMPTY_PTR_FIFO(xcno)    (0 + ((xcno) << 3))	/* Index of the empty pointer FIFO */
> diff --git a/arch/arm/mach-netx/include/mach/eth.h b/include/linux/platform_data/eth-netx.h
> similarity index 100%
> rename from arch/arm/mach-netx/include/mach/eth.h
> rename to include/linux/platform_data/eth-netx.h
> -- 
> 1.7.10
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH 06/16] ARM: netx: move platform_data definitions
From: Arnd Bergmann @ 2012-09-11 12:59 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Russell King, Arnd Bergmann, David S. Miller,
	netdev, Sascha Hauer
In-Reply-To: <1347368390-31252-1-git-send-email-arnd@arndb.de>

Platform data for device drivers should be defined in
include/linux/platform_data/*.h, not in the architecture
and platform specific directories.

This moves such data out of the netx include directories

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
Cc: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-netx/nxdb500.c                                         |    2 +-
 arch/arm/mach-netx/nxdkn.c                                           |    2 +-
 arch/arm/mach-netx/nxeb500hmi.c                                      |    2 +-
 drivers/net/ethernet/netx-eth.c                                      |    2 +-
 .../include/mach/eth.h => include/linux/platform_data/eth-netx.h     |    0
 5 files changed, 4 insertions(+), 4 deletions(-)
 rename arch/arm/mach-netx/include/mach/eth.h => include/linux/platform_data/eth-netx.h (100%)

diff --git a/arch/arm/mach-netx/nxdb500.c b/arch/arm/mach-netx/nxdb500.c
index 180ea89..8b781ff 100644
--- a/arch/arm/mach-netx/nxdb500.c
+++ b/arch/arm/mach-netx/nxdb500.c
@@ -30,7 +30,7 @@
 #include <asm/mach/arch.h>
 #include <asm/hardware/vic.h>
 #include <mach/netx-regs.h>
-#include <mach/eth.h>
+#include <linux/platform_data/eth-netx.h>
 
 #include "generic.h"
 #include "fb.h"
diff --git a/arch/arm/mach-netx/nxdkn.c b/arch/arm/mach-netx/nxdkn.c
index 58009e2..b26dbce 100644
--- a/arch/arm/mach-netx/nxdkn.c
+++ b/arch/arm/mach-netx/nxdkn.c
@@ -30,7 +30,7 @@
 #include <asm/mach/arch.h>
 #include <asm/hardware/vic.h>
 #include <mach/netx-regs.h>
-#include <mach/eth.h>
+#include <linux/platform_data/eth-netx.h>
 
 #include "generic.h"
 
diff --git a/arch/arm/mach-netx/nxeb500hmi.c b/arch/arm/mach-netx/nxeb500hmi.c
index 122e998..257382e 100644
--- a/arch/arm/mach-netx/nxeb500hmi.c
+++ b/arch/arm/mach-netx/nxeb500hmi.c
@@ -30,7 +30,7 @@
 #include <asm/mach/arch.h>
 #include <asm/hardware/vic.h>
 #include <mach/netx-regs.h>
-#include <mach/eth.h>
+#include <linux/platform_data/eth-netx.h>
 
 #include "generic.h"
 #include "fb.h"
diff --git a/drivers/net/ethernet/netx-eth.c b/drivers/net/ethernet/netx-eth.c
index 9d11ab7..63e7af4 100644
--- a/drivers/net/ethernet/netx-eth.c
+++ b/drivers/net/ethernet/netx-eth.c
@@ -34,7 +34,7 @@
 #include <mach/netx-regs.h>
 #include <mach/pfifo.h>
 #include <mach/xc.h>
-#include <mach/eth.h>
+#include <linux/platform_data/eth-netx.h>
 
 /* XC Fifo Offsets */
 #define EMPTY_PTR_FIFO(xcno)    (0 + ((xcno) << 3))	/* Index of the empty pointer FIFO */
diff --git a/arch/arm/mach-netx/include/mach/eth.h b/include/linux/platform_data/eth-netx.h
similarity index 100%
rename from arch/arm/mach-netx/include/mach/eth.h
rename to include/linux/platform_data/eth-netx.h
-- 
1.7.10

^ permalink raw reply related

* [PATCH 00/16] ARM: big platform data header rename
From: Arnd Bergmann @ 2012-09-11 12:59 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Russell King, Arnd Bergmann, netdev, openezx-devel,
	spear-devel, davinci-linux-open-source, linux-arm-msm, linux-omap,
	linux-samsung-soc, linux-tegra
In-Reply-To: <1347368245-30989-1-git-send-email-arnd@arndb.de>

As we discussed at the ARM mini summit in San Diego, we are
going to move all platform specific header files that are used
in drivers out of the mach-* directories, at least for those
platforms that we want to have in a multiplatform kernel.

A big step in this direction is to move all the platform_data
definitions into include/linux/platform_data/. This takes
care of about a third of the header files in question and
should be relatively uncontroversial.

I changed the file names after the rename to be
include/linux/${subsystem}-${driver}.h where possible, to
have a more consistent naming there.

I would like to merge the series through the arm-soc tree
as an early branch so other branches can be based on top
or merge this branch into the other one to avoid conflicts.

Platform maintainers: please provide ACKs so I can take
it into the for-next branch as a stable sub-branch.

Driver maintainers: There should be nothing controversial
here, just a heads-up so you know that some one-line changes
are coming through the arm-soc tree that might cause an
occasional merge conflict. I've put a lot of people on
bcc in this mail so they know what the individual ones are
about. If you have specific comments, please reply on the
patches you are Cc'd on.

	Arnd

Arnd Bergmann (16):
  ARM: at91: move platform_data definitions
  ARM: davinci: move platform_data definitions
  ARM: ep93xx: move platform_data definitions
  ARM: imx: move platform_data definitions
  ARM: msm: move platform_data definitions
  ARM: netx: move platform_data definitions
  ARM: pxa: move platform_data definitions
  ARM: sa1100: move platform_data definitions
  ARM: tegra: move platform_data definitions
  ARM: vt8500: move platform_data definitions
  ARM: w90x900: move platform_data definitions
  ARM: nomadik: move platform_data definitions
  ARM: omap: move platform_data definitions
  ARM: orion: move platform_data definitions
  ARM: samsung: move platform_data definitions
  ARM: spear: move platform_data definitions

 Documentation/spi/ep93xx_spi                       |    2 +-
 arch/arm/mach-at91/at91sam9g45_devices.c           |    2 +-
 arch/arm/mach-at91/at91sam9rl_devices.c            |    2 +-
 arch/arm/mach-at91/include/mach/at_hdmac.h         |   61 -------
 arch/arm/mach-at91/include/mach/atmel-mci.h        |    2 +-
 arch/arm/mach-davinci/aemif.c                      |    2 +-
 arch/arm/mach-davinci/board-da830-evm.c            |    8 +-
 arch/arm/mach-davinci/board-da850-evm.c            |    6 +-
 arch/arm/mach-davinci/board-dm355-evm.c            |    8 +-
 arch/arm/mach-davinci/board-dm355-leopard.c        |    8 +-
 arch/arm/mach-davinci/board-dm365-evm.c            |    8 +-
 arch/arm/mach-davinci/board-dm644x-evm.c           |   10 +-
 arch/arm/mach-davinci/board-dm646x-evm.c           |    6 +-
 arch/arm/mach-davinci/board-mityomapl138.c         |    4 +-
 arch/arm/mach-davinci/board-neuros-osd2.c          |    8 +-
 arch/arm/mach-davinci/board-sffsdr.c               |    4 +-
 arch/arm/mach-davinci/davinci.h                    |    4 +-
 arch/arm/mach-davinci/devices.c                    |    4 +-
 arch/arm/mach-davinci/dm355.c                      |    4 +-
 arch/arm/mach-davinci/dm365.c                      |    6 +-
 arch/arm/mach-davinci/dm644x.c                     |    2 +-
 arch/arm/mach-davinci/dm646x.c                     |    2 +-
 arch/arm/mach-davinci/include/mach/aemif.h         |   36 ----
 arch/arm/mach-davinci/include/mach/asp.h           |  137 ---------------
 arch/arm/mach-davinci/include/mach/da8xx.h         |   10 +-
 arch/arm/mach-davinci/include/mach/i2c.h           |   26 ---
 arch/arm/mach-davinci/include/mach/keyscan.h       |   42 -----
 arch/arm/mach-davinci/include/mach/mmc.h           |   39 -----
 arch/arm/mach-davinci/include/mach/nand.h          |   90 ----------
 arch/arm/mach-davinci/include/mach/spi.h           |   89 ----------
 arch/arm/mach-davinci/include/mach/tnetv107x.h     |    4 +-
 arch/arm/mach-davinci/include/mach/usb.h           |   59 -------
 arch/arm/mach-davinci/usb.c                        |    2 +-
 arch/arm/mach-dove/common.c                        |    2 +-
 arch/arm/mach-ep93xx/core.c                        |    6 +-
 arch/arm/mach-ep93xx/dma.c                         |    2 +-
 arch/arm/mach-ep93xx/edb93xx.c                     |    4 +-
 arch/arm/mach-ep93xx/include/mach/dma.h            |   93 -----------
 arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h  |   35 ----
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h     |   29 ----
 arch/arm/mach-ep93xx/include/mach/fb.h             |   56 -------
 arch/arm/mach-ep93xx/simone.c                      |    2 +-
 arch/arm/mach-ep93xx/snappercl15.c                 |    2 +-
 arch/arm/mach-ep93xx/vision_ep9307.c               |    4 +-
 arch/arm/mach-exynos/dev-audio.c                   |    2 +-
 arch/arm/mach-exynos/dev-ohci.c                    |    2 +-
 arch/arm/mach-exynos/include/mach/ohci.h           |   21 ---
 arch/arm/mach-exynos/mach-nuri.c                   |    6 +-
 arch/arm/mach-exynos/mach-origen.c                 |    6 +-
 arch/arm/mach-exynos/mach-smdk4x12.c               |    2 +-
 arch/arm/mach-exynos/mach-smdkv310.c               |    6 +-
 arch/arm/mach-exynos/mach-universal_c210.c         |    4 +-
 arch/arm/mach-exynos/setup-i2c0.c                  |    2 +-
 arch/arm/mach-exynos/setup-i2c1.c                  |    2 +-
 arch/arm/mach-exynos/setup-i2c2.c                  |    2 +-
 arch/arm/mach-exynos/setup-i2c3.c                  |    2 +-
 arch/arm/mach-exynos/setup-i2c4.c                  |    2 +-
 arch/arm/mach-exynos/setup-i2c5.c                  |    2 +-
 arch/arm/mach-exynos/setup-i2c6.c                  |    2 +-
 arch/arm/mach-exynos/setup-i2c7.c                  |    2 +-
 arch/arm/mach-imx/ehci-imx25.c                     |    2 +-
 arch/arm/mach-imx/ehci-imx27.c                     |    2 +-
 arch/arm/mach-imx/ehci-imx31.c                     |    2 +-
 arch/arm/mach-imx/ehci-imx35.c                     |    2 +-
 arch/arm/mach-imx/ehci-imx5.c                      |    2 +-
 arch/arm/mach-imx/mach-mx31moboard.c               |    2 +-
 arch/arm/mach-imx/mx1-camera-fiq-ksym.c            |    2 +-
 arch/arm/mach-kirkwood/board-dreamplug.c           |    2 +-
 arch/arm/mach-kirkwood/board-goflexnet.c           |    2 +-
 arch/arm/mach-kirkwood/common.c                    |   10 +-
 arch/arm/mach-kirkwood/d2net_v2-setup.c            |    2 +-
 arch/arm/mach-kirkwood/db88f6281-bp-setup.c        |    2 +-
 arch/arm/mach-kirkwood/dockstar-setup.c            |    2 +-
 arch/arm/mach-kirkwood/guruplug-setup.c            |    2 +-
 arch/arm/mach-kirkwood/include/mach/leds-netxbig.h |   55 ------
 arch/arm/mach-kirkwood/include/mach/leds-ns2.h     |   26 ---
 arch/arm/mach-kirkwood/netspace_v2-setup.c         |    2 +-
 arch/arm/mach-kirkwood/netxbig_v2-setup.c          |    2 +-
 arch/arm/mach-kirkwood/openrd-setup.c              |    2 +-
 arch/arm/mach-kirkwood/rd88f6281-setup.c           |    2 +-
 arch/arm/mach-kirkwood/sheevaplug-setup.c          |    2 +-
 arch/arm/mach-mmp/aspenite.c                       |    2 +-
 arch/arm/mach-mmp/include/mach/mmp2.h              |    2 +-
 arch/arm/mach-mmp/include/mach/pxa168.h            |    4 +-
 arch/arm/mach-mmp/include/mach/pxa910.h            |    2 +-
 arch/arm/mach-mmp/include/mach/sram.h              |   35 ----
 arch/arm/mach-mmp/sram.c                           |    2 +-
 arch/arm/mach-mmp/teton_bga.c                      |    2 +-
 arch/arm/mach-msm/board-qsd8x50.c                  |    2 +-
 arch/arm/mach-msm/board-trout-mmc.c                |    2 +-
 arch/arm/mach-msm/board-trout-panel.c              |    2 +-
 arch/arm/mach-msm/devices-msm7x00.c                |    2 +-
 arch/arm/mach-msm/devices-msm7x30.c                |    2 +-
 arch/arm/mach-msm/devices-qsd8x50.c                |    2 +-
 arch/arm/mach-msm/include/mach/board.h             |    2 +-
 arch/arm/mach-msm/include/mach/mmc.h               |   30 ----
 arch/arm/mach-msm/include/mach/msm_fb.h            |  147 ----------------
 arch/arm/mach-mv78xx0/common.c                     |    4 +-
 arch/arm/mach-netx/include/mach/eth.h              |   27 ---
 arch/arm/mach-netx/nxdb500.c                       |    2 +-
 arch/arm/mach-netx/nxdkn.c                         |    2 +-
 arch/arm/mach-netx/nxeb500hmi.c                    |    2 +-
 arch/arm/mach-nomadik/board-nhk8815.c              |    2 +-
 arch/arm/mach-nomadik/include/mach/nand.h          |   16 --
 arch/arm/mach-omap1/board-ams-delta.c              |    2 +-
 arch/arm/mach-omap1/board-fsample.c                |    2 +-
 arch/arm/mach-omap1/board-h2.c                     |    2 +-
 arch/arm/mach-omap1/board-h3.c                     |    2 +-
 arch/arm/mach-omap1/board-htcherald.c              |    2 +-
 arch/arm/mach-omap1/board-innovator.c              |    2 +-
 arch/arm/mach-omap1/board-nokia770.c               |    4 +-
 arch/arm/mach-omap1/board-osk.c                    |    2 +-
 arch/arm/mach-omap1/board-palmte.c                 |    2 +-
 arch/arm/mach-omap1/board-palmtt.c                 |    2 +-
 arch/arm/mach-omap1/board-palmz71.c                |    2 +-
 arch/arm/mach-omap1/board-perseus2.c               |    2 +-
 arch/arm/mach-omap1/board-sx1.c                    |    2 +-
 arch/arm/mach-omap1/mcbsp.c                        |    2 +-
 arch/arm/mach-omap2/board-3430sdp.c                |    2 +-
 arch/arm/mach-omap2/board-cm-t35.c                 |    4 +-
 arch/arm/mach-omap2/board-cm-t3517.c               |    2 +-
 arch/arm/mach-omap2/board-devkit8000.c             |    4 +-
 arch/arm/mach-omap2/board-flash.c                  |    4 +-
 arch/arm/mach-omap2/board-igep0020.c               |    2 +-
 arch/arm/mach-omap2/board-ldp.c                    |    2 +-
 arch/arm/mach-omap2/board-n8x0.c                   |    4 +-
 arch/arm/mach-omap2/board-omap3beagle.c            |    2 +-
 arch/arm/mach-omap2/board-omap3evm.c               |    4 +-
 arch/arm/mach-omap2/board-omap3pandora.c           |    4 +-
 arch/arm/mach-omap2/board-omap3stalker.c           |    4 +-
 arch/arm/mach-omap2/board-omap3touchbook.c         |    4 +-
 arch/arm/mach-omap2/board-overo.c                  |    4 +-
 arch/arm/mach-omap2/board-rm680.c                  |    2 +-
 arch/arm/mach-omap2/board-rx51-peripherals.c       |    4 +-
 arch/arm/mach-omap2/board-rx51-video.c             |    2 +-
 arch/arm/mach-omap2/board-rx51.c                   |    2 +-
 arch/arm/mach-omap2/board-zoom-display.c           |    2 +-
 arch/arm/mach-omap2/common-board-devices.c         |    4 +-
 arch/arm/mach-omap2/devices.c                      |    2 +-
 arch/arm/mach-omap2/dsp.c                          |    2 +-
 arch/arm/mach-omap2/gpmc-nand.c                    |    2 +-
 arch/arm/mach-omap2/gpmc-onenand.c                 |    2 +-
 arch/arm/mach-omap2/mcbsp.c                        |    2 +-
 arch/arm/mach-omap2/omap_hwmod_2420_data.c         |    2 +-
 arch/arm/mach-omap2/omap_hwmod_2430_data.c         |    4 +-
 arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c |    2 +-
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |    4 +-
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c         |    4 +-
 arch/arm/mach-omap2/voltage.h                      |    2 +-
 arch/arm/mach-orion5x/common.c                     |    4 +-
 arch/arm/mach-orion5x/db88f5281-setup.c            |    2 +-
 arch/arm/mach-orion5x/kurobox_pro-setup.c          |    2 +-
 arch/arm/mach-pxa/am200epd.c                       |    2 +-
 arch/arm/mach-pxa/am300epd.c                       |    2 +-
 arch/arm/mach-pxa/balloon3.c                       |    8 +-
 arch/arm/mach-pxa/cm-x270.c                        |    4 +-
 arch/arm/mach-pxa/cm-x2xx.c                        |    2 +-
 arch/arm/mach-pxa/cm-x300.c                        |   10 +-
 arch/arm/mach-pxa/colibri-evalboard.c              |    4 +-
 arch/arm/mach-pxa/colibri-pxa270-income.c          |    6 +-
 arch/arm/mach-pxa/colibri-pxa300.c                 |    4 +-
 arch/arm/mach-pxa/colibri-pxa320.c                 |    4 +-
 arch/arm/mach-pxa/colibri-pxa3xx.c                 |    6 +-
 arch/arm/mach-pxa/corgi.c                          |    4 +-
 arch/arm/mach-pxa/csb726.c                         |    4 +-
 arch/arm/mach-pxa/devices.c                        |   16 +-
 arch/arm/mach-pxa/em-x270.c                        |   10 +-
 arch/arm/mach-pxa/eseries.c                        |    4 +-
 arch/arm/mach-pxa/ezx.c                            |    8 +-
 arch/arm/mach-pxa/gumstix.c                        |    2 +-
 arch/arm/mach-pxa/hx4700.c                         |    2 +-
 arch/arm/mach-pxa/idp.c                            |    4 +-
 arch/arm/mach-pxa/include/mach/arcom-pcmcia.h      |   11 --
 arch/arm/mach-pxa/include/mach/camera.h            |   44 -----
 arch/arm/mach-pxa/include/mach/irda.h              |   25 ---
 arch/arm/mach-pxa/include/mach/mmc.h               |   28 ----
 arch/arm/mach-pxa/include/mach/ohci.h              |   36 ----
 arch/arm/mach-pxa/include/mach/palmasoc.h          |    8 -
 arch/arm/mach-pxa/include/mach/pata_pxa.h          |   33 ----
 arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h        |   35 ----
 arch/arm/mach-pxa/include/mach/pxa930_rotary.h     |   20 ---
 arch/arm/mach-pxa/include/mach/pxa930_trkball.h    |   10 --
 arch/arm/mach-pxa/include/mach/pxafb.h             |  175 --------------------
 arch/arm/mach-pxa/littleton.c                      |    8 +-
 arch/arm/mach-pxa/lpd270.c                         |    8 +-
 arch/arm/mach-pxa/lubbock.c                        |    6 +-
 arch/arm/mach-pxa/magician.c                       |    8 +-
 arch/arm/mach-pxa/mainstone.c                      |   10 +-
 arch/arm/mach-pxa/mioa701.c                        |    8 +-
 arch/arm/mach-pxa/mxm8x10.c                        |    8 +-
 arch/arm/mach-pxa/palm27x.c                        |    8 +-
 arch/arm/mach-pxa/palmld.c                         |   10 +-
 arch/arm/mach-pxa/palmt5.c                         |   10 +-
 arch/arm/mach-pxa/palmtc.c                         |    6 +-
 arch/arm/mach-pxa/palmte2.c                        |    8 +-
 arch/arm/mach-pxa/palmtreo.c                       |   14 +-
 arch/arm/mach-pxa/palmtx.c                         |   10 +-
 arch/arm/mach-pxa/palmz72.c                        |   12 +-
 arch/arm/mach-pxa/pcm990-baseboard.c               |    8 +-
 arch/arm/mach-pxa/poodle.c                         |    6 +-
 arch/arm/mach-pxa/pxa27x.c                         |    2 +-
 arch/arm/mach-pxa/pxa2xx.c                         |    2 +-
 arch/arm/mach-pxa/pxa3xx-ulpi.c                    |    2 +-
 arch/arm/mach-pxa/pxa3xx.c                         |    2 +-
 arch/arm/mach-pxa/raumfeld.c                       |    8 +-
 arch/arm/mach-pxa/saar.c                           |    2 +-
 arch/arm/mach-pxa/spitz.c                          |    8 +-
 arch/arm/mach-pxa/stargate2.c                      |    2 +-
 arch/arm/mach-pxa/tavorevb.c                       |    4 +-
 arch/arm/mach-pxa/tosa.c                           |    4 +-
 arch/arm/mach-pxa/trizeps4.c                       |    8 +-
 arch/arm/mach-pxa/viper.c                          |    4 +-
 arch/arm/mach-pxa/vpac270.c                        |    8 +-
 arch/arm/mach-pxa/z2.c                             |    6 +-
 arch/arm/mach-pxa/zeus.c                           |    8 +-
 arch/arm/mach-pxa/zylonite.c                       |   10 +-
 arch/arm/mach-s3c24xx/common-smdk.c                |    4 +-
 arch/arm/mach-s3c24xx/include/mach/leds-gpio.h     |   28 ----
 arch/arm/mach-s3c24xx/mach-amlm5900.c              |    2 +-
 arch/arm/mach-s3c24xx/mach-anubis.c                |    6 +-
 arch/arm/mach-s3c24xx/mach-at2440evb.c             |    6 +-
 arch/arm/mach-s3c24xx/mach-bast.c                  |    8 +-
 arch/arm/mach-s3c24xx/mach-gta02.c                 |   10 +-
 arch/arm/mach-s3c24xx/mach-h1940.c                 |    8 +-
 arch/arm/mach-s3c24xx/mach-jive.c                  |    6 +-
 arch/arm/mach-s3c24xx/mach-mini2440.c              |   10 +-
 arch/arm/mach-s3c24xx/mach-n30.c                   |    8 +-
 arch/arm/mach-s3c24xx/mach-nexcoder.c              |    2 +-
 arch/arm/mach-s3c24xx/mach-osiris.c                |    4 +-
 arch/arm/mach-s3c24xx/mach-otom.c                  |    2 +-
 arch/arm/mach-s3c24xx/mach-qt2410.c                |    8 +-
 arch/arm/mach-s3c24xx/mach-rx1950.c                |   10 +-
 arch/arm/mach-s3c24xx/mach-rx3715.c                |    2 +-
 arch/arm/mach-s3c24xx/mach-smdk2410.c              |    2 +-
 arch/arm/mach-s3c24xx/mach-smdk2413.c              |    4 +-
 arch/arm/mach-s3c24xx/mach-smdk2416.c              |    8 +-
 arch/arm/mach-s3c24xx/mach-smdk2440.c              |    2 +-
 arch/arm/mach-s3c24xx/mach-smdk2443.c              |    2 +-
 arch/arm/mach-s3c24xx/mach-tct_hammer.c            |    2 +-
 arch/arm/mach-s3c24xx/mach-vr1000.c                |    6 +-
 arch/arm/mach-s3c24xx/mach-vstms.c                 |    4 +-
 arch/arm/mach-s3c24xx/setup-i2c.c                  |    2 +-
 arch/arm/mach-s3c24xx/simtec-audio.c               |    2 +-
 arch/arm/mach-s3c24xx/simtec-usb.c                 |    2 +-
 arch/arm/mach-s3c64xx/dev-audio.c                  |    2 +-
 arch/arm/mach-s3c64xx/mach-anw6410.c               |    2 +-
 arch/arm/mach-s3c64xx/mach-crag6410-module.c       |    2 +-
 arch/arm/mach-s3c64xx/mach-crag6410.c              |    4 +-
 arch/arm/mach-s3c64xx/mach-hmt.c                   |    4 +-
 arch/arm/mach-s3c64xx/mach-mini6410.c              |    4 +-
 arch/arm/mach-s3c64xx/mach-ncp.c                   |    2 +-
 arch/arm/mach-s3c64xx/mach-real6410.c              |    4 +-
 arch/arm/mach-s3c64xx/mach-smartq.c                |    8 +-
 arch/arm/mach-s3c64xx/mach-smdk6400.c              |    2 +-
 arch/arm/mach-s3c64xx/mach-smdk6410.c              |    6 +-
 arch/arm/mach-s3c64xx/setup-i2c0.c                 |    2 +-
 arch/arm/mach-s3c64xx/setup-i2c1.c                 |    2 +-
 arch/arm/mach-s3c64xx/setup-ide.c                  |    2 +-
 arch/arm/mach-s5p64x0/dev-audio.c                  |    2 +-
 arch/arm/mach-s5p64x0/mach-smdk6440.c              |    4 +-
 arch/arm/mach-s5p64x0/mach-smdk6450.c              |    4 +-
 arch/arm/mach-s5p64x0/setup-i2c0.c                 |    2 +-
 arch/arm/mach-s5p64x0/setup-i2c1.c                 |    2 +-
 arch/arm/mach-s5pc100/dev-audio.c                  |    2 +-
 arch/arm/mach-s5pc100/mach-smdkc100.c              |    8 +-
 arch/arm/mach-s5pc100/setup-i2c0.c                 |    2 +-
 arch/arm/mach-s5pc100/setup-i2c1.c                 |    2 +-
 arch/arm/mach-s5pv210/dev-audio.c                  |    2 +-
 arch/arm/mach-s5pv210/mach-goni.c                  |    2 +-
 arch/arm/mach-s5pv210/mach-smdkc110.c              |    4 +-
 arch/arm/mach-s5pv210/mach-smdkv210.c              |    6 +-
 arch/arm/mach-s5pv210/mach-torbreck.c              |    2 +-
 arch/arm/mach-s5pv210/setup-i2c0.c                 |    2 +-
 arch/arm/mach-s5pv210/setup-i2c1.c                 |    2 +-
 arch/arm/mach-s5pv210/setup-i2c2.c                 |    2 +-
 arch/arm/mach-sa1100/assabet.c                     |    2 +-
 arch/arm/mach-sa1100/cerf.c                        |    2 +-
 arch/arm/mach-sa1100/collie.c                      |    2 +-
 arch/arm/mach-sa1100/include/mach/mcp.h            |   22 ---
 arch/arm/mach-sa1100/lart.c                        |    2 +-
 arch/arm/mach-sa1100/shannon.c                     |    2 +-
 arch/arm/mach-sa1100/simpad.c                      |    2 +-
 arch/arm/mach-tegra/board-harmony.c                |    4 +-
 arch/arm/mach-tegra/board-paz00.c                  |    2 +-
 arch/arm/mach-tegra/board-trimslice.c              |    2 +-
 arch/arm/mach-tegra/include/mach/kbc.h             |   62 -------
 arch/arm/mach-tegra/include/mach/sdhci.h           |   30 ----
 .../mach-tegra/include/mach/tegra_wm8903_pdata.h   |   23 ---
 arch/arm/mach-u300/core.c                          |    2 +-
 arch/arm/mach-u300/include/mach/gpio-u300.h        |   37 -----
 arch/arm/mach-ux500/board-mop500.c                 |    2 +-
 arch/arm/mach-ux500/cpu-db8500.c                   |    2 +-
 arch/arm/mach-ux500/devices-common.h               |    2 +-
 arch/arm/mach-ux500/include/mach/crypto-ux500.h    |   22 ---
 arch/arm/mach-ux500/include/mach/usb.h             |   25 ---
 arch/arm/mach-ux500/usb.c                          |    2 +-
 arch/arm/mach-vt8500/devices.c                     |    2 +-
 arch/arm/mach-vt8500/include/mach/vt8500fb.h       |   31 ----
 arch/arm/mach-w90x900/dev.c                        |    6 +-
 arch/arm/mach-w90x900/include/mach/fb.h            |   83 ----------
 arch/arm/mach-w90x900/include/mach/i2c.h           |    9 -
 arch/arm/mach-w90x900/include/mach/nuc900_spi.h    |   35 ----
 .../arm/mach-w90x900/include/mach/w90p910_keypad.h |   15 --
 arch/arm/mach-w90x900/mach-nuc950evb.c             |    2 +-
 .../plat-mxc/devices/platform-sdhci-esdhc-imx.c    |    2 +-
 arch/arm/plat-mxc/include/mach/devices-common.h    |   32 ++--
 arch/arm/plat-mxc/include/mach/dma.h               |   67 --------
 arch/arm/plat-mxc/include/mach/esdhc.h             |   43 -----
 arch/arm/plat-mxc/include/mach/i2c.h               |   21 ---
 arch/arm/plat-mxc/include/mach/imx-uart.h          |   35 ----
 arch/arm/plat-mxc/include/mach/imxfb.h             |   84 ----------
 arch/arm/plat-mxc/include/mach/mmc.h               |   39 -----
 arch/arm/plat-mxc/include/mach/mx1_camera.h        |   35 ----
 arch/arm/plat-mxc/include/mach/mx21-usbhost.h      |   38 -----
 arch/arm/plat-mxc/include/mach/mx2_cam.h           |   46 -----
 arch/arm/plat-mxc/include/mach/mx3_camera.h        |   48 ------
 arch/arm/plat-mxc/include/mach/mx3fb.h             |   53 ------
 arch/arm/plat-mxc/include/mach/mxc_ehci.h          |   59 -------
 arch/arm/plat-mxc/include/mach/mxc_nand.h          |   32 ----
 arch/arm/plat-mxc/include/mach/sdma.h              |   59 -------
 arch/arm/plat-mxc/include/mach/spi.h               |   27 ---
 arch/arm/plat-mxc/include/mach/ssi.h               |   21 ---
 arch/arm/plat-mxc/include/mach/usb.h               |   23 ---
 arch/arm/plat-mxc/ssi-fiq-ksym.c                   |    2 +-
 arch/arm/plat-nomadik/include/plat/ske.h           |   50 ------
 arch/arm/plat-omap/common.c                        |    2 +-
 arch/arm/plat-omap/include/plat/dsp.h              |   34 ----
 arch/arm/plat-omap/include/plat/keypad.h           |   52 ------
 arch/arm/plat-omap/include/plat/lcd_mipid.h        |   29 ----
 arch/arm/plat-omap/include/plat/mcbsp.h            |   62 -------
 arch/arm/plat-omap/include/plat/mcspi.h            |   23 ---
 arch/arm/plat-omap/include/plat/nand.h             |   44 -----
 arch/arm/plat-omap/include/plat/onenand.h          |   53 ------
 arch/arm/plat-omap/include/plat/remoteproc.h       |   57 -------
 arch/arm/plat-omap/include/plat/voltage.h          |   39 -----
 arch/arm/plat-orion/common.c                       |    4 +-
 arch/arm/plat-orion/include/plat/audio.h           |    7 -
 arch/arm/plat-orion/include/plat/ehci-orion.h      |   26 ---
 arch/arm/plat-orion/include/plat/mv_xor.h          |   24 ---
 arch/arm/plat-orion/include/plat/mvsdio.h          |   20 ---
 arch/arm/plat-orion/include/plat/orion_nand.h      |   26 ---
 arch/arm/plat-pxa/include/plat/pxa27x_keypad.h     |   73 --------
 arch/arm/plat-pxa/include/plat/pxa3xx_nand.h       |   79 ---------
 arch/arm/plat-samsung/devs.c                       |   20 +--
 arch/arm/plat-samsung/include/plat/ata.h           |   36 ----
 arch/arm/plat-samsung/include/plat/audio-simtec.h  |   34 ----
 arch/arm/plat-samsung/include/plat/audio.h         |   59 -------
 arch/arm/plat-samsung/include/plat/ehci.h          |   21 ---
 arch/arm/plat-samsung/include/plat/hwmon.h         |   51 ------
 arch/arm/plat-samsung/include/plat/iic.h           |   77 ---------
 arch/arm/plat-samsung/include/plat/mci.h           |   52 ------
 arch/arm/plat-samsung/include/plat/mipi_csis.h     |   43 -----
 arch/arm/plat-samsung/include/plat/nand.h          |   67 --------
 arch/arm/plat-samsung/include/plat/s3c64xx-spi.h   |   68 --------
 arch/arm/plat-samsung/include/plat/ts.h            |   25 ---
 arch/arm/plat-samsung/include/plat/udc.h           |   44 -----
 arch/arm/plat-samsung/include/plat/usb-control.h   |   43 -----
 arch/arm/plat-spear/include/plat/keyboard.h        |  164 ------------------
 drivers/ata/pata_ep93xx.c                          |    2 +-
 drivers/ata/pata_pxa.c                             |    2 +-
 drivers/ata/pata_samsung_cf.c                      |    2 +-
 drivers/crypto/ux500/cryp/cryp_core.c              |    2 +-
 drivers/crypto/ux500/hash/hash_core.c              |    2 +-
 drivers/dma/at_hdmac_regs.h                        |    2 +-
 drivers/dma/ep93xx_dma.c                           |    2 +-
 drivers/dma/imx-dma.c                              |    2 +-
 drivers/dma/imx-sdma.c                             |    4 +-
 drivers/dma/mmp_tdma.c                             |    2 +-
 drivers/dma/mv_xor.c                               |    2 +-
 drivers/hwmon/s3c-hwmon.c                          |    2 +-
 drivers/i2c/busses/i2c-davinci.c                   |    2 +-
 drivers/i2c/busses/i2c-imx.c                       |    2 +-
 drivers/i2c/busses/i2c-nuc900.c                    |    2 +-
 drivers/i2c/busses/i2c-s3c2410.c                   |    2 +-
 drivers/input/keyboard/davinci_keyscan.c           |    2 +-
 drivers/input/keyboard/ep93xx_keypad.c             |    2 +-
 drivers/input/keyboard/nomadik-ske-keypad.c        |    2 +-
 drivers/input/keyboard/omap-keypad.c               |    2 +-
 drivers/input/keyboard/pxa27x_keypad.c             |    2 +-
 drivers/input/keyboard/pxa930_rotary.c             |    2 +-
 drivers/input/keyboard/spear-keyboard.c            |    2 +-
 drivers/input/keyboard/tegra-kbc.c                 |    2 +-
 drivers/input/keyboard/w90p910_keypad.c            |    2 +-
 drivers/input/mouse/pxa930_trkball.c               |    2 +-
 drivers/input/touchscreen/s3c2410_ts.c             |    2 +-
 drivers/leds/leds-netxbig.c                        |    2 +-
 drivers/leds/leds-ns2.c                            |    2 +-
 drivers/leds/leds-s3c24xx.c                        |    2 +-
 drivers/media/video/davinci/vpbe_venc.c            |    2 +-
 drivers/media/video/mx1_camera.c                   |    2 +-
 drivers/media/video/mx2_camera.c                   |    2 +-
 drivers/media/video/mx3_camera.c                   |    4 +-
 drivers/media/video/pxa_camera.c                   |    2 +-
 drivers/media/video/s5p-fimc/mipi-csis.c           |    2 +-
 drivers/mfd/mcp-sa11x0.c                           |    2 +-
 drivers/mmc/host/davinci_mmc.c                     |    2 +-
 drivers/mmc/host/msm_sdcc.c                        |    2 +-
 drivers/mmc/host/mvsdio.c                          |    2 +-
 drivers/mmc/host/mxcmmc.c                          |    4 +-
 drivers/mmc/host/pxamci.c                          |    2 +-
 drivers/mmc/host/s3cmci.c                          |    2 +-
 drivers/mmc/host/sdhci-esdhc-imx.c                 |    2 +-
 drivers/mmc/host/sdhci-tegra.c                     |    2 +-
 drivers/mtd/nand/davinci_nand.c                    |    4 +-
 drivers/mtd/nand/mxc_nand.c                        |    2 +-
 drivers/mtd/nand/nomadik_nand.c                    |    2 +-
 drivers/mtd/nand/omap2.c                           |    2 +-
 drivers/mtd/nand/orion_nand.c                      |    2 +-
 drivers/mtd/nand/pxa3xx_nand.c                     |    2 +-
 drivers/mtd/nand/s3c2410.c                         |    2 +-
 drivers/mtd/onenand/omap2.c                        |    2 +-
 drivers/net/ethernet/netx-eth.c                    |    2 +-
 drivers/net/irda/pxaficp_ir.c                      |    2 +-
 drivers/pcmcia/pxa2xx_viper.c                      |    2 +-
 drivers/pinctrl/pinctrl-coh901.c                   |    2 +-
 drivers/remoteproc/omap_remoteproc.c               |    2 +-
 drivers/spi/spi-davinci.c                          |    2 +-
 drivers/spi/spi-ep93xx.c                           |    4 +-
 drivers/spi/spi-imx.c                              |    2 +-
 drivers/spi/spi-nuc900.c                           |    2 +-
 drivers/spi/spi-omap2-mcspi.c                      |    2 +-
 drivers/spi/spi-s3c64xx.c                          |    2 +-
 drivers/staging/tidspbridge/core/dsp-clock.c       |    2 +-
 drivers/staging/tidspbridge/core/tiomap3430.c      |    2 +-
 drivers/staging/tidspbridge/core/tiomap3430_pwr.c  |    2 +-
 drivers/staging/tidspbridge/core/tiomap_io.c       |    2 +-
 drivers/staging/tidspbridge/rmgr/drv_interface.c   |    2 +-
 drivers/tty/serial/imx.c                           |    2 +-
 drivers/usb/gadget/imx_udc.c                       |    2 +-
 drivers/usb/gadget/s3c2410_udc.c                   |    2 +-
 drivers/usb/host/ehci-mxc.c                        |    2 +-
 drivers/usb/host/ehci-orion.c                      |    2 +-
 drivers/usb/host/ehci-s5p.c                        |    2 +-
 drivers/usb/host/imx21-hcd.h                       |    2 +-
 drivers/usb/host/ohci-da8xx.c                      |    2 +-
 drivers/usb/host/ohci-exynos.c                     |    2 +-
 drivers/usb/host/ohci-pxa27x.c                     |    4 +-
 drivers/usb/host/ohci-s3c2410.c                    |    2 +-
 drivers/usb/musb/da8xx.c                           |    2 +-
 drivers/usb/musb/ux500_dma.c                       |    2 +-
 drivers/video/ep93xx-fb.c                          |    2 +-
 drivers/video/imxfb.c                              |    2 +-
 drivers/video/msm/mddi.c                           |    2 +-
 drivers/video/msm/mddi_client_dummy.c              |    2 +-
 drivers/video/msm/mddi_client_nt35399.c            |    2 +-
 drivers/video/msm/mddi_client_toshiba.c            |    2 +-
 drivers/video/msm/mdp.c                            |    2 +-
 drivers/video/msm/mdp_hw.h                         |    2 +-
 drivers/video/msm/mdp_ppp.c                        |    2 +-
 drivers/video/msm/msm_fb.c                         |    2 +-
 drivers/video/mx3fb.c                              |    4 +-
 drivers/video/nuc900fb.c                           |    2 +-
 drivers/video/nuc900fb.h                           |    2 +-
 drivers/video/omap/lcd_mipid.c                     |    2 +-
 drivers/video/pxafb.c                              |    2 +-
 drivers/video/vt8500lcdfb.c                        |    2 +-
 drivers/video/wm8505fb.c                           |    2 +-
 include/linux/platform_data/asoc-davinci-evm.h     |  137 +++++++++++++++
 include/linux/platform_data/asoc-imx-ssi.h         |   21 +++
 include/linux/platform_data/asoc-kirkwood.h        |    7 +
 include/linux/platform_data/asoc-palm27x.h         |    8 +
 include/linux/platform_data/asoc-s3c.h             |   59 +++++++
 include/linux/platform_data/asoc-s3c24xx_simtec.h  |   34 ++++
 include/linux/platform_data/asoc-tegra_wm8903.h    |   23 +++
 include/linux/platform_data/ata-pxa.h              |   33 ++++
 include/linux/platform_data/ata-samsung_cf.h       |   36 ++++
 include/linux/platform_data/atmel-aes.h            |    2 +-
 include/linux/platform_data/camera-mx1.h           |   35 ++++
 include/linux/platform_data/camera-mx2.h           |   46 +++++
 include/linux/platform_data/camera-mx3.h           |   48 ++++++
 include/linux/platform_data/camera-pxa.h           |   44 +++++
 include/linux/platform_data/crypto-ux500.h         |   22 +++
 include/linux/platform_data/dma-atmel.h            |   61 +++++++
 include/linux/platform_data/dma-ep93xx.h           |   93 +++++++++++
 include/linux/platform_data/dma-imx-sdma.h         |   59 +++++++
 include/linux/platform_data/dma-imx.h              |   67 ++++++++
 include/linux/platform_data/dma-mmp_tdma.h         |   35 ++++
 include/linux/platform_data/dma-mv_xor.h           |   24 +++
 include/linux/platform_data/dsp-mcbsp.h            |   62 +++++++
 include/linux/platform_data/dsp-omap.h             |   34 ++++
 include/linux/platform_data/eth-netx.h             |   27 +++
 include/linux/platform_data/hwmon-s3c.h            |   51 ++++++
 include/linux/platform_data/i2c-davinci.h          |   26 +++
 include/linux/platform_data/i2c-imx.h              |   21 +++
 include/linux/platform_data/i2c-nuc900.h           |    9 +
 include/linux/platform_data/i2c-s3c2410.h          |   77 +++++++++
 include/linux/platform_data/irda-pxaficp.h         |   25 +++
 .../linux/platform_data/keyboard-pxa930_rotary.h   |   20 +++
 include/linux/platform_data/keyboard-spear.h       |  164 ++++++++++++++++++
 include/linux/platform_data/keyboard-tegra-kbc.h   |   62 +++++++
 include/linux/platform_data/keypad-ep93xx.h        |   35 ++++
 include/linux/platform_data/keypad-nomadik-ske.h   |   50 ++++++
 include/linux/platform_data/keypad-omap.h          |   52 ++++++
 include/linux/platform_data/keypad-pxa27x.h        |   73 ++++++++
 include/linux/platform_data/keypad-w90p910.h       |   15 ++
 include/linux/platform_data/keyscan-davinci.h      |   42 +++++
 include/linux/platform_data/lcd-mipid.h            |   29 ++++
 .../linux/platform_data/leds-kirkwood-netxbig.h    |   55 ++++++
 include/linux/platform_data/leds-kirkwood-ns2.h    |   26 +++
 include/linux/platform_data/leds-s3c24xx.h         |   28 ++++
 include/linux/platform_data/mfd-mcp-sa11x0.h       |   22 +++
 include/linux/platform_data/mipi-csis.h            |   43 +++++
 include/linux/platform_data/mmc-davinci.h          |   39 +++++
 include/linux/platform_data/mmc-esdhc-imx.h        |   43 +++++
 include/linux/platform_data/mmc-msm_sdcc.h         |   30 ++++
 include/linux/platform_data/mmc-mvsdio.h           |   20 +++
 include/linux/platform_data/mmc-mxcmmc.h           |   39 +++++
 include/linux/platform_data/mmc-pxamci.h           |   28 ++++
 include/linux/platform_data/mmc-s3cmci.h           |   52 ++++++
 include/linux/platform_data/mmc-sdhci-tegra.h      |   30 ++++
 include/linux/platform_data/mouse-pxa930_trkball.h |   10 ++
 include/linux/platform_data/mtd-davinci-aemif.h    |   36 ++++
 include/linux/platform_data/mtd-davinci.h          |   90 ++++++++++
 include/linux/platform_data/mtd-mxc_nand.h         |   32 ++++
 include/linux/platform_data/mtd-nand-omap2.h       |   44 +++++
 include/linux/platform_data/mtd-nand-pxa3xx.h      |   79 +++++++++
 include/linux/platform_data/mtd-nand-s3c2410.h     |   67 ++++++++
 include/linux/platform_data/mtd-nomadik-nand.h     |   16 ++
 include/linux/platform_data/mtd-onenand-omap2.h    |   53 ++++++
 include/linux/platform_data/mtd-orion_nand.h       |   26 +++
 include/linux/platform_data/pcmcia-pxa2xx_viper.h  |   11 ++
 include/linux/platform_data/pinctrl-coh901.h       |   37 +++++
 include/linux/platform_data/remoteproc-omap.h      |   57 +++++++
 include/linux/platform_data/serial-imx.h           |   35 ++++
 include/linux/platform_data/smartreflex-omap.h     |   39 +++++
 include/linux/platform_data/spi-davinci.h          |   89 ++++++++++
 include/linux/platform_data/spi-ep93xx.h           |   29 ++++
 include/linux/platform_data/spi-imx.h              |   27 +++
 include/linux/platform_data/spi-nuc900.h           |   35 ++++
 include/linux/platform_data/spi-omap2-mcspi.h      |   23 +++
 include/linux/platform_data/spi-s3c64xx.h          |   68 ++++++++
 include/linux/platform_data/touchscreen-s3c2410.h  |   25 +++
 include/linux/platform_data/usb-davinci.h          |   59 +++++++
 include/linux/platform_data/usb-ehci-mxc.h         |   59 +++++++
 include/linux/platform_data/usb-ehci-orion.h       |   26 +++
 include/linux/platform_data/usb-ehci-s5p.h         |   21 +++
 include/linux/platform_data/usb-exynos.h           |   21 +++
 include/linux/platform_data/usb-imx_udc.h          |   23 +++
 include/linux/platform_data/usb-musb-ux500.h       |   25 +++
 include/linux/platform_data/usb-mx2.h              |   38 +++++
 include/linux/platform_data/usb-ohci-pxa27x.h      |   36 ++++
 include/linux/platform_data/usb-ohci-s3c2410.h     |   43 +++++
 include/linux/platform_data/usb-pxa3xx-ulpi.h      |   35 ++++
 include/linux/platform_data/usb-s3c2410_udc.h      |   44 +++++
 include/linux/platform_data/video-ep93xx.h         |   56 +++++++
 include/linux/platform_data/video-imxfb.h          |   84 ++++++++++
 include/linux/platform_data/video-msm_fb.h         |  147 ++++++++++++++++
 include/linux/platform_data/video-mx3fb.h          |   53 ++++++
 include/linux/platform_data/video-nuc900fb.h       |   83 ++++++++++
 include/linux/platform_data/video-pxafb.h          |  175 ++++++++++++++++++++
 include/linux/platform_data/video-vt8500lcdfb.h    |   31 ++++
 include/linux/power/smartreflex.h                  |    2 +-
 sound/soc/davinci/davinci-evm.c                    |    2 +-
 sound/soc/davinci/davinci-i2s.c                    |    2 +-
 sound/soc/davinci/davinci-mcasp.h                  |    2 +-
 sound/soc/davinci/davinci-pcm.h                    |    2 +-
 sound/soc/ep93xx/ep93xx-ac97.c                     |    2 +-
 sound/soc/ep93xx/ep93xx-i2s.c                      |    2 +-
 sound/soc/ep93xx/ep93xx-pcm.c                      |    2 +-
 sound/soc/fsl/imx-pcm-dma.c                        |    2 +-
 sound/soc/fsl/imx-pcm-fiq.c                        |    2 +-
 sound/soc/fsl/imx-ssi.c                            |    2 +-
 sound/soc/fsl/imx-ssi.h                            |    2 +-
 sound/soc/kirkwood/kirkwood-i2s.c                  |    2 +-
 sound/soc/kirkwood/kirkwood-openrd.c               |    2 +-
 sound/soc/kirkwood/kirkwood-t5325.c                |    2 +-
 sound/soc/omap/am3517evm.c                         |    2 +-
 sound/soc/omap/ams-delta.c                         |    2 +-
 sound/soc/omap/igep0020.c                          |    2 +-
 sound/soc/omap/mcbsp.c                             |    2 +-
 sound/soc/omap/n810.c                              |    2 +-
 sound/soc/omap/omap-mcbsp.c                        |    2 +-
 sound/soc/omap/omap3beagle.c                       |    2 +-
 sound/soc/omap/omap3evm.c                          |    2 +-
 sound/soc/omap/omap3pandora.c                      |    2 +-
 sound/soc/omap/osk5912.c                           |    2 +-
 sound/soc/omap/overo.c                             |    2 +-
 sound/soc/omap/rx51.c                              |    2 +-
 sound/soc/omap/sdp3430.c                           |    2 +-
 sound/soc/omap/zoom2.c                             |    2 +-
 sound/soc/pxa/palm27x.c                            |    2 +-
 sound/soc/samsung/ac97.c                           |    2 +-
 sound/soc/samsung/i2s.c                            |    2 +-
 sound/soc/samsung/pcm.c                            |    2 +-
 sound/soc/samsung/s3c24xx_simtec.c                 |    2 +-
 sound/soc/samsung/spdif.c                          |    2 +-
 sound/soc/tegra/tegra_wm8903.c                     |    2 +-
 587 files changed, 4882 insertions(+), 4882 deletions(-)
 delete mode 100644 arch/arm/mach-at91/include/mach/at_hdmac.h
 delete mode 100644 arch/arm/mach-davinci/include/mach/aemif.h
 delete mode 100644 arch/arm/mach-davinci/include/mach/asp.h
 delete mode 100644 arch/arm/mach-davinci/include/mach/i2c.h
 delete mode 100644 arch/arm/mach-davinci/include/mach/keyscan.h
 delete mode 100644 arch/arm/mach-davinci/include/mach/mmc.h
 delete mode 100644 arch/arm/mach-davinci/include/mach/nand.h
 delete mode 100644 arch/arm/mach-davinci/include/mach/spi.h
 delete mode 100644 arch/arm/mach-davinci/include/mach/usb.h
 delete mode 100644 arch/arm/mach-ep93xx/include/mach/dma.h
 delete mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h
 delete mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
 delete mode 100644 arch/arm/mach-ep93xx/include/mach/fb.h
 delete mode 100644 arch/arm/mach-exynos/include/mach/ohci.h
 delete mode 100644 arch/arm/mach-kirkwood/include/mach/leds-netxbig.h
 delete mode 100644 arch/arm/mach-kirkwood/include/mach/leds-ns2.h
 delete mode 100644 arch/arm/mach-mmp/include/mach/sram.h
 delete mode 100644 arch/arm/mach-msm/include/mach/mmc.h
 delete mode 100644 arch/arm/mach-msm/include/mach/msm_fb.h
 delete mode 100644 arch/arm/mach-netx/include/mach/eth.h
 delete mode 100644 arch/arm/mach-nomadik/include/mach/nand.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/arcom-pcmcia.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/camera.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/irda.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/mmc.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/ohci.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/palmasoc.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/pata_pxa.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/pxa930_rotary.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/pxa930_trkball.h
 delete mode 100644 arch/arm/mach-pxa/include/mach/pxafb.h
 delete mode 100644 arch/arm/mach-s3c24xx/include/mach/leds-gpio.h
 delete mode 100644 arch/arm/mach-sa1100/include/mach/mcp.h
 delete mode 100644 arch/arm/mach-tegra/include/mach/kbc.h
 delete mode 100644 arch/arm/mach-tegra/include/mach/sdhci.h
 delete mode 100644 arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
 delete mode 100644 arch/arm/mach-u300/include/mach/gpio-u300.h
 delete mode 100644 arch/arm/mach-ux500/include/mach/crypto-ux500.h
 delete mode 100644 arch/arm/mach-ux500/include/mach/usb.h
 delete mode 100644 arch/arm/mach-vt8500/include/mach/vt8500fb.h
 delete mode 100644 arch/arm/mach-w90x900/include/mach/fb.h
 delete mode 100644 arch/arm/mach-w90x900/include/mach/i2c.h
 delete mode 100644 arch/arm/mach-w90x900/include/mach/nuc900_spi.h
 delete mode 100644 arch/arm/mach-w90x900/include/mach/w90p910_keypad.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/dma.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/esdhc.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/i2c.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/imx-uart.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/imxfb.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/mmc.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/mx1_camera.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/mx21-usbhost.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/mx2_cam.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/mx3_camera.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/mx3fb.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/mxc_ehci.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/mxc_nand.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/sdma.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/spi.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/ssi.h
 delete mode 100644 arch/arm/plat-mxc/include/mach/usb.h
 delete mode 100644 arch/arm/plat-nomadik/include/plat/ske.h
 delete mode 100644 arch/arm/plat-omap/include/plat/dsp.h
 delete mode 100644 arch/arm/plat-omap/include/plat/keypad.h
 delete mode 100644 arch/arm/plat-omap/include/plat/lcd_mipid.h
 delete mode 100644 arch/arm/plat-omap/include/plat/mcbsp.h
 delete mode 100644 arch/arm/plat-omap/include/plat/mcspi.h
 delete mode 100644 arch/arm/plat-omap/include/plat/nand.h
 delete mode 100644 arch/arm/plat-omap/include/plat/onenand.h
 delete mode 100644 arch/arm/plat-omap/include/plat/remoteproc.h
 delete mode 100644 arch/arm/plat-omap/include/plat/voltage.h
 delete mode 100644 arch/arm/plat-orion/include/plat/audio.h
 delete mode 100644 arch/arm/plat-orion/include/plat/ehci-orion.h
 delete mode 100644 arch/arm/plat-orion/include/plat/mv_xor.h
 delete mode 100644 arch/arm/plat-orion/include/plat/mvsdio.h
 delete mode 100644 arch/arm/plat-orion/include/plat/orion_nand.h
 delete mode 100644 arch/arm/plat-pxa/include/plat/pxa27x_keypad.h
 delete mode 100644 arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/ata.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/audio-simtec.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/audio.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/ehci.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/hwmon.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/iic.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/mci.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/mipi_csis.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/nand.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/ts.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/udc.h
 delete mode 100644 arch/arm/plat-samsung/include/plat/usb-control.h
 delete mode 100644 arch/arm/plat-spear/include/plat/keyboard.h
 create mode 100644 include/linux/platform_data/asoc-davinci-evm.h
 create mode 100644 include/linux/platform_data/asoc-imx-ssi.h
 create mode 100644 include/linux/platform_data/asoc-kirkwood.h
 create mode 100644 include/linux/platform_data/asoc-palm27x.h
 create mode 100644 include/linux/platform_data/asoc-s3c.h
 create mode 100644 include/linux/platform_data/asoc-s3c24xx_simtec.h
 create mode 100644 include/linux/platform_data/asoc-tegra_wm8903.h
 create mode 100644 include/linux/platform_data/ata-pxa.h
 create mode 100644 include/linux/platform_data/ata-samsung_cf.h
 create mode 100644 include/linux/platform_data/camera-mx1.h
 create mode 100644 include/linux/platform_data/camera-mx2.h
 create mode 100644 include/linux/platform_data/camera-mx3.h
 create mode 100644 include/linux/platform_data/camera-pxa.h
 create mode 100644 include/linux/platform_data/crypto-ux500.h
 create mode 100644 include/linux/platform_data/dma-atmel.h
 create mode 100644 include/linux/platform_data/dma-ep93xx.h
 create mode 100644 include/linux/platform_data/dma-imx-sdma.h
 create mode 100644 include/linux/platform_data/dma-imx.h
 create mode 100644 include/linux/platform_data/dma-mmp_tdma.h
 create mode 100644 include/linux/platform_data/dma-mv_xor.h
 create mode 100644 include/linux/platform_data/dsp-mcbsp.h
 create mode 100644 include/linux/platform_data/dsp-omap.h
 create mode 100644 include/linux/platform_data/eth-netx.h
 create mode 100644 include/linux/platform_data/hwmon-s3c.h
 create mode 100644 include/linux/platform_data/i2c-davinci.h
 create mode 100644 include/linux/platform_data/i2c-imx.h
 create mode 100644 include/linux/platform_data/i2c-nuc900.h
 create mode 100644 include/linux/platform_data/i2c-s3c2410.h
 create mode 100644 include/linux/platform_data/irda-pxaficp.h
 create mode 100644 include/linux/platform_data/keyboard-pxa930_rotary.h
 create mode 100644 include/linux/platform_data/keyboard-spear.h
 create mode 100644 include/linux/platform_data/keyboard-tegra-kbc.h
 create mode 100644 include/linux/platform_data/keypad-ep93xx.h
 create mode 100644 include/linux/platform_data/keypad-nomadik-ske.h
 create mode 100644 include/linux/platform_data/keypad-omap.h
 create mode 100644 include/linux/platform_data/keypad-pxa27x.h
 create mode 100644 include/linux/platform_data/keypad-w90p910.h
 create mode 100644 include/linux/platform_data/keyscan-davinci.h
 create mode 100644 include/linux/platform_data/lcd-mipid.h
 create mode 100644 include/linux/platform_data/leds-kirkwood-netxbig.h
 create mode 100644 include/linux/platform_data/leds-kirkwood-ns2.h
 create mode 100644 include/linux/platform_data/leds-s3c24xx.h
 create mode 100644 include/linux/platform_data/mfd-mcp-sa11x0.h
 create mode 100644 include/linux/platform_data/mipi-csis.h
 create mode 100644 include/linux/platform_data/mmc-davinci.h
 create mode 100644 include/linux/platform_data/mmc-esdhc-imx.h
 create mode 100644 include/linux/platform_data/mmc-msm_sdcc.h
 create mode 100644 include/linux/platform_data/mmc-mvsdio.h
 create mode 100644 include/linux/platform_data/mmc-mxcmmc.h
 create mode 100644 include/linux/platform_data/mmc-pxamci.h
 create mode 100644 include/linux/platform_data/mmc-s3cmci.h
 create mode 100644 include/linux/platform_data/mmc-sdhci-tegra.h
 create mode 100644 include/linux/platform_data/mouse-pxa930_trkball.h
 create mode 100644 include/linux/platform_data/mtd-davinci-aemif.h
 create mode 100644 include/linux/platform_data/mtd-davinci.h
 create mode 100644 include/linux/platform_data/mtd-mxc_nand.h
 create mode 100644 include/linux/platform_data/mtd-nand-omap2.h
 create mode 100644 include/linux/platform_data/mtd-nand-pxa3xx.h
 create mode 100644 include/linux/platform_data/mtd-nand-s3c2410.h
 create mode 100644 include/linux/platform_data/mtd-nomadik-nand.h
 create mode 100644 include/linux/platform_data/mtd-onenand-omap2.h
 create mode 100644 include/linux/platform_data/mtd-orion_nand.h
 create mode 100644 include/linux/platform_data/pcmcia-pxa2xx_viper.h
 create mode 100644 include/linux/platform_data/pinctrl-coh901.h
 create mode 100644 include/linux/platform_data/remoteproc-omap.h
 create mode 100644 include/linux/platform_data/serial-imx.h
 create mode 100644 include/linux/platform_data/smartreflex-omap.h
 create mode 100644 include/linux/platform_data/spi-davinci.h
 create mode 100644 include/linux/platform_data/spi-ep93xx.h
 create mode 100644 include/linux/platform_data/spi-imx.h
 create mode 100644 include/linux/platform_data/spi-nuc900.h
 create mode 100644 include/linux/platform_data/spi-omap2-mcspi.h
 create mode 100644 include/linux/platform_data/spi-s3c64xx.h
 create mode 100644 include/linux/platform_data/touchscreen-s3c2410.h
 create mode 100644 include/linux/platform_data/usb-davinci.h
 create mode 100644 include/linux/platform_data/usb-ehci-mxc.h
 create mode 100644 include/linux/platform_data/usb-ehci-orion.h
 create mode 100644 include/linux/platform_data/usb-ehci-s5p.h
 create mode 100644 include/linux/platform_data/usb-exynos.h
 create mode 100644 include/linux/platform_data/usb-imx_udc.h
 create mode 100644 include/linux/platform_data/usb-musb-ux500.h
 create mode 100644 include/linux/platform_data/usb-mx2.h
 create mode 100644 include/linux/platform_data/usb-ohci-pxa27x.h
 create mode 100644 include/linux/platform_data/usb-ohci-s3c2410.h
 create mode 100644 include/linux/platform_data/usb-pxa3xx-ulpi.h
 create mode 100644 include/linux/platform_data/usb-s3c2410_udc.h
 create mode 100644 include/linux/platform_data/video-ep93xx.h
 create mode 100644 include/linux/platform_data/video-imxfb.h
 create mode 100644 include/linux/platform_data/video-msm_fb.h
 create mode 100644 include/linux/platform_data/video-mx3fb.h
 create mode 100644 include/linux/platform_data/video-nuc900fb.h
 create mode 100644 include/linux/platform_data/video-pxafb.h
 create mode 100644 include/linux/platform_data/video-vt8500lcdfb.h

Cc: netdev@vger.kernel.org
Cc: openezx-devel@lists.openezx.org
Cc: spear-devel@list.st.com
Cc: davinci-linux-open-source@linux.davincidsp.com
Cc: linux-arm-msm@vger.kernel.org
Cc: linux-omap@vger.kernel.org
Cc: linux-samsung-soc@vger.kernel.org
Cc: linux-tegra@vger.kernel.org
Bcc: "Ben Dooks" <ben-linux@fluff.org>
Bcc: "Benoît Cousson" <b-cousson@ti.com>
Bcc: "David S. Miller" <davem@davemloft.net>
Bcc: "Wolfram Sang" <w.sang@pengutronix.de>
Bcc: Alan Cox <alan@linux.intel.com>
Bcc: Alan Stern <stern@rowland.harvard.edu>
Bcc: Alessandro Rubini <rubini@unipv.it>
Bcc: Andreas Westin <andreas.westin@stericsson.com>
Bcc: Andrew Lunn <andrew@lunn.ch>
Bcc: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Bcc: Axel Lin <axel.lin@gmail.com>
Bcc: Ben Dooks <ben-linux@fluff.org>
Bcc: Bryan Huntsman <bryanh@codeaurora.org>
Bcc: Bryan Wu <bryan.wu@canonical.com>
Bcc: Chris Ball <cjb@laptop.org>
Bcc: Colin Cross <ccross@android.com>
Bcc: Dan Williams <djbw@fb.com>
Bcc: Daniel Ribeiro <drwyrm@gmail.com>
Bcc: Daniel Walker <dwalker@fifo99.com>
Bcc: David Brown <davidb@codeaurora.org>
Bcc: David Woodhouse <dwmw2@infradead.org>
Bcc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Bcc: Eric Miao <eric.y.miao@gmail.com>
Bcc: Felipe Balbi <balbi@ti.com>
Bcc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Bcc: Grant Likely <grant.likely@secretlab.ca>
Bcc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Bcc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Bcc: Guenter Roeck <linux@roeck-us.net>
Bcc: Haojian Zhuang <haojian.zhuang@gmail.com>
Bcc: Harald Welte <laforge@openezx.org>
Bcc: Hartley Sweeten <hsweeten@visionengravers.com>
Bcc: Herbert Xu <herbert@gondor.apana.org.au>
Bcc: J Keerthy <j-keerthy@ti.com>
Bcc: Jarkko Nikula <jarkko.nikula@bitmer.com>
Bcc: Jaroslav Kysela <perex@perex.cz>
Bcc: Jason Cooper <jason@lakedaemon.net>
Bcc: Javier Martin <javier.martin@vista-silicon.com>
Bcc: Jean Pihet <j-pihet@ti.com>
Bcc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
Bcc: Jeff Garzik <jgarzik@pobox.com>
Bcc: Jochen Friedrich <jochen@scram.de>
Bcc: Jonathan Cameron <jic23@cam.ac.uk>
Bcc: Kevin Hilman <khilman@ti.com>
Bcc: Kukjin Kim <kgene.kim@samsung.com>
Bcc: Kyungmin Park <kyungmin.park@samsung.com>
Bcc: Liam Girdwood <lrg@ti.com>
Bcc: Linus Walleij <linus.walleij@linaro.org>
Bcc: Marek Vasut <marek.vasut@gmail.com>
Bcc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Bcc: Mauro Carvalho Chehab <mchehab@infradead.org>
Bcc: Mika Westerberg <mika.westerberg@iki.fi>
Bcc: Nicolas Ferre <nicolas.ferre@atmel.com>
Bcc: Nicolas Pitre <nico@fluxnic.net>
Bcc: Ohad Ben-Cohen <ohad@wizery.com>
Bcc: Olof Johansson <olof@lixom.net>
Bcc: Omar Ramirez Luna <omar.ramirez@ti.com>
Bcc: Paul Parsons <lost.distance@yahoo.com>
Bcc: Peter Ujfalusi <peter.ujfalusi@ti.com>
Bcc: Philipp Zabel <philipp.zabel@gmail.com>
Bcc: Richard Purdie <rpurdie@rpsys.net>
Bcc: Robert Jarzmik <robert.jarzmik@free.fr>
Bcc: Russell King <linux@arm.linux.org.uk>
Bcc: Ryan Mallon <rmallon@gmail.com>
Bcc: STEricsson <STEricsson_nomadik_linux@list.st.com>
Bcc: Samuel Ortiz <samuel@sortiz.org>
Bcc: Sangbeom Kim <sbkim73@samsung.com>
Bcc: Sascha Hauer <s.hauer@pengutronix.de>
Bcc: Sekhar Nori <nsekhar@ti.com>
Bcc: Sergey Lapin <slapin@ossfans.org>
Bcc: Shawn Guo <shawn.guo@linaro.org>
Bcc: Shiraz Hashim <shiraz.hashim@st.com>
Bcc: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
Bcc: Stefan Schmidt <stefan@openezx.org>
Bcc: Stephen Warren <swarren@wwwdotorg.org>
Bcc: Sylwester Nawrocki <s.nawrocki@samsung.com>
Bcc: Takashi Iwai <tiwai@suse.de>
Bcc: Tomas Cech <sleep_walker@suse.cz>
Bcc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Bcc: Tony Lindgren <tony@atomide.com>
Bcc: Tony Prisk <linux@prisktech.co.nz>
Bcc: Vinod Koul <vinod.koul@intel.com>
Bcc: Viresh Kumar <viresh.linux@gmail.com>
Bcc: Wan ZongShun <mcuos.com@gmail.com>

^ permalink raw reply

* Re: IPv6 multipath routes
From: Ulrich Weber @ 2012-09-11 12:57 UTC (permalink / raw)
  To: Vincent Bernat; +Cc: netdev
In-Reply-To: <1346952649-5716-1-git-send-email-bernat@luffy.cx>

Hi Vincent,

there is no multipath support for IPv6 in the kernel.
RTA_MULTIPATH attributes are not parsed for IPv6.

Cheers
  Ulrich

On 09/06/2012 07:30 PM, Vincent Bernat wrote:
> Hi!
>
> It appears that "ip -6 route add" expects IPv4 addresses with nexthop directives:
>
> $ ip -6 route add to 2a01:c9c0:a1:982::/64 proto bird \
>     nexthop via fe80::ea39:35ff:febd:f9e dev bai2.2008 weight 1 \
>     nexthop via fe80::ea39:35ff:febd:fd6 dev bai1.2009 weight 1
> Error: an IP address is expected rather than "fe80::ea39:35ff:febd:f9e"
>
> The following patch fix this problem. However, it does not work. I now have:
>   RTNETLINK answers: No such device
>
> I have little knowledge of netlink so it is likely that my patch is
> buggy. However, I have found this problem by trying to debug what
> appears to be a valid netlink message refused by the kernel with the
> same error. Therefore, I suspect that there is also a bug in the kernel.
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox