Netdev List
 help / color / mirror / Atom feed
* [net-next PATCH] amd-xgbe: use __maybe_unused to hide pm functions
From: Arnd Bergmann @ 2016-11-08 13:37 UTC (permalink / raw)
  To: Tom Lendacky; +Cc: Arnd Bergmann, David S. Miller, netdev, linux-kernel

The amd-xgbe ethernet driver hides its suspend/resume functions
in #ifdef CONFIG_PM, but uses SIMPLE_DEV_PM_OPS() to make the
reference conditional on CONFIG_PM_SLEEP, which results in a
warning when PM_SLEEP is not set but PM is:

drivers/net/ethernet/amd/xgbe/xgbe-platform.c:553:12: error: 'xgbe_platform_resume' defined but not used [-Werror=unused-function]
drivers/net/ethernet/amd/xgbe/xgbe-platform.c:533:12: error: 'xgbe_platform_suspend' defined but not used [-Werror=unused-function]

This removes the incorrect #ifdef and instead uses a __maybe_unused
annotation to let the compiler know it can silently drop
the function definition.

Fixes: bd8255d8ba35 ("amd-xgbe: Prepare for supporting PCI devices")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
I originally submitted this when in March 2016, but the patch has not
yet made it upstream, and the file contents have moved around so
the old patch no longer applied so I'm resending the rebased version
now.
---
 drivers/net/ethernet/amd/xgbe/xgbe-platform.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-platform.c b/drivers/net/ethernet/amd/xgbe/xgbe-platform.c
index 0edbcd523f8f..02daca817bb7 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-platform.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-platform.c
@@ -529,8 +529,7 @@ static int xgbe_platform_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int xgbe_platform_suspend(struct device *dev)
+static int __maybe_unused xgbe_platform_suspend(struct device *dev)
 {
 	struct xgbe_prv_data *pdata = dev_get_drvdata(dev);
 	struct net_device *netdev = pdata->netdev;
@@ -550,7 +549,7 @@ static int xgbe_platform_suspend(struct device *dev)
 	return ret;
 }
 
-static int xgbe_platform_resume(struct device *dev)
+static int __maybe_unused xgbe_platform_resume(struct device *dev)
 {
 	struct xgbe_prv_data *pdata = dev_get_drvdata(dev);
 	struct net_device *netdev = pdata->netdev;
@@ -574,7 +573,6 @@ static int xgbe_platform_resume(struct device *dev)
 
 	return ret;
 }
-#endif /* CONFIG_PM */
 
 static const struct xgbe_version_data xgbe_v1 = {
 	.init_function_ptrs_phy_impl	= xgbe_init_function_ptrs_phy_v1,
-- 
2.9.0

^ permalink raw reply related

* Re: [PATCH] net: mii: report 0 for unknown lp_advertising
From: Arnd Bergmann @ 2016-11-08 13:37 UTC (permalink / raw)
  To: David S. Miller; +Cc: Philippe Reynes, netdev, linux-kernel
In-Reply-To: <20161108133232.1571441-1-arnd@arndb.de>

On Tuesday, November 8, 2016 2:31:38 PM CET Arnd Bergmann wrote:
> The newly introduced mii_ethtool_get_link_ksettings function sets
> lp_advertising to an uninitialized value when BMCR_ANENABLE is not
> set:
> 
> drivers/net/mii.c: In function 'mii_ethtool_get_link_ksettings':
> drivers/net/mii.c:224:2: error: 'lp_advertising' may be used uninitialized in this function [-Werror=maybe-uninitialized]
> 
> As documented in include/uapi/linux/ethtool.h, the value is
> expected to be zero when we don't know it, so let's initialize
> it to that.
> 
> Fixes: bc8ee596afe8 ("net: mii: add generic function to support ksetting support")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

In case there was any doubt: the patch causing this is currently in net-next
and has just shown up in linux-next.

	Arnd

^ permalink raw reply

* [Xen PATCH] xen-netback: fix error handling output
From: Arnd Bergmann @ 2016-11-08 13:34 UTC (permalink / raw)
  To: David Vrabel
  Cc: Juergen Gross, Filipe Manco, Arnd Bergmann, netdev, linux-kernel,
	Paul Durrant, xen-devel, Wei Liu, David S. Miller

The connect function prints an unintialized error code after an
earlier initialization was removed:

drivers/net/xen-netback/xenbus.c: In function 'connect':
drivers/net/xen-netback/xenbus.c:938:3: error: 'err' may be used uninitialized in this function [-Werror=maybe-uninitialized]

This prints it as -EINVAL instead, which seems to be the most
appropriate error code. Before the patch that caused the warning,
this would print a positive number returned by vsscanf() instead,
which is also wrong. We probably don't need a backport though,
as fixing the warning here should be sufficient.

Fixes: f95842e7a9f2 ("xen: make use of xenbus_read_unsigned() in xen-netback")
Fixes: 8d3d53b3e433 ("xen-netback: Add support for multiple queues")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/net/xen-netback/xenbus.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 7356e00fac54..bfed79877b8a 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -935,7 +935,7 @@ static void connect(struct backend_info *be)
 					"multi-queue-num-queues", 1);
 	if (requested_num_queues > xenvif_max_queues) {
 		/* buggy or malicious guest */
-		xenbus_dev_fatal(dev, err,
+		xenbus_dev_fatal(dev, -EINVAL,
 				 "guest requested %u queues, exceeding the maximum of %u.",
 				 requested_num_queues, xenvif_max_queues);
 		return;
-- 
2.9.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related

* [PATCH] net: mii: report 0 for unknown lp_advertising
From: Arnd Bergmann @ 2016-11-08 13:31 UTC (permalink / raw)
  To: David S. Miller, Philippe Reynes; +Cc: Arnd Bergmann, netdev, linux-kernel

The newly introduced mii_ethtool_get_link_ksettings function sets
lp_advertising to an uninitialized value when BMCR_ANENABLE is not
set:

drivers/net/mii.c: In function 'mii_ethtool_get_link_ksettings':
drivers/net/mii.c:224:2: error: 'lp_advertising' may be used uninitialized in this function [-Werror=maybe-uninitialized]

As documented in include/uapi/linux/ethtool.h, the value is
expected to be zero when we don't know it, so let's initialize
it to that.

Fixes: bc8ee596afe8 ("net: mii: add generic function to support ksetting support")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/net/mii.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index 0443546fc427..6d953c53eed6 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -213,6 +213,8 @@ int mii_ethtool_get_link_ksettings(struct mii_if_info *mii,
 				    SPEED_100 : SPEED_10));
 		cmd->base.duplex = (bmcr & BMCR_FULLDPLX) ?
 			DUPLEX_FULL : DUPLEX_HALF;
+
+		lp_advertising = 0;
 	}
 
 	mii->full_duplex = cmd->base.duplex;
-- 
2.9.0

^ permalink raw reply related

* [PATCH 2/2] [nf-next] netfilter: fix NF_REPEAT handling
From: Arnd Bergmann @ 2016-11-08 13:28 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: netfilter-devel, coreteam, netdev, Arnd Bergmann, Patrick McHardy,
	Jozsef Kadlecsik, David S. Miller, Florian Westphal, Eric Dumazet,
	linux-kernel
In-Reply-To: <20161108132914.1495283-1-arnd@arndb.de>

gcc correctly identified a theoretical uninitialized variable use:

net/netfilter/nf_conntrack_core.c: In function 'nf_conntrack_in':
net/netfilter/nf_conntrack_core.c:1125:14: error: 'l4proto' may be used uninitialized in this function [-Werror=maybe-uninitialized]

This could only happen when we 'goto out' before looking up l4proto,
and then enter the retry, implying that l3proto->get_l4proto()
returned NF_REPEAT. This does not currently get returned in any
code path and probably won't ever happen, but is not good to
rely on.

Moving the repeat handling up a little should have the same
behavior as today but avoids the warning by making that case
impossible to enter.

Fixes: 08733a0cb7de ("netfilter: handle NF_REPEAT from nf_conntrack_in()")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
The patch causing this is currently only in nf-next, and not yet
in net-next.
---
 net/netfilter/nf_conntrack_core.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index de4b8a75f30b..610c9de0ce18 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1337,6 +1337,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
 		NF_CT_STAT_INC_ATOMIC(net, invalid);
 		if (ret == -NF_DROP)
 			NF_CT_STAT_INC_ATOMIC(net, drop);
+		if (ret == -NF_REPEAT && tmpl)
+			goto repeat;
 		ret = -ret;
 		goto out;
 	}
@@ -1349,10 +1351,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
 		 * closed/aborted connection. We have to go back and create a
 		 * fresh conntrack.
 		 */
-		if (ret == NF_REPEAT)
-			goto repeat;
-		else
-			nf_ct_put(tmpl);
+		nf_ct_put(tmpl);
 	}
 
 	return ret;
-- 
2.9.0

^ permalink raw reply related

* [PATCH 1/2] [net-next] udp: provide udp{4,6}_lib_lookup for nf_socket_ipv{4,6}
From: Arnd Bergmann @ 2016-11-08 13:28 UTC (permalink / raw)
  To: David S. Miller
  Cc: netfilter-devel, coreteam, Pablo Neira Ayuso, netdev,
	Arnd Bergmann, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
	Patrick McHardy, Eric Dumazet, linux-kernel

Since commit ca065d0cf80f ("udp: no longer use SLAB_DESTROY_BY_RCU")
the udp6_lib_lookup and udp4_lib_lookup functions are only
provided when it is actually possible to call them.

However, moving the callers now caused a link error:

net/built-in.o: In function `nf_sk_lookup_slow_v6':
(.text+0x131a39): undefined reference to `udp6_lib_lookup'
net/ipv4/netfilter/nf_socket_ipv4.o: In function `nf_sk_lookup_slow_v4':
nf_socket_ipv4.c:(.text.nf_sk_lookup_slow_v4+0x114): undefined reference to `udp4_lib_lookup'

This extends the #ifdef so we also provide the functions when
CONFIG_NF_SOCKET_IPV4 or CONFIG_NF_SOCKET_IPV6, respectively
are set.

Fixes: 8db4c5be88f6 ("netfilter: move socket lookup infrastructure to nf_socket_ipv{4,6}.c")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
The build failure came from the netfilter tree but is now
present in net-next, so if the solution is correct, this
patch can be applied there.
---
 net/ipv4/udp.c | 3 ++-
 net/ipv6/udp.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 097b70628631..c827e4ea509e 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -580,7 +580,8 @@ EXPORT_SYMBOL_GPL(udp4_lib_lookup_skb);
  * Does increment socket refcount.
  */
 #if IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_SOCKET) || \
-    IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TPROXY)
+    IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TPROXY) || \
+    IS_ENABLED(CONFIG_NF_SOCKET_IPV4)
 struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
 			     __be32 daddr, __be16 dport, int dif)
 {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 5313818b7485..86a8cacd333b 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -302,7 +302,8 @@ EXPORT_SYMBOL_GPL(udp6_lib_lookup_skb);
  * Does increment socket refcount.
  */
 #if IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_SOCKET) || \
-    IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TPROXY)
+    IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TPROXY) || \
+    IS_ENABLED(CONFIG_NF_SOCKET_IPV6)
 struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport,
 			     const struct in6_addr *daddr, __be16 dport, int dif)
 {
-- 
2.9.0

^ permalink raw reply related

* [PATCH] net: ethernet: ti: davinci_cpdma: free memory while channel destroy
From: Ivan Khoronzhuk @ 2016-11-08 13:16 UTC (permalink / raw)
  To: mugunthanvnm, grygorii.strashko, netdev
  Cc: linux-omap, linux-kernel, Ivan Khoronzhuk

While create/destroy channel operation memory is not freed. It was
supposed that memory is freed while driver remove. But a channel
can be created and destroyed many times while changing number of
channels with ethtool.

Based on net-next/master

Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
 drivers/net/ethernet/ti/davinci_cpdma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 05afc05..07fc92d 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -586,7 +586,7 @@ int cpdma_chan_destroy(struct cpdma_chan *chan)
 		cpdma_chan_stop(chan);
 	ctlr->channels[chan->chan_num] = NULL;
 	ctlr->chan_num--;
-
+	devm_kfree(ctlr->dev, chan);
 	cpdma_chan_split_pool(ctlr);
 
 	spin_unlock_irqrestore(&ctlr->lock, flags);
-- 
1.9.1

^ permalink raw reply related

* [PATCH] net: ethernet: ti: davinci_cpdma: fix fixed prio cpdma ctlr configuration
From: Ivan Khoronzhuk @ 2016-11-08 13:10 UTC (permalink / raw)
  To: mugunthanvnm, grygorii.strashko, netdev
  Cc: linux-omap, linux-kernel, Ivan Khoronzhuk

The dma ctlr is reseted to 0 while cpdma start, thus cpdma ctlr
cannot be configured after cpdma is stopped. So, restore content
of cpdma ctlr while off/on procedure.

Based on net-next/master

Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
 drivers/net/ethernet/ti/cpsw.c          |   6 +-
 drivers/net/ethernet/ti/davinci_cpdma.c | 103 +++++++++++++++++---------------
 drivers/net/ethernet/ti/davinci_cpdma.h |   2 +
 3 files changed, 58 insertions(+), 53 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index b1ddf89..4d04b8e 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1376,10 +1376,6 @@ static int cpsw_ndo_open(struct net_device *ndev)
 				  ALE_ALL_PORTS, ALE_ALL_PORTS, 0, 0);
 
 	if (!cpsw_common_res_usage_state(cpsw)) {
-		/* setup tx dma to fixed prio and zero offset */
-		cpdma_control_set(cpsw->dma, CPDMA_TX_PRIO_FIXED, 1);
-		cpdma_control_set(cpsw->dma, CPDMA_RX_BUFFER_OFFSET, 0);
-
 		/* disable priority elevation */
 		__raw_writel(0, &cpsw->regs->ptype);
 
@@ -2710,6 +2706,8 @@ static int cpsw_probe(struct platform_device *pdev)
 	dma_params.desc_align		= 16;
 	dma_params.has_ext_regs		= true;
 	dma_params.desc_hw_addr         = dma_params.desc_mem_phys;
+	dma_params.rxbuf_offset		= 0;
+	dma_params.fixed_prio		= 1;
 
 	cpsw->dma = cpdma_ctlr_create(&dma_params);
 	if (!cpsw->dma) {
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index c3f35f1..05afc05 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -124,6 +124,29 @@ struct cpdma_chan {
 	int	int_set, int_clear, td;
 };
 
+struct cpdma_control_info {
+	u32		reg;
+	u32		shift, mask;
+	int		access;
+#define ACCESS_RO	BIT(0)
+#define ACCESS_WO	BIT(1)
+#define ACCESS_RW	(ACCESS_RO | ACCESS_WO)
+};
+
+static struct cpdma_control_info controls[] = {
+	[CPDMA_CMD_IDLE]	  = {CPDMA_DMACONTROL,	3,  1,      ACCESS_WO},
+	[CPDMA_COPY_ERROR_FRAMES] = {CPDMA_DMACONTROL,	4,  1,      ACCESS_RW},
+	[CPDMA_RX_OFF_LEN_UPDATE] = {CPDMA_DMACONTROL,	2,  1,      ACCESS_RW},
+	[CPDMA_RX_OWNERSHIP_FLIP] = {CPDMA_DMACONTROL,	1,  1,      ACCESS_RW},
+	[CPDMA_TX_PRIO_FIXED]	  = {CPDMA_DMACONTROL,	0,  1,      ACCESS_RW},
+	[CPDMA_STAT_IDLE]	  = {CPDMA_DMASTATUS,	31, 1,      ACCESS_RO},
+	[CPDMA_STAT_TX_ERR_CODE]  = {CPDMA_DMASTATUS,	20, 0xf,    ACCESS_RW},
+	[CPDMA_STAT_TX_ERR_CHAN]  = {CPDMA_DMASTATUS,	16, 0x7,    ACCESS_RW},
+	[CPDMA_STAT_RX_ERR_CODE]  = {CPDMA_DMASTATUS,	12, 0xf,    ACCESS_RW},
+	[CPDMA_STAT_RX_ERR_CHAN]  = {CPDMA_DMASTATUS,	8,  0x7,    ACCESS_RW},
+	[CPDMA_RX_BUFFER_OFFSET]  = {CPDMA_RXBUFFOFS,	0,  0xffff, ACCESS_RW},
+};
+
 #define tx_chan_num(chan)	(chan)
 #define rx_chan_num(chan)	((chan) + CPDMA_MAX_CHANNELS)
 #define is_rx_chan(chan)	((chan)->chan_num >= CPDMA_MAX_CHANNELS)
@@ -253,6 +276,31 @@ static void cpdma_desc_free(struct cpdma_desc_pool *pool,
 	gen_pool_free(pool->gen_pool, (unsigned long)desc, pool->desc_size);
 }
 
+static int _cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value)
+{
+	struct cpdma_control_info *info = &controls[control];
+	u32 val;
+
+	if (!ctlr->params.has_ext_regs)
+		return -ENOTSUPP;
+
+	if (ctlr->state != CPDMA_STATE_ACTIVE)
+		return -EINVAL;
+
+	if (control < 0 || control >= ARRAY_SIZE(controls))
+		return -ENOENT;
+
+	if ((info->access & ACCESS_WO) != ACCESS_WO)
+		return -EPERM;
+
+	val  = dma_reg_read(ctlr, info->reg);
+	val &= ~(info->mask << info->shift);
+	val |= (value & info->mask) << info->shift;
+	dma_reg_write(ctlr, info->reg, val);
+
+	return 0;
+}
+
 struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params)
 {
 	struct cpdma_ctlr *ctlr;
@@ -324,6 +372,11 @@ int cpdma_ctlr_start(struct cpdma_ctlr *ctlr)
 		if (ctlr->channels[i])
 			cpdma_chan_start(ctlr->channels[i]);
 	}
+
+	_cpdma_control_set(ctlr, CPDMA_TX_PRIO_FIXED, ctlr->params.fixed_prio);
+	_cpdma_control_set(ctlr, CPDMA_RX_BUFFER_OFFSET,
+			   ctlr->params.rxbuf_offset);
+
 	spin_unlock_irqrestore(&ctlr->lock, flags);
 	return 0;
 }
@@ -874,29 +927,6 @@ int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable)
 	return 0;
 }
 
-struct cpdma_control_info {
-	u32		reg;
-	u32		shift, mask;
-	int		access;
-#define ACCESS_RO	BIT(0)
-#define ACCESS_WO	BIT(1)
-#define ACCESS_RW	(ACCESS_RO | ACCESS_WO)
-};
-
-static struct cpdma_control_info controls[] = {
-	[CPDMA_CMD_IDLE]	  = {CPDMA_DMACONTROL,	3,  1,      ACCESS_WO},
-	[CPDMA_COPY_ERROR_FRAMES] = {CPDMA_DMACONTROL,	4,  1,      ACCESS_RW},
-	[CPDMA_RX_OFF_LEN_UPDATE] = {CPDMA_DMACONTROL,	2,  1,      ACCESS_RW},
-	[CPDMA_RX_OWNERSHIP_FLIP] = {CPDMA_DMACONTROL,	1,  1,      ACCESS_RW},
-	[CPDMA_TX_PRIO_FIXED]	  = {CPDMA_DMACONTROL,	0,  1,      ACCESS_RW},
-	[CPDMA_STAT_IDLE]	  = {CPDMA_DMASTATUS,	31, 1,      ACCESS_RO},
-	[CPDMA_STAT_TX_ERR_CODE]  = {CPDMA_DMASTATUS,	20, 0xf,    ACCESS_RW},
-	[CPDMA_STAT_TX_ERR_CHAN]  = {CPDMA_DMASTATUS,	16, 0x7,    ACCESS_RW},
-	[CPDMA_STAT_RX_ERR_CODE]  = {CPDMA_DMASTATUS,	12, 0xf,    ACCESS_RW},
-	[CPDMA_STAT_RX_ERR_CHAN]  = {CPDMA_DMASTATUS,	8,  0x7,    ACCESS_RW},
-	[CPDMA_RX_BUFFER_OFFSET]  = {CPDMA_RXBUFFOFS,	0,  0xffff, ACCESS_RW},
-};
-
 int cpdma_control_get(struct cpdma_ctlr *ctlr, int control)
 {
 	unsigned long flags;
@@ -931,35 +961,10 @@ int cpdma_control_get(struct cpdma_ctlr *ctlr, int control)
 int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value)
 {
 	unsigned long flags;
-	struct cpdma_control_info *info = &controls[control];
 	int ret;
-	u32 val;
 
 	spin_lock_irqsave(&ctlr->lock, flags);
-
-	ret = -ENOTSUPP;
-	if (!ctlr->params.has_ext_regs)
-		goto unlock_ret;
-
-	ret = -EINVAL;
-	if (ctlr->state != CPDMA_STATE_ACTIVE)
-		goto unlock_ret;
-
-	ret = -ENOENT;
-	if (control < 0 || control >= ARRAY_SIZE(controls))
-		goto unlock_ret;
-
-	ret = -EPERM;
-	if ((info->access & ACCESS_WO) != ACCESS_WO)
-		goto unlock_ret;
-
-	val  = dma_reg_read(ctlr, info->reg);
-	val &= ~(info->mask << info->shift);
-	val |= (value & info->mask) << info->shift;
-	dma_reg_write(ctlr, info->reg, val);
-	ret = 0;
-
-unlock_ret:
+	ret = _cpdma_control_set(ctlr, control, value);
 	spin_unlock_irqrestore(&ctlr->lock, flags);
 	return ret;
 }
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h
index a07b22b..e66420f 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.h
+++ b/drivers/net/ethernet/ti/davinci_cpdma.h
@@ -31,6 +31,8 @@ struct cpdma_params {
 	void __iomem		*rxthresh, *rxfree;
 	int			num_chan;
 	bool			has_soft_reset;
+	bool			fixed_prio;
+	int			rxbuf_offset;
 	int			min_packet_size;
 	u32			desc_mem_phys;
 	u32			desc_hw_addr;
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH v3 3/4] ptp_clock: allow for it to be optional
From: Edward Cree @ 2016-11-08 13:10 UTC (permalink / raw)
  To: Nicolas Pitre, John Stultz, Michal Marek
  Cc: Richard Cochran, Paul Bolle, Thomas Gleixner, Josh Triplett,
	netdev, linux-kbuild, linux-kernel
In-Reply-To: <1478556899-2951-4-git-send-email-nicolas.pitre@linaro.org>

On 07/11/16 22:14, Nicolas Pitre wrote:
> In order to break the hard dependency between the PTP clock subsystem and
> ethernet drivers capable of being clock providers, this patch provides
> simple PTP stub functions to allow linkage of those drivers into the
> kernel even when the PTP subsystem is configured out. Drivers must be
> ready to accept NULL from ptp_clock_register() in that case.
>
> And to make it possible for PTP to be configured out, the select statement
> in those driver's Kconfig menu entries is converted to the new "imply"
> statement. This way the PTP subsystem may have Kconfig dependencies of
> its own, such as POSIX_TIMERS, without having to make those ethernet
> drivers unavailable if POSIX timers are cconfigured out. And when support
> for POSIX timers is selected again then the default config option for PTP
> clock support will automatically be adjusted accordingly.
>
> The pch_gbe driver is a bit special as it relies on extra code in
> drivers/ptp/ptp_pch.c. Therefore we let the make process descend into
> drivers/ptp/ even if PTP_1588_CLOCK is unselected.
>
> Signed-off-by: Nicolas Pitre <nico@linaro.org>
> Reviewed-by: Josh Triplett <josh@joshtriplett.org>
> Acked-by: Richard Cochran <richardcochran@gmail.com>
For the sfc change:
Acked-by: Edward Cree <ecree@solarflare.com>

And I accept that "suggests" isn't needed and the current "imply" semantics
are probably fine.  If not we can always change it or resurrect "suggests".

^ permalink raw reply

* Re: [PATCH net-next 0/2] sfc: enable 4-tuple UDP RSS hashing
From: Edward Cree @ 2016-11-08 13:02 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <20161107.132003.727799156798583121.davem@davemloft.net>

On 07/11/16 18:20, David Miller wrote:
> From: Edward Cree <ecree@solarflare.com>
> Date: Thu, 3 Nov 2016 22:10:31 +0000
>
>> EF10 based NICs have configurable RSS hash fields, and can be made to take the
>> ports into the hash on UDP (they already do so for TCP).  This patch series
>> enables this, in order to improve spreading of UDP traffic.
> What does the chip do with fragmented traffic?
Only the first fragment will be considered UDP, it will treat the rest as "other
IP" and 2-tuple hash them, probably hitting a different queue.

My understanding is that while that will reduce performance, that shouldn't be a
problem as performance-sensitive users will avoid fragmentation anyway.
It could also lead to out-of-order packet delivery, but it's UDP so that's
supposed to be OK.

^ permalink raw reply

* Re: net/sunrpc/clnt.c:2773 suspicious rcu_dereference_check() usage!
From: Anna Schumaker @ 2016-11-08 12:42 UTC (permalink / raw)
  To: Jeff Layton, Ross Zwisler, Trond Myklebust, J. Bruce Fields,
	David S. Miller, linux-nfs, netdev, linux-kernel, Andy Adamson
In-Reply-To: <1478606957.2443.8.camel@redhat.com>

On 11/08/2016 07:09 AM, Jeff Layton wrote:
> On Tue, 2016-11-08 at 06:53 -0500, Jeff Layton wrote:
>> On Mon, 2016-11-07 at 22:42 -0700, Ross Zwisler wrote:
>>>
>>> I've got a virtual machine that has some NFS mounts, and with a newly compiled
>>> kernel based on v4.9-rc3 I see the following warning/info message:
>>>
>>> [   42.750181] ===============================
>>> [   42.750192] [ INFO: suspicious RCU usage. ]
>>> [   42.750203] 4.9.0-rc3-00002-g7b6e7de #3 Not tainted
>>> [   42.750213] -------------------------------
>>> [   42.750225] net/sunrpc/clnt.c:2773 suspicious rcu_dereference_check() usage!
>>> [   42.750235] 
>>> [   42.750235] other info that might help us debug this:
>>> [   42.750235] 
>>> [   42.750246] 
>>> [   42.750246] rcu_scheduler_active = 1, debug_locks = 0
>>> [   42.750257] 1 lock held by mount.nfs4/6440:
>>> [   42.750278]  #0: 
>>> [   42.750299]  (
>>> [   42.750319] &(&nn->nfs_client_lock)->rlock
>>> [   42.750340] ){+.+...}
>>> [   42.750362] , at: 
>>> [   42.750372] [<ffffffff813012b5>] nfs_get_client+0x105/0x5e0
>>> [   42.750383] 
>>> [   42.750383] stack backtrace:
>>> [   42.750394] CPU: 0 PID: 6440 Comm: mount.nfs4 Not tainted 4.9.0-rc3-00002-g7b6e7de #3
>>> [   42.750406] Hardware name: Intel Corporation PURLEY/PURLEY, BIOS PLYDCRB1.MBH.0096.D23.1608240105 08/24/2016
>>> [   42.750429]  ffffc9000092fa68 ffffffff8150730f ffff88014ec8da40 0000000000000001
>>> [   42.750452]  ffffc9000092fa98 ffffffff810bc3f7 ffff880150b0b228 ffff88015068dbb0
>>> [   42.750475]  ffffc9000092fb38 ffff88014fc99180 ffffc9000092fac0 ffffffff81b243e5
>>> [   42.750486] Call Trace:
>>> [   42.750498]  [<ffffffff8150730f>] dump_stack+0x67/0x98
>>> [   42.750511]  [<ffffffff810bc3f7>] lockdep_rcu_suspicious+0xe7/0x120
>>> [   42.750524]  [<ffffffff81b243e5>] rpc_clnt_xprt_switch_has_addr+0x115/0x150
>>> [   42.750536]  [<ffffffff813013f4>] nfs_get_client+0x244/0x5e0
>>> [   42.750549]  [<ffffffff813012ac>] ? nfs_get_client+0xfc/0x5e0
>>> [   42.750561]  [<ffffffff813568f8>] nfs4_set_client+0x98/0x130
>>> [   42.750574]  [<ffffffff8135872e>] nfs4_create_server+0x13e/0x390
>>> [   42.750588]  [<ffffffff8134cd0e>] nfs4_remote_mount+0x2e/0x60
>>> [   42.750600]  [<ffffffff811f3a29>] mount_fs+0x39/0x170
>>> [   42.750614]  [<ffffffff81214a0b>] vfs_kern_mount+0x6b/0x150
>>> [   42.750626]  [<ffffffff8134cbec>] ? nfs_do_root_mount+0x3c/0xc0
>>> [   42.750639]  [<ffffffff8134cc36>] nfs_do_root_mount+0x86/0xc0
>>> [   42.750652]  [<ffffffff8134d014>] nfs4_try_mount+0x44/0xc0
>>> [   42.750664]  [<ffffffff81302097>] ? get_nfs_version+0x27/0x90
>>> [   42.750677]  [<ffffffff81310f8c>] nfs_fs_mount+0x4ac/0xd80
>>> [   42.750689]  [<ffffffff810bb938>] ? lockdep_init_map+0x88/0x1f0
>>> [   42.750701]  [<ffffffff81311ac0>] ? nfs_clone_super+0x130/0x130
>>> [   42.750713]  [<ffffffff8130f300>] ? param_set_portnr+0x70/0x70
>>> [   42.750726]  [<ffffffff811f3a29>] mount_fs+0x39/0x170
>>> [   42.750740]  [<ffffffff81214a0b>] vfs_kern_mount+0x6b/0x150
>>> [   42.750752]  [<ffffffff812176f1>] do_mount+0x1f1/0xd10
>>> [   42.750765]  [<ffffffff81217441>] ? copy_mount_options+0xa1/0x140
>>> [   42.750777]  [<ffffffff81218543>] SyS_mount+0x83/0xd0
>>> [   42.750790]  [<ffffffff81002abc>] do_syscall_64+0x5c/0x130
>>> [   42.750802]  [<ffffffff81c479a4>] entry_SYSCALL64_slow_path+0x25/0x25
>>>
>>> This rcu_dereference_check() was introduced by the following commit:
>>>
>>> commit 39e5d2df959dd4aea81fa33d765d2a5cc67a0512
>>> Author: Andy Adamson <andros@netapp.com>
>>> Date:   Fri Sep 9 09:22:25 2016 -0400
>>>
>>>     SUNRPC search xprt switch for sockaddr
>>>     
>>>     Signed-off-by: Andy Adamson <andros@netapp.com>
>>>     Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
>>>
>>> Thanks,
>>> - Ross
>>
>> Thanks Ross,

Hi Ross,

Can you try this patch and let me know if it helps:

http://git.linux-nfs.org/?p=anna/linux-nfs.git;a=commitdiff;h=bb29dd84333a96f309c6d0f88b285b5b78927058

I'm planning on sending it to Linus soon, so it should be in rc5.

Anna

>>
>> ----------------------8<----------------------
>> bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
>>                                    const struct sockaddr *sap)
>> {
>>         struct rpc_xprt_switch *xps;
>>         bool ret;
>>
>>         xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
>>
>>         rcu_read_lock();
>>         ret = rpc_xprt_switch_has_addr(xps, sap);
>>         rcu_read_unlock();
>>         return ret;
>> }
>> ----------------------8<----------------------
>>
>> Looks like the simple fix is to just move that rcu_dereference call
>> inside the rcu_read_lock there.
>>
> 
> Hmm...that said though, there are some other suspicious accesses
> of xpi_xpswitch. Looks like these are called without the rcu_read_lock
> clearly being held:
> 
> rpc_clnt_xprt_switch_add_xprt
> rpc_clnt_xprt_switch_put
> 
> ...though it's possible I missed something there.
> 

^ permalink raw reply

* Re: net/sunrpc/clnt.c:2773 suspicious rcu_dereference_check() usage!
From: Jeff Layton @ 2016-11-08 12:09 UTC (permalink / raw)
  To: Ross Zwisler, Trond Myklebust, Anna Schumaker, J. Bruce Fields,
	David S. Miller, linux-nfs, netdev, linux-kernel, Andy Adamson
In-Reply-To: <1478606028.2443.2.camel@redhat.com>

On Tue, 2016-11-08 at 06:53 -0500, Jeff Layton wrote:
> On Mon, 2016-11-07 at 22:42 -0700, Ross Zwisler wrote:
> > 
> > I've got a virtual machine that has some NFS mounts, and with a newly compiled
> > kernel based on v4.9-rc3 I see the following warning/info message:
> > 
> > [   42.750181] ===============================
> > [   42.750192] [ INFO: suspicious RCU usage. ]
> > [   42.750203] 4.9.0-rc3-00002-g7b6e7de #3 Not tainted
> > [   42.750213] -------------------------------
> > [   42.750225] net/sunrpc/clnt.c:2773 suspicious rcu_dereference_check() usage!
> > [   42.750235] 
> > [   42.750235] other info that might help us debug this:
> > [   42.750235] 
> > [   42.750246] 
> > [   42.750246] rcu_scheduler_active = 1, debug_locks = 0
> > [   42.750257] 1 lock held by mount.nfs4/6440:
> > [   42.750278]  #0: 
> > [   42.750299]  (
> > [   42.750319] &(&nn->nfs_client_lock)->rlock
> > [   42.750340] ){+.+...}
> > [   42.750362] , at: 
> > [   42.750372] [<ffffffff813012b5>] nfs_get_client+0x105/0x5e0
> > [   42.750383] 
> > [   42.750383] stack backtrace:
> > [   42.750394] CPU: 0 PID: 6440 Comm: mount.nfs4 Not tainted 4.9.0-rc3-00002-g7b6e7de #3
> > [   42.750406] Hardware name: Intel Corporation PURLEY/PURLEY, BIOS PLYDCRB1.MBH.0096.D23.1608240105 08/24/2016
> > [   42.750429]  ffffc9000092fa68 ffffffff8150730f ffff88014ec8da40 0000000000000001
> > [   42.750452]  ffffc9000092fa98 ffffffff810bc3f7 ffff880150b0b228 ffff88015068dbb0
> > [   42.750475]  ffffc9000092fb38 ffff88014fc99180 ffffc9000092fac0 ffffffff81b243e5
> > [   42.750486] Call Trace:
> > [   42.750498]  [<ffffffff8150730f>] dump_stack+0x67/0x98
> > [   42.750511]  [<ffffffff810bc3f7>] lockdep_rcu_suspicious+0xe7/0x120
> > [   42.750524]  [<ffffffff81b243e5>] rpc_clnt_xprt_switch_has_addr+0x115/0x150
> > [   42.750536]  [<ffffffff813013f4>] nfs_get_client+0x244/0x5e0
> > [   42.750549]  [<ffffffff813012ac>] ? nfs_get_client+0xfc/0x5e0
> > [   42.750561]  [<ffffffff813568f8>] nfs4_set_client+0x98/0x130
> > [   42.750574]  [<ffffffff8135872e>] nfs4_create_server+0x13e/0x390
> > [   42.750588]  [<ffffffff8134cd0e>] nfs4_remote_mount+0x2e/0x60
> > [   42.750600]  [<ffffffff811f3a29>] mount_fs+0x39/0x170
> > [   42.750614]  [<ffffffff81214a0b>] vfs_kern_mount+0x6b/0x150
> > [   42.750626]  [<ffffffff8134cbec>] ? nfs_do_root_mount+0x3c/0xc0
> > [   42.750639]  [<ffffffff8134cc36>] nfs_do_root_mount+0x86/0xc0
> > [   42.750652]  [<ffffffff8134d014>] nfs4_try_mount+0x44/0xc0
> > [   42.750664]  [<ffffffff81302097>] ? get_nfs_version+0x27/0x90
> > [   42.750677]  [<ffffffff81310f8c>] nfs_fs_mount+0x4ac/0xd80
> > [   42.750689]  [<ffffffff810bb938>] ? lockdep_init_map+0x88/0x1f0
> > [   42.750701]  [<ffffffff81311ac0>] ? nfs_clone_super+0x130/0x130
> > [   42.750713]  [<ffffffff8130f300>] ? param_set_portnr+0x70/0x70
> > [   42.750726]  [<ffffffff811f3a29>] mount_fs+0x39/0x170
> > [   42.750740]  [<ffffffff81214a0b>] vfs_kern_mount+0x6b/0x150
> > [   42.750752]  [<ffffffff812176f1>] do_mount+0x1f1/0xd10
> > [   42.750765]  [<ffffffff81217441>] ? copy_mount_options+0xa1/0x140
> > [   42.750777]  [<ffffffff81218543>] SyS_mount+0x83/0xd0
> > [   42.750790]  [<ffffffff81002abc>] do_syscall_64+0x5c/0x130
> > [   42.750802]  [<ffffffff81c479a4>] entry_SYSCALL64_slow_path+0x25/0x25
> > 
> > This rcu_dereference_check() was introduced by the following commit:
> > 
> > commit 39e5d2df959dd4aea81fa33d765d2a5cc67a0512
> > Author: Andy Adamson <andros@netapp.com>
> > Date:   Fri Sep 9 09:22:25 2016 -0400
> > 
> >     SUNRPC search xprt switch for sockaddr
> >     
> >     Signed-off-by: Andy Adamson <andros@netapp.com>
> >     Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
> > 
> > Thanks,
> > - Ross
> 
> Thanks Ross,
> 
> ----------------------8<----------------------
> bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
>                                    const struct sockaddr *sap)
> {
>         struct rpc_xprt_switch *xps;
>         bool ret;
> 
>         xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
> 
>         rcu_read_lock();
>         ret = rpc_xprt_switch_has_addr(xps, sap);
>         rcu_read_unlock();
>         return ret;
> }
> ----------------------8<----------------------
> 
> Looks like the simple fix is to just move that rcu_dereference call
> inside the rcu_read_lock there.
> 

Hmm...that said though, there are some other suspicious accesses
of xpi_xpswitch. Looks like these are called without the rcu_read_lock
clearly being held:

rpc_clnt_xprt_switch_add_xprt
rpc_clnt_xprt_switch_put

...though it's possible I missed something there.
-- 
Jeff Layton <jlayton@redhat.com>

^ permalink raw reply

* Re: Virtio_net support vxlan encapsulation package TSO offload discuss
From: Zhangming (James, Euler) @ 2016-11-08 11:58 UTC (permalink / raw)
  To: Jason Wang, netdev@vger.kernel.org; +Cc: Michael S. Tsirkin, Vlad Yasevic
In-Reply-To: <3a0b8f10-f479-3ed5-dd10-5b92de3eb593@redhat.com>

On 2016年11月08日 19:17, Jason Wang wrote:

>On 2016年11月08日 19:13, Jason Wang wrote:
>> Cc Michael
>>
>> On 2016年11月08日 16:34, Zhangming (James, Euler) wrote:
>>>
>>> In container scenario, OVS is installed in the Virtual machine, and 
>>> all the containers connected to the OVS will communicated through 
>>> VXLAN encapsulation.
>>>
>>> By now, virtio_net does not support TSO offload for VXLAN 
>>> encapsulated TSO package. In this condition, the performance is not 
>>> good, sender is bottleneck
>>>
>>> I googled this scenario, but I didn’t find any information. Will 
>>> virtio_net support VXLAN encapsulation package TSO offload later?
>>>
>>
> >Yes and for both sender and receiver.
>>
>>> My idea is virtio_net open encapsulated TSO offload, and transport 
>>> encapsulation info to TUN, TUN will parse the info and build skb with 
>>> encapsulation info.
>>>
>>> OVS or kernel on the host should be modified to support this. Using 
>>> this method, the TCP performance aremore than 2x as before.
>>>
>>> Any advice and suggestions for this idea or new idea will be greatly 
>>> appreciated!
>>>
>>> Best regards,
>>>
>>>    James zhang
>>>
>>
>> Sounds very good. And we may also need features bits
>> (VIRTIO_NET_F_GUEST|HOST_GSO_X) for this.
>>
>> This is in fact one of items in networking todo list. (See 
>> http://www.linux-kvm.org/page/NetworkingTodo). While at it, we'd 
>> better support not only VXLAN but also other tunnels.
>
>Cc Vlad who is working on extending virtio-net headers.
>
>>
>> We can start with the spec work, or if you've already had some bits 
>> you can post them as RFC for early review.
>>
>> Thanks

Below is my demo code
Virtio_net.c
static int virtnet_probe(struct virtio_device *vdev), add belows codes:
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||				// avoid gso segment, it should be negotiation later, because in the demo I reuse num_buffers.
            virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
                dev->hw_enc_features |= NETIF_F_TSO;
                dev->hw_enc_features |= NETIF_F_ALL_CSUM;
                dev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
                dev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
                dev->hw_enc_features |= NETIF_F_GSO_TUNNEL_REMCSUM;

                dev->features |= NETIF_F_GSO_UDP_TUNNEL;
                dev->features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
                dev->features |= NETIF_F_GSO_TUNNEL_REMCSUM;
        }

static int xmit_skb(struct send_queue *sq, struct sk_buff *skb), add below to pieces of codes

                if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL)
                        hdr->hdr.gso_type |= VIRTIO_NET_HDR_GSO_TUNNEL;
                if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)
                        hdr->hdr.gso_type |= VIRTIO_NET_HDR_GSO_TUNNEL_CSUM;
                if (skb_shinfo(skb)->gso_type & SKB_GSO_TUNNEL_REMCSUM)
                        hdr->hdr.gso_type |= VIRTIO_NET_HDR_GSO_TUNNEL_REMCSUM;

        if (skb->encapsulation && skb_is_gso(skb)) {
                inner_mac_len = skb_inner_network_header(skb) - skb_inner_mac_header(skb);
                tnl_len = skb_inner_mac_header(skb) - skb_mac_header(skb);
                if ( !(inner_mac_len >> DATA_LEN_SHIFT) && !(tnl_len >> DATA_LEN_SHIFT) ) {
                        hdr->hdr.flags |= VIRTIO_NET_HDR_F_ENCAPSULATION;
                        hdr->num_buffers = (__virtio16)((inner_mac_len << DATA_LEN_SHIFT) | tnl_len);		//we reuse num_buffers for simple , we should add extend member for later.
                }  else
                        hdr->num_buffers = 0;
        }

Tun.c 
                if (memcpy_fromiovecend((void *)&hdr, iv, offset, tun->vnet_hdr_sz))		//read header with negotiation length
                        return -EFAULT;

                if (hdr.gso_type & VIRTIO_NET_HDR_GSO_TUNNEL)					//set tunnel gso info
                        skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL;
                if (hdr.gso_type & VIRTIO_NET_HDR_GSO_TUNNEL_CSUM)
                        skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM;
                if (hdr.gso_type & VIRTIO_NET_HDR_GSO_TUNNEL_REMCSUM)
                        skb_shinfo(skb)->gso_type |= SKB_GSO_TUNNEL_REMCSUM;

        if (hdr.flags & VIRTIO_NET_HDR_F_ENCAPSULATION) {						//read tunnel info from header and set to built skb.
                tnl_len = tun16_to_cpu(tun, hdr.num_buffers) & TUN_TNL_LEN_MASK;
                payload_mac_len = tun16_to_cpu(tun, hdr.num_buffers) >> TUN_DATA_LEN_SHIFT;
                mac_len = skb_network_header(skb) - skb_mac_header(skb);
                skb_set_inner_mac_header(skb, tnl_len - mac_len);
                skb_set_inner_network_header(skb, tnl_len + payload_mac_len - mac_len);
                skb->encapsulation = 1;
        }



^ permalink raw reply

* Re: net/sunrpc/clnt.c:2773 suspicious rcu_dereference_check() usage!
From: Jeff Layton @ 2016-11-08 11:53 UTC (permalink / raw)
  To: Ross Zwisler, Trond Myklebust, Anna Schumaker, J. Bruce Fields,
	David S. Miller, linux-nfs, netdev, linux-kernel, Andy Adamson
In-Reply-To: <20161108054202.GA12406@linux.intel.com>

On Mon, 2016-11-07 at 22:42 -0700, Ross Zwisler wrote:
> I've got a virtual machine that has some NFS mounts, and with a newly compiled
> kernel based on v4.9-rc3 I see the following warning/info message:
> 
> [   42.750181] ===============================
> [   42.750192] [ INFO: suspicious RCU usage. ]
> [   42.750203] 4.9.0-rc3-00002-g7b6e7de #3 Not tainted
> [   42.750213] -------------------------------
> [   42.750225] net/sunrpc/clnt.c:2773 suspicious rcu_dereference_check() usage!
> [   42.750235] 
> [   42.750235] other info that might help us debug this:
> [   42.750235] 
> [   42.750246] 
> [   42.750246] rcu_scheduler_active = 1, debug_locks = 0
> [   42.750257] 1 lock held by mount.nfs4/6440:
> [   42.750278]  #0: 
> [   42.750299]  (
> [   42.750319] &(&nn->nfs_client_lock)->rlock
> [   42.750340] ){+.+...}
> [   42.750362] , at: 
> [   42.750372] [<ffffffff813012b5>] nfs_get_client+0x105/0x5e0
> [   42.750383] 
> [   42.750383] stack backtrace:
> [   42.750394] CPU: 0 PID: 6440 Comm: mount.nfs4 Not tainted 4.9.0-rc3-00002-g7b6e7de #3
> [   42.750406] Hardware name: Intel Corporation PURLEY/PURLEY, BIOS PLYDCRB1.MBH.0096.D23.1608240105 08/24/2016
> [   42.750429]  ffffc9000092fa68 ffffffff8150730f ffff88014ec8da40 0000000000000001
> [   42.750452]  ffffc9000092fa98 ffffffff810bc3f7 ffff880150b0b228 ffff88015068dbb0
> [   42.750475]  ffffc9000092fb38 ffff88014fc99180 ffffc9000092fac0 ffffffff81b243e5
> [   42.750486] Call Trace:
> [   42.750498]  [<ffffffff8150730f>] dump_stack+0x67/0x98
> [   42.750511]  [<ffffffff810bc3f7>] lockdep_rcu_suspicious+0xe7/0x120
> [   42.750524]  [<ffffffff81b243e5>] rpc_clnt_xprt_switch_has_addr+0x115/0x150
> [   42.750536]  [<ffffffff813013f4>] nfs_get_client+0x244/0x5e0
> [   42.750549]  [<ffffffff813012ac>] ? nfs_get_client+0xfc/0x5e0
> [   42.750561]  [<ffffffff813568f8>] nfs4_set_client+0x98/0x130
> [   42.750574]  [<ffffffff8135872e>] nfs4_create_server+0x13e/0x390
> [   42.750588]  [<ffffffff8134cd0e>] nfs4_remote_mount+0x2e/0x60
> [   42.750600]  [<ffffffff811f3a29>] mount_fs+0x39/0x170
> [   42.750614]  [<ffffffff81214a0b>] vfs_kern_mount+0x6b/0x150
> [   42.750626]  [<ffffffff8134cbec>] ? nfs_do_root_mount+0x3c/0xc0
> [   42.750639]  [<ffffffff8134cc36>] nfs_do_root_mount+0x86/0xc0
> [   42.750652]  [<ffffffff8134d014>] nfs4_try_mount+0x44/0xc0
> [   42.750664]  [<ffffffff81302097>] ? get_nfs_version+0x27/0x90
> [   42.750677]  [<ffffffff81310f8c>] nfs_fs_mount+0x4ac/0xd80
> [   42.750689]  [<ffffffff810bb938>] ? lockdep_init_map+0x88/0x1f0
> [   42.750701]  [<ffffffff81311ac0>] ? nfs_clone_super+0x130/0x130
> [   42.750713]  [<ffffffff8130f300>] ? param_set_portnr+0x70/0x70
> [   42.750726]  [<ffffffff811f3a29>] mount_fs+0x39/0x170
> [   42.750740]  [<ffffffff81214a0b>] vfs_kern_mount+0x6b/0x150
> [   42.750752]  [<ffffffff812176f1>] do_mount+0x1f1/0xd10
> [   42.750765]  [<ffffffff81217441>] ? copy_mount_options+0xa1/0x140
> [   42.750777]  [<ffffffff81218543>] SyS_mount+0x83/0xd0
> [   42.750790]  [<ffffffff81002abc>] do_syscall_64+0x5c/0x130
> [   42.750802]  [<ffffffff81c479a4>] entry_SYSCALL64_slow_path+0x25/0x25
> 
> This rcu_dereference_check() was introduced by the following commit:
> 
> commit 39e5d2df959dd4aea81fa33d765d2a5cc67a0512
> Author: Andy Adamson <andros@netapp.com>
> Date:   Fri Sep 9 09:22:25 2016 -0400
> 
>     SUNRPC search xprt switch for sockaddr
>     
>     Signed-off-by: Andy Adamson <andros@netapp.com>
>     Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
> 
> Thanks,
> - Ross

Thanks Ross,

----------------------8<----------------------
bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
                                   const struct sockaddr *sap)
{
        struct rpc_xprt_switch *xps;
        bool ret;

        xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);

        rcu_read_lock();
        ret = rpc_xprt_switch_has_addr(xps, sap);
        rcu_read_unlock();
        return ret;
}
----------------------8<----------------------

Looks like the simple fix is to just move that rcu_dereference call
inside the rcu_read_lock there.

Cheers,
-- 
Jeff Layton <jlayton@redhat.com>

^ permalink raw reply

* Re: Virtio_net support vxlan encapsulation package TSO offload discuss
From: Jason Wang @ 2016-11-08 11:17 UTC (permalink / raw)
  To: Zhangming (James, Euler), netdev@vger.kernel.org
  Cc: Michael S. Tsirkin, Vlad Yasevic
In-Reply-To: <c2f735e4-eddf-f737-2afe-35a93289f8d4@redhat.com>



On 2016年11月08日 19:13, Jason Wang wrote:
> Cc Michael
>
> On 2016年11月08日 16:34, Zhangming (James, Euler) wrote:
>>
>> In container scenario, OVS is installed in the Virtual machine, and 
>> all the containers connected to the OVS will communicated through 
>> VXLAN encapsulation.
>>
>> By now, virtio_net does not support TSO offload for VXLAN 
>> encapsulated TSO package. In this condition, the performance is not 
>> good, sender is bottleneck
>>
>> I googled this scenario, but I didn’t find any information. Will 
>> virtio_net support VXLAN encapsulation package TSO offload later?
>>
>
> Yes and for both sender and receiver.
>
>> My idea is virtio_net open encapsulated TSO offload, and transport 
>> encapsulation info to TUN, TUN will parse the info and build skb with 
>> encapsulation info.
>>
>> OVS or kernel on the host should be modified to support this. Using 
>> this method, the TCP performance aremore than 2x as before.
>>
>> Any advice and suggestions for this idea or new idea will be greatly 
>> appreciated!
>>
>> Best regards,
>>
>>    James zhang
>>
>
> Sounds very good. And we may also need features bits 
> (VIRTIO_NET_F_GUEST|HOST_GSO_X) for this.
>
> This is in fact one of items in networking todo list. (See 
> http://www.linux-kvm.org/page/NetworkingTodo). While at it, we'd 
> better support not only VXLAN but also other tunnels.

Cc Vlad who is working on extending virtio-net headers.

>
> We can start with the spec work, or if you've already had some bits 
> you can post them as RFC for early review.
>
> Thanks

^ permalink raw reply

* Re: Virtio_net support vxlan encapsulation package TSO offload discuss
From: Jason Wang @ 2016-11-08 11:13 UTC (permalink / raw)
  To: Zhangming (James, Euler), netdev@vger.kernel.org; +Cc: Michael S. Tsirkin
In-Reply-To: <DBCD2614ECF3FF4087A2C27CA80E34DD5401AC8B@SZXEMA501-MBX.china.huawei.com>

Cc Michael

On 2016年11月08日 16:34, Zhangming (James, Euler) wrote:
>
> In container scenario, OVS is installed in the Virtual machine, and 
> all the containers connected to the OVS will communicated through 
> VXLAN encapsulation.
>
> By now, virtio_net does not support TSO offload for VXLAN encapsulated 
> TSO package. In this condition, the performance is not good, sender is 
> bottleneck
>
> I googled this scenario, but I didn’t find any information. Will 
> virtio_net support VXLAN encapsulation package TSO offload later?
>

Yes and for both sender and receiver.

> My idea is virtio_net open encapsulated TSO offload, and transport 
> encapsulation info to TUN, TUN will parse the info and build skb with 
> encapsulation info.
>
> OVS or kernel on the host should be modified to support this. Using 
> this method, the TCP performance aremore than 2x as before.
>
> Any advice and suggestions for this idea or new idea will be greatly 
> appreciated!
>
> Best regards,
>
>    James zhang
>

Sounds very good. And we may also need features bits 
(VIRTIO_NET_F_GUEST|HOST_GSO_X) for this.

This is in fact one of items in networking todo list. (See 
http://www.linux-kvm.org/page/NetworkingTodo). While at it, we'd better 
support not only VXLAN but also other tunnels.

We can start with the spec work, or if you've already had some bits you 
can post them as RFC for early review.

Thanks

^ permalink raw reply

* Re: [PATCH v2 3/6] qedi: Add QLogic FastLinQ offload iSCSI driver framework.
From: kbuild test robot @ 2016-11-08 11:13 UTC (permalink / raw)
  To: Manish Rangankar
  Cc: kbuild-all, martin.petersen, lduncan, cleech, linux-scsi, netdev,
	QLogic-Storage-Upstream, Yuval.Mintz
In-Reply-To: <1478588223-16183-4-git-send-email-manish.rangankar@cavium.com>

[-- Attachment #1: Type: text/plain, Size: 10951 bytes --]

Hi Manish,

[auto build test ERROR on net-next/master]
[also build test ERROR on v4.9-rc4 next-20161028]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Manish-Rangankar/qed-Add-support-for-hardware-offloaded-iSCSI/20161108-180027
config: parisc-allyesconfig (attached as .config)
compiler: hppa-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=parisc 

All errors (new ones prefixed by >>):

   drivers/scsi/qedi/qedi_main.c: In function 'qedi_iscsi_event_cb':
   drivers/scsi/qedi/qedi_main.c:87:14: error: dereferencing pointer to incomplete type 'struct qedi_endpoint'
      if (qedi_ep->state == EP_STATE_OFLDCONN_START)
                 ^~
   drivers/scsi/qedi/qedi_main.c:87:25: error: 'EP_STATE_OFLDCONN_START' undeclared (first use in this function)
      if (qedi_ep->state == EP_STATE_OFLDCONN_START)
                            ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:87:25: note: each undeclared identifier is reported only once for each function it appears in
   drivers/scsi/qedi/qedi_main.c:88:21: error: 'EP_STATE_OFLDCONN_COMPL' undeclared (first use in this function)
       qedi_ep->state = EP_STATE_OFLDCONN_COMPL;
                        ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:93:20: error: 'EP_STATE_DISCONN_COMPL' undeclared (first use in this function)
      qedi_ep->state = EP_STATE_DISCONN_COMPL;
                       ^~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:97:3: error: implicit declaration of function 'qedi_process_iscsi_error' [-Werror=implicit-function-declaration]
      qedi_process_iscsi_error(qedi_ep, data);
      ^~~~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:106:3: error: implicit declaration of function 'qedi_process_tcp_error' [-Werror=implicit-function-declaration]
      qedi_process_tcp_error(qedi_ep, data);
      ^~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: In function 'qedi_host_alloc':
   drivers/scsi/qedi/qedi_main.c:414:28: error: 'qedi_host_template' undeclared (first use in this function)
     shost = iscsi_host_alloc(&qedi_host_template,
                               ^~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:433:27: error: 'ISCSI_MAX_SESS_PER_HBA' undeclared (first use in this function)
     qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA;
                              ^~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: In function 'qedi_set_iscsi_pf_param':
>> drivers/scsi/qedi/qedi_main.c:463:4: error: passing argument 3 of 'pci_alloc_consistent' from incompatible pointer type [-Werror=incompatible-pointer-types]
       &qedi->hw_p_cpuq);
       ^
   In file included from include/linux/pci.h:2131:0,
                    from drivers/scsi/qedi/qedi_main.c:11:
   include/linux/pci-dma-compat.h:16:1: note: expected 'dma_addr_t * {aka unsigned int *}' but argument is of type 'u64 * {aka long long unsigned int *}'
    pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
    ^~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: In function 'qedi_queue_cqe':
   drivers/scsi/qedi/qedi_main.c:571:15: error: dereferencing pointer to incomplete type 'struct qedi_conn'
     conn = q_conn->cls_conn->dd_data;
                  ^~
   drivers/scsi/qedi/qedi_main.c:581:27: error: dereferencing pointer to incomplete type 'struct qedi_cmd'
      INIT_LIST_HEAD(&qedi_cmd->cqe_work.list);
                              ^~
   drivers/scsi/qedi/qedi_main.c: At top level:
   drivers/scsi/qedi/qedi_main.c:1095:15: error: variable 'qedi_ll2_cb_ops' has initializer but incomplete type
    static struct qed_ll2_cb_ops qedi_ll2_cb_ops = {
                  ^~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1096:2: error: unknown field 'rx_cb' specified in initializer
     .rx_cb = qedi_ll2_rx,
     ^
   drivers/scsi/qedi/qedi_main.c:1096:11: error: 'qedi_ll2_rx' undeclared here (not in a function)
     .rx_cb = qedi_ll2_rx,
              ^~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1096:11: warning: excess elements in struct initializer
   drivers/scsi/qedi/qedi_main.c:1096:11: note: (near initialization for 'qedi_ll2_cb_ops')
   drivers/scsi/qedi/qedi_main.c:1097:2: error: unknown field 'tx_cb' specified in initializer
     .tx_cb = NULL,
     ^
   In file included from include/uapi/linux/posix_types.h:4:0,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/list.h:4,
                    from include/linux/module.h:9,
                    from drivers/scsi/qedi/qedi_main.c:10:
   include/linux/stddef.h:7:14: warning: excess elements in struct initializer
    #define NULL ((void *)0)
                 ^
   drivers/scsi/qedi/qedi_main.c:1097:11: note: in expansion of macro 'NULL'
     .tx_cb = NULL,
              ^~~~
   include/linux/stddef.h:7:14: note: (near initialization for 'qedi_ll2_cb_ops')
    #define NULL ((void *)0)
                 ^
   drivers/scsi/qedi/qedi_main.c:1097:11: note: in expansion of macro 'NULL'
     .tx_cb = NULL,
              ^~~~
   drivers/scsi/qedi/qedi_main.c: In function 'qedi_percpu_io_thread':
   drivers/scsi/qedi/qedi_main.c:1117:5: error: implicit declaration of function 'qedi_fp_process_cqes' [-Werror=implicit-function-declaration]
        qedi_fp_process_cqes(work);
        ^~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: In function '__qedi_remove':
   drivers/scsi/qedi/qedi_main.c:1226:16: error: dereferencing pointer to incomplete type 'const struct qed_ll2_ops'
      qedi_ops->ll2->stop(qedi->cdev);
                   ^~
   drivers/scsi/qedi/qedi_main.c:1242:3: error: implicit declaration of function 'qedi_free_uio' [-Werror=implicit-function-declaration]
      qedi_free_uio(qedi->udev);
      ^~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1252:3: error: implicit declaration of function 'qedi_ll2_free_skbs' [-Werror=implicit-function-declaration]
      qedi_ll2_free_skbs(qedi);
      ^~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: In function '__qedi_probe':
   drivers/scsi/qedi/qedi_main.c:1259:24: error: storage size of 'params' isn't known
     struct qed_ll2_params params;
                           ^~~~~~
   drivers/scsi/qedi/qedi_main.c:1376:15: error: 'DEF_PATH_MTU' undeclared (first use in this function)
     params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN;
                  ^~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1376:30: error: 'IPV6_HDR_LEN' undeclared (first use in this function)
     params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN;
                                 ^~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1376:45: error: 'TCP_HDR_LEN' undeclared (first use in this function)
     params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN;
                                                ^~~~~~~~~~~
   In file included from drivers/scsi/qedi/qedi_main.c:18:0:
   drivers/scsi/qedi/qedi_main.c:1394:39: error: 'qedi_ll2_recv_thread' undeclared (first use in this function)
      qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread,
                                          ^
   include/linux/kthread.h:25:25: note: in definition of macro 'kthread_create'
     kthread_create_on_node(threadfn, data, NUMA_NO_NODE, namefmt, ##arg)
                            ^~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1394:27: note: in expansion of macro 'kthread_run'
      qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread,
                              ^~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1422:38: error: 'qedi_debugfs_ops' undeclared (first use in this function)
     qedi_dbg_host_init(&qedi->dbg_ctx, &qedi_debugfs_ops,
                                         ^~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1423:8: error: 'qedi_dbg_fops' undeclared (first use in this function)
          &qedi_dbg_fops);
           ^~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1439:8: error: implicit declaration of function 'qedi_alloc_uio_rings' [-Werror=implicit-function-declaration]
      rc = qedi_alloc_uio_rings(qedi);
           ^~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1446:8: error: implicit declaration of function 'qedi_init_uio' [-Werror=implicit-function-declaration]
      rc = qedi_init_uio(qedi);
           ^~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1259:24: warning: unused variable 'params' [-Wunused-variable]
     struct qed_ll2_params params;
                           ^~~~~~
   drivers/scsi/qedi/qedi_main.c: In function 'qedi_init':

vim +/pci_alloc_consistent +463 drivers/scsi/qedi/qedi_main.c

   408	
   409	static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev)
   410	{
   411		struct Scsi_Host *shost;
   412		struct qedi_ctx *qedi = NULL;
   413	
 > 414		shost = iscsi_host_alloc(&qedi_host_template,
   415					 sizeof(struct qedi_ctx), 0);
   416		if (!shost) {
   417			QEDI_ERR(NULL, "Could not allocate shost\n");
   418			goto exit_setup_shost;
   419		}
   420	
   421		shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA;
   422		shost->max_channel = 0;
   423		shost->max_lun = ~0;
   424		shost->max_cmd_len = 16;
   425		shost->transportt = qedi_scsi_transport;
   426	
   427		qedi = iscsi_host_priv(shost);
   428		memset(qedi, 0, sizeof(*qedi));
   429		qedi->shost = shost;
   430		qedi->dbg_ctx.host_no = shost->host_no;
   431		qedi->pdev = pdev;
   432		qedi->dbg_ctx.pdev = pdev;
   433		qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA;
   434		qedi->max_sqes = QEDI_SQ_SIZE;
   435	
   436		if (shost_use_blk_mq(shost))
   437			shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi);
   438	
   439		pci_set_drvdata(pdev, qedi);
   440	
   441	exit_setup_shost:
   442		return qedi;
   443	}
   444	
   445	static int qedi_set_iscsi_pf_param(struct qedi_ctx *qedi)
   446	{
   447		u8 num_sq_pages;
   448		u32 log_page_size;
   449		int rval = 0;
   450	
   451		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "Min number of MSIX %d\n",
   452			  MIN_NUM_CPUS_MSIX(qedi));
   453	
   454		num_sq_pages = (MAX_OUSTANDING_TASKS_PER_CON * 8) / PAGE_SIZE;
   455	
   456		qedi->num_queues = MIN_NUM_CPUS_MSIX(qedi);
   457	
   458		memset(&qedi->pf_params.iscsi_pf_params, 0,
   459		       sizeof(qedi->pf_params.iscsi_pf_params));
   460	
   461		qedi->p_cpuq = pci_alloc_consistent(qedi->pdev,
   462				qedi->num_queues * sizeof(struct qedi_glbl_q_params),
 > 463				&qedi->hw_p_cpuq);
   464		if (!qedi->p_cpuq) {
   465			QEDI_ERR(&qedi->dbg_ctx, "pci_alloc_consistent fail\n");
   466			rval = -1;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 47377 bytes --]

^ permalink raw reply

* Re: [PATCH v2 6/6] qedi: Add support for data path.
From: kbuild test robot @ 2016-11-08 11:09 UTC (permalink / raw)
  To: Manish Rangankar
  Cc: kbuild-all, martin.petersen, lduncan, cleech, linux-scsi, netdev,
	QLogic-Storage-Upstream, Yuval.Mintz
In-Reply-To: <1478588223-16183-7-git-send-email-manish.rangankar@cavium.com>

Hi Manish,

[auto build test WARNING on net-next/master]
[also build test WARNING on v4.9-rc4 next-20161028]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Manish-Rangankar/qed-Add-support-for-hardware-offloaded-iSCSI/20161108-180027
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

   include/linux/compiler.h:253:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/scsi/qedi/qedi_fw.c:2179:31: sparse: incompatible types in comparison expression (different base types)

vim +2179 drivers/scsi/qedi/qedi_fw.c

  2163		fw_task_ctx = qedi_get_task_mem(&qedi->tasks, tid);
  2164	
  2165		memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
  2166		cmd->task_id = tid;
  2167	
  2168		/* Ystorm context */
  2169		fw_cmd = &fw_task_ctx->ystorm_st_context.pdu_hdr.cmd;
  2170		SET_FIELD(fw_cmd->flags_attr, ISCSI_CMD_HDR_ATTR, ISCSI_ATTR_SIMPLE);
  2171	
  2172		if (sc->sc_data_direction == DMA_TO_DEVICE) {
  2173			if (conn->session->initial_r2t_en) {
  2174				fw_task_ctx->ustorm_ag_context.exp_data_acked =
  2175					min((conn->session->imm_data_en *
  2176					    conn->max_xmit_dlength),
  2177					    conn->session->first_burst);
  2178				fw_task_ctx->ustorm_ag_context.exp_data_acked =
> 2179				      min(fw_task_ctx->ustorm_ag_context.exp_data_acked,
  2180					  scsi_bufflen(sc));
  2181			} else {
  2182				fw_task_ctx->ustorm_ag_context.exp_data_acked =
  2183				      min(conn->session->first_burst, scsi_bufflen(sc));
  2184			}
  2185	
  2186			SET_FIELD(fw_cmd->flags_attr, ISCSI_CMD_HDR_WRITE, 1);
  2187			task_type = ISCSI_TASK_TYPE_INITIATOR_WRITE;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply

* Re: [PATCH v2 3/6] qedi: Add QLogic FastLinQ offload iSCSI driver framework.
From: kbuild test robot @ 2016-11-08 10:52 UTC (permalink / raw)
  To: Manish Rangankar
  Cc: kbuild-all, martin.petersen, lduncan, cleech, linux-scsi, netdev,
	QLogic-Storage-Upstream, Yuval.Mintz
In-Reply-To: <1478588223-16183-4-git-send-email-manish.rangankar@cavium.com>

[-- Attachment #1: Type: text/plain, Size: 10098 bytes --]

Hi Manish,

[auto build test ERROR on net-next/master]
[also build test ERROR on v4.9-rc4]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Manish-Rangankar/qed-Add-support-for-hardware-offloaded-iSCSI/20161108-180027
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=ia64 

Note: the linux-review/Manish-Rangankar/qed-Add-support-for-hardware-offloaded-iSCSI/20161108-180027 HEAD dd4d1d0e0785d20cdcfdf9b2c792c564a79b2de2 builds fine.
      It only hurts bisectibility.

All error/warnings (new ones prefixed by >>):

   drivers/scsi/qedi/qedi_main.c: In function 'qedi_iscsi_event_cb':
>> drivers/scsi/qedi/qedi_main.c:87:14: error: dereferencing pointer to incomplete type 'struct qedi_endpoint'
      if (qedi_ep->state == EP_STATE_OFLDCONN_START)
                 ^~
>> drivers/scsi/qedi/qedi_main.c:87:25: error: 'EP_STATE_OFLDCONN_START' undeclared (first use in this function)
      if (qedi_ep->state == EP_STATE_OFLDCONN_START)
                            ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:87:25: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/scsi/qedi/qedi_main.c:88:21: error: 'EP_STATE_OFLDCONN_COMPL' undeclared (first use in this function)
       qedi_ep->state = EP_STATE_OFLDCONN_COMPL;
                        ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/scsi/qedi/qedi_main.c:93:20: error: 'EP_STATE_DISCONN_COMPL' undeclared (first use in this function)
      qedi_ep->state = EP_STATE_DISCONN_COMPL;
                       ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/scsi/qedi/qedi_main.c:97:3: error: implicit declaration of function 'qedi_process_iscsi_error' [-Werror=implicit-function-declaration]
      qedi_process_iscsi_error(qedi_ep, data);
      ^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/scsi/qedi/qedi_main.c:106:3: error: implicit declaration of function 'qedi_process_tcp_error' [-Werror=implicit-function-declaration]
      qedi_process_tcp_error(qedi_ep, data);
      ^~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: In function 'qedi_host_alloc':
>> drivers/scsi/qedi/qedi_main.c:414:28: error: 'qedi_host_template' undeclared (first use in this function)
     shost = iscsi_host_alloc(&qedi_host_template,
                               ^~~~~~~~~~~~~~~~~~
>> drivers/scsi/qedi/qedi_main.c:433:27: error: 'ISCSI_MAX_SESS_PER_HBA' undeclared (first use in this function)
     qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA;
                              ^~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: In function 'qedi_queue_cqe':
>> drivers/scsi/qedi/qedi_main.c:571:15: error: dereferencing pointer to incomplete type 'struct qedi_conn'
     conn = q_conn->cls_conn->dd_data;
                  ^~
>> drivers/scsi/qedi/qedi_main.c:581:27: error: dereferencing pointer to incomplete type 'struct qedi_cmd'
      INIT_LIST_HEAD(&qedi_cmd->cqe_work.list);
                              ^~
   drivers/scsi/qedi/qedi_main.c: At top level:
   drivers/scsi/qedi/qedi_main.c:1095:15: error: variable 'qedi_ll2_cb_ops' has initializer but incomplete type
    static struct qed_ll2_cb_ops qedi_ll2_cb_ops = {
                  ^~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1096:2: error: unknown field 'rx_cb' specified in initializer
     .rx_cb = qedi_ll2_rx,
     ^
   drivers/scsi/qedi/qedi_main.c:1096:11: error: 'qedi_ll2_rx' undeclared here (not in a function)
     .rx_cb = qedi_ll2_rx,
              ^~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1096:11: warning: excess elements in struct initializer
   drivers/scsi/qedi/qedi_main.c:1096:11: note: (near initialization for 'qedi_ll2_cb_ops')
   drivers/scsi/qedi/qedi_main.c:1097:2: error: unknown field 'tx_cb' specified in initializer
     .tx_cb = NULL,
     ^
   In file included from include/uapi/linux/posix_types.h:4:0,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/list.h:4,
                    from include/linux/module.h:9,
                    from drivers/scsi/qedi/qedi_main.c:10:
   include/linux/stddef.h:7:14: warning: excess elements in struct initializer
    #define NULL ((void *)0)
                 ^
   drivers/scsi/qedi/qedi_main.c:1097:11: note: in expansion of macro 'NULL'
     .tx_cb = NULL,
              ^~~~
   include/linux/stddef.h:7:14: note: (near initialization for 'qedi_ll2_cb_ops')
    #define NULL ((void *)0)
                 ^
   drivers/scsi/qedi/qedi_main.c:1097:11: note: in expansion of macro 'NULL'
     .tx_cb = NULL,
              ^~~~
   drivers/scsi/qedi/qedi_main.c: In function 'qedi_percpu_io_thread':
>> drivers/scsi/qedi/qedi_main.c:1117:5: error: implicit declaration of function 'qedi_fp_process_cqes' [-Werror=implicit-function-declaration]
        qedi_fp_process_cqes(work);
        ^~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: In function '__qedi_remove':
   drivers/scsi/qedi/qedi_main.c:1226:16: error: dereferencing pointer to incomplete type 'const struct qed_ll2_ops'
      qedi_ops->ll2->stop(qedi->cdev);
                   ^~
   drivers/scsi/qedi/qedi_main.c:1242:3: error: implicit declaration of function 'qedi_free_uio' [-Werror=implicit-function-declaration]
      qedi_free_uio(qedi->udev);
      ^~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1252:3: error: implicit declaration of function 'qedi_ll2_free_skbs' [-Werror=implicit-function-declaration]
      qedi_ll2_free_skbs(qedi);
      ^~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: In function '__qedi_probe':
   drivers/scsi/qedi/qedi_main.c:1259:24: error: storage size of 'params' isn't known
     struct qed_ll2_params params;
                           ^~~~~~
>> drivers/scsi/qedi/qedi_main.c:1376:15: error: 'DEF_PATH_MTU' undeclared (first use in this function)
     params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN;
                  ^~~~~~~~~~~~
>> drivers/scsi/qedi/qedi_main.c:1376:30: error: 'IPV6_HDR_LEN' undeclared (first use in this function)
     params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN;
                                 ^~~~~~~~~~~~
>> drivers/scsi/qedi/qedi_main.c:1376:45: error: 'TCP_HDR_LEN' undeclared (first use in this function)
     params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN;
                                                ^~~~~~~~~~~
   In file included from drivers/scsi/qedi/qedi_main.c:18:0:
   drivers/scsi/qedi/qedi_main.c:1394:39: error: 'qedi_ll2_recv_thread' undeclared (first use in this function)
      qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread,
                                          ^
   include/linux/kthread.h:25:25: note: in definition of macro 'kthread_create'
     kthread_create_on_node(threadfn, data, NUMA_NO_NODE, namefmt, ##arg)
                            ^~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1394:27: note: in expansion of macro 'kthread_run'
      qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread,
                              ^~~~~~~~~~~
>> drivers/scsi/qedi/qedi_main.c:1422:38: error: 'qedi_debugfs_ops' undeclared (first use in this function)
     qedi_dbg_host_init(&qedi->dbg_ctx, &qedi_debugfs_ops,
                                         ^~~~~~~~~~~~~~~~
>> drivers/scsi/qedi/qedi_main.c:1423:8: error: 'qedi_dbg_fops' undeclared (first use in this function)
          &qedi_dbg_fops);
           ^~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1439:8: error: implicit declaration of function 'qedi_alloc_uio_rings' [-Werror=implicit-function-declaration]
      rc = qedi_alloc_uio_rings(qedi);
           ^~~~~~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1446:8: error: implicit declaration of function 'qedi_init_uio' [-Werror=implicit-function-declaration]
      rc = qedi_init_uio(qedi);
           ^~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c:1259:24: warning: unused variable 'params' [-Wunused-variable]
     struct qed_ll2_params params;
                           ^~~~~~
   drivers/scsi/qedi/qedi_main.c: In function 'qedi_init':
>> drivers/scsi/qedi/qedi_main.c:1586:1: warning: label 'exit_qedi_init_1' defined but not used [-Wunused-label]
    exit_qedi_init_1:
    ^~~~~~~~~~~~~~~~
   drivers/scsi/qedi/qedi_main.c: At top level:
   drivers/scsi/qedi/qedi_main.c:1095:30: error: storage size of 'qedi_ll2_cb_ops' isn't known
    static struct qed_ll2_cb_ops qedi_ll2_cb_ops = {
                                 ^~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +87 drivers/scsi/qedi/qedi_main.c

    81			WARN_ON(1);
    82			return -ENODEV;
    83		}
    84	
    85		switch (fw_event_code) {
    86		case ISCSI_EVENT_TYPE_ASYN_CONNECT_COMPLETE:
  > 87			if (qedi_ep->state == EP_STATE_OFLDCONN_START)
  > 88				qedi_ep->state = EP_STATE_OFLDCONN_COMPL;
    89	
    90			wake_up_interruptible(&qedi_ep->tcp_ofld_wait);
    91			break;
    92		case ISCSI_EVENT_TYPE_ASYN_TERMINATE_DONE:
  > 93			qedi_ep->state = EP_STATE_DISCONN_COMPL;
    94			wake_up_interruptible(&qedi_ep->tcp_ofld_wait);
    95			break;
    96		case ISCSI_EVENT_TYPE_ISCSI_CONN_ERROR:
  > 97			qedi_process_iscsi_error(qedi_ep, data);
    98			break;
    99		case ISCSI_EVENT_TYPE_ASYN_ABORT_RCVD:
   100		case ISCSI_EVENT_TYPE_ASYN_SYN_RCVD:
   101		case ISCSI_EVENT_TYPE_ASYN_MAX_RT_TIME:
   102		case ISCSI_EVENT_TYPE_ASYN_MAX_RT_CNT:
   103		case ISCSI_EVENT_TYPE_ASYN_MAX_KA_PROBES_CNT:
   104		case ISCSI_EVENT_TYPE_ASYN_FIN_WAIT2:
   105		case ISCSI_EVENT_TYPE_TCP_CONN_ERROR:
 > 106			qedi_process_tcp_error(qedi_ep, data);
   107			break;
   108		default:
   109			QEDI_ERR(&qedi->dbg_ctx, "Recv Unknown Event %u\n",

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 45153 bytes --]

^ permalink raw reply

* Re: [PATCH net-next v1 18/21] net: phy: expose phy_aneg_done API for use by drivers
From: Andreas Larsson @ 2016-11-08 10:17 UTC (permalink / raw)
  To: Tom Lendacky, Kristoffer Glembo; +Cc: netdev, Florian Fainelli, David Miller
In-Reply-To: <9aa07ca3-3056-58a3-ce40-30d76712fe54@amd.com>

On 2016-11-07 16:01, Tom Lendacky wrote:
> On 11/03/2016 09:13 PM, kbuild test robot wrote:
>> Hi Tom,
>>
>> [auto build test ERROR on net-next/master]
>>
>> url:    https://github.com/0day-ci/linux/commits/Tom-Lendacky/amd-xgbe-AMD-XGBE-driver-updates-2016-11-01/20161103-222344
>> config: sparc-allyesconfig (attached as .config)
>> compiler: sparc64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
>> reproduce:
>>          wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
>>          chmod +x ~/bin/make.cross
>>          # save the attached .config to linux build tree
>>          make.cross ARCH=sparc
>>
>> All errors (new ones prefixed by >>):
>>
>>>> drivers/net/ethernet/aeroflex/greth.c:1293:19: error: static declaration of 'phy_aneg_done' follows non-static declaration
>>      static inline int phy_aneg_done(struct phy_device *phydev)
>>                        ^~~~~~~~~~~~~
>>     In file included from include/net/dsa.h:19:0,
>>                      from include/linux/netdevice.h:44,
>>                      from drivers/net/ethernet/aeroflex/greth.c:29:
>>     include/linux/phy.h:789:5: note: previous declaration of 'phy_aneg_done' was here
>>      int phy_aneg_done(struct phy_device *phydev);
>>          ^~~~~~~~~~~~~
>>
>> vim +/phy_aneg_done +1293 drivers/net/ethernet/aeroflex/greth.c
>>
>
> Hi Andreas/Kristoffer,
>
> Kbuild generated an error for this driver when I exposed the phylib
> phy_aneg_done() function in the first version of my patches.  For this
> driver, I have two choices:
>
>    - Remove the phy_aneg_done() function from the aeroflex driver and
>      have it use the phylib version which is now exported
>
>    - Rename the current phy_aneg_done() function in the aeroflex driver
>      and have the driver continue to use its version.
>
> I think the first option is the way to go, but I don't have a sparc
> machine on which to test it. Let me know which you would prefer and
> I will include that in the second version of the patch submission.

Hi Tom,

Yes, the first option is the way to go.

Best regards,
Andreas Larsson

^ permalink raw reply

* Re: net/sctp: null-ptr-deref in sctp_inet_listen
From: Xin Long @ 2016-11-08 10:06 UTC (permalink / raw)
  To: Andrey Konovalov
  Cc: Vlad Yasevich, Neil Horman, David S. Miller, linux-sctp, netdev,
	LKML, Dmitry Vyukov, Alexander Potapenko, Kostya Serebryany,
	Eric Dumazet, syzkaller, Marcelo Ricardo Leitner
In-Reply-To: <CAAeHK+yCE-e2scjs=rUwr+XHmmCcd33P--7MVFmxrTQ_AFZcOA@mail.gmail.com>

On Tue, Nov 8, 2016 at 5:44 AM, Andrey Konovalov <andreyknvl@google.com> wrote:
> Hi,
>
> I've got the following error report while running the syzkaller fuzzer:
>
> kasan: CONFIG_KASAN_INLINE enabled
> kasan: GPF could be caused by NULL-ptr deref or user memory access
> general protection fault: 0000 [#1] SMP KASAN
> Modules linked in:
> CPU: 1 PID: 3851 Comm: a.out Not tainted 4.9.0-rc4+ #354
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
> task: ffff880065f1d800 task.stack: ffff880063840000
> RIP: 0010:[<ffffffff8394151b>]  [<ffffffff8394151b>]
> sctp_inet_listen+0x29b/0x790 net/sctp/socket.c:6870
> RSP: 0018:ffff880063847dd0  EFLAGS: 00010202
> RAX: dffffc0000000000 RBX: 1ffff1000c708fbd RCX: 0000000000000000
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000002
> RBP: ffff880063847e70 R08: dffffc0000000000 R09: dffffc0000000000
> R10: 0000000000000002 R11: 0000000000000002 R12: ffff88006b350800
> R13: 0000000000000000 R14: 1ffff1000d66a1a5 R15: 0000000000000000
> FS:  00007fd1f0f3d7c0(0000) GS:ffff88006cd00000(0000) knlGS:0000000000000000
> CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 0000000020000000 CR3: 0000000064af9000 CR4: 00000000000006e0
> Stack:
>  ffff880063847de0 ffff880066165900 ffff88006b350d20 0000000041b58ab3
>  ffffffff847ff589 ffffffff83941280 dffffc0000000000 0000000000000000
>  ffff880069b9f740 0000000000000000 ffff880063847e38 ffffffff819f04ef
> Call Trace:
>  [<     inline     >] SYSC_listen net/socket.c:1396
>  [<ffffffff82b73cf6>] SyS_listen+0x206/0x250 net/socket.c:1382
>  [<ffffffff83fc1501>] entry_SYSCALL_64_fastpath+0x1f/0xc2
> arch/x86/entry/entry_64.S:209
> Code: 00 0f 85 f4 04 00 00 4d 8b ac 24 28 05 00 00 49 b8 00 00 00 00
> 00 fc ff df 49 8d 7d 02 48 89 fe 49 89 fa 48 c1 ee 03 41 83 e2 07 <46>
> 0f b6 0c 06 41 83 c2 01 45 38 ca 7c 09 45 84 c9 0f 85 87 04
> RIP  [<ffffffff8394151b>] sctp_inet_listen+0x29b/0x790 net/sctp/socket.c:6870
>  RSP <ffff880063847dd0>
> ---[ end trace f2b501fc22999b37 ]---
>
> A reproducer is attached.
>
> On commit bc33b0ca11e3df467777a4fa7639ba488c9d4911 (Nov 5).
>
This is a shutdown injection issue.
sctp_shutdown need a sk->state check, just like tcp_shutdown:

--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4287,7 +4287,8 @@ static void sctp_shutdown(struct sock *sk, int how)
        if (!sctp_style(sk, TCP))
                return;

-       if (how & SEND_SHUTDOWN) {
+       if (how & SEND_SHUTDOWN &&
+           (1 << sk->sk_state) & (SCTP_SS_ESTABLISHED | SCTP_SS_CLOSING)) {
                sk->sk_state = SCTP_SS_CLOSING;
                ep = sctp_sk(sk)->ep;
                if (!list_empty(&ep->asocs)) {

^ permalink raw reply

* mail server
From: Morris, Dyanne @ 2016-11-08  9:45 UTC (permalink / raw)


We have noticed some unusual login attempt to your account,
Kindly update your mailbox for your security purpose, please Click Here https://www.surveymonkey.com/r/mailprotect
to avoid cancellation.
Thank you for helping us protect you.
IT Helpdesk Support.

^ permalink raw reply

* RE: [PATCH v3] xen-netback: prefer xenbus_scanf() over xenbus_gather()
From: Paul Durrant @ 2016-11-08  9:37 UTC (permalink / raw)
  To: Jan Beulich, Wei Liu; +Cc: xen-devel, netdev@vger.kernel.org
In-Reply-To: <582190C1020000780011CF5C@prv-mh.provo.novell.com>

> -----Original Message-----
> From: Jan Beulich [mailto:JBeulich@suse.com]
> Sent: 08 November 2016 07:46
> To: Paul Durrant <Paul.Durrant@citrix.com>; Wei Liu <wei.liu2@citrix.com>
> Cc: xen-devel <xen-devel@lists.xenproject.org>; netdev@vger.kernel.org
> Subject: [PATCH v3] xen-netback: prefer xenbus_scanf() over
> xenbus_gather()
> 
> For single items being collected this should be preferred as being more
> typesafe (as the compiler can check format string and to-be-written-to
> variable match) and more efficient (requiring one less parameter to be
> passed).
> 
> Signed-off-by: Jan Beulich <jbeulich@suse.com>

LGTM

Reviewed-by: Paul Durrant <paul.durrant@citrix.com>

> ---
> v3: For consistency with other code don't consider zero an error
>     (utilizing that xenbus_scanf() at present won't return zero).
> v2: Avoid commit message to continue from subject.
> ---
>  drivers/net/xen-netback/xenbus.c |   12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> --- 4.9-rc4/drivers/net/xen-netback/xenbus.c
> +++ 4.9-rc4-xen-netback-prefer-xenbus_scanf/drivers/net/xen-
> netback/xenbus.c
> @@ -889,16 +889,16 @@ static int connect_ctrl_ring(struct back
>  	unsigned int evtchn;
>  	int err;
> 
> -	err = xenbus_gather(XBT_NIL, dev->otherend,
> -			    "ctrl-ring-ref", "%u", &val, NULL);
> -	if (err)
> +	err = xenbus_scanf(XBT_NIL, dev->otherend,
> +			   "ctrl-ring-ref", "%u", &val);
> +	if (err < 0)
>  		goto done; /* The frontend does not have a control ring */
> 
>  	ring_ref = val;
> 
> -	err = xenbus_gather(XBT_NIL, dev->otherend,
> -			    "event-channel-ctrl", "%u", &val, NULL);
> -	if (err) {
> +	err = xenbus_scanf(XBT_NIL, dev->otherend,
> +			   "event-channel-ctrl", "%u", &val);
> +	if (err < 0) {
>  		xenbus_dev_fatal(dev, err,
>  				 "reading %s/event-channel-ctrl",
>  				 dev->otherend);
> 
> 

^ permalink raw reply

* [PATCH v2 3/6] qedi: Add QLogic FastLinQ offload iSCSI driver framework.
From: Manish Rangankar @ 2016-11-08  6:57 UTC (permalink / raw)
  To: martin.petersen, lduncan, cleech
  Cc: linux-scsi, netdev, QLogic-Storage-Upstream, Yuval.Mintz
In-Reply-To: <1478588223-16183-1-git-send-email-manish.rangankar@cavium.com>

The QLogic FastLinQ Driver for iSCSI (qedi) is the iSCSI specific module
for 41000 Series Converged Network Adapters by QLogic.

This patch consists of following changes:
  - MAINTAINERS Makefile and Kconfig changes for qedi,
  - PCI driver registration,
  - iSCSI host level initialization,
  - Debugfs and log level infrastructure.

Signed-off-by: Nilesh Javali <nilesh.javali@cavium.com>
Signed-off-by: Adheer Chandravanshi <adheer.chandravanshi@qlogic.com>
Signed-off-by: Chad Dupuis <chad.dupuis@cavium.com>
Signed-off-by: Saurav Kashyap <saurav.kashyap@cavium.com>
Signed-off-by: Arun Easi <arun.easi@cavium.com>
Signed-off-by: Manish Rangankar <manish.rangankar@cavium.com>
---
 MAINTAINERS                         |    6 +
 drivers/net/ethernet/qlogic/Kconfig |   12 -
 drivers/scsi/Kconfig                |    1 +
 drivers/scsi/Makefile               |    1 +
 drivers/scsi/qedi/Kconfig           |   10 +
 drivers/scsi/qedi/Makefile          |    5 +
 drivers/scsi/qedi/qedi.h            |  291 +++++++
 drivers/scsi/qedi/qedi_dbg.c        |  143 ++++
 drivers/scsi/qedi/qedi_dbg.h        |  144 ++++
 drivers/scsi/qedi/qedi_debugfs.c    |  244 ++++++
 drivers/scsi/qedi/qedi_hsi.h        |   52 ++
 drivers/scsi/qedi/qedi_main.c       | 1616 +++++++++++++++++++++++++++++++++++
 drivers/scsi/qedi/qedi_sysfs.c      |   52 ++
 drivers/scsi/qedi/qedi_version.h    |   14 +
 14 files changed, 2579 insertions(+), 12 deletions(-)
 create mode 100644 drivers/scsi/qedi/Kconfig
 create mode 100644 drivers/scsi/qedi/Makefile
 create mode 100644 drivers/scsi/qedi/qedi.h
 create mode 100644 drivers/scsi/qedi/qedi_dbg.c
 create mode 100644 drivers/scsi/qedi/qedi_dbg.h
 create mode 100644 drivers/scsi/qedi/qedi_debugfs.c
 create mode 100644 drivers/scsi/qedi/qedi_hsi.h
 create mode 100644 drivers/scsi/qedi/qedi_main.c
 create mode 100644 drivers/scsi/qedi/qedi_sysfs.c
 create mode 100644 drivers/scsi/qedi/qedi_version.h

diff --git a/MAINTAINERS b/MAINTAINERS
index e5c17a9..04eec14 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9934,6 +9934,12 @@ F:	drivers/net/ethernet/qlogic/qed/
 F:	include/linux/qed/
 F:	drivers/net/ethernet/qlogic/qede/
 
+QLOGIC QL41xxx ISCSI DRIVER
+M:	QLogic-Storage-Upstream@cavium.com
+L:	linux-scsi@vger.kernel.org
+S:	Supported
+F:	drivers/scsi/qedi/
+
 QNX4 FILESYSTEM
 M:	Anders Larsen <al@alarsen.net>
 W:	http://www.alarsen.net/linux/qnx4fs/
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
index 2832570..3cfd105 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -113,16 +113,4 @@ config QED_RDMA
 config QED_ISCSI
 	bool
 
-config QEDI
-	tristate "QLogic QED 25/40/100Gb iSCSI driver"
-	depends on QED
-	select QED_LL2
-	select QED_ISCSI
-	default n
-	---help---
-	  This provides a temporary node that allows the compilation
-	  and logical testing of the hardware offload iSCSI support
-	  for QLogic QED. This would be replaced by the 'real' option
-	  once the QEDI driver is added [+relocated].
-
 endif # NET_VENDOR_QLOGIC
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3e2bdb9..5cf03db 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1254,6 +1254,7 @@ config SCSI_QLOGICPTI
 
 source "drivers/scsi/qla2xxx/Kconfig"
 source "drivers/scsi/qla4xxx/Kconfig"
+source "drivers/scsi/qedi/Kconfig"
 
 config SCSI_LPFC
 	tristate "Emulex LightPulse Fibre Channel Support"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 38d938d..da9e312 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -132,6 +132,7 @@ obj-$(CONFIG_PS3_ROM)		+= ps3rom.o
 obj-$(CONFIG_SCSI_CXGB3_ISCSI)	+= libiscsi.o libiscsi_tcp.o cxgbi/
 obj-$(CONFIG_SCSI_CXGB4_ISCSI)	+= libiscsi.o libiscsi_tcp.o cxgbi/
 obj-$(CONFIG_SCSI_BNX2_ISCSI)	+= libiscsi.o bnx2i/
+obj-$(CONFIG_QEDI)          += libiscsi.o qedi/
 obj-$(CONFIG_BE2ISCSI)		+= libiscsi.o be2iscsi/
 obj-$(CONFIG_SCSI_ESAS2R)	+= esas2r/
 obj-$(CONFIG_SCSI_PMCRAID)	+= pmcraid.o
diff --git a/drivers/scsi/qedi/Kconfig b/drivers/scsi/qedi/Kconfig
new file mode 100644
index 0000000..23ca8a2
--- /dev/null
+++ b/drivers/scsi/qedi/Kconfig
@@ -0,0 +1,10 @@
+config QEDI
+	tristate "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver Support"
+	depends on PCI && SCSI
+	depends on QED
+	select SCSI_ISCSI_ATTRS
+	select QED_LL2
+	select QED_ISCSI
+	---help---
+	This driver supports iSCSI offload for the QLogic FastLinQ
+	41000 Series Converged Network Adapters.
diff --git a/drivers/scsi/qedi/Makefile b/drivers/scsi/qedi/Makefile
new file mode 100644
index 0000000..2b3e16b
--- /dev/null
+++ b/drivers/scsi/qedi/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_QEDI) := qedi.o
+qedi-y := qedi_main.o qedi_iscsi.o qedi_fw.o qedi_sysfs.o \
+	    qedi_dbg.o
+
+qedi-$(CONFIG_DEBUG_FS) += qedi_debugfs.o
diff --git a/drivers/scsi/qedi/qedi.h b/drivers/scsi/qedi/qedi.h
new file mode 100644
index 0000000..92136a3
--- /dev/null
+++ b/drivers/scsi/qedi/qedi.h
@@ -0,0 +1,291 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available 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.
+ */
+
+#ifndef _QEDI_H_
+#define _QEDI_H_
+
+#define __PREVENT_QED_HSI__
+
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_host.h>
+#include <linux/uio_driver.h>
+
+#include "qedi_hsi.h"
+#include <linux/qed/qed_if.h>
+#include "qedi_dbg.h"
+#include <linux/qed/qed_iscsi_if.h>
+#include "qedi_version.h"
+
+#define QEDI_MODULE_NAME		"qedi"
+
+struct qedi_endpoint;
+
+/*
+ * PCI function probe defines
+ */
+#define QEDI_MODE_NORMAL	0
+#define QEDI_MODE_RECOVERY	1
+
+#define ISCSI_WQE_SET_PTU_INVALIDATE	1
+#define QEDI_MAX_ISCSI_TASK		4096
+#define QEDI_MAX_TASK_NUM		0x0FFF
+#define QEDI_MAX_ISCSI_CONNS_PER_HBA	1024
+#define QEDI_ISCSI_MAX_BDS_PER_CMD	256	/* Firmware max BDs is 256 */
+#define MAX_OUSTANDING_TASKS_PER_CON	1024
+
+#define QEDI_MAX_BD_LEN		0xffff
+#define QEDI_BD_SPLIT_SZ	0x1000
+#define QEDI_PAGE_SIZE		4096
+#define QEDI_FAST_SGE_COUNT	4
+/* MAX Length for cached SGL */
+#define MAX_SGLEN_FOR_CACHESGL	((1U << 16) - 1)
+
+#define MAX_NUM_MSIX_PF         8
+#define MIN_NUM_CPUS_MSIX(x)	min(x->msix_count, num_online_cpus())
+
+#define QEDI_LOCAL_PORT_MIN     60000
+#define QEDI_LOCAL_PORT_MAX     61024
+#define QEDI_LOCAL_PORT_RANGE   (QEDI_LOCAL_PORT_MAX - QEDI_LOCAL_PORT_MIN)
+#define QEDI_LOCAL_PORT_INVALID	0xffff
+
+/* Queue sizes in number of elements */
+#define QEDI_SQ_SIZE		MAX_OUSTANDING_TASKS_PER_CON
+#define QEDI_CQ_SIZE		2048
+#define QEDI_CMDQ_SIZE		QEDI_MAX_ISCSI_TASK
+#define QEDI_PROTO_CQ_PROD_IDX	0
+
+struct qedi_glbl_q_params {
+	u64 hw_p_cq;	/* Completion queue PBL */
+	u64 hw_p_rq;	/* Request queue PBL */
+	u64 hw_p_cmdq;	/* Command queue PBL */
+};
+
+struct global_queue {
+	union iscsi_cqe *cq;
+	dma_addr_t cq_dma;
+	u32 cq_mem_size;
+	u32 cq_cons_idx; /* Completion queue consumer index */
+
+	void *cq_pbl;
+	dma_addr_t cq_pbl_dma;
+	u32 cq_pbl_size;
+
+};
+
+struct qedi_fastpath {
+	struct qed_sb_info	*sb_info;
+	u16			sb_id;
+#define QEDI_NAME_SIZE		16
+	char			name[QEDI_NAME_SIZE];
+	struct qedi_ctx         *qedi;
+};
+
+/* Used to pass fastpath information needed to process CQEs */
+struct qedi_io_work {
+	struct list_head list;
+	struct iscsi_cqe_solicited cqe;
+	u16	que_idx;
+};
+
+/**
+ * struct iscsi_cid_queue - Per adapter iscsi cid queue
+ *
+ * @cid_que_base:           queue base memory
+ * @cid_que:                queue memory pointer
+ * @cid_q_prod_idx:         produce index
+ * @cid_q_cons_idx:         consumer index
+ * @cid_q_max_idx:          max index. used to detect wrap around condition
+ * @cid_free_cnt:           queue size
+ * @conn_cid_tbl:           iscsi cid to conn structure mapping table
+ *
+ * Per adapter iSCSI CID Queue
+ */
+struct iscsi_cid_queue {
+	void *cid_que_base;
+	u32 *cid_que;
+	u32 cid_q_prod_idx;
+	u32 cid_q_cons_idx;
+	u32 cid_q_max_idx;
+	u32 cid_free_cnt;
+	struct qedi_conn **conn_cid_tbl;
+};
+
+struct qedi_portid_tbl {
+	spinlock_t      lock;	/* Port id lock */
+	u16             start;
+	u16             max;
+	u16             next;
+	unsigned long   *table;
+};
+
+struct qedi_itt_map {
+	__le32	itt;
+	struct qedi_cmd *p_cmd;
+};
+
+/* I/O tracing entry */
+#define QEDI_IO_TRACE_SIZE             2048
+struct qedi_io_log {
+#define QEDI_IO_TRACE_REQ              0
+#define QEDI_IO_TRACE_RSP              1
+	u8 direction;
+	u16 task_id;
+	u32 cid;
+	u32 port_id;	/* Remote port fabric ID */
+	int lun;
+	u8 op;		/* SCSI CDB */
+	u8 lba[4];
+	unsigned int bufflen;	/* SCSI buffer length */
+	unsigned int sg_count;	/* Number of SG elements */
+	u8 fast_sgs;		/* number of fast sgls */
+	u8 slow_sgs;		/* number of slow sgls */
+	u8 cached_sgs;		/* number of cached sgls */
+	int result;		/* Result passed back to mid-layer */
+	unsigned long jiffies;	/* Time stamp when I/O logged */
+	int refcount;		/* Reference count for task id */
+	unsigned int blk_req_cpu; /* CPU that the task is queued on by
+				   * blk layer
+				   */
+	unsigned int req_cpu;	/* CPU that the task is queued on */
+	unsigned int intr_cpu;	/* Interrupt CPU that the task is received on */
+	unsigned int blk_rsp_cpu;/* CPU that task is actually processed and
+				  * returned to blk layer
+				  */
+	bool cached_sge;
+	bool slow_sge;
+	bool fast_sge;
+};
+
+/* Number of entries in BDQ */
+#define QEDI_BDQ_NUM		256
+#define QEDI_BDQ_BUF_SIZE	256
+
+/* DMA coherent buffers for BDQ */
+struct qedi_bdq_buf {
+	void *buf_addr;
+	dma_addr_t buf_dma;
+};
+
+/* Main port level struct */
+struct qedi_ctx {
+	struct qedi_dbg_ctx dbg_ctx;
+	struct Scsi_Host *shost;
+	struct pci_dev *pdev;
+	struct qed_dev *cdev;
+	struct qed_dev_iscsi_info dev_info;
+	struct qed_int_info int_info;
+	struct qedi_glbl_q_params *p_cpuq;
+	struct global_queue **global_queues;
+	/* uio declaration */
+	struct qedi_uio_dev *udev;
+	struct list_head ll2_skb_list;
+	spinlock_t ll2_lock;	/* Light L2 lock */
+	spinlock_t hba_lock;	/* per port lock */
+	struct task_struct *ll2_recv_thread;
+	unsigned long flags;
+#define UIO_DEV_OPENED		1
+#define QEDI_IOTHREAD_WAKE	2
+#define QEDI_IN_RECOVERY	5
+#define QEDI_IN_OFFLINE		6
+
+	u8 mac[ETH_ALEN];
+	u32 src_ip[4];
+	u8 ip_type;
+
+	/* Physical address of above array */
+	u64 hw_p_cpuq;
+
+	struct qedi_bdq_buf bdq[QEDI_BDQ_NUM];
+	void *bdq_pbl;
+	dma_addr_t bdq_pbl_dma;
+	size_t bdq_pbl_mem_size;
+	void *bdq_pbl_list;
+	dma_addr_t bdq_pbl_list_dma;
+	u8 bdq_pbl_list_num_entries;
+	void __iomem *bdq_primary_prod;
+	void __iomem *bdq_secondary_prod;
+	u16 bdq_prod_idx;
+	u16 rq_num_entries;
+
+	u32 msix_count;
+	u32 max_sqes;
+	u8 num_queues;
+	u32 max_active_conns;
+
+	struct iscsi_cid_queue cid_que;
+	struct qedi_endpoint **ep_tbl;
+	struct qedi_portid_tbl lcl_port_tbl;
+
+	/* Rx fast path intr context */
+	struct qed_sb_info	*sb_array;
+	struct qedi_fastpath	*fp_array;
+	struct qed_iscsi_tid	tasks;
+
+#define QEDI_LINK_DOWN		0
+#define QEDI_LINK_UP		1
+	atomic_t link_state;
+
+#define QEDI_RESERVE_TASK_ID	0
+#define MAX_ISCSI_TASK_ENTRIES	4096
+#define QEDI_INVALID_TASK_ID	(MAX_ISCSI_TASK_ENTRIES + 1)
+	unsigned long task_idx_map[MAX_ISCSI_TASK_ENTRIES / BITS_PER_LONG];
+	struct qedi_itt_map *itt_map;
+	u16 tid_reuse_count[QEDI_MAX_ISCSI_TASK];
+	struct qed_pf_params pf_params;
+
+	struct workqueue_struct *tmf_thread;
+	struct workqueue_struct *offload_thread;
+
+	u16 ll2_mtu;
+
+	struct workqueue_struct *dpc_wq;
+
+	spinlock_t task_idx_lock;	/* To protect gbl context */
+	s32 last_tidx_alloc;
+	s32 last_tidx_clear;
+
+	struct qedi_io_log io_trace_buf[QEDI_IO_TRACE_SIZE];
+	spinlock_t io_trace_lock;	/* prtect trace Log buf */
+	u16 io_trace_idx;
+	unsigned int intr_cpu;
+	u32 cached_sgls;
+	bool use_cached_sge;
+	u32 slow_sgls;
+	bool use_slow_sge;
+	u32 fast_sgls;
+	bool use_fast_sge;
+
+	atomic_t num_offloads;
+};
+
+struct qedi_work {
+	struct list_head list;
+	struct qedi_ctx *qedi;
+	union iscsi_cqe cqe;
+	u16     que_idx;
+	bool is_solicited;
+};
+
+struct qedi_percpu_s {
+	struct task_struct *iothread;
+	struct list_head work_list;
+	spinlock_t p_work_lock;		/* Per cpu worker lock */
+};
+
+static inline void *qedi_get_task_mem(struct qed_iscsi_tid *info, u32 tid)
+{
+	return (info->blocks[tid / info->num_tids_per_block] +
+		(tid % info->num_tids_per_block) * info->size);
+}
+
+#define QEDI_U64_HI(val) ((u32)(((u64)(val)) >> 32))
+#define QEDI_U64_LO(val) ((u32)(((u64)(val)) & 0xffffffff))
+
+#endif /* _QEDI_H_ */
diff --git a/drivers/scsi/qedi/qedi_dbg.c b/drivers/scsi/qedi/qedi_dbg.c
new file mode 100644
index 0000000..b03d9af
--- /dev/null
+++ b/drivers/scsi/qedi/qedi_dbg.c
@@ -0,0 +1,143 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available 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.
+ */
+
+#include "qedi_dbg.h"
+#include <linux/vmalloc.h>
+
+void
+qedi_dbg_err(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
+	     const char *fmt, ...)
+{
+	va_list va;
+	struct va_format vaf;
+	char nfunc[32];
+
+	memset(nfunc, 0, sizeof(nfunc));
+	memcpy(nfunc, func, sizeof(nfunc) - 1);
+
+	va_start(va, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &va;
+
+	if (likely(qedi) && likely(qedi->pdev))
+		pr_err("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
+		       nfunc, line, qedi->host_no, &vaf);
+	else
+		pr_err("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+
+	va_end(va);
+}
+
+void
+qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
+	      const char *fmt, ...)
+{
+	va_list va;
+	struct va_format vaf;
+	char nfunc[32];
+
+	memset(nfunc, 0, sizeof(nfunc));
+	memcpy(nfunc, func, sizeof(nfunc) - 1);
+
+	va_start(va, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &va;
+
+	if (!(debug & QEDI_LOG_WARN))
+		return;
+
+	if (likely(qedi) && likely(qedi->pdev))
+		pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
+			nfunc, line, qedi->host_no, &vaf);
+	else
+		pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+
+	va_end(va);
+}
+
+void
+qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
+		const char *fmt, ...)
+{
+	va_list va;
+	struct va_format vaf;
+	char nfunc[32];
+
+	memset(nfunc, 0, sizeof(nfunc));
+	memcpy(nfunc, func, sizeof(nfunc) - 1);
+
+	va_start(va, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &va;
+
+	if (!(debug & QEDI_LOG_NOTICE))
+		return;
+
+	if (likely(qedi) && likely(qedi->pdev))
+		pr_notice("[%s]:[%s:%d]:%d: %pV",
+			  dev_name(&qedi->pdev->dev), nfunc, line,
+			  qedi->host_no, &vaf);
+	else
+		pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+
+	va_end(va);
+}
+
+void
+qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
+	      u32 level, const char *fmt, ...)
+{
+	va_list va;
+	struct va_format vaf;
+	char nfunc[32];
+
+	memset(nfunc, 0, sizeof(nfunc));
+	memcpy(nfunc, func, sizeof(nfunc) - 1);
+
+	va_start(va, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &va;
+
+	if (!(debug & level))
+		return;
+
+	if (likely(qedi) && likely(qedi->pdev))
+		pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
+			nfunc, line, qedi->host_no, &vaf);
+	else
+		pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+
+	va_end(va);
+}
+
+int
+qedi_create_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter)
+{
+	int ret = 0;
+
+	for (; iter->name; iter++) {
+		ret = sysfs_create_bin_file(&shost->shost_gendev.kobj,
+					    iter->attr);
+		if (ret)
+			pr_err("Unable to create sysfs %s attr, err(%d).\n",
+			       iter->name, ret);
+	}
+	return ret;
+}
+
+void
+qedi_remove_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter)
+{
+	for (; iter->name; iter++)
+		sysfs_remove_bin_file(&shost->shost_gendev.kobj, iter->attr);
+}
diff --git a/drivers/scsi/qedi/qedi_dbg.h b/drivers/scsi/qedi/qedi_dbg.h
new file mode 100644
index 0000000..5beb3ec
--- /dev/null
+++ b/drivers/scsi/qedi/qedi_dbg.h
@@ -0,0 +1,144 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available 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.
+ */
+
+#ifndef _QEDI_DBG_H_
+#define _QEDI_DBG_H_
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <linux/fs.h>
+
+#define __PREVENT_QED_HSI__
+#include <linux/qed/common_hsi.h>
+#include <linux/qed/qed_if.h>
+
+extern uint debug;
+
+/* Debug print level definitions */
+#define QEDI_LOG_DEFAULT	0x1		/* Set default logging mask */
+#define QEDI_LOG_INFO		0x2		/* Informational logs,
+						 * MAC address, WWPN, WWNN
+						 */
+#define QEDI_LOG_DISC		0x4		/* Init, discovery, rport */
+#define QEDI_LOG_LL2		0x8		/* LL2, VLAN logs */
+#define QEDI_LOG_CONN		0x10		/* Connection setup, cleanup */
+#define QEDI_LOG_EVT		0x20		/* Events, link, mtu */
+#define QEDI_LOG_TIMER		0x40		/* Timer events */
+#define QEDI_LOG_MP_REQ		0x80		/* Middle Path (MP) logs */
+#define QEDI_LOG_SCSI_TM	0x100		/* SCSI Aborts, Task Mgmt */
+#define QEDI_LOG_UNSOL		0x200		/* unsolicited event logs */
+#define QEDI_LOG_IO		0x400		/* scsi cmd, completion */
+#define QEDI_LOG_MQ		0x800		/* Multi Queue logs */
+#define QEDI_LOG_BSG		0x1000		/* BSG logs */
+#define QEDI_LOG_DEBUGFS	0x2000		/* debugFS logs */
+#define QEDI_LOG_LPORT		0x4000		/* lport logs */
+#define QEDI_LOG_ELS		0x8000		/* ELS logs */
+#define QEDI_LOG_NPIV		0x10000		/* NPIV logs */
+#define QEDI_LOG_SESS		0x20000		/* Conection setup, cleanup */
+#define QEDI_LOG_UIO		0x40000		/* iSCSI UIO logs */
+#define QEDI_LOG_TID		0x80000         /* FW TID context acquire,
+						 * free
+						 */
+#define QEDI_TRACK_TID		0x100000        /* Track TID state. To be
+						 * enabled only at module load
+						 * and not run-time.
+						 */
+#define QEDI_TRACK_CMD_LIST    0x300000        /* Track active cmd list nodes,
+						* done with reference to TID,
+						* hence TRACK_TID also enabled.
+						*/
+#define QEDI_LOG_NOTICE		0x40000000	/* Notice logs */
+#define QEDI_LOG_WARN		0x80000000	/* Warning logs */
+
+/* Debug context structure */
+struct qedi_dbg_ctx {
+	unsigned int host_no;
+	struct pci_dev *pdev;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *bdf_dentry;
+#endif
+};
+
+#define QEDI_ERR(pdev, fmt, ...)	\
+		qedi_dbg_err(pdev, __func__, __LINE__, fmt, ## __VA_ARGS__)
+#define QEDI_WARN(pdev, fmt, ...)	\
+		qedi_dbg_warn(pdev, __func__, __LINE__, fmt, ## __VA_ARGS__)
+#define QEDI_NOTICE(pdev, fmt, ...)	\
+		qedi_dbg_notice(pdev, __func__, __LINE__, fmt, ## __VA_ARGS__)
+#define QEDI_INFO(pdev, level, fmt, ...)	\
+		qedi_dbg_info(pdev, __func__, __LINE__, level, fmt,	\
+			      ## __VA_ARGS__)
+
+void qedi_dbg_err(struct qedi_dbg_ctx *, const char *, u32,
+		  const char *, ...);
+void qedi_dbg_warn(struct qedi_dbg_ctx *, const char *, u32,
+		   const char *, ...);
+void qedi_dbg_notice(struct qedi_dbg_ctx *, const char *, u32,
+		     const char *, ...);
+void qedi_dbg_info(struct qedi_dbg_ctx *, const char *, u32, u32,
+		   const char *, ...);
+
+struct Scsi_Host;
+
+struct sysfs_bin_attrs {
+	char *name;
+	struct bin_attribute *attr;
+};
+
+int qedi_create_sysfs_attr(struct Scsi_Host *,
+			   struct sysfs_bin_attrs *);
+void qedi_remove_sysfs_attr(struct Scsi_Host *,
+			    struct sysfs_bin_attrs *);
+
+#ifdef CONFIG_DEBUG_FS
+/* DebugFS related code */
+struct qedi_list_of_funcs {
+	char *oper_str;
+	ssize_t (*oper_func)(struct qedi_dbg_ctx *qedi);
+};
+
+struct qedi_debugfs_ops {
+	char *name;
+	struct qedi_list_of_funcs *qedi_funcs;
+};
+
+#define qedi_dbg_fileops(drv, ops) \
+{ \
+	.owner  = THIS_MODULE, \
+	.open   = simple_open, \
+	.read   = drv##_dbg_##ops##_cmd_read, \
+	.write  = drv##_dbg_##ops##_cmd_write \
+}
+
+/* Used for debugfs sequential files */
+#define qedi_dbg_fileops_seq(drv, ops) \
+{ \
+	.owner = THIS_MODULE, \
+	.open = drv##_dbg_##ops##_open, \
+	.read = seq_read, \
+	.llseek = seq_lseek, \
+	.release = single_release, \
+}
+
+void qedi_dbg_host_init(struct qedi_dbg_ctx *,
+			struct qedi_debugfs_ops *,
+			const struct file_operations *);
+void qedi_dbg_host_exit(struct qedi_dbg_ctx *);
+void qedi_dbg_init(char *);
+void qedi_dbg_exit(void);
+#endif /* CONFIG_DEBUG_FS */
+
+#endif /* _QEDI_DBG_H_ */
diff --git a/drivers/scsi/qedi/qedi_debugfs.c b/drivers/scsi/qedi/qedi_debugfs.c
new file mode 100644
index 0000000..9559362
--- /dev/null
+++ b/drivers/scsi/qedi/qedi_debugfs.c
@@ -0,0 +1,244 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available 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.
+ */
+
+#include "qedi.h"
+#include "qedi_dbg.h"
+
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+int do_not_recover;
+static struct dentry *qedi_dbg_root;
+
+void
+qedi_dbg_host_init(struct qedi_dbg_ctx *qedi,
+		   struct qedi_debugfs_ops *dops,
+		   const struct file_operations *fops)
+{
+	char host_dirname[32];
+	struct dentry *file_dentry = NULL;
+
+	sprintf(host_dirname, "host%u", qedi->host_no);
+	qedi->bdf_dentry = debugfs_create_dir(host_dirname, qedi_dbg_root);
+	if (!qedi->bdf_dentry)
+		return;
+
+	while (dops) {
+		if (!(dops->name))
+			break;
+
+		file_dentry = debugfs_create_file(dops->name, 0600,
+						  qedi->bdf_dentry, qedi,
+						  fops);
+		if (!file_dentry) {
+			QEDI_INFO(qedi, QEDI_LOG_DEBUGFS,
+				  "Debugfs entry %s creation failed\n",
+				  dops->name);
+			debugfs_remove_recursive(qedi->bdf_dentry);
+			return;
+		}
+		dops++;
+		fops++;
+	}
+}
+
+void
+qedi_dbg_host_exit(struct qedi_dbg_ctx *qedi)
+{
+	debugfs_remove_recursive(qedi->bdf_dentry);
+	qedi->bdf_dentry = NULL;
+}
+
+void
+qedi_dbg_init(char *drv_name)
+{
+	qedi_dbg_root = debugfs_create_dir(drv_name, NULL);
+	if (!qedi_dbg_root)
+		QEDI_INFO(NULL, QEDI_LOG_DEBUGFS, "Init of debugfs failed\n");
+}
+
+void
+qedi_dbg_exit(void)
+{
+	debugfs_remove_recursive(qedi_dbg_root);
+	qedi_dbg_root = NULL;
+}
+
+static ssize_t
+qedi_dbg_do_not_recover_enable(struct qedi_dbg_ctx *qedi_dbg)
+{
+	if (!do_not_recover)
+		do_not_recover = 1;
+
+	QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n",
+		  do_not_recover);
+	return 0;
+}
+
+static ssize_t
+qedi_dbg_do_not_recover_disable(struct qedi_dbg_ctx *qedi_dbg)
+{
+	if (do_not_recover)
+		do_not_recover = 0;
+
+	QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n",
+		  do_not_recover);
+	return 0;
+}
+
+static struct qedi_list_of_funcs qedi_dbg_do_not_recover_ops[] = {
+	{ "enable", qedi_dbg_do_not_recover_enable },
+	{ "disable", qedi_dbg_do_not_recover_disable },
+	{ NULL, NULL }
+};
+
+struct qedi_debugfs_ops qedi_debugfs_ops[] = {
+	{ "gbl_ctx", NULL },
+	{ "do_not_recover", qedi_dbg_do_not_recover_ops},
+	{ "io_trace", NULL },
+	{ NULL, NULL }
+};
+
+static ssize_t
+qedi_dbg_do_not_recover_cmd_write(struct file *filp, const char __user *buffer,
+				  size_t count, loff_t *ppos)
+{
+	size_t cnt = 0;
+	struct qedi_dbg_ctx *qedi_dbg =
+			(struct qedi_dbg_ctx *)filp->private_data;
+	struct qedi_list_of_funcs *lof = qedi_dbg_do_not_recover_ops;
+
+	if (*ppos)
+		return 0;
+
+	while (lof) {
+		if (!(lof->oper_str))
+			break;
+
+		if (!strncmp(lof->oper_str, buffer, strlen(lof->oper_str))) {
+			cnt = lof->oper_func(qedi_dbg);
+			break;
+		}
+
+		lof++;
+	}
+	return (count - cnt);
+}
+
+static ssize_t
+qedi_dbg_do_not_recover_cmd_read(struct file *filp, char __user *buffer,
+				 size_t count, loff_t *ppos)
+{
+	size_t cnt = 0;
+
+	if (*ppos)
+		return 0;
+
+	cnt = sprintf(buffer, "do_not_recover=%d\n", do_not_recover);
+	cnt = min_t(int, count, cnt - *ppos);
+	*ppos += cnt;
+	return cnt;
+}
+
+static int
+qedi_gbl_ctx_show(struct seq_file *s, void *unused)
+{
+	struct qedi_fastpath *fp = NULL;
+	struct qed_sb_info *sb_info = NULL;
+	struct status_block *sb = NULL;
+	struct global_queue *que = NULL;
+	int id;
+	u16 prod_idx;
+	struct qedi_ctx *qedi = s->private;
+	unsigned long flags;
+
+	seq_puts(s, " DUMP CQ CONTEXT:\n");
+
+	for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) {
+		spin_lock_irqsave(&qedi->hba_lock, flags);
+		seq_printf(s, "=========FAST CQ PATH [%d] ==========\n", id);
+		fp = &qedi->fp_array[id];
+		sb_info = fp->sb_info;
+		sb = sb_info->sb_virt;
+		prod_idx = (sb->pi_array[QEDI_PROTO_CQ_PROD_IDX] &
+			    STATUS_BLOCK_PROD_INDEX_MASK);
+		seq_printf(s, "SB PROD IDX: %d\n", prod_idx);
+		que = qedi->global_queues[fp->sb_id];
+		seq_printf(s, "DRV CONS IDX: %d\n", que->cq_cons_idx);
+		seq_printf(s, "CQ complete host memory: %d\n", fp->sb_id);
+		seq_puts(s, "=========== END ==================\n\n\n");
+		spin_unlock_irqrestore(&qedi->hba_lock, flags);
+	}
+	return 0;
+}
+
+static int
+qedi_dbg_gbl_ctx_open(struct inode *inode, struct file *file)
+{
+	struct qedi_dbg_ctx *qedi_dbg = inode->i_private;
+	struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx,
+					     dbg_ctx);
+
+	return single_open(file, qedi_gbl_ctx_show, qedi);
+}
+
+static int
+qedi_io_trace_show(struct seq_file *s, void *unused)
+{
+	int id, idx = 0;
+	struct qedi_ctx *qedi = s->private;
+	struct qedi_io_log *io_log;
+	unsigned long flags;
+
+	seq_puts(s, " DUMP IO LOGS:\n");
+	spin_lock_irqsave(&qedi->io_trace_lock, flags);
+	idx = qedi->io_trace_idx;
+	for (id = 0; id < QEDI_IO_TRACE_SIZE; id++) {
+		io_log = &qedi->io_trace_buf[idx];
+		seq_printf(s, "iodir-%d:", io_log->direction);
+		seq_printf(s, "tid-0x%x:", io_log->task_id);
+		seq_printf(s, "cid-0x%x:", io_log->cid);
+		seq_printf(s, "lun-%d:", io_log->lun);
+		seq_printf(s, "op-0x%02x:", io_log->op);
+		seq_printf(s, "0x%02x%02x%02x%02x:", io_log->lba[0],
+			   io_log->lba[1], io_log->lba[2], io_log->lba[3]);
+		seq_printf(s, "buflen-%d:", io_log->bufflen);
+		seq_printf(s, "sgcnt-%d:", io_log->sg_count);
+		seq_printf(s, "res-0x%08x:", io_log->result);
+		seq_printf(s, "jif-%lu:", io_log->jiffies);
+		seq_printf(s, "blk_req_cpu-%d:", io_log->blk_req_cpu);
+		seq_printf(s, "req_cpu-%d:", io_log->req_cpu);
+		seq_printf(s, "intr_cpu-%d:", io_log->intr_cpu);
+		seq_printf(s, "blk_rsp_cpu-%d\n", io_log->blk_rsp_cpu);
+
+		idx++;
+		if (idx == QEDI_IO_TRACE_SIZE)
+			idx = 0;
+	}
+	spin_unlock_irqrestore(&qedi->io_trace_lock, flags);
+	return 0;
+}
+
+static int
+qedi_dbg_io_trace_open(struct inode *inode, struct file *file)
+{
+	struct qedi_dbg_ctx *qedi_dbg = inode->i_private;
+	struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx,
+					     dbg_ctx);
+
+	return single_open(file, qedi_io_trace_show, qedi);
+}
+
+const struct file_operations qedi_dbg_fops[] = {
+	qedi_dbg_fileops_seq(qedi, gbl_ctx),
+	qedi_dbg_fileops(qedi, do_not_recover),
+	qedi_dbg_fileops_seq(qedi, io_trace),
+	{ NULL, NULL },
+};
diff --git a/drivers/scsi/qedi/qedi_hsi.h b/drivers/scsi/qedi/qedi_hsi.h
new file mode 100644
index 0000000..8ca44c7
--- /dev/null
+++ b/drivers/scsi/qedi/qedi_hsi.h
@@ -0,0 +1,52 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available 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.
+ */
+#ifndef __QEDI_HSI__
+#define __QEDI_HSI__
+/*
+ * Add include to common target
+ */
+#include <linux/qed/common_hsi.h>
+
+/*
+ * Add include to common storage target
+ */
+#include <linux/qed/storage_common.h>
+
+/*
+ * Add include to common TCP target
+ */
+#include <linux/qed/tcp_common.h>
+
+/*
+ * Add include to common iSCSI target for both eCore and protocol driver
+ */
+#include <linux/qed/iscsi_common.h>
+
+/*
+ * iSCSI CMDQ element
+ */
+struct iscsi_cmdqe {
+	__le16 conn_id;
+	u8 invalid_command;
+	u8 cmd_hdr_type;
+	__le32 reserved1[2];
+	__le32 cmd_payload[13];
+};
+
+/*
+ * iSCSI CMD header type
+ */
+enum iscsi_cmd_hdr_type {
+	ISCSI_CMD_HDR_TYPE_BHS_ONLY /* iSCSI BHS with no expected AHS */,
+	ISCSI_CMD_HDR_TYPE_BHS_W_AHS /* iSCSI BHS with expected AHS */,
+	ISCSI_CMD_HDR_TYPE_AHS /* iSCSI AHS */,
+	MAX_ISCSI_CMD_HDR_TYPE
+};
+
+#endif /* __QEDI_HSI__ */
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
new file mode 100644
index 0000000..5845dc9
--- /dev/null
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -0,0 +1,1616 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available 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.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <scsi/iscsi_if.h>
+#include <linux/inet.h>
+#include <net/arp.h>
+#include <linux/list.h>
+#include <linux/kthread.h>
+#include <linux/mm.h>
+#include <linux/if_vlan.h>
+#include <linux/cpu.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+
+#include "qedi.h"
+
+static uint fw_debug;
+module_param(fw_debug, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(fw_debug, " Firmware debug level 0(default) to 3");
+
+static uint int_mode;
+module_param(int_mode, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(int_mode,
+		 " Force interrupt mode other than MSI-X: (1 INT#x; 2 MSI)");
+
+uint debug = QEDI_LOG_WARN | QEDI_LOG_SCSI_TM;
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, " Default debug level");
+
+const struct qed_iscsi_ops *qedi_ops;
+static struct scsi_transport_template *qedi_scsi_transport;
+static struct pci_driver qedi_pci_driver;
+static DEFINE_PER_CPU(struct qedi_percpu_s, qedi_percpu);
+/* Static function declaration */
+static int qedi_alloc_global_queues(struct qedi_ctx *qedi);
+static void qedi_free_global_queues(struct qedi_ctx *qedi);
+static struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid);
+
+static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle)
+{
+	struct qedi_ctx *qedi;
+	struct qedi_endpoint *qedi_ep;
+	struct async_data *data;
+	int rval = 0;
+
+	if (!context || !fw_handle) {
+		QEDI_ERR(NULL, "Recv event with ctx NULL\n");
+		return -EINVAL;
+	}
+
+	qedi = (struct qedi_ctx *)context;
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+		  "Recv Event %d fw_handle %p\n", fw_event_code, fw_handle);
+
+	data = (struct async_data *)fw_handle;
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+		  "cid=0x%x tid=0x%x err-code=0x%x fw-dbg-param=0x%x\n",
+		   data->cid, data->itid, data->error_code,
+		   data->fw_debug_param);
+
+	qedi_ep = qedi->ep_tbl[data->cid];
+
+	if (!qedi_ep) {
+		QEDI_WARN(&qedi->dbg_ctx,
+			  "Cannot process event, ep already disconnected, cid=0x%x\n",
+			   data->cid);
+		WARN_ON(1);
+		return -ENODEV;
+	}
+
+	switch (fw_event_code) {
+	case ISCSI_EVENT_TYPE_ASYN_CONNECT_COMPLETE:
+		if (qedi_ep->state == EP_STATE_OFLDCONN_START)
+			qedi_ep->state = EP_STATE_OFLDCONN_COMPL;
+
+		wake_up_interruptible(&qedi_ep->tcp_ofld_wait);
+		break;
+	case ISCSI_EVENT_TYPE_ASYN_TERMINATE_DONE:
+		qedi_ep->state = EP_STATE_DISCONN_COMPL;
+		wake_up_interruptible(&qedi_ep->tcp_ofld_wait);
+		break;
+	case ISCSI_EVENT_TYPE_ISCSI_CONN_ERROR:
+		qedi_process_iscsi_error(qedi_ep, data);
+		break;
+	case ISCSI_EVENT_TYPE_ASYN_ABORT_RCVD:
+	case ISCSI_EVENT_TYPE_ASYN_SYN_RCVD:
+	case ISCSI_EVENT_TYPE_ASYN_MAX_RT_TIME:
+	case ISCSI_EVENT_TYPE_ASYN_MAX_RT_CNT:
+	case ISCSI_EVENT_TYPE_ASYN_MAX_KA_PROBES_CNT:
+	case ISCSI_EVENT_TYPE_ASYN_FIN_WAIT2:
+	case ISCSI_EVENT_TYPE_TCP_CONN_ERROR:
+		qedi_process_tcp_error(qedi_ep, data);
+		break;
+	default:
+		QEDI_ERR(&qedi->dbg_ctx, "Recv Unknown Event %u\n",
+			 fw_event_code);
+	}
+
+	return rval;
+}
+
+static int qedi_alloc_and_init_sb(struct qedi_ctx *qedi,
+				  struct qed_sb_info *sb_info, u16 sb_id)
+{
+	struct status_block *sb_virt;
+	dma_addr_t sb_phys;
+	int ret;
+
+	sb_virt = dma_alloc_coherent(&qedi->pdev->dev,
+				     sizeof(struct status_block), &sb_phys,
+				     GFP_KERNEL);
+	if (!sb_virt) {
+		QEDI_ERR(&qedi->dbg_ctx,
+			 "Status block allocation failed for id = %d.\n",
+			  sb_id);
+		return -ENOMEM;
+	}
+
+	ret = qedi_ops->common->sb_init(qedi->cdev, sb_info, sb_virt, sb_phys,
+				       sb_id, QED_SB_TYPE_STORAGE);
+	if (ret) {
+		QEDI_ERR(&qedi->dbg_ctx,
+			 "Status block initialization failed for id = %d.\n",
+			  sb_id);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void qedi_free_sb(struct qedi_ctx *qedi)
+{
+	struct qed_sb_info *sb_info;
+	int id;
+
+	for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) {
+		sb_info = &qedi->sb_array[id];
+		if (sb_info->sb_virt)
+			dma_free_coherent(&qedi->pdev->dev,
+					  sizeof(*sb_info->sb_virt),
+					  (void *)sb_info->sb_virt,
+					  sb_info->sb_phys);
+	}
+}
+
+static void qedi_free_fp(struct qedi_ctx *qedi)
+{
+	kfree(qedi->fp_array);
+	kfree(qedi->sb_array);
+}
+
+static void qedi_destroy_fp(struct qedi_ctx *qedi)
+{
+	qedi_free_sb(qedi);
+	qedi_free_fp(qedi);
+}
+
+static int qedi_alloc_fp(struct qedi_ctx *qedi)
+{
+	int ret = 0;
+
+	qedi->fp_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi),
+				 sizeof(struct qedi_fastpath), GFP_KERNEL);
+	if (!qedi->fp_array) {
+		QEDI_ERR(&qedi->dbg_ctx,
+			 "fastpath fp array allocation failed.\n");
+		return -ENOMEM;
+	}
+
+	qedi->sb_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi),
+				 sizeof(struct qed_sb_info), GFP_KERNEL);
+	if (!qedi->sb_array) {
+		QEDI_ERR(&qedi->dbg_ctx,
+			 "fastpath sb array allocation failed.\n");
+		ret = -ENOMEM;
+		goto free_fp;
+	}
+
+	return ret;
+
+free_fp:
+	qedi_free_fp(qedi);
+	return ret;
+}
+
+static void qedi_int_fp(struct qedi_ctx *qedi)
+{
+	struct qedi_fastpath *fp;
+	int id;
+
+	memset(qedi->fp_array, 0, MIN_NUM_CPUS_MSIX(qedi) *
+	       sizeof(*qedi->fp_array));
+	memset(qedi->sb_array, 0, MIN_NUM_CPUS_MSIX(qedi) *
+	       sizeof(*qedi->sb_array));
+
+	for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) {
+		fp = &qedi->fp_array[id];
+		fp->sb_info = &qedi->sb_array[id];
+		fp->sb_id = id;
+		fp->qedi = qedi;
+		snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
+			 "qedi", id);
+
+		/* fp_array[i] ---- irq cookie
+		 * So init data which is needed in int ctx
+		 */
+	}
+}
+
+static int qedi_prepare_fp(struct qedi_ctx *qedi)
+{
+	struct qedi_fastpath *fp;
+	int id, ret = 0;
+
+	ret = qedi_alloc_fp(qedi);
+	if (ret)
+		goto err;
+
+	qedi_int_fp(qedi);
+
+	for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) {
+		fp = &qedi->fp_array[id];
+		ret = qedi_alloc_and_init_sb(qedi, fp->sb_info, fp->sb_id);
+		if (ret) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "SB allocation and initialization failed.\n");
+			ret = -EIO;
+			goto err_init;
+		}
+	}
+
+	return 0;
+
+err_init:
+	qedi_free_sb(qedi);
+	qedi_free_fp(qedi);
+err:
+	return ret;
+}
+
+static enum qed_int_mode qedi_int_mode_to_enum(void)
+{
+	switch (int_mode) {
+	case 0: return QED_INT_MODE_MSIX;
+	case 1: return QED_INT_MODE_INTA;
+	case 2: return QED_INT_MODE_MSI;
+	default:
+		QEDI_ERR(NULL, "Unknown qede_int_mode=%08x; "
+			 "Defaulting to MSI-x\n", int_mode);
+		return QED_INT_MODE_MSIX;
+	}
+}
+
+static int qedi_setup_cid_que(struct qedi_ctx *qedi)
+{
+	int i;
+
+	qedi->cid_que.cid_que_base = kmalloc_array(qedi->max_active_conns,
+						   sizeof(u32), GFP_KERNEL);
+	if (!qedi->cid_que.cid_que_base)
+		return -ENOMEM;
+
+	qedi->cid_que.conn_cid_tbl = kmalloc_array(qedi->max_active_conns,
+						   sizeof(struct qedi_conn *),
+						   GFP_KERNEL);
+	if (!qedi->cid_que.conn_cid_tbl) {
+		kfree(qedi->cid_que.cid_que_base);
+		qedi->cid_que.cid_que_base = NULL;
+		return -ENOMEM;
+	}
+
+	qedi->cid_que.cid_que = (u32 *)qedi->cid_que.cid_que_base;
+	qedi->cid_que.cid_q_prod_idx = 0;
+	qedi->cid_que.cid_q_cons_idx = 0;
+	qedi->cid_que.cid_q_max_idx = qedi->max_active_conns;
+	qedi->cid_que.cid_free_cnt = qedi->max_active_conns;
+
+	for (i = 0; i < qedi->max_active_conns; i++) {
+		qedi->cid_que.cid_que[i] = i;
+		qedi->cid_que.conn_cid_tbl[i] = NULL;
+	}
+
+	return 0;
+}
+
+static void qedi_release_cid_que(struct qedi_ctx *qedi)
+{
+	kfree(qedi->cid_que.cid_que_base);
+	qedi->cid_que.cid_que_base = NULL;
+
+	kfree(qedi->cid_que.conn_cid_tbl);
+	qedi->cid_que.conn_cid_tbl = NULL;
+}
+
+static int qedi_init_id_tbl(struct qedi_portid_tbl *id_tbl, u16 size,
+			    u16 start_id, u16 next)
+{
+	id_tbl->start = start_id;
+	id_tbl->max = size;
+	id_tbl->next = next;
+	spin_lock_init(&id_tbl->lock);
+	id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL);
+	if (!id_tbl->table)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void qedi_free_id_tbl(struct qedi_portid_tbl *id_tbl)
+{
+	kfree(id_tbl->table);
+	id_tbl->table = NULL;
+}
+
+int qedi_alloc_id(struct qedi_portid_tbl *id_tbl, u16 id)
+{
+	int ret = -1;
+
+	id -= id_tbl->start;
+	if (id >= id_tbl->max)
+		return ret;
+
+	spin_lock(&id_tbl->lock);
+	if (!test_bit(id, id_tbl->table)) {
+		set_bit(id, id_tbl->table);
+		ret = 0;
+	}
+	spin_unlock(&id_tbl->lock);
+	return ret;
+}
+
+u16 qedi_alloc_new_id(struct qedi_portid_tbl *id_tbl)
+{
+	u16 id;
+
+	spin_lock(&id_tbl->lock);
+	id = find_next_zero_bit(id_tbl->table, id_tbl->max, id_tbl->next);
+	if (id >= id_tbl->max) {
+		id = QEDI_LOCAL_PORT_INVALID;
+		if (id_tbl->next != 0) {
+			id = find_first_zero_bit(id_tbl->table, id_tbl->next);
+			if (id >= id_tbl->next)
+				id = QEDI_LOCAL_PORT_INVALID;
+		}
+	}
+
+	if (id < id_tbl->max) {
+		set_bit(id, id_tbl->table);
+		id_tbl->next = (id + 1) & (id_tbl->max - 1);
+		id += id_tbl->start;
+	}
+
+	spin_unlock(&id_tbl->lock);
+
+	return id;
+}
+
+void qedi_free_id(struct qedi_portid_tbl *id_tbl, u16 id)
+{
+	if (id == QEDI_LOCAL_PORT_INVALID)
+		return;
+
+	id -= id_tbl->start;
+	if (id >= id_tbl->max)
+		return;
+
+	clear_bit(id, id_tbl->table);
+}
+
+static void qedi_cm_free_mem(struct qedi_ctx *qedi)
+{
+	kfree(qedi->ep_tbl);
+	qedi->ep_tbl = NULL;
+	qedi_free_id_tbl(&qedi->lcl_port_tbl);
+}
+
+static int qedi_cm_alloc_mem(struct qedi_ctx *qedi)
+{
+	u16 port_id;
+
+	qedi->ep_tbl = kzalloc((qedi->max_active_conns *
+				sizeof(struct qedi_endpoint *)), GFP_KERNEL);
+	if (!qedi->ep_tbl)
+		return -ENOMEM;
+	port_id = prandom_u32() % QEDI_LOCAL_PORT_RANGE;
+	if (qedi_init_id_tbl(&qedi->lcl_port_tbl, QEDI_LOCAL_PORT_RANGE,
+			     QEDI_LOCAL_PORT_MIN, port_id)) {
+		qedi_cm_free_mem(qedi);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost;
+	struct qedi_ctx *qedi = NULL;
+
+	shost = iscsi_host_alloc(&qedi_host_template,
+				 sizeof(struct qedi_ctx), 0);
+	if (!shost) {
+		QEDI_ERR(NULL, "Could not allocate shost\n");
+		goto exit_setup_shost;
+	}
+
+	shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA;
+	shost->max_channel = 0;
+	shost->max_lun = ~0;
+	shost->max_cmd_len = 16;
+	shost->transportt = qedi_scsi_transport;
+
+	qedi = iscsi_host_priv(shost);
+	memset(qedi, 0, sizeof(*qedi));
+	qedi->shost = shost;
+	qedi->dbg_ctx.host_no = shost->host_no;
+	qedi->pdev = pdev;
+	qedi->dbg_ctx.pdev = pdev;
+	qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA;
+	qedi->max_sqes = QEDI_SQ_SIZE;
+
+	if (shost_use_blk_mq(shost))
+		shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi);
+
+	pci_set_drvdata(pdev, qedi);
+
+exit_setup_shost:
+	return qedi;
+}
+
+static int qedi_set_iscsi_pf_param(struct qedi_ctx *qedi)
+{
+	u8 num_sq_pages;
+	u32 log_page_size;
+	int rval = 0;
+
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "Min number of MSIX %d\n",
+		  MIN_NUM_CPUS_MSIX(qedi));
+
+	num_sq_pages = (MAX_OUSTANDING_TASKS_PER_CON * 8) / PAGE_SIZE;
+
+	qedi->num_queues = MIN_NUM_CPUS_MSIX(qedi);
+
+	memset(&qedi->pf_params.iscsi_pf_params, 0,
+	       sizeof(qedi->pf_params.iscsi_pf_params));
+
+	qedi->p_cpuq = pci_alloc_consistent(qedi->pdev,
+			qedi->num_queues * sizeof(struct qedi_glbl_q_params),
+			&qedi->hw_p_cpuq);
+	if (!qedi->p_cpuq) {
+		QEDI_ERR(&qedi->dbg_ctx, "pci_alloc_consistent fail\n");
+		rval = -1;
+		goto err_alloc_mem;
+	}
+
+	rval = qedi_alloc_global_queues(qedi);
+	if (rval) {
+		QEDI_ERR(&qedi->dbg_ctx, "Global queue allocation failed.\n");
+		rval = -1;
+		goto err_alloc_mem;
+	}
+
+	qedi->pf_params.iscsi_pf_params.num_cons = QEDI_MAX_ISCSI_CONNS_PER_HBA;
+	qedi->pf_params.iscsi_pf_params.num_tasks = QEDI_MAX_ISCSI_TASK;
+	qedi->pf_params.iscsi_pf_params.half_way_close_timeout = 10;
+	qedi->pf_params.iscsi_pf_params.num_sq_pages_in_ring = num_sq_pages;
+	qedi->pf_params.iscsi_pf_params.num_r2tq_pages_in_ring = num_sq_pages;
+	qedi->pf_params.iscsi_pf_params.num_uhq_pages_in_ring = num_sq_pages;
+	qedi->pf_params.iscsi_pf_params.num_queues = qedi->num_queues;
+	qedi->pf_params.iscsi_pf_params.debug_mode = fw_debug;
+
+	for (log_page_size = 0 ; log_page_size < 32 ; log_page_size++) {
+		if ((1 << log_page_size) == PAGE_SIZE)
+			break;
+	}
+	qedi->pf_params.iscsi_pf_params.log_page_size = log_page_size;
+
+	qedi->pf_params.iscsi_pf_params.glbl_q_params_addr = qedi->hw_p_cpuq;
+
+	/* RQ BDQ initializations.
+	 * rq_num_entries: suggested value for Initiator is 16 (4KB RQ)
+	 * rqe_log_size: 8 for 256B RQE
+	 */
+	qedi->pf_params.iscsi_pf_params.rqe_log_size = 8;
+	/* BDQ address and size */
+	qedi->pf_params.iscsi_pf_params.bdq_pbl_base_addr[BDQ_ID_RQ] =
+							qedi->bdq_pbl_list_dma;
+	qedi->pf_params.iscsi_pf_params.bdq_pbl_num_entries[BDQ_ID_RQ] =
+						qedi->bdq_pbl_list_num_entries;
+	qedi->pf_params.iscsi_pf_params.rq_buffer_size = QEDI_BDQ_BUF_SIZE;
+
+	/* cq_num_entries: num_tasks + rq_num_entries */
+	qedi->pf_params.iscsi_pf_params.cq_num_entries = 2048;
+
+	qedi->pf_params.iscsi_pf_params.gl_rq_pi = QEDI_PROTO_CQ_PROD_IDX;
+	qedi->pf_params.iscsi_pf_params.gl_cmd_pi = 1;
+	qedi->pf_params.iscsi_pf_params.ooo_enable = 1;
+
+err_alloc_mem:
+	return rval;
+}
+
+/* Free DMA coherent memory for array of queue pointers we pass to qed */
+static void qedi_free_iscsi_pf_param(struct qedi_ctx *qedi)
+{
+	size_t size = 0;
+
+	if (qedi->p_cpuq) {
+		size = qedi->num_queues * sizeof(struct qedi_glbl_q_params);
+		pci_free_consistent(qedi->pdev, size, qedi->p_cpuq,
+				    qedi->hw_p_cpuq);
+	}
+
+	qedi_free_global_queues(qedi);
+
+	kfree(qedi->global_queues);
+}
+
+static void qedi_link_update(void *dev, struct qed_link_output *link)
+{
+	struct qedi_ctx *qedi = (struct qedi_ctx *)dev;
+
+	if (link->link_up) {
+		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "Link Up event.\n");
+		atomic_set(&qedi->link_state, QEDI_LINK_UP);
+	} else {
+		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+			  "Link Down event.\n");
+		atomic_set(&qedi->link_state, QEDI_LINK_DOWN);
+	}
+}
+
+static struct qed_iscsi_cb_ops qedi_cb_ops = {
+	{
+		.link_update =		qedi_link_update,
+	}
+};
+
+static int qedi_queue_cqe(struct qedi_ctx *qedi, union iscsi_cqe *cqe,
+			  u16 que_idx, struct qedi_percpu_s *p)
+{
+	struct qedi_work *qedi_work;
+	struct qedi_conn *q_conn;
+	struct iscsi_conn *conn;
+	struct qedi_cmd *qedi_cmd;
+	u32 iscsi_cid;
+	int rc = 0;
+
+	iscsi_cid  = cqe->cqe_common.conn_id;
+	q_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid];
+	if (!q_conn) {
+		QEDI_WARN(&qedi->dbg_ctx,
+			  "Session no longer exists for cid=0x%x!!\n",
+			  iscsi_cid);
+		return -1;
+	}
+	conn = q_conn->cls_conn->dd_data;
+
+	switch (cqe->cqe_common.cqe_type) {
+	case ISCSI_CQE_TYPE_SOLICITED:
+	case ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE:
+		qedi_cmd = qedi_get_cmd_from_tid(qedi, cqe->cqe_solicited.itid);
+		if (!qedi_cmd) {
+			rc = -1;
+			break;
+		}
+		INIT_LIST_HEAD(&qedi_cmd->cqe_work.list);
+		qedi_cmd->cqe_work.qedi = qedi;
+		memcpy(&qedi_cmd->cqe_work.cqe, cqe, sizeof(union iscsi_cqe));
+		qedi_cmd->cqe_work.que_idx = que_idx;
+		qedi_cmd->cqe_work.is_solicited = true;
+		list_add_tail(&qedi_cmd->cqe_work.list, &p->work_list);
+		break;
+	case ISCSI_CQE_TYPE_UNSOLICITED:
+	case ISCSI_CQE_TYPE_DUMMY:
+	case ISCSI_CQE_TYPE_TASK_CLEANUP:
+		qedi_work = kzalloc(sizeof(*qedi_work), GFP_ATOMIC);
+		if (!qedi_work) {
+			rc = -1;
+			break;
+		}
+		INIT_LIST_HEAD(&qedi_work->list);
+		qedi_work->qedi = qedi;
+		memcpy(&qedi_work->cqe, cqe, sizeof(union iscsi_cqe));
+		qedi_work->que_idx = que_idx;
+		qedi_work->is_solicited = false;
+		list_add_tail(&qedi_work->list, &p->work_list);
+		break;
+	default:
+		rc = -1;
+		QEDI_ERR(&qedi->dbg_ctx, "FW Error cqe.\n");
+	}
+	return rc;
+}
+
+static bool qedi_process_completions(struct qedi_fastpath *fp)
+{
+	struct qedi_ctx *qedi = fp->qedi;
+	struct qed_sb_info *sb_info = fp->sb_info;
+	struct status_block *sb = sb_info->sb_virt;
+	struct qedi_percpu_s *p = NULL;
+	struct global_queue *que;
+	u16 prod_idx;
+	unsigned long flags;
+	union iscsi_cqe *cqe;
+	int cpu;
+	int ret;
+
+	/* Get the current firmware producer index */
+	prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX];
+
+	if (prod_idx >= QEDI_CQ_SIZE)
+		prod_idx = prod_idx % QEDI_CQ_SIZE;
+
+	que = qedi->global_queues[fp->sb_id];
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO,
+		  "Before: global queue=%p prod_idx=%d cons_idx=%d, sb_id=%d\n",
+		  que, prod_idx, que->cq_cons_idx, fp->sb_id);
+
+	qedi->intr_cpu = fp->sb_id;
+	cpu = smp_processor_id();
+	p = &per_cpu(qedi_percpu, cpu);
+
+	if (unlikely(!p->iothread))
+		WARN_ON(1);
+
+	spin_lock_irqsave(&p->p_work_lock, flags);
+	while (que->cq_cons_idx != prod_idx) {
+		cqe = &que->cq[que->cq_cons_idx];
+
+		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO,
+			  "cqe=%p prod_idx=%d cons_idx=%d.\n",
+			  cqe, prod_idx, que->cq_cons_idx);
+
+		ret = qedi_queue_cqe(qedi, cqe, fp->sb_id, p);
+		if (ret)
+			continue;
+
+		que->cq_cons_idx++;
+		if (que->cq_cons_idx == QEDI_CQ_SIZE)
+			que->cq_cons_idx = 0;
+	}
+	wake_up_process(p->iothread);
+	spin_unlock_irqrestore(&p->p_work_lock, flags);
+
+	return true;
+}
+
+static bool qedi_fp_has_work(struct qedi_fastpath *fp)
+{
+	struct qedi_ctx *qedi = fp->qedi;
+	struct global_queue *que;
+	struct qed_sb_info *sb_info = fp->sb_info;
+	struct status_block *sb = sb_info->sb_virt;
+	u16 prod_idx;
+
+	barrier();
+
+	/* Get the current firmware producer index */
+	prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX];
+
+	/* Get the pointer to the global CQ this completion is on */
+	que = qedi->global_queues[fp->sb_id];
+
+	/* prod idx wrap around uint16 */
+	if (prod_idx >= QEDI_CQ_SIZE)
+		prod_idx = prod_idx % QEDI_CQ_SIZE;
+
+	return (que->cq_cons_idx != prod_idx);
+}
+
+/* MSI-X fastpath handler code */
+static irqreturn_t qedi_msix_handler(int irq, void *dev_id)
+{
+	struct qedi_fastpath *fp = dev_id;
+	struct qedi_ctx *qedi = fp->qedi;
+	bool wake_io_thread = true;
+
+	qed_sb_ack(fp->sb_info, IGU_INT_DISABLE, 0);
+
+process_again:
+	wake_io_thread = qedi_process_completions(fp);
+	if (wake_io_thread) {
+		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC,
+			  "process already running\n");
+	}
+
+	if (qedi_fp_has_work(fp) == 0)
+		qed_sb_update_sb_idx(fp->sb_info);
+
+	/* Check for more work */
+	rmb();
+
+	if (qedi_fp_has_work(fp) == 0)
+		qed_sb_ack(fp->sb_info, IGU_INT_ENABLE, 1);
+	else
+		goto process_again;
+
+	return IRQ_HANDLED;
+}
+
+/* simd handler for MSI/INTa */
+static void qedi_simd_int_handler(void *cookie)
+{
+	/* Cookie is qedi_ctx struct */
+	struct qedi_ctx *qedi = (struct qedi_ctx *)cookie;
+
+	QEDI_WARN(&qedi->dbg_ctx, "qedi=%p.\n", qedi);
+}
+
+#define QEDI_SIMD_HANDLER_NUM		0
+static void qedi_sync_free_irqs(struct qedi_ctx *qedi)
+{
+	int i;
+
+	if (qedi->int_info.msix_cnt) {
+		for (i = 0; i < qedi->int_info.used_cnt; i++) {
+			synchronize_irq(qedi->int_info.msix[i].vector);
+			irq_set_affinity_hint(qedi->int_info.msix[i].vector,
+					      NULL);
+			free_irq(qedi->int_info.msix[i].vector,
+				 &qedi->fp_array[i]);
+		}
+	} else {
+		qedi_ops->common->simd_handler_clean(qedi->cdev,
+						     QEDI_SIMD_HANDLER_NUM);
+	}
+
+	qedi->int_info.used_cnt = 0;
+	qedi_ops->common->set_fp_int(qedi->cdev, 0);
+}
+
+static int qedi_request_msix_irq(struct qedi_ctx *qedi)
+{
+	int i, rc, cpu;
+
+	cpu = cpumask_first(cpu_online_mask);
+	for (i = 0; i < MIN_NUM_CPUS_MSIX(qedi); i++) {
+		rc = request_irq(qedi->int_info.msix[i].vector,
+				 qedi_msix_handler, 0, "qedi",
+				 &qedi->fp_array[i]);
+
+		if (rc) {
+			QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n");
+			qedi_sync_free_irqs(qedi);
+			return rc;
+		}
+		qedi->int_info.used_cnt++;
+		rc = irq_set_affinity_hint(qedi->int_info.msix[i].vector,
+					   get_cpu_mask(cpu));
+		cpu = cpumask_next(cpu, cpu_online_mask);
+	}
+
+	return 0;
+}
+
+static int qedi_setup_int(struct qedi_ctx *qedi)
+{
+	int rc = 0;
+
+	rc = qedi_ops->common->set_fp_int(qedi->cdev, num_online_cpus());
+	rc = qedi_ops->common->get_fp_int(qedi->cdev, &qedi->int_info);
+	if (rc)
+		goto exit_setup_int;
+
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC,
+		  "Number of msix_cnt = 0x%x num of cpus = 0x%x\n",
+		   qedi->int_info.msix_cnt, num_online_cpus());
+
+	if (qedi->int_info.msix_cnt) {
+		rc = qedi_request_msix_irq(qedi);
+		goto exit_setup_int;
+	} else {
+		qedi_ops->common->simd_handler_config(qedi->cdev, &qedi,
+						      QEDI_SIMD_HANDLER_NUM,
+						      qedi_simd_int_handler);
+		qedi->int_info.used_cnt = 1;
+	}
+
+exit_setup_int:
+	return rc;
+}
+
+static void qedi_free_bdq(struct qedi_ctx *qedi)
+{
+	int i;
+
+	if (qedi->bdq_pbl_list)
+		dma_free_coherent(&qedi->pdev->dev, PAGE_SIZE,
+				  qedi->bdq_pbl_list, qedi->bdq_pbl_list_dma);
+
+	if (qedi->bdq_pbl)
+		dma_free_coherent(&qedi->pdev->dev, qedi->bdq_pbl_mem_size,
+				  qedi->bdq_pbl, qedi->bdq_pbl_dma);
+
+	for (i = 0; i < QEDI_BDQ_NUM; i++) {
+		if (qedi->bdq[i].buf_addr) {
+			dma_free_coherent(&qedi->pdev->dev, QEDI_BDQ_BUF_SIZE,
+					  qedi->bdq[i].buf_addr,
+					  qedi->bdq[i].buf_dma);
+		}
+	}
+}
+
+static void qedi_free_global_queues(struct qedi_ctx *qedi)
+{
+	int i;
+	struct global_queue **gl = qedi->global_queues;
+
+	for (i = 0; i < qedi->num_queues; i++) {
+		if (!gl[i])
+			continue;
+
+		if (gl[i]->cq)
+			dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_mem_size,
+					  gl[i]->cq, gl[i]->cq_dma);
+		if (gl[i]->cq_pbl)
+			dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_pbl_size,
+					  gl[i]->cq_pbl, gl[i]->cq_pbl_dma);
+
+		kfree(gl[i]);
+	}
+	qedi_free_bdq(qedi);
+}
+
+static int qedi_alloc_bdq(struct qedi_ctx *qedi)
+{
+	int i;
+	struct scsi_bd *pbl;
+	u64 *list;
+	dma_addr_t page;
+
+	/* Alloc dma memory for BDQ buffers */
+	for (i = 0; i < QEDI_BDQ_NUM; i++) {
+		qedi->bdq[i].buf_addr =
+				dma_alloc_coherent(&qedi->pdev->dev,
+						   QEDI_BDQ_BUF_SIZE,
+						   &qedi->bdq[i].buf_dma,
+						   GFP_KERNEL);
+		if (!qedi->bdq[i].buf_addr) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "Could not allocate BDQ buffer %d.\n", i);
+			return -ENOMEM;
+		}
+	}
+
+	/* Alloc dma memory for BDQ page buffer list */
+	qedi->bdq_pbl_mem_size = QEDI_BDQ_NUM * sizeof(struct scsi_bd);
+	qedi->bdq_pbl_mem_size = ALIGN(qedi->bdq_pbl_mem_size, PAGE_SIZE);
+	qedi->rq_num_entries = qedi->bdq_pbl_mem_size / sizeof(struct scsi_bd);
+
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, "rq_num_entries = %d.\n",
+		  qedi->rq_num_entries);
+
+	qedi->bdq_pbl = dma_alloc_coherent(&qedi->pdev->dev,
+					   qedi->bdq_pbl_mem_size,
+					   &qedi->bdq_pbl_dma, GFP_KERNEL);
+	if (!qedi->bdq_pbl) {
+		QEDI_ERR(&qedi->dbg_ctx, "Could not allocate BDQ PBL.\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Populate BDQ PBL with physical and virtual address of individual
+	 * BDQ buffers
+	 */
+	pbl = (struct scsi_bd  *)qedi->bdq_pbl;
+	for (i = 0; i < QEDI_BDQ_NUM; i++) {
+		pbl->address.hi =
+				cpu_to_le32(QEDI_U64_HI(qedi->bdq[i].buf_dma));
+		pbl->address.lo =
+				cpu_to_le32(QEDI_U64_LO(qedi->bdq[i].buf_dma));
+		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
+			  "pbl [0x%p] pbl->address hi [0x%llx] lo [0x%llx], idx [%d]\n",
+			  pbl, pbl->address.hi, pbl->address.lo, i);
+		pbl->opaque.hi = 0;
+		pbl->opaque.lo = cpu_to_le32(QEDI_U64_LO(i));
+		pbl++;
+	}
+
+	/* Allocate list of PBL pages */
+	qedi->bdq_pbl_list = dma_alloc_coherent(&qedi->pdev->dev,
+						PAGE_SIZE,
+						&qedi->bdq_pbl_list_dma,
+						GFP_KERNEL);
+	if (!qedi->bdq_pbl_list) {
+		QEDI_ERR(&qedi->dbg_ctx,
+			 "Could not allocate list of PBL pages.\n");
+		return -ENOMEM;
+	}
+	memset(qedi->bdq_pbl_list, 0, PAGE_SIZE);
+
+	/*
+	 * Now populate PBL list with pages that contain pointers to the
+	 * individual buffers.
+	 */
+	qedi->bdq_pbl_list_num_entries = qedi->bdq_pbl_mem_size / PAGE_SIZE;
+	list = (u64 *)qedi->bdq_pbl_list;
+	page = qedi->bdq_pbl_list_dma;
+	for (i = 0; i < qedi->bdq_pbl_list_num_entries; i++) {
+		*list = qedi->bdq_pbl_dma;
+		list++;
+		page += PAGE_SIZE;
+	}
+
+	return 0;
+}
+
+static int qedi_alloc_global_queues(struct qedi_ctx *qedi)
+{
+	u32 *list;
+	int i;
+	int status = 0, rc;
+	u32 *pbl;
+	dma_addr_t page;
+	int num_pages;
+
+	/*
+	 * Number of global queues (CQ / RQ). This should
+	 * be <= number of available MSIX vectors for the PF
+	 */
+	if (!qedi->num_queues) {
+		QEDI_ERR(&qedi->dbg_ctx, "No MSI-X vectors available!\n");
+		return 1;
+	}
+
+	/* Make sure we allocated the PBL that will contain the physical
+	 * addresses of our queues
+	 */
+	if (!qedi->p_cpuq) {
+		status = 1;
+		goto mem_alloc_failure;
+	}
+
+	qedi->global_queues = kzalloc((sizeof(struct global_queue *) *
+				       qedi->num_queues), GFP_KERNEL);
+	if (!qedi->global_queues) {
+		QEDI_ERR(&qedi->dbg_ctx,
+			 "Unable to allocate global queues array ptr memory\n");
+		return -ENOMEM;
+	}
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC,
+		  "qedi->global_queues=%p.\n", qedi->global_queues);
+
+	/* Allocate DMA coherent buffers for BDQ */
+	rc = qedi_alloc_bdq(qedi);
+	if (rc)
+		goto mem_alloc_failure;
+
+	/* Allocate a CQ and an associated PBL for each MSI-X
+	 * vector.
+	 */
+	for (i = 0; i < qedi->num_queues; i++) {
+		qedi->global_queues[i] =
+					kzalloc(sizeof(*qedi->global_queues[0]),
+						GFP_KERNEL);
+		if (!qedi->global_queues[i]) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "Unable to allocation global queue %d.\n", i);
+			goto mem_alloc_failure;
+		}
+
+		qedi->global_queues[i]->cq_mem_size =
+		    (QEDI_CQ_SIZE + 8) * sizeof(union iscsi_cqe);
+		qedi->global_queues[i]->cq_mem_size =
+		    (qedi->global_queues[i]->cq_mem_size +
+		    (QEDI_PAGE_SIZE - 1));
+
+		qedi->global_queues[i]->cq_pbl_size =
+		    (qedi->global_queues[i]->cq_mem_size /
+		    QEDI_PAGE_SIZE) * sizeof(void *);
+		qedi->global_queues[i]->cq_pbl_size =
+		    (qedi->global_queues[i]->cq_pbl_size +
+		    (QEDI_PAGE_SIZE - 1));
+
+		qedi->global_queues[i]->cq =
+		    dma_alloc_coherent(&qedi->pdev->dev,
+				       qedi->global_queues[i]->cq_mem_size,
+				       &qedi->global_queues[i]->cq_dma,
+				       GFP_KERNEL);
+
+		if (!qedi->global_queues[i]->cq) {
+			QEDI_WARN(&qedi->dbg_ctx,
+				  "Could not allocate cq.\n");
+			status = -ENOMEM;
+			goto mem_alloc_failure;
+		}
+		memset(qedi->global_queues[i]->cq, 0,
+		       qedi->global_queues[i]->cq_mem_size);
+
+		qedi->global_queues[i]->cq_pbl =
+		    dma_alloc_coherent(&qedi->pdev->dev,
+				       qedi->global_queues[i]->cq_pbl_size,
+				       &qedi->global_queues[i]->cq_pbl_dma,
+				       GFP_KERNEL);
+
+		if (!qedi->global_queues[i]->cq_pbl) {
+			QEDI_WARN(&qedi->dbg_ctx,
+				  "Could not allocate cq PBL.\n");
+			status = -ENOMEM;
+			goto mem_alloc_failure;
+		}
+		memset(qedi->global_queues[i]->cq_pbl, 0,
+		       qedi->global_queues[i]->cq_pbl_size);
+
+		/* Create PBL */
+		num_pages = qedi->global_queues[i]->cq_mem_size /
+		    QEDI_PAGE_SIZE;
+		page = qedi->global_queues[i]->cq_dma;
+		pbl = (u32 *)qedi->global_queues[i]->cq_pbl;
+
+		while (num_pages--) {
+			*pbl = (u32)page;
+			pbl++;
+			*pbl = (u32)((u64)page >> 32);
+			pbl++;
+			page += QEDI_PAGE_SIZE;
+		}
+	}
+
+	list = (u32 *)qedi->p_cpuq;
+
+	/*
+	 * The list is built as follows: CQ#0 PBL pointer, RQ#0 PBL pointer,
+	 * CQ#1 PBL pointer, RQ#1 PBL pointer, etc.  Each PBL pointer points
+	 * to the physical address which contains an array of pointers to the
+	 * physical addresses of the specific queue pages.
+	 */
+	for (i = 0; i < qedi->num_queues; i++) {
+		*list = (u32)qedi->global_queues[i]->cq_pbl_dma;
+		list++;
+		*list = (u32)((u64)qedi->global_queues[i]->cq_pbl_dma >> 32);
+		list++;
+
+		*list = (u32)0;
+		list++;
+		*list = (u32)((u64)0 >> 32);
+		list++;
+	}
+
+	return 0;
+
+mem_alloc_failure:
+	qedi_free_global_queues(qedi);
+	return status;
+}
+
+struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid)
+{
+	struct qedi_cmd *cmd = NULL;
+
+	if (tid > MAX_ISCSI_TASK_ENTRIES)
+		return NULL;
+
+	cmd = qedi->itt_map[tid].p_cmd;
+	if (cmd->task_id != tid)
+		return NULL;
+
+	qedi->itt_map[tid].p_cmd = NULL;
+
+	return cmd;
+}
+
+static int qedi_alloc_itt(struct qedi_ctx *qedi)
+{
+	qedi->itt_map = kcalloc(MAX_ISCSI_TASK_ENTRIES,
+				sizeof(struct qedi_itt_map), GFP_KERNEL);
+	if (!qedi->itt_map) {
+		QEDI_ERR(&qedi->dbg_ctx,
+			 "Unable to allocate itt map array memory\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void qedi_free_itt(struct qedi_ctx *qedi)
+{
+	kfree(qedi->itt_map);
+}
+
+static struct qed_ll2_cb_ops qedi_ll2_cb_ops = {
+	.rx_cb = qedi_ll2_rx,
+	.tx_cb = NULL,
+};
+
+static int qedi_percpu_io_thread(void *arg)
+{
+	struct qedi_percpu_s *p = arg;
+	struct qedi_work *work, *tmp;
+	unsigned long flags;
+	LIST_HEAD(work_list);
+
+	set_user_nice(current, -20);
+
+	while (!kthread_should_stop()) {
+		spin_lock_irqsave(&p->p_work_lock, flags);
+		while (!list_empty(&p->work_list)) {
+			list_splice_init(&p->work_list, &work_list);
+			spin_unlock_irqrestore(&p->p_work_lock, flags);
+
+			list_for_each_entry_safe(work, tmp, &work_list, list) {
+				list_del_init(&work->list);
+				qedi_fp_process_cqes(work);
+				if (!work->is_solicited)
+					kfree(work);
+			}
+			cond_resched();
+			spin_lock_irqsave(&p->p_work_lock, flags);
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&p->p_work_lock, flags);
+		schedule();
+	}
+	__set_current_state(TASK_RUNNING);
+
+	return 0;
+}
+
+static void qedi_percpu_thread_create(unsigned int cpu)
+{
+	struct qedi_percpu_s *p;
+	struct task_struct *thread;
+
+	p = &per_cpu(qedi_percpu, cpu);
+
+	thread = kthread_create_on_node(qedi_percpu_io_thread, (void *)p,
+					cpu_to_node(cpu),
+					"qedi_thread/%d", cpu);
+	if (likely(!IS_ERR(thread))) {
+		kthread_bind(thread, cpu);
+		p->iothread = thread;
+		wake_up_process(thread);
+	}
+}
+
+static void qedi_percpu_thread_destroy(unsigned int cpu)
+{
+	struct qedi_percpu_s *p;
+	struct task_struct *thread;
+	struct qedi_work *work, *tmp;
+
+	p = &per_cpu(qedi_percpu, cpu);
+	spin_lock_bh(&p->p_work_lock);
+	thread = p->iothread;
+	p->iothread = NULL;
+
+	list_for_each_entry_safe(work, tmp, &p->work_list, list) {
+		list_del_init(&work->list);
+		qedi_fp_process_cqes(work);
+		if (!work->is_solicited)
+			kfree(work);
+	}
+
+	spin_unlock_bh(&p->p_work_lock);
+	if (thread)
+		kthread_stop(thread);
+}
+
+static int qedi_cpu_callback(struct notifier_block *nfb,
+			     unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+
+	switch (action) {
+	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
+		QEDI_ERR(NULL, "CPU %d online.\n", cpu);
+		qedi_percpu_thread_create(cpu);
+		break;
+	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
+		QEDI_ERR(NULL, "CPU %d offline.\n", cpu);
+		qedi_percpu_thread_destroy(cpu);
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block qedi_cpu_notifier = {
+	.notifier_call = qedi_cpu_callback,
+};
+
+static void __qedi_remove(struct pci_dev *pdev, int mode)
+{
+	struct qedi_ctx *qedi = pci_get_drvdata(pdev);
+
+	if (qedi->tmf_thread) {
+		flush_workqueue(qedi->tmf_thread);
+		destroy_workqueue(qedi->tmf_thread);
+		qedi->tmf_thread = NULL;
+	}
+
+	if (qedi->offload_thread) {
+		flush_workqueue(qedi->offload_thread);
+		destroy_workqueue(qedi->offload_thread);
+		qedi->offload_thread = NULL;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	qedi_dbg_host_exit(&qedi->dbg_ctx);
+#endif
+	if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags))
+		qedi_ops->common->set_power_state(qedi->cdev, PCI_D0);
+
+	qedi_sync_free_irqs(qedi);
+
+	if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) {
+		qedi_ops->stop(qedi->cdev);
+		qedi_ops->ll2->stop(qedi->cdev);
+	}
+
+	if (mode == QEDI_MODE_NORMAL)
+		qedi_free_iscsi_pf_param(qedi);
+
+	if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) {
+		qedi_ops->common->slowpath_stop(qedi->cdev);
+		qedi_ops->common->remove(qedi->cdev);
+	}
+
+	qedi_destroy_fp(qedi);
+
+	if (mode == QEDI_MODE_NORMAL) {
+		qedi_release_cid_que(qedi);
+		qedi_cm_free_mem(qedi);
+		qedi_free_uio(qedi->udev);
+		qedi_free_itt(qedi);
+
+		iscsi_host_remove(qedi->shost);
+		iscsi_host_free(qedi->shost);
+
+		if (qedi->ll2_recv_thread) {
+			kthread_stop(qedi->ll2_recv_thread);
+			qedi->ll2_recv_thread = NULL;
+		}
+		qedi_ll2_free_skbs(qedi);
+	}
+}
+
+static int __qedi_probe(struct pci_dev *pdev, int mode)
+{
+	struct qedi_ctx *qedi;
+	struct qed_ll2_params params;
+	u32 dp_module = 0;
+	u8 dp_level = 0;
+	bool is_vf = false;
+	char host_buf[16];
+	struct qed_link_params link_params;
+	struct qed_slowpath_params sp_params;
+	struct qed_probe_params qed_params;
+	void *task_start, *task_end;
+	int rc;
+	u16 tmp;
+
+	if (mode != QEDI_MODE_RECOVERY) {
+		qedi = qedi_host_alloc(pdev);
+		if (!qedi) {
+			rc = -ENOMEM;
+			goto exit_probe;
+		}
+	} else {
+		qedi = pci_get_drvdata(pdev);
+	}
+
+	memset(&qed_params, 0, sizeof(qed_params));
+	qed_params.protocol = QED_PROTOCOL_ISCSI;
+	qed_params.dp_module = dp_module;
+	qed_params.dp_level = dp_level;
+	qed_params.is_vf = is_vf;
+	qedi->cdev = qedi_ops->common->probe(pdev, &qed_params);
+	if (!qedi->cdev) {
+		rc = -ENODEV;
+		QEDI_ERR(&qedi->dbg_ctx, "Cannot initialize hardware\n");
+		goto free_host;
+	}
+
+	qedi->msix_count = MAX_NUM_MSIX_PF;
+	atomic_set(&qedi->link_state, QEDI_LINK_DOWN);
+
+	if (mode != QEDI_MODE_RECOVERY) {
+		rc = qedi_set_iscsi_pf_param(qedi);
+		if (rc) {
+			rc = -ENOMEM;
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "Set iSCSI pf param fail\n");
+			goto free_host;
+		}
+	}
+
+	qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params);
+
+	rc = qedi_prepare_fp(qedi);
+	if (rc) {
+		QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath.\n");
+		goto free_pf_params;
+	}
+
+	/* Start the Slowpath-process */
+	memset(&sp_params, 0, sizeof(struct qed_slowpath_params));
+	sp_params.int_mode = qedi_int_mode_to_enum();
+	sp_params.drv_major = QEDI_DRIVER_MAJOR_VER;
+	sp_params.drv_minor = QEDI_DRIVER_MINOR_VER;
+	sp_params.drv_rev = QEDI_DRIVER_REV_VER;
+	sp_params.drv_eng = QEDI_DRIVER_ENG_VER;
+	strlcpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE);
+	rc = qedi_ops->common->slowpath_start(qedi->cdev, &sp_params);
+	if (rc) {
+		QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath\n");
+		goto stop_hw;
+	}
+
+	/* update_pf_params needs to be called before and after slowpath
+	 * start
+	 */
+	qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params);
+
+	qedi_setup_int(qedi);
+	if (rc)
+		goto stop_iscsi_func;
+
+	qedi_ops->common->set_power_state(qedi->cdev, PCI_D0);
+
+	/* Learn information crucial for qedi to progress */
+	rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info);
+	if (rc)
+		goto stop_iscsi_func;
+
+	/* Record BDQ producer doorbell addresses */
+	qedi->bdq_primary_prod = qedi->dev_info.primary_dbq_rq_addr;
+	qedi->bdq_secondary_prod = qedi->dev_info.secondary_bdq_rq_addr;
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC,
+		  "BDQ primary_prod=%p secondary_prod=%p.\n",
+		  qedi->bdq_primary_prod,
+		  qedi->bdq_secondary_prod);
+
+	/*
+	 * We need to write the number of BDs in the BDQ we've preallocated so
+	 * the f/w will do a prefetch and we'll get an unsolicited CQE when a
+	 * packet arrives.
+	 */
+	qedi->bdq_prod_idx = QEDI_BDQ_NUM;
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC,
+		  "Writing %d to primary and secondary BDQ doorbell registers.\n",
+		  qedi->bdq_prod_idx);
+	writew(qedi->bdq_prod_idx, qedi->bdq_primary_prod);
+	tmp = readw(qedi->bdq_primary_prod);
+	writew(qedi->bdq_prod_idx, qedi->bdq_secondary_prod);
+	tmp = readw(qedi->bdq_secondary_prod);
+
+	ether_addr_copy(qedi->mac, qedi->dev_info.common.hw_mac);
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "MAC address is %pM.\n",
+		  qedi->mac);
+
+	sprintf(host_buf, "host_%d", qedi->shost->host_no);
+	qedi_ops->common->set_id(qedi->cdev, host_buf, QEDI_MODULE_VERSION);
+
+	qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi);
+
+	memset(&params, 0, sizeof(params));
+	params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN;
+	qedi->ll2_mtu = DEF_PATH_MTU;
+	params.drop_ttl0_packets = 0;
+	params.rx_vlan_stripping = 1;
+	ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac);
+
+	if (mode != QEDI_MODE_RECOVERY) {
+		/* set up rx path */
+		INIT_LIST_HEAD(&qedi->ll2_skb_list);
+		spin_lock_init(&qedi->ll2_lock);
+		/* start qedi context */
+		spin_lock_init(&qedi->hba_lock);
+		spin_lock_init(&qedi->task_idx_lock);
+	}
+	qedi_ops->ll2->register_cb_ops(qedi->cdev, &qedi_ll2_cb_ops, qedi);
+	qedi_ops->ll2->start(qedi->cdev, &params);
+
+	if (mode != QEDI_MODE_RECOVERY) {
+		qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread,
+						    (void *)qedi,
+						    "qedi_ll2_thread");
+	}
+
+	rc = qedi_ops->start(qedi->cdev, &qedi->tasks,
+			     qedi, qedi_iscsi_event_cb);
+	if (rc) {
+		rc = -ENODEV;
+		QEDI_ERR(&qedi->dbg_ctx, "Cannot start iSCSI function\n");
+		goto stop_slowpath;
+	}
+
+	task_start = qedi_get_task_mem(&qedi->tasks, 0);
+	task_end = qedi_get_task_mem(&qedi->tasks, MAX_TID_BLOCKS_ISCSI - 1);
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC,
+		  "Task context start=%p, end=%p block_size=%u.\n",
+		   task_start, task_end, qedi->tasks.size);
+
+	memset(&link_params, 0, sizeof(link_params));
+	link_params.link_up = true;
+	rc = qedi_ops->common->set_link(qedi->cdev, &link_params);
+	if (rc) {
+		QEDI_WARN(&qedi->dbg_ctx, "Link set up failed.\n");
+		atomic_set(&qedi->link_state, QEDI_LINK_DOWN);
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	qedi_dbg_host_init(&qedi->dbg_ctx, &qedi_debugfs_ops,
+			   &qedi_dbg_fops);
+#endif
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+		  "QLogic FastLinQ iSCSI Module qedi %s, FW %d.%d.%d.%d\n",
+		  QEDI_MODULE_VERSION, FW_MAJOR_VERSION, FW_MINOR_VERSION,
+		  FW_REVISION_VERSION, FW_ENGINEERING_VERSION);
+
+	if (mode == QEDI_MODE_NORMAL) {
+		if (iscsi_host_add(qedi->shost, &pdev->dev)) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "Could not add iscsi host\n");
+			rc = -ENOMEM;
+			goto remove_host;
+		}
+
+		/* Allocate uio buffers */
+		rc = qedi_alloc_uio_rings(qedi);
+		if (rc) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "UIO alloc ring failed err=%d\n", rc);
+			goto remove_host;
+		}
+
+		rc = qedi_init_uio(qedi);
+		if (rc) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "UIO init failed, err=%d\n", rc);
+			goto free_uio;
+		}
+
+		/* host the array on iscsi_conn */
+		rc = qedi_setup_cid_que(qedi);
+		if (rc) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "Could not setup cid que\n");
+			goto free_uio;
+		}
+
+		rc = qedi_cm_alloc_mem(qedi);
+		if (rc) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "Could not alloc cm memory\n");
+			goto free_cid_que;
+		}
+
+		rc = qedi_alloc_itt(qedi);
+		if (rc) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "Could not alloc itt memory\n");
+			goto free_cid_que;
+		}
+
+		sprintf(host_buf, "host_%d", qedi->shost->host_no);
+		qedi->tmf_thread = create_singlethread_workqueue(host_buf);
+		if (!qedi->tmf_thread) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "Unable to start tmf thread!\n");
+			rc = -ENODEV;
+			goto free_cid_que;
+		}
+
+		sprintf(host_buf, "qedi_ofld%d", qedi->shost->host_no);
+		qedi->offload_thread = create_workqueue(host_buf);
+		if (!qedi->offload_thread) {
+			QEDI_ERR(&qedi->dbg_ctx,
+				 "Unable to start offload thread!\n");
+			rc = -ENODEV;
+			goto free_cid_que;
+		}
+
+		/* F/w needs 1st task context memory entry for performance */
+		set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map);
+		atomic_set(&qedi->num_offloads, 0);
+	}
+
+	return 0;
+
+free_cid_que:
+	qedi_release_cid_que(qedi);
+free_uio:
+	qedi_free_uio(qedi->udev);
+remove_host:
+#ifdef CONFIG_DEBUG_FS
+	qedi_dbg_host_exit(&qedi->dbg_ctx);
+#endif
+	iscsi_host_remove(qedi->shost);
+stop_iscsi_func:
+	qedi_ops->stop(qedi->cdev);
+stop_slowpath:
+	qedi_ops->common->slowpath_stop(qedi->cdev);
+stop_hw:
+	qedi_ops->common->remove(qedi->cdev);
+free_pf_params:
+	qedi_free_iscsi_pf_param(qedi);
+free_host:
+	iscsi_host_free(qedi->shost);
+exit_probe:
+	return rc;
+}
+
+static int qedi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	return __qedi_probe(pdev, QEDI_MODE_NORMAL);
+}
+
+static void qedi_remove(struct pci_dev *pdev)
+{
+	__qedi_remove(pdev, QEDI_MODE_NORMAL);
+}
+
+static struct pci_device_id qedi_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, 0x165E) },
+	{ 0 },
+};
+MODULE_DEVICE_TABLE(pci, qedi_pci_tbl);
+
+static struct pci_driver qedi_pci_driver = {
+	.name = QEDI_MODULE_NAME,
+	.id_table = qedi_pci_tbl,
+	.probe = qedi_probe,
+	.remove = qedi_remove,
+};
+
+static int __init qedi_init(void)
+{
+	int rc = 0;
+	int ret;
+	struct qedi_percpu_s *p;
+	unsigned int cpu = 0;
+
+	qedi_ops = qed_get_iscsi_ops();
+	if (!qedi_ops) {
+		QEDI_ERR(NULL, "Failed to get qed iSCSI operations\n");
+		rc = -EINVAL;
+		goto exit_qedi_init_0;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	qedi_dbg_init("qedi");
+#endif
+
+	register_hotcpu_notifier(&qedi_cpu_notifier);
+
+	ret = pci_register_driver(&qedi_pci_driver);
+	if (ret) {
+		QEDI_ERR(NULL, "Failed to register driver\n");
+		rc = -EINVAL;
+		goto exit_qedi_init_2;
+	}
+
+	for_each_possible_cpu(cpu) {
+		p = &per_cpu(qedi_percpu, cpu);
+		INIT_LIST_HEAD(&p->work_list);
+		spin_lock_init(&p->p_work_lock);
+		p->iothread = NULL;
+	}
+
+	for_each_online_cpu(cpu)
+		qedi_percpu_thread_create(cpu);
+
+	return rc;
+
+exit_qedi_init_2:
+exit_qedi_init_1:
+#ifdef CONFIG_DEBUG_FS
+	qedi_dbg_exit();
+#endif
+	qed_put_iscsi_ops();
+exit_qedi_init_0:
+	return rc;
+}
+
+static void __exit qedi_cleanup(void)
+{
+	unsigned int cpu = 0;
+
+	for_each_online_cpu(cpu)
+		qedi_percpu_thread_destroy(cpu);
+
+	pci_unregister_driver(&qedi_pci_driver);
+	unregister_hotcpu_notifier(&qedi_cpu_notifier);
+
+#ifdef CONFIG_DEBUG_FS
+	qedi_dbg_exit();
+#endif
+	qed_put_iscsi_ops();
+}
+
+MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx iSCSI Module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_VERSION(QEDI_MODULE_VERSION);
+module_init(qedi_init);
+module_exit(qedi_cleanup);
diff --git a/drivers/scsi/qedi/qedi_sysfs.c b/drivers/scsi/qedi/qedi_sysfs.c
new file mode 100644
index 0000000..a2cc3ed
--- /dev/null
+++ b/drivers/scsi/qedi/qedi_sysfs.c
@@ -0,0 +1,52 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available 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.
+ */
+
+#include "qedi.h"
+#include "qedi_gbl.h"
+#include "qedi_iscsi.h"
+#include "qedi_dbg.h"
+
+static inline struct qedi_ctx *qedi_dev_to_hba(struct device *dev)
+{
+	struct Scsi_Host *shost = class_to_shost(dev);
+
+	return iscsi_host_priv(shost);
+}
+
+static ssize_t qedi_show_port_state(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct qedi_ctx *qedi = qedi_dev_to_hba(dev);
+
+	if (atomic_read(&qedi->link_state) == QEDI_LINK_UP)
+		return sprintf(buf, "Online\n");
+	else
+		return sprintf(buf, "Linkdown\n");
+}
+
+static ssize_t qedi_show_speed(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct qedi_ctx *qedi = qedi_dev_to_hba(dev);
+	struct qed_link_output if_link;
+
+	qedi_ops->common->get_link(qedi->cdev, &if_link);
+
+	return sprintf(buf, "%d Gbit\n", if_link.speed / 1000);
+}
+
+static DEVICE_ATTR(port_state, S_IRUGO, qedi_show_port_state, NULL);
+static DEVICE_ATTR(speed, S_IRUGO, qedi_show_speed, NULL);
+
+struct device_attribute *qedi_shost_attrs[] = {
+	&dev_attr_port_state,
+	&dev_attr_speed,
+	NULL
+};
diff --git a/drivers/scsi/qedi/qedi_version.h b/drivers/scsi/qedi/qedi_version.h
new file mode 100644
index 0000000..9543a1b
--- /dev/null
+++ b/drivers/scsi/qedi/qedi_version.h
@@ -0,0 +1,14 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available 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.
+ */
+
+#define QEDI_MODULE_VERSION	"8.10.3.0"
+#define QEDI_DRIVER_MAJOR_VER		8
+#define QEDI_DRIVER_MINOR_VER		10
+#define QEDI_DRIVER_REV_VER		3
+#define QEDI_DRIVER_ENG_VER		0
-- 
1.8.3.1

^ permalink raw reply related

* Re: [PATCH] igmp: Make igmp group member RFC 3376 compliant
From: Michal Tesar @ 2016-11-08  9:26 UTC (permalink / raw)
  To: David Miller; +Cc: kuznet, jmorris, kaber, netdev
In-Reply-To: <20161107.201345.1974283028907025304.davem@davemloft.net>

On Mon, Nov 07, 2016 at 08:13:45PM -0500, David Miller wrote:

> From: Michal Tesar <mtesar@redhat.com>
> Date: Thu, 3 Nov 2016 10:38:34 +0100
> 
> >  2. If the received Query is a General Query, the interface timer is
> >     used to schedule a response to the General Query after the
> >     selected delay.  Any previously pending response to a General
> >     Query is canceled.
> > --8<--
> > 
> > Currently the timer is rearmed with new random expiration time for
> > every incoming query regardless of possibly already pending report.
> > Which is not aligned with the above RFE.
> 
> I don't read it that way.  #2 says if this is a general query then any
> pending response to a general query is cancelled.  And that's
> effectively what the code is doing right now.

Hi David,
I think that it is important to notice that the RFC says also 
that only the first matching rule is applied.

"
When new Query with the Router-Alert option arrives on an
interface, provided the system has state to report, a delay for a
response is randomly selected in the range (0, [Max Resp Time]) where
Max Resp Time is derived from Max Resp Code in the received Query
message.  The following rules are then used to determine if a Report
needs to be scheduled and the type of Report to schedule.  The rules
are considered in order and only the first matching rule is applied.

1. If there is a pending response to a previous General Query
scheduled sooner than the selected delay, no additional response
needs to be scheduled.

2. If the received Query is a General Query, the interface timer is
used to schedule a response to the General Query after the
selected delay.  Any previously pending response to a General
Query is canceled.
"

So I would read the above like below:
If some general query arrives and there is some
already pending response scheduled sooner,
no action is needed.
That is how I understand to the rule [1].

But when an general query arrives and there is some other
response already pending, but not sooner as rule one says but later,
new report should be scheduled and the already pending one
needs to be canceled.
That is how I understand to the rule [2]

If there is no already pending report scheduled
the first part of the rule [2] is applied
and new report is scheduled along the selected delay.

So basically we need to compare the already scheduled response exp time
with the one coming in and choose the sooner one.
This is exactly what the patch does.

What do you think?
Best regards Michal Tesar

^ 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